initial public commit

This commit is contained in:
Gani Georgiev
2022-07-07 00:19:05 +03:00
commit 3d07f0211d
484 changed files with 92412 additions and 0 deletions
@@ -0,0 +1,12 @@
<script>
import { SchemaField } from "pocketbase";
import Field from "@/components/base/Field.svelte";
export let field = new SchemaField();
export let value = false;
</script>
<Field class="form-field form-field-toggle {field.required ? 'required' : ''}" name={field.name} let:uniqueId>
<input type="checkbox" id={uniqueId} bind:checked={value} />
<label for={uniqueId}>{field.name}</label>
</Field>
@@ -0,0 +1,22 @@
<script>
import { SchemaField } from "pocketbase";
import Flatpickr from "svelte-flatpickr";
import CommonHelper from "@/utils/CommonHelper";
import Field from "@/components/base/Field.svelte";
export let field = new SchemaField();
export let value = undefined;
</script>
<Field class="form-field {field.required ? 'required' : ''}" name={field.name} let:uniqueId>
<label for={uniqueId}>
<i class={CommonHelper.getFieldTypeIcon(field.type)} />
<span class="txt">{field.name} (UTC)</span>
</label>
<Flatpickr
id={uniqueId}
options={CommonHelper.defaultFlatpickrOptions()}
{value}
bind:formattedValue={value}
/>
</Field>
@@ -0,0 +1,16 @@
<script>
import { SchemaField } from "pocketbase";
import CommonHelper from "@/utils/CommonHelper";
import Field from "@/components/base/Field.svelte";
export let field = new SchemaField();
export let value = undefined;
</script>
<Field class="form-field {field.required ? 'required' : ''}" name={field.name} let:uniqueId>
<label for={uniqueId}>
<i class={CommonHelper.getFieldTypeIcon(field.type)} />
<span class="txt">{field.name}</span>
</label>
<input type="email" id={uniqueId} required={field.required} bind:value />
</Field>
@@ -0,0 +1,177 @@
<script>
import { SchemaField } from "pocketbase";
import ApiClient from "@/utils/ApiClient";
import CommonHelper from "@/utils/CommonHelper";
import tooltip from "@/actions/tooltip";
import Field from "@/components/base/Field.svelte";
import UploadedFilePreview from "@/components/base/UploadedFilePreview.svelte";
import PreviewPopup from "@/components/base/PreviewPopup.svelte";
import RecordFilePreview from "@/components/records/RecordFilePreview.svelte";
export let record;
export let value = null;
export let uploadedFiles = []; // Array<File> array
export let deletedFileIndexes = []; // Array<int> array
export let field = new SchemaField();
let fileInput;
let previewPopup;
let filesListElem;
// normalize uploadedFiles type
$: if (!Array.isArray(uploadedFiles)) {
uploadedFiles = CommonHelper.toArray(uploadedFiles);
}
// normalize delited file indexes
$: if (!Array.isArray(deletedFileIndexes)) {
deletedFileIndexes = CommonHelper.toArray(deletedFileIndexes);
}
$: isMultiple = field.options?.maxSelect > 1;
$: if (typeof value === "undefined" || value === null) {
value = isMultiple ? [] : null;
}
$: valueAsArray = CommonHelper.toArray(value);
$: maxReached =
(valueAsArray.length || uploadedFiles.length) &&
field.options?.maxSelect <= valueAsArray.length + uploadedFiles.length - deletedFileIndexes.length;
$: if (uploadedFiles !== -1 || deletedFileIndexes !== -1) {
triggerListChange();
}
function restoreExistingFile(valueIndex) {
CommonHelper.removeByValue(deletedFileIndexes, valueIndex);
deletedFileIndexes = deletedFileIndexes;
}
function removeExistingFile(valueIndex) {
CommonHelper.pushUnique(deletedFileIndexes, valueIndex);
deletedFileIndexes = deletedFileIndexes;
}
function removeNewFile(index) {
if (!CommonHelper.isEmpty(uploadedFiles[index])) {
uploadedFiles.splice(index, 1);
}
uploadedFiles = uploadedFiles;
}
// emulate native change event
function triggerListChange() {
filesListElem?.dispatchEvent(
new CustomEvent("change", {
detail: { value, uploadedFiles, deletedFileIndexes },
bubbles: true,
})
);
}
</script>
<Field class="form-field form-field-file {field.required ? 'required' : ''}" name={field.name} let:uniqueId>
<label for={uniqueId}>
<i class={CommonHelper.getFieldTypeIcon(field.type)} />
<span class="txt">{field.name}</span>
</label>
<div bind:this={filesListElem} class="files-list">
{#each valueAsArray as filename, i (filename)}
<div class="list-item">
<figute
class="thumb"
class:fade={deletedFileIndexes.includes(i)}
class:link-fade={CommonHelper.hasImageExtension(filename)}
title={CommonHelper.hasImageExtension(filename) ? "Preview" : ""}
on:click={() =>
CommonHelper.hasImageExtension(filename)
? previewPopup?.show(ApiClient.Records.getFileUrl(record, filename))
: false}
>
<RecordFilePreview {record} {filename} />
</figute>
<a
href={ApiClient.Records.getFileUrl(record, filename)}
class="filename"
class:txt-strikethrough={deletedFileIndexes.includes(i)}
title={"Download " + filename}
target="_blank"
rel="noopener"
download
>
/.../{filename}
</a>
{#if deletedFileIndexes.includes(i)}
<button
type="button"
class="btn btn-sm btn-danger btn-secondary"
on:click={() => restoreExistingFile(i)}
>
<span class="txt">Restore</span>
</button>
{:else}
<button
type="button"
class="btn btn-secondary btn-sm btn-circle btn-remove txt-hint"
use:tooltip={"Remove file"}
on:click={() => removeExistingFile(i)}
>
<i class="ri-close-line" />
</button>
{/if}
</div>
{/each}
{#each uploadedFiles as file, i}
<div class="list-item">
<figute class="thumb">
<UploadedFilePreview {file} />
</figute>
<div class="filename" title={file.name}>
<small class="label label-success m-r-5">New</small>
<span class="txt">{file.name}</span>
</div>
<button
type="button"
class="btn btn-secondary btn-sm btn-circle btn-remove"
use:tooltip={"Remove file"}
on:click={() => removeNewFile(i)}
>
<i class="ri-close-line" />
</button>
</div>
{/each}
{#if !maxReached}
<div class="list-item btn-list-item">
<input
bind:this={fileInput}
type="file"
class="hidden"
multiple={isMultiple}
on:change={() => {
for (let file of fileInput.files) {
uploadedFiles.push(file);
}
uploadedFiles = uploadedFiles;
fileInput.value = null; // reset
}}
/>
<button
type="button"
class="btn btn-secondary btn-sm btn-block"
on:click={() => fileInput?.click()}
>
<i class="ri-upload-cloud-line" />
<span class="txt">Upload new file</span>
</button>
</div>
{/if}
</div>
</Field>
<PreviewPopup bind:this={previewPopup} />
@@ -0,0 +1,22 @@
<script>
import { SchemaField } from "pocketbase";
import CommonHelper from "@/utils/CommonHelper";
import Field from "@/components/base/Field.svelte";
export let field = new SchemaField();
export let value = undefined;
$: if (typeof value !== "undefined" && typeof value !== "string" && value !== null) {
// the JSON field support both js primitives and encoded JSON string
// so we are normalizing the value to only a string
value = JSON.stringify(value, null, 2);
}
</script>
<Field class="form-field {field.required ? 'required' : ''}" name={field.name} let:uniqueId>
<label for={uniqueId}>
<i class={CommonHelper.getFieldTypeIcon(field.type)} />
<span class="txt">{field.name}</span>
</label>
<textarea id={uniqueId} required={field.required} class="txt-mono txt-sm" bind:value />
</Field>
@@ -0,0 +1,23 @@
<script>
import { SchemaField } from "pocketbase";
import CommonHelper from "@/utils/CommonHelper";
import Field from "@/components/base/Field.svelte";
export let field = new SchemaField();
export let value = undefined;
</script>
<Field class="form-field {field.required ? 'required' : ''}" name={field.name} let:uniqueId>
<label for={uniqueId}>
<i class={CommonHelper.getFieldTypeIcon(field.type)} />
<span class="txt">{field.name}</span>
</label>
<input
type="number"
id={uniqueId}
required={field.required}
min={field.options?.min}
max={field.options?.max}
bind:value
/>
</Field>
@@ -0,0 +1,32 @@
<script>
import { SchemaField } from "pocketbase";
import CommonHelper from "@/utils/CommonHelper";
import RecordSelect from "@/components/records/RecordSelect.svelte";
import Field from "@/components/base/Field.svelte";
export let field = new SchemaField();
export let value = undefined;
$: isMultiple = field.options?.maxSelect > 1;
$: if (isMultiple && Array.isArray(value) && value.length > field.options.maxSelect) {
value = value.slice(field.options.maxSelect - 1);
}
</script>
<Field class="form-field {field.required ? 'required' : ''}" name={field.name} let:uniqueId>
<label for={uniqueId}>
<i class={CommonHelper.getFieldTypeIcon(field.type)} />
<span class="txt">{field.name}</span>
</label>
<RecordSelect
toggle
id={uniqueId}
multiple={isMultiple}
collectionId={field.options?.collectionId}
bind:keyOfSelected={value}
/>
{#if field.options?.maxSelect > 1}
<div class="help-block">Select up to {field.options.maxSelect} items.</div>
{/if}
</Field>
@@ -0,0 +1,37 @@
<script>
import { SchemaField } from "pocketbase";
import CommonHelper from "@/utils/CommonHelper";
import Select from "@/components/base/Select.svelte";
import Field from "@/components/base/Field.svelte";
export let field = new SchemaField();
export let value = undefined;
$: isMultiple = field.options?.maxSelect > 1;
$: if (typeof value === "undefined") {
value = isMultiple ? [] : null;
}
$: if (isMultiple && Array.isArray(value) && value.length > field.options.maxSelect) {
value = value.slice(value.length - field.options.maxSelect);
}
</script>
<Field class="form-field {field.required ? 'required' : ''}" name={field.name} let:uniqueId>
<label for={uniqueId}>
<i class={CommonHelper.getFieldTypeIcon(field.type)} />
<span class="txt">{field.name}</span>
</label>
<Select
id={uniqueId}
toggle={!field.required || isMultiple}
multiple={isMultiple}
items={field.options?.values}
searchable={field.options?.values > 5}
bind:selected={value}
/>
{#if field.options?.maxSelect > 1}
<div class="help-block">Select up to {field.options.maxSelect} items.</div>
{/if}
</Field>
@@ -0,0 +1,17 @@
<script>
import { SchemaField } from "pocketbase";
import CommonHelper from "@/utils/CommonHelper";
import Field from "@/components/base/Field.svelte";
import AutoExpandTextarea from "@/components/base/AutoExpandTextarea.svelte";
export let field = new SchemaField();
export let value = undefined;
</script>
<Field class="form-field {field.required ? 'required' : ''}" name={field.name} let:uniqueId>
<label for={uniqueId}>
<i class={CommonHelper.getFieldTypeIcon(field.type)} />
<span class="txt">{field.name}</span>
</label>
<AutoExpandTextarea id={uniqueId} required={field.required} bind:value />
</Field>
@@ -0,0 +1,16 @@
<script>
import { SchemaField } from "pocketbase";
import CommonHelper from "@/utils/CommonHelper";
import Field from "@/components/base/Field.svelte";
export let field = new SchemaField();
export let value = undefined;
</script>
<Field class="form-field {field.required ? 'required' : ''}" name={field.name} let:uniqueId>
<label for={uniqueId}>
<i class={CommonHelper.getFieldTypeIcon(field.type)} />
<span class="txt">{field.name}</span>
</label>
<input type="url" id={uniqueId} required={field.required} bind:value />
</Field>
@@ -0,0 +1,33 @@
<script>
import { SchemaField } from "pocketbase";
import CommonHelper from "@/utils/CommonHelper";
import UserSelect from "@/components/users/UserSelect.svelte";
import Field from "@/components/base/Field.svelte";
export let field = new SchemaField();
export let value = undefined;
// to prevent accidental changes, disable editing system user field values from the UI
$: isDisabled = !CommonHelper.isEmpty(value) && field.system;
$: isMultiple = field.options?.maxSelect > 1;
$: if (isMultiple && Array.isArray(value) && value.length > field.options.maxSelect) {
value = value.slice(field.options.maxSelect - 1);
}
</script>
<Field
class="form-field {field.required ? 'required' : ''} {isDisabled ? 'disabled' : ''}"
name={field.name}
let:uniqueId
>
<label for={uniqueId}>
<i class={CommonHelper.getFieldTypeIcon(field.type)} />
<span class="txt">{field.name}</span>
</label>
<UserSelect toggle id={uniqueId} multiple={isMultiple} disabled={isDisabled} bind:keyOfSelected={value} />
{#if field.options?.maxSelect > 1}
<div class="help-block">Select up to {field.options.maxSelect} users.</div>
{/if}
</Field>