diff options
| author | ivarlovlie <git@ivarlovlie.no> | 2022-12-09 03:57:12 +0100 |
|---|---|---|
| committer | ivarlovlie <git@ivarlovlie.no> | 2022-12-09 03:57:12 +0100 |
| commit | 4dbef3fcd7a14437d55c555cf10d50de8e50d7d1 (patch) | |
| tree | 632589ecfcfb4dfddeafb71d0077257584b5e7ec /code/app/src/lib/components | |
| parent | 914c75e0ceeb3e11ddd55e94bb461c26b0db5b7a (diff) | |
| download | greatoffice-4dbef3fcd7a14437d55c555cf10d50de8e50d7d1.tar.xz greatoffice-4dbef3fcd7a14437d55c555cf10d50de8e50d7d1.zip | |
feat: Move everything out of $lib
Diffstat (limited to 'code/app/src/lib/components')
34 files changed, 0 insertions, 1691 deletions
diff --git a/code/app/src/lib/components/alert.svelte b/code/app/src/lib/components/alert.svelte deleted file mode 100644 index fd57105..0000000 --- a/code/app/src/lib/components/alert.svelte +++ /dev/null @@ -1,268 +0,0 @@ -<script lang="ts"> - import { random_string } from "$lib/helpers"; - import { createEventDispatcher } from "svelte"; - import { onMount } from "svelte"; - import pwKey from "$actions/pwKey"; - import { Temporal } from "temporal-polyfill"; - import { ExclamationTriangleIcon, CheckCircleIcon, InformationCircleIcon, XCircleIcon, XMarkIcon } from "./icons"; - - const dispatch = createEventDispatcher(); - const noCooldownSetting = "no-cooldown"; - - let iconComponent: any; - let colorClassPart = ""; - - /** - * An optional id for this alert, a default is set if not specified. - * This value is necessary for closeable cooldown to work. - */ - // if no unique id is supplied, cooldown will not work between page loads. - // Therefore we are disabling it with noCooldownSetting in the fallback id. - export let id = "alert--" + noCooldownSetting + "--" + random_string(4); - /** - * The title to communicate, value is optional - */ - export let title = ""; - /** - * The message to communicate, value is optional - */ - export let message = ""; - /** - * Changes the alerts color and icon. - */ - export let type: "info" | "success" | "warning" | "error" = "info"; - /** - * If true the alert can be removed from the DOM by clicking on a X icon on the upper right hand courner - */ - export let closeable = false; - /** - * The amount of seconds that should go by before this alert is shown again, only works when a unique id is set. - * Set to ~ if it should only be shown once per client (State stored in localestorage). - **/ - export let closeableCooldown = "-1"; - /** - * The text that is displayed on the right link - */ - export let rightLinkText = ""; - /** - * An array of list items displayed under the message or title - */ - export let listItems: Array<string> = []; - /** - * An array of {id:string;text:string;color?:string}, where id is dispatched back as an svelte event with this syntax act$id (ex: on:actcancel). - * Text is the button text - * Color is the optional tailwind color to used, the value is used in classes like bg-$color-50. - */ - export let actions: Array<{ id: string; text: string; color?: string }> = []; - /** - * This value is set on a plain anchor tag without any svelte routing, - * listen to the on:rightLinkClick if you want to intercept the click without navigating - */ - export let rightLinkHref = "javascript:void(0)"; - $: cooldownEnabled = - id.indexOf(noCooldownSetting) === -1 && closeable && (closeableCooldown === "~" || parseInt(closeableCooldown) > 0); - /** - * Sets this alerts visibility state, when this is false it is removed from the dom using an {#if} block. - */ - export let visible = closeableCooldown === "~" || parseInt(closeableCooldown) > 0 ? false : true; - - export let _pwKey: string | undefined = undefined; - - const cooldownStorageKey = "lastseen--" + id; - - $: switch (type) { - case "info": { - colorClassPart = "blue"; - iconComponent = InformationCircleIcon; - break; - } - case "warning": { - colorClassPart = "yellow"; - iconComponent = ExclamationTriangleIcon; - break; - } - case "error": { - colorClassPart = "red"; - iconComponent = XCircleIcon; - break; - } - case "success": { - colorClassPart = "green"; - iconComponent = CheckCircleIcon; - break; - } - } - - function close() { - visible = false; - if (cooldownEnabled) { - console.log("Cooldown enabled for " + id + ", " + closeableCooldown === "~" ? "with an endless cooldown" : ""); - localStorage.setItem(cooldownStorageKey, String(Temporal.Now.instant().epochSeconds)); - } - } - - function rightLinkClicked() { - dispatch("rightLinkCliked"); - } - - function actionClicked(name: string) { - dispatch("act" + name); - } - - // Manages the state of the alert if cooldown is enabled - function run_cooldown() { - if (!cooldownEnabled) { - console.log("Alert cooldown is not enabled for " + id); - return; - } - if (!localStorage.getItem(cooldownStorageKey)) { - console.log("Alert " + id + " has not been seen yet, displaying"); - visible = true; - return; - } - // if (!visible) { - // console.log( - // "Alert " + id + " is not visible, stopping cooldown change" - // ); - // return; - // } - if (closeableCooldown === "~") { - console.log("Alert " + id + " has an infinite cooldown, hiding"); - visible = false; - return; - } - - const lastSeen = Temporal.Instant.fromEpochSeconds(parseInt(localStorage.getItem(cooldownStorageKey) ?? "-1")); - if (Temporal.Instant.compare(Temporal.Now.instant(), lastSeen.add({ seconds: parseInt(closeableCooldown) })) === 1) { - console.log( - "Alert " + - id + - " has a cooldown of " + - closeableCooldown + - " and was last seen " + - lastSeen.toLocaleString() + - " making it due for a showing" - ); - visible = true; - } else { - visible = false; - } - } - - onMount(() => { - if (cooldownEnabled) { - run_cooldown(); - } - - if (closeable && closeableCooldown && id.indexOf(noCooldownSetting) !== -1) { - // TODO: This prints twice before shutting up as it should, in this example look at the only alert with closeableCooldown in alertsbook. - // Looks like svelte mounts three times and that my id is only set on the third. Not sure it does at all after logging the id onMount. - console.error("Alert cooldown does not work without specifying a unique id, related id: " + id); - } - }); -</script> - -{#if visible} - <div class="rounded-md bg-{colorClassPart}-50 p-4 {$$restProps.class ?? ''}" use:pwKey={_pwKey}> - <div class="flex"> - <div class="flex-shrink-0"> - <svelte:component this={iconComponent} class="text-{colorClassPart}-400" /> - </div> - <div class="ml-3 text-sm w-full"> - {#if !rightLinkText} - {#if title} - <h3 class="font-medium text-{colorClassPart}-800"> - {title} - </h3> - {/if} - {#if message} - <div class="{title ? 'mt-2' : ''} text-{colorClassPart}-700 justify-start"> - <p> - {@html message} - </p> - </div> - {/if} - {#if listItems?.length ?? 0} - <ul class="list-disc space-y-1 pl-5 text-{colorClassPart}-700"> - {#each listItems as listItem} - <li>{listItem}</li> - {/each} - </ul> - {/if} - {:else} - <div class="flex-1 md:flex md:justify-between"> - <div> - {#if title} - <h3 class="font-medium text-{colorClassPart}-800"> - {title} - </h3> - {/if} - {#if message} - <div class="{title ? 'mt-2' : ''} text-{colorClassPart}-700 justify-start"> - <p> - {@html message} - </p> - </div> - {/if} - {#if listItems?.length ?? 0} - <ul class="list-disc space-y-1 pl-5 text-{colorClassPart}-700"> - {#each listItems as listItem} - <li>{listItem}</li> - {/each} - </ul> - {/if} - </div> - <p class="mt-3 text-sm md:mt-0 md:ml-6 flex items-end"> - <a - href={rightLinkHref} - on:click={() => rightLinkClicked()} - class="whitespace-nowrap font-medium text-{colorClassPart}-700 hover:text-{colorClassPart}-600" - > - {rightLinkText} - <span aria-hidden="true"> →</span> - </a> - </p> - </div> - {/if} - {#if actions?.length ?? 0} - <div class="ml-2 mt-4"> - <div class="-mx-2 -my-1.5 flex gap-1"> - {#each actions as action} - {@const color = action?.color ?? colorClassPart} - <button - type="button" - on:click={() => actionClicked(action.id)} - class="rounded-md - bg-{color}-50 - px-2 py-1.5 text-sm font-medium - text-{color}-800 - hover:bg-{color}-100 - focus:outline-none focus:ring-2 - focus:ring-{color}-600 - focus:ring-offset-2 - focus:ring-offset-{color}-50" - > - {action.text} - </button> - {/each} - </div> - </div> - {/if} - </div> - {#if closeable} - <div class="ml-auto pl-3"> - <div class="-mx-1.5 -my-1.5"> - <button - type="button" - on:click={() => close()} - class="inline-flex rounded-md bg-{colorClassPart}-50 p-1.5 text-{colorClassPart}-500 hover:bg-{colorClassPart}-100 focus:outline-none focus:ring-2 focus:ring-{colorClassPart}-600 focus:ring-offset-2 focus:ring-offset-{colorClassPart}-50" - > - <span class="sr-only">Dismiss</span> - <XMarkIcon /> - </button> - </div> - </div> - {/if} - </div> - </div> -{/if} diff --git a/code/app/src/lib/components/badge.svelte b/code/app/src/lib/components/badge.svelte deleted file mode 100644 index 6ec48d5..0000000 --- a/code/app/src/lib/components/badge.svelte +++ /dev/null @@ -1,76 +0,0 @@ -<script lang="ts"> - import { createEventDispatcher } from "svelte"; - - export let id: string | undefined = undefined; - export let type: "default" | "red" | "yellow" | "green" | "blue" | "tame" = "default"; - export let text: string; - export let size: "large" | "default" = "default"; - export let withDot: boolean = false; - export let removable: boolean = false; - export let uppercase: boolean = false; - export let tabindex: string | undefined = undefined; - - let colorName = "gray"; - let sizeClass = "rounded px-2 py-0.5 text-xs"; - let dotSizeClass = "mr-1.5 h-2 w-2"; - - const dispatch = createEventDispatcher(); - - function handle_remove(event) { - dispatch("remove", { event, id, text }); - } - - $: switch (type) { - case "red": - colorName = "red"; - break; - case "yellow": - colorName = "yellow"; - break; - case "blue": - colorName = "blue"; - break; - case "green": - colorName = "teal"; - break; - case "default": - case "tame": - default: - colorName = "gray"; - break; - } - - $: switch (size) { - case "large": - sizeClass = "rounded-md px-2.5 py-0.5 text-sm"; - dotSizeClass = "-ml-0.5 mr-1.5 h-2 w-2"; - break; - case "default": - default: - sizeClass = "rounded px-2 py-0.5 text-xs"; - dotSizeClass = "mr-1.5 h-2 w-2"; - break; - } -</script> - -<span class="inline-flex items-center font-medium {uppercase ? 'uppercase' : ''} bg-{colorName}-100 text-{colorName}-800 {sizeClass}" {id}> - {#if withDot} - <svg class="{dotSizeClass} text-{colorName}-400" fill="currentColor" viewBox="0 0 8 8"> - <circle cx="4" cy="4" r="3" /> - </svg> - {/if} - {text} - {#if removable} - <button - on:click={handle_remove} - tabindex={parseInt(tabindex)} - type="button" - class="ml-0.5 inline-flex h-4 w-4 flex-shrink-0 items-center justify-center rounded-full text-{colorName}-400 hover:bg-{colorName}-200 hover:text-{colorName}-500 focus:bg-{colorName}-500 focus:text-white focus:outline-none" - > - <span class="sr-only">Remove badge</span> - <svg class="h-2 w-2" stroke="currentColor" fill="none" viewBox="0 0 8 8"> - <path stroke-linecap="round" stroke-width="1.5" d="M1 1l6 6m0-6L1 7" /> - </svg> - </button> - {/if} -</span> diff --git a/code/app/src/lib/components/button.svelte b/code/app/src/lib/components/button.svelte deleted file mode 100644 index 49a9354..0000000 --- a/code/app/src/lib/components/button.svelte +++ /dev/null @@ -1,115 +0,0 @@ -<script context="module" lang="ts"> - export type ButtonKind = "primary" | "secondary" | "white" | "reset"; - export type ButtonSize = "sm" | "lg" | "md" | "xl"; -</script> - -<script lang="ts"> - import pwKey from "$actions/pwKey"; - import { SpinnerIcon } from "./icons"; - - export let kind = "primary" as ButtonKind; - export let size = "md" as ButtonSize; - export let type: "button" | "submit" | "reset" = "button"; - export let id: string | undefined = undefined; - export let tabindex: string | undefined = undefined; - export let style: string | undefined = undefined; - export let title: string | undefined = undefined; - export let disabled: boolean | null = false; - export let href: string | undefined = undefined; - export let text: string; - export let loading = false; - export let fullWidth = false; - export let _pwKey: string | undefined = undefined; - - let sizeClasses = ""; - let kindClasses = ""; - let spinnerTextClasses = ""; - let spinnerMarginClasses = ""; - - $: shared_props = { - type: type, - id: id || null, - title: title || null, - disabled: disabled || loading || null, - tabindex: tabindex || null, - style: style || null, - } as any; - - $: switch (size) { - case "sm": - sizeClasses = "px-2.5 py-1.5 text-xs"; - spinnerMarginClasses = "mr-2"; - break; - case "md": - sizeClasses = "px-3 py-2 text-sm"; - spinnerMarginClasses = "mr-2"; - break; - case "lg": - sizeClasses = "px-3 py-2 text-lg"; - spinnerMarginClasses = "mr-2"; - break; - case "xl": - sizeClasses = "px-6 py-3 text-xl"; - spinnerMarginClasses = "mr-2"; - break; - } - - $: switch (kind) { - case "secondary": - kindClasses = "border-transparent text-teal-800 bg-teal-100 hover:bg-teal-200 focus:ring-teal-500"; - spinnerTextClasses = "teal-800"; - break; - case "primary": - kindClasses = "border-transparent text-teal-900 bg-teal-300 hover:bg-teal-400 focus:ring-teal-500"; - spinnerTextClasses = "text-teal-900"; - break; - case "white": - kindClasses = "border-gray-300 text-gray-700 bg-white hover:bg-gray-50 focus:ring-gray-400"; - spinnerTextClasses = "text-gray-700"; - break; - case "reset": - kindClasses = "reset outline-none ring-0 focus:ring-0 focus-visible:ring-0"; - break; - } -</script> - -{#if href} - <a - use:pwKey={_pwKey} - {...shared_props} - {href} - class="{sizeClasses} {kindClasses} {loading ? 'disabled:' : ''} {$$restProps.class ?? ''} {fullWidth - ? 'w-full justify-center' - : ''} inline-flex items-center border font-medium rounded shadow-sm focus:outline-none focus:ring-2" - > - {#if loading} - <SpinnerIcon class={spinnerTextClasses + " " + spinnerMarginClasses} /> - {/if} - {text} - </a> -{:else} - <button - use:pwKey={_pwKey} - {...shared_props} - on:click - class="btn {sizeClasses} {kindClasses} {$$restProps.class ?? ''} - {fullWidth - ? 'w-full justify-center' - : ''} inline-flex items-center border font-medium rounded shadow-sm focus:outline-none focus:ring-2" - > - {#if loading} - <SpinnerIcon class={spinnerTextClasses + " " + spinnerMarginClasses} /> - {/if} - {text} - </button> -{/if} - -<style> - .reset { - border: 0px; - outline: none; - } - .reset:focus { - outline: none; - } -</style> diff --git a/code/app/src/lib/components/checkbox.svelte b/code/app/src/lib/components/checkbox.svelte deleted file mode 100644 index 12ebedb..0000000 --- a/code/app/src/lib/components/checkbox.svelte +++ /dev/null @@ -1,29 +0,0 @@ -<script lang="ts"> - import pwKey from "$actions/pwKey"; - import { random_string } from "$lib/helpers"; - - export let label: string; - export let id: string | undefined = "input__" + random_string(4); - export let name: string | undefined = undefined; - export let disabled: boolean | null = null; - export let checked: boolean; - export let required: boolean | null = null; - export let _pwKey: string | undefined = undefined; -</script> - -<div class="flex items-center"> - <input - {name} - use:pwKey={_pwKey} - {disabled} - {id} - {required} - type="checkbox" - bind:checked - class="h-4 w-4 text-teal-600 focus:ring-teal-500 border-gray-300 rounded" - /> - <label for={id} class="ml-2 block text-sm text-gray-900"> - {@html required ? "<span class='text-red-500'>*</span>" : ""} - {label} - </label> -</div> diff --git a/code/app/src/lib/components/combobox.svelte b/code/app/src/lib/components/combobox.svelte deleted file mode 100644 index 4e7b1cd..0000000 --- a/code/app/src/lib/components/combobox.svelte +++ /dev/null @@ -1,450 +0,0 @@ -<script lang="ts" context="module"> - export type ComboboxOption = { - id: string; - name: string; - selected?: boolean; - }; -</script> - -<script lang="ts"> - import { CheckCircleIcon, ChevronUpDownIcon, XIcon } from "./icons"; - import { element_has_focus, random_string } from "$lib/helpers"; - import { go, highlight } from "fuzzysort"; - import Badge from "./badge.svelte"; - import Button from "./button.svelte"; - import LL from "$lib/i18n/i18n-svelte"; - - export let id = "combobox-" + random_string(3); - export let label: string | undefined = undefined; - export let errorText: string | undefined = undefined; - export let disabled: boolean | undefined = undefined; - export let required: boolean | undefined = undefined; - export let maxlength: number | undefined = undefined; - export let placeholder: string = $LL.combobox.search(); - export let options: Array<ComboboxOption> | undefined = []; - export let createable = false; - export let loading = false; - export let multiple = false; - export let noResultsText: string = $LL.combobox.noRecordsFound(); - export let on_create_async = async ({ name: string }) => {}; - - export const reset = () => methods.reset(); - export const select = (id: string) => methods.select_entry(id); - export const deselect = (id: string) => methods.deselect_entry(id); - - const INTERNAL_ID = "INTERNAL__" + id; - - let optionsListId = id + "--options"; - let searchInputNode; - let searchResults: Array<any> = []; - let searchValue = ""; - let showCreationHint = false; - let showDropdown = false; - let inputHasFocus = false; - let lastKeydownCode = ""; - let mouseIsOverDropdown = false; - let mouseIsOverComponent = false; - - $: ariaErrorDescribedBy = id + "__" + "error"; - $: colorName = errorText ? "red" : "teal"; - $: attributes = { - "aria-describedby": errorText ? ariaErrorDescribedBy : null, - "aria-invalid": errorText ? "true" : null, - disabled: disabled || null, - required: required || null, - maxlength: maxlength || null, - id: id || null, - placeholder: placeholder || null, - } as any; - $: hasSelection = options.some((c) => c.selected === true); - $: if (searchValue.trim()) { - showCreationHint = createable && options.every((c) => search.normalise_value(c.name) !== search.normalise_value(searchValue)); - } else { - showCreationHint = false; - options = methods.get_sorted_array(options); - } - - function on_select(event) { - const node = event.target.closest("[data-id]"); - if (!node) return; - methods.select_entry(node.dataset.id); - } - - const search = { - normalise_value(value: string): string { - if (!value) { - return ""; - } - return value.trim().toLowerCase(); - }, - do() { - const query = search.normalise_value(searchValue); - - if (!query.trim()) { - searchResults = []; - return; - } - - // @ts-ignore - searchResults = go(query, options, { - limit: 15, - allowTypo: true, - threshold: -10000, - key: "name", - }); - showDropdown = true; - }, - on_input_focus() { - showDropdown = true; - inputHasFocus = true; - }, - on_input_click() { - showDropdown = true; - inputHasFocus = true; - }, - on_input_focusout() { - inputHasFocus = false; - if (lastKeydownCode !== "Tab" && (mouseIsOverDropdown || lastKeydownCode === "ArrowDown")) { - return; - } - const selected = options.find((c) => c.selected === true); - if (selected && !multiple) { - searchValue = selected.name; - } - document.querySelector("#" + INTERNAL_ID + " ul li.focus")?.classList.remove("focus"); - showDropdown = false; - }, - on_input_wrapper_focus(event) { - if (event.code && event.code !== "Space" && event.code !== "Enter") return; - if (!element_has_focus(searchInputNode)) searchInputNode.focus(); - showDropdown = true; - }, - }; - - const methods = { - reset(focus_input = false) { - searchValue = ""; - const copy = options; - for (const entry of copy) { - entry.selected = false; - } - options = methods.get_sorted_array(copy); - if (focus_input) { - searchInputNode?.focus(); - showDropdown = true; - } else { - showDropdown = false; - } - }, - async create_entry(name: string) { - if (!name || !createable || loading) { - console.log("Not sending creation event due to failed preconditions", { name, createable, loading }); - return; - } - try { - await on_create_async({ name }); - searchValue = ""; - loading = false; - } catch (e) { - console.error(e); - } - }, - select_entry(entryId: string) { - if (!entryId || loading) { - console.log("Not selecting entry due to failed preconditions", { - entryId, - loading, - }); - return; - } - - const copy = options; - for (const entry of options) { - if (entry.id === entryId) { - entry.selected = true; - if (multiple) { - searchValue = ""; - } else { - searchValue = entry.name; - } - } else if (!multiple) { - entry.selected = false; - } - } - options = methods.get_sorted_array(copy); - searchInputNode?.focus(); - searchResults = []; - }, - deselect_entry(entryId: string) { - if (!entryId || loading) { - console.log("Not deselecting entry due to failed preconditions", { - entryId, - loading, - }); - return; - } - console.log("Deselecting entry", entryId); - - const copy = options; - - for (const entry of copy) { - if (entry.id === entryId) { - entry.selected = false; - } - } - - options = methods.get_sorted_array(copy); - searchInputNode?.focus(); - }, - get_sorted_array(options: Array<ComboboxOption>): Array<ComboboxOption> { - if (!options) { - return; - } - if (options.length < 1) { - return []; - } - if (searchValue) { - return options; - } - - return options.sort((a, b) => search.normalise_value(a.name).localeCompare(search.normalise_value(b.name))); - }, - }; - - const windowEvents = { - on_mousemove(event: any) { - if (!event.target) return; - mouseIsOverDropdown = event.target?.closest("#" + INTERNAL_ID + " .tongue") != null ?? false; - mouseIsOverComponent = event.target?.closest("#" + INTERNAL_ID) != null ?? false; - }, - on_click() { - if (showDropdown && !mouseIsOverDropdown && !mouseIsOverComponent) { - showDropdown = false; - } - }, - on_keydown(event: any) { - lastKeydownCode = event.code; - const enterPressed = event.code === "Enter"; - const backspacePressed = event.code === "Backspace"; - const arrowUpPressed = event.code === "ArrowUp"; - const spacePressed = event.code === "Space"; - const arrowDownPressed = event.code === "ArrowDown"; - const searchInputHasFocus = element_has_focus(searchInputNode); - const focusedEntry = document.querySelector("#" + INTERNAL_ID + " ul li.focus") as HTMLLIElement; - - if (showDropdown && (enterPressed || arrowDownPressed || arrowUpPressed)) { - event.preventDefault(); - } - - if (searchInputHasFocus && backspacePressed && !searchValue && options.length > 0) { - if (options.filter((c) => c.selected === true).at(-1)?.id ?? false) { - methods.deselect_entry(options.filter((c) => c.selected === true).at(-1)?.id ?? ""); - } - return; - } - - if (searchInputHasFocus && enterPressed && showCreationHint) { - methods.create_entry(searchValue.trim()); - return; - } - - if (searchInputHasFocus && !focusedEntry && arrowDownPressed) { - const firstEntry = document.querySelector("#" + INTERNAL_ID + " ul li:first-of-type"); - if (firstEntry) { - firstEntry.classList.add("focus"); - return; - } - } - - if (focusedEntry && (arrowUpPressed || arrowDownPressed)) { - if (arrowDownPressed) { - if (focusedEntry.nextElementSibling) { - focusedEntry.nextElementSibling.classList.add("focus"); - focusedEntry.nextElementSibling.scrollIntoView(false); - } else { - const firstLIEl = document.querySelector("#" + INTERNAL_ID + " ul li:first-of-type"); - firstLIEl.classList.add("focus"); - firstLIEl.scrollIntoView(false); - } - } else if (arrowUpPressed) { - if (focusedEntry.previousElementSibling) { - focusedEntry.previousElementSibling.classList.add("focus"); - focusedEntry.previousElementSibling.scrollIntoView(false); - } else { - const lastLIEl = document.querySelector("#" + INTERNAL_ID + " ul li:last-of-type"); - lastLIEl.classList.add("focus"); - lastLIEl.scrollIntoView(false); - } - } - focusedEntry.classList.remove("focus"); - return; - } - - if (focusedEntry && (spacePressed || enterPressed)) { - methods.select_entry(focusedEntry.dataset.id); - return; - } - - if (lastKeydownCode === "Tab" && !searchInputHasFocus) { - showDropdown = false; - } - }, - on_touchend(event) { - windowEvents.on_mousemove(event); - }, - }; -</script> - -<svelte:window - on:keydown={windowEvents.on_keydown} - on:mousemove={windowEvents.on_mousemove} - on:touchend={windowEvents.on_touchend} - on:click={windowEvents.on_click} -/> - -<div id={INTERNAL_ID} class:cursor-wait={loading}> - {#if label} - <label for={id} class="block text-sm font-medium text-gray-700"> - {label} - {@html required ? "<span class='text-red-500'>*</span>" : ""} - </label> - {/if} - <div class="relative {label ? 'mt-1' : ''}"> - <div - on:click={search.on_input_wrapper_focus} - on:keypress={search.on_input_wrapper_focus} - class="cursor-text w-full flex rounded-md border bg-white py-2 pl-3 pr-12 sm:text-sm - {inputHasFocus ? `border-${colorName}-500 outline-none ring-1 ring-${colorName}-500` : 'shadow-sm border-gray-300'}" - > - {#if multiple === true && hasSelection} - <div class="flex gap-1 flex-wrap"> - {#each options.filter((c) => c.selected === true) as option} - <Badge - id={option.id} - removable - tabindex="-1" - on:remove={(e) => methods.deselect_entry(e.detail.id)} - text={option.name} - /> - {/each} - </div> - {/if} - <div> - <input - {...attributes} - type="text" - style="all: unset;" - role="combobox" - aria-controls={optionsListId} - aria-expanded={showDropdown} - bind:value={searchValue} - bind:this={searchInputNode} - on:input={() => search.do()} - on:click={search.on_input_click} - on:focus={search.on_input_focus} - on:blur={search.on_input_focusout} - autocomplete="off" - /> - {#if hasSelection} - <button - type="button" - on:click={() => reset()} - title={$LL.reset()} - tabindex="-1" - class="text-gray-400 absolute cursor-pointer inset-y-0 right-0 flex items-center rounded-r-md px-2" - > - <XIcon /> - </button> - {:else} - <span tabindex="-1" class="text-gray-400 absolute inset-y-0 right-0 flex items-center rounded-r-md px-2"> - <ChevronUpDownIcon /> - </span> - {/if} - </div> - </div> - {#if errorText} - <p class="mt-2 text-sm text-red-600" id={ariaErrorDescribedBy}> - {errorText} - </p> - {/if} - <div - class="tongue {showDropdown ? 'absolute' : 'hidden'} - z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white - text-base shadow-lg ring-1 ring-teal ring-opacity-5 focus:outline-none sm:text-sm" - > - <ul id={optionsListId} role="listbox" tabindex="-1"> - {#if searchResults.length > 0} - {#each searchResults.filter((c) => !c.selected) as result} - <li - class="item" - data-id={result.obj.id} - aria-selected={result.obj.selected} - role="option" - on:click={on_select} - on:keypress={on_select} - tabindex="-1" - > - {@html highlight(result, '<span class="font-bold">', "</span>")} - </li> - {/each} - {:else if options.length > 0} - {#each options as option} - <!-- - Combobox option, manage highlight styles based on mouseenter/mouseleave and keyboard navigation. - Active: "text-white bg-indigo-600", Not Active: "text-gray-900" - --> - <li - class="item" - aria-selected={option.selected} - role="option" - data-id={option.id} - on:click={on_select} - on:keypress={on_select} - tabindex="-1" - > - <span class="block truncate {option.selected ? 'text-semibold' : ''}">{option.name}</span> - {#if option.selected} - <span class="absolute inset-y-0 right-0 flex items-center pr-4 text-{colorName}-600"> - <CheckCircleIcon /> - </span> - {/if} - </li> - {/each} - {:else} - <slot name="no-records"> - <p class="px-2">{noResultsText}</p> - {#if createable && !searchValue} - <p class="px-2 text-gray-500">{$LL.combobox.createRecordHelpText()}</p> - {/if} - </slot> - {/if} - </ul> - {#if showCreationHint} - <div class="sticky bottom-0 w-full bg-white"> - <Button - text={$LL.combobox.createRecordButtonText(searchValue.trim())} - title={$LL.combobox.createRecordButtonText(searchValue.trim())} - {loading} - kind="reset" - type="button" - on:click={() => methods.create_entry(searchValue.trim())} - /> - </div> - {/if} - </div> - </div> -</div> - -<style lang="postcss"> - .focus { - @apply text-white bg-teal-300; - } - - .item { - @apply relative cursor-pointer select-none py-2 pl-3 pr-9 text-gray-900; - } - - .item[aria-selected="true"] { - @apply bg-teal-200; - } -</style> diff --git a/code/app/src/lib/components/icons/adjustments.svelte b/code/app/src/lib/components/icons/adjustments.svelte deleted file mode 100644 index 83bda27..0000000 --- a/code/app/src/lib/components/icons/adjustments.svelte +++ /dev/null @@ -1,14 +0,0 @@ -<svg - xmlns="http://www.w3.org/2000/svg" - class="h-6 w-6 {$$restProps.class ?? ''}" - fill="none" - viewBox="0 0 24 24" - stroke="currentColor" - stroke-width="2" -> - <path - stroke-linecap="round" - stroke-linejoin="round" - d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4" - /> -</svg> diff --git a/code/app/src/lib/components/icons/bars-3-center-left.svelte b/code/app/src/lib/components/icons/bars-3-center-left.svelte deleted file mode 100644 index 785ece3..0000000 --- a/code/app/src/lib/components/icons/bars-3-center-left.svelte +++ /dev/null @@ -1,15 +0,0 @@ -<svg - class="h-6 w-6 {$$restProps.class ?? ''}" - xmlns="http://www.w3.org/2000/svg" - fill="none" - viewBox="0 0 24 24" - stroke-width="1.5" - stroke="currentColor" - aria-hidden="true" -> - <path - stroke-linecap="round" - stroke-linejoin="round" - d="M3.75 6.75h16.5M3.75 12H12m-8.25 5.25h16.5" - /> -</svg> diff --git a/code/app/src/lib/components/icons/calendar.svelte b/code/app/src/lib/components/icons/calendar.svelte deleted file mode 100644 index e0053ee..0000000 --- a/code/app/src/lib/components/icons/calendar.svelte +++ /dev/null @@ -1,14 +0,0 @@ -<svg - xmlns="http://www.w3.org/2000/svg" - fill="none" - viewBox="0 0 24 24" - stroke-width="1.5" - stroke="currentColor" - class="w-6 h-6 {$$restProps.class ?? ''}" -> - <path - stroke-linecap="round" - stroke-linejoin="round" - d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 012.25-2.25h13.5A2.25 2.25 0 0121 7.5v11.25m-18 0A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75m-18 0v-7.5A2.25 2.25 0 015.25 9h13.5A2.25 2.25 0 0121 11.25v7.5m-9-6h.008v.008H12v-.008zM12 15h.008v.008H12V15zm0 2.25h.008v.008H12v-.008zM9.75 15h.008v.008H9.75V15zm0 2.25h.008v.008H9.75v-.008zM7.5 15h.008v.008H7.5V15zm0 2.25h.008v.008H7.5v-.008zm6.75-4.5h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V15zm0 2.25h.008v.008h-.008v-.008zm2.25-4.5h.008v.008H16.5v-.008zm0 2.25h.008v.008H16.5V15z" - /> -</svg> diff --git a/code/app/src/lib/components/icons/check-circle.svelte b/code/app/src/lib/components/icons/check-circle.svelte deleted file mode 100644 index e30778e..0000000 --- a/code/app/src/lib/components/icons/check-circle.svelte +++ /dev/null @@ -1,13 +0,0 @@ -<svg - class="h-5 w-5 {$$restProps.class ?? ''}" - xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 20 20" - fill="currentColor" - aria-hidden="true" -> - <path - fill-rule="evenodd" - d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z" - clip-rule="evenodd" - /> -</svg> diff --git a/code/app/src/lib/components/icons/chevron-down.svelte b/code/app/src/lib/components/icons/chevron-down.svelte deleted file mode 100644 index 5b29ece..0000000 --- a/code/app/src/lib/components/icons/chevron-down.svelte +++ /dev/null @@ -1,7 +0,0 @@ -<svg class="h-5 w-5 {$$restProps.class ?? ''}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"> - <path - fill-rule="evenodd" - d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z" - clip-rule="evenodd" - /> -</svg> diff --git a/code/app/src/lib/components/icons/chevron-up-down.svelte b/code/app/src/lib/components/icons/chevron-up-down.svelte deleted file mode 100644 index c07aed5..0000000 --- a/code/app/src/lib/components/icons/chevron-up-down.svelte +++ /dev/null @@ -1,13 +0,0 @@ -<svg - class="h-5 w-5 {$$restProps.class ?? ''}" - xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 20 20" - fill="currentColor" - aria-hidden="true" -> - <path - fill-rule="evenodd" - d="M10 3a.75.75 0 01.55.24l3.25 3.5a.75.75 0 11-1.1 1.02L10 4.852 7.3 7.76a.75.75 0 01-1.1-1.02l3.25-3.5A.75.75 0 0110 3zm-3.76 9.2a.75.75 0 011.06.04l2.7 2.908 2.7-2.908a.75.75 0 111.1 1.02l-3.25 3.5a.75.75 0 01-1.1 0l-3.25-3.5a.75.75 0 01.04-1.06z" - clip-rule="evenodd" - /> -</svg> diff --git a/code/app/src/lib/components/icons/chevron-up.svelte b/code/app/src/lib/components/icons/chevron-up.svelte deleted file mode 100644 index 289e71d..0000000 --- a/code/app/src/lib/components/icons/chevron-up.svelte +++ /dev/null @@ -1,7 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="w-5 h-5"> - <path - fill-rule="evenodd" - d="M14.77 12.79a.75.75 0 01-1.06-.02L10 8.832 6.29 12.77a.75.75 0 11-1.08-1.04l4.25-4.5a.75.75 0 011.08 0l4.25 4.5a.75.75 0 01-.02 1.06z" - clip-rule="evenodd" - /> -</svg> diff --git a/code/app/src/lib/components/icons/database.svelte b/code/app/src/lib/components/icons/database.svelte deleted file mode 100644 index 6ffdadb..0000000 --- a/code/app/src/lib/components/icons/database.svelte +++ /dev/null @@ -1,14 +0,0 @@ -<svg - xmlns="http://www.w3.org/2000/svg" - class="h-6 w-6 {$$restProps.class ?? ''}" - fill="none" - viewBox="0 0 24 24" - stroke="currentColor" - stroke-width="2" -> - <path - stroke-linecap="round" - stroke-linejoin="round" - d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4" - /> -</svg> diff --git a/code/app/src/lib/components/icons/exclamation-circle.svelte b/code/app/src/lib/components/icons/exclamation-circle.svelte deleted file mode 100644 index 2ce79b1..0000000 --- a/code/app/src/lib/components/icons/exclamation-circle.svelte +++ /dev/null @@ -1,13 +0,0 @@ -<svg - class="h-5 w-5 {$$restProps.class ?? ''}" - xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 20 20" - fill="currentColor" - aria-hidden="true" -> - <path - fill-rule="evenodd" - d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-5a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 0110 5zm0 10a1 1 0 100-2 1 1 0 000 2z" - clip-rule="evenodd" - /> -</svg> diff --git a/code/app/src/lib/components/icons/exclamation-triangle.svelte b/code/app/src/lib/components/icons/exclamation-triangle.svelte deleted file mode 100644 index 8d807db..0000000 --- a/code/app/src/lib/components/icons/exclamation-triangle.svelte +++ /dev/null @@ -1,13 +0,0 @@ -<svg - class="h-5 w-5 {$$restProps.class ?? ''}" - xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 20 20" - fill="currentColor" - aria-hidden="true" -> - <path - fill-rule="evenodd" - d="M8.485 3.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 3.495zM10 6a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 6zm0 9a1 1 0 100-2 1 1 0 000 2z" - clip-rule="evenodd" - /> -</svg> diff --git a/code/app/src/lib/components/icons/folder-open.svelte b/code/app/src/lib/components/icons/folder-open.svelte deleted file mode 100644 index 409c8e2..0000000 --- a/code/app/src/lib/components/icons/folder-open.svelte +++ /dev/null @@ -1,14 +0,0 @@ -<svg - xmlns="http://www.w3.org/2000/svg" - fill="none" - viewBox="0 0 24 24" - stroke-width="1.5" - stroke="currentColor" - class="w-6 h-6 {$$restProps.class ?? ''}" -> - <path - stroke-linecap="round" - stroke-linejoin="round" - d="M3.75 9.776c.112-.017.227-.026.344-.026h15.812c.117 0 .232.009.344.026m-16.5 0a2.25 2.25 0 00-1.883 2.542l.857 6a2.25 2.25 0 002.227 1.932H19.05a2.25 2.25 0 002.227-1.932l.857-6a2.25 2.25 0 00-1.883-2.542m-16.5 0V6A2.25 2.25 0 016 3.75h3.879a1.5 1.5 0 011.06.44l2.122 2.12a1.5 1.5 0 001.06.44H18A2.25 2.25 0 0120.25 9v.776" - /> -</svg> diff --git a/code/app/src/lib/components/icons/funnel.svelte b/code/app/src/lib/components/icons/funnel.svelte deleted file mode 100644 index 7e9daeb..0000000 --- a/code/app/src/lib/components/icons/funnel.svelte +++ /dev/null @@ -1,7 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="w-5 h-5"> - <path - fill-rule="evenodd" - d="M2.628 1.601C5.028 1.206 7.49 1 10 1s4.973.206 7.372.601a.75.75 0 01.628.74v2.288a2.25 2.25 0 01-.659 1.59l-4.682 4.683a2.25 2.25 0 00-.659 1.59v3.037c0 .684-.31 1.33-.844 1.757l-1.937 1.55A.75.75 0 018 18.25v-5.757a2.25 2.25 0 00-.659-1.591L2.659 6.22A2.25 2.25 0 012 4.629V2.34a.75.75 0 01.628-.74z" - clip-rule="evenodd" - /> -</svg> diff --git a/code/app/src/lib/components/icons/home.svelte b/code/app/src/lib/components/icons/home.svelte deleted file mode 100644 index ee8305d..0000000 --- a/code/app/src/lib/components/icons/home.svelte +++ /dev/null @@ -1,14 +0,0 @@ -<svg - xmlns="http://www.w3.org/2000/svg" - class="h-6 w-6 {$$restProps.class ?? ''}" - fill="none" - viewBox="0 0 24 24" - stroke="currentColor" - stroke-width="2" -> - <path - stroke-linecap="round" - stroke-linejoin="round" - d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" - /> -</svg> diff --git a/code/app/src/lib/components/icons/index.ts b/code/app/src/lib/components/icons/index.ts deleted file mode 100644 index eb5b439..0000000 --- a/code/app/src/lib/components/icons/index.ts +++ /dev/null @@ -1,47 +0,0 @@ -import XIcon from "./x.svelte"; -import MenuIcon from "./menu.svelte"; -import AdjustmentsIcon from "./adjustments.svelte"; -import DatabaseIcon from "./database.svelte"; -import HomeIcon from "./home.svelte"; -import InformationCircleIcon from "./information-circle.svelte"; -import ExclamationTriangleIcon from "./exclamation-triangle.svelte"; -import XCircleIcon from "./x-circle.svelte"; -import CheckCircleIcon from "./check-circle.svelte"; -import XMarkIcon from "./x-mark.svelte"; -import SpinnerIcon from "./spinner.svelte"; -import ExclamationCircleIcon from "./exclamation-circle.svelte"; -import ChevronUpDownIcon from "./chevron-up-down.svelte"; -import MagnifyingGlassIcon from "./magnifying-glass.svelte"; -import Bars3CenterLeftIcon from "./bars-3-center-left.svelte"; -import CalendarIcon from "./calendar.svelte"; -import FolderOpenIcon from "./folder-open.svelte"; -import MegaphoneIcon from "./megaphone.svelte"; -import QueueListIcon from "./queue-list.svelte"; -import ChevronDownIcon from "./chevron-down.svelte"; -import ChevronUpIcon from "./chevron-up.svelte"; -import FunnelIcon from "./funnel.svelte"; - -export { - FunnelIcon, - ChevronDownIcon, - ChevronUpIcon, - QueueListIcon, - FolderOpenIcon, - MegaphoneIcon, - CalendarIcon, - Bars3CenterLeftIcon, - MagnifyingGlassIcon, - ChevronUpDownIcon, - XIcon, - MenuIcon, - HomeIcon, - DatabaseIcon, - AdjustmentsIcon, - InformationCircleIcon, - ExclamationTriangleIcon, - ExclamationCircleIcon, - XCircleIcon, - CheckCircleIcon, - XMarkIcon, - SpinnerIcon -}
\ No newline at end of file diff --git a/code/app/src/lib/components/icons/information-circle.svelte b/code/app/src/lib/components/icons/information-circle.svelte deleted file mode 100644 index 68dbc60..0000000 --- a/code/app/src/lib/components/icons/information-circle.svelte +++ /dev/null @@ -1,13 +0,0 @@ -<svg - class="h-5 w-5 {$$restProps.class ?? ''}" - xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 20 20" - fill="currentColor" - aria-hidden="true" -> - <path - fill-rule="evenodd" - d="M19 10.5a8.5 8.5 0 11-17 0 8.5 8.5 0 0117 0zM8.25 9.75A.75.75 0 019 9h.253a1.75 1.75 0 011.709 2.13l-.46 2.066a.25.25 0 00.245.304H11a.75.75 0 010 1.5h-.253a1.75 1.75 0 01-1.709-2.13l.46-2.066a.25.25 0 00-.245-.304H9a.75.75 0 01-.75-.75zM10 7a1 1 0 100-2 1 1 0 000 2z" - clip-rule="evenodd" - /> -</svg> diff --git a/code/app/src/lib/components/icons/magnifying-glass.svelte b/code/app/src/lib/components/icons/magnifying-glass.svelte deleted file mode 100644 index f8fdb6e..0000000 --- a/code/app/src/lib/components/icons/magnifying-glass.svelte +++ /dev/null @@ -1,13 +0,0 @@ -<svg - class="h-5 w-5 {$$restProps.class ?? ''}" - xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 20 20" - fill="currentColor" - aria-hidden="true" -> - <path - fill-rule="evenodd" - d="M9 3.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM2 9a7 7 0 1112.452 4.391l3.328 3.329a.75.75 0 11-1.06 1.06l-3.329-3.328A7 7 0 012 9z" - clip-rule="evenodd" - /> -</svg> diff --git a/code/app/src/lib/components/icons/megaphone.svelte b/code/app/src/lib/components/icons/megaphone.svelte deleted file mode 100644 index 7ada5f3..0000000 --- a/code/app/src/lib/components/icons/megaphone.svelte +++ /dev/null @@ -1,14 +0,0 @@ -<svg - xmlns="http://www.w3.org/2000/svg" - fill="none" - viewBox="0 0 24 24" - stroke-width="1.5" - stroke="currentColor" - class="w-6 h-6 {$$restProps.class ?? ''}" -> - <path - stroke-linecap="round" - stroke-linejoin="round" - d="M10.34 15.84c-.688-.06-1.386-.09-2.09-.09H7.5a4.5 4.5 0 110-9h.75c.704 0 1.402-.03 2.09-.09m0 9.18c.253.962.584 1.892.985 2.783.247.55.06 1.21-.463 1.511l-.657.38c-.551.318-1.26.117-1.527-.461a20.845 20.845 0 01-1.44-4.282m3.102.069a18.03 18.03 0 01-.59-4.59c0-1.586.205-3.124.59-4.59m0 9.18a23.848 23.848 0 018.835 2.535M10.34 6.66a23.847 23.847 0 008.835-2.535m0 0A23.74 23.74 0 0018.795 3m.38 1.125a23.91 23.91 0 011.014 5.395m-1.014 8.855c-.118.38-.245.754-.38 1.125m.38-1.125a23.91 23.91 0 001.014-5.395m0-3.46c.495.413.811 1.035.811 1.73 0 .695-.316 1.317-.811 1.73m0-3.46a24.347 24.347 0 010 3.46" - /> -</svg> diff --git a/code/app/src/lib/components/icons/menu.svelte b/code/app/src/lib/components/icons/menu.svelte deleted file mode 100644 index 471d85f..0000000 --- a/code/app/src/lib/components/icons/menu.svelte +++ /dev/null @@ -1,14 +0,0 @@ -<svg - xmlns="http://www.w3.org/2000/svg" - class="h-6 w-6 {$$restProps.class ?? ''}" - fill="none" - viewBox="0 0 24 24" - stroke="currentColor" - stroke-width="2" -> - <path - stroke-linecap="round" - stroke-linejoin="round" - d="M4 6h16M4 12h16M4 18h16" - /> -</svg> diff --git a/code/app/src/lib/components/icons/queue-list.svelte b/code/app/src/lib/components/icons/queue-list.svelte deleted file mode 100644 index 6148394..0000000 --- a/code/app/src/lib/components/icons/queue-list.svelte +++ /dev/null @@ -1,14 +0,0 @@ -<svg - xmlns="http://www.w3.org/2000/svg" - fill="none" - viewBox="0 0 24 24" - stroke-width="1.5" - stroke="currentColor" - class="w-6 h-6 {$$restProps.class ?? ''}" -> - <path - stroke-linecap="round" - stroke-linejoin="round" - d="M3.75 12h16.5m-16.5 3.75h16.5M3.75 19.5h16.5M5.625 4.5h12.75a1.875 1.875 0 010 3.75H5.625a1.875 1.875 0 010-3.75z" - /> -</svg> diff --git a/code/app/src/lib/components/icons/spinner.svelte b/code/app/src/lib/components/icons/spinner.svelte deleted file mode 100644 index 80cc57c..0000000 --- a/code/app/src/lib/components/icons/spinner.svelte +++ /dev/null @@ -1,20 +0,0 @@ -<svg - class="-ml-1 mr-3 h-5 w-5 animate-spin {$$restProps.class ?? ''}" - xmlns="http://www.w3.org/2000/svg" - fill="none" - viewBox="0 0 24 24" -> - <circle - class="opacity-25" - cx="12" - cy="12" - r="10" - stroke="currentColor" - stroke-width="4" - /> - <path - class="opacity-75" - fill="currentColor" - d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" - /> -</svg> diff --git a/code/app/src/lib/components/icons/x-circle.svelte b/code/app/src/lib/components/icons/x-circle.svelte deleted file mode 100644 index 3793b5a..0000000 --- a/code/app/src/lib/components/icons/x-circle.svelte +++ /dev/null @@ -1,13 +0,0 @@ -<svg - class="h-5 w-5 {$$restProps.class ?? ''}" - xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 20 20" - fill="currentColor" - aria-hidden="true" -> - <path - fill-rule="evenodd" - d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z" - clip-rule="evenodd" - /> -</svg> diff --git a/code/app/src/lib/components/icons/x-mark.svelte b/code/app/src/lib/components/icons/x-mark.svelte deleted file mode 100644 index fd1c6a1..0000000 --- a/code/app/src/lib/components/icons/x-mark.svelte +++ /dev/null @@ -1,11 +0,0 @@ -<svg - class="h-5 w-5 {$$restProps.class ?? ''}" - xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 20 20" - fill="currentColor" - aria-hidden="true" -> - <path - d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" - /> -</svg> diff --git a/code/app/src/lib/components/icons/x.svelte b/code/app/src/lib/components/icons/x.svelte deleted file mode 100644 index 6125ab8..0000000 --- a/code/app/src/lib/components/icons/x.svelte +++ /dev/null @@ -1,14 +0,0 @@ -<svg - xmlns="http://www.w3.org/2000/svg" - class="h-6 w-6 {$$restProps.class ?? ''}" - fill="none" - viewBox="0 0 24 24" - stroke="currentColor" - stroke-width="2" -> - <path - stroke-linecap="round" - stroke-linejoin="round" - d="M6 18L18 6M6 6l12 12" - /> -</svg> diff --git a/code/app/src/lib/components/index.ts b/code/app/src/lib/components/index.ts deleted file mode 100644 index d6abd4c..0000000 --- a/code/app/src/lib/components/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -import Alert from "./alert.svelte"; -import Button from "./button.svelte"; -import Checkbox from "./checkbox.svelte"; -import Input from "./input.svelte"; -import LocaleSwitcher from "./locale-switcher.svelte"; -import Switch from "./switch.svelte"; -import Badge from "./badge.svelte"; -import ProjectStatusBadge from "./project-status-badge.svelte"; -import TextArea from "./textarea.svelte"; -import Combobox from "./combobox.svelte"; - -export { - Badge, - Combobox, - TextArea, - ProjectStatusBadge, - Alert, - Button, - Checkbox, - Input, - LocaleSwitcher, - Switch -}
\ No newline at end of file diff --git a/code/app/src/lib/components/input.svelte b/code/app/src/lib/components/input.svelte deleted file mode 100644 index 80b1543..0000000 --- a/code/app/src/lib/components/input.svelte +++ /dev/null @@ -1,113 +0,0 @@ -<script lang="ts"> - import pwKey from "$actions/pwKey"; - import { random_string } from "$lib/helpers"; - import { error } from "@sveltejs/kit"; - import { ExclamationCircleIcon } from "./icons"; - - export let label: string | undefined = undefined; - export let type: string = "text"; - export let autocomplete: string | undefined = undefined; - export let required: boolean | undefined = undefined; - export let id: string | undefined = "input__" + random_string(4); - export let name: string | undefined = undefined; - export let placeholder: string | undefined = undefined; - export let helpText: string | undefined = undefined; - export let errorText: string | undefined = undefined; - export let errors: Array<string> | undefined = undefined; - export let disabled = false; - export let hideLabel = false; - export let cornerHint: string | undefined = undefined; - export let icon: any = undefined; - export let addon: string | undefined = undefined; - export let value: string | undefined; - export let wrapperClass: string | undefined = undefined; - export let _pwKey: string | undefined = undefined; - - $: ariaErrorDescribedBy = id + "__" + "error"; - $: attributes = { - "aria-describedby": errorText || errors?.length ? ariaErrorDescribedBy : null, - "aria-invalid": errorText || errors?.length ? "true" : null, - disabled: disabled || null, - autocomplete: autocomplete || null, - required: required || null, - } as any; - $: hasBling = icon || addon || errorText; - const defaultColorClass = "border-gray-300 focus:border-teal-500 focus:ring-teal-500"; - let colorClass = defaultColorClass; - $: if (errorText) { - colorClass = "placeholder-red-300 focus:border-red-500 focus:outline-none focus:ring-red-500 text-red-900 pr-10 border-red-300"; - } else { - colorClass = defaultColorClass; - } - - function typeAction(node: HTMLInputElement) { - node.type = type; - } -</script> - -<div class={wrapperClass}> - {#if label && !cornerHint && !hideLabel} - <label for={id} class={hideLabel ? "sr-only" : "block text-sm font-medium text-gray-700"}> - {label} - {@html required ? "<span class='text-red-500'>*</span>" : ""} - </label> - {:else if cornerHint && !hideLabel} - <div class="flex justify-between"> - {#if label} - <label for={id} class={hideLabel ? "sr-only" : "block text-sm font-medium text-gray-700"}> - {label} - {@html required ? "<span class='text-red-500'>*</span>" : ""} - </label> - {/if} - <span class="text-sm text-gray-500"> - {cornerHint} - </span> - </div> - {/if} - <div class="{label ? 'mt-1' : ''} {hasBling ? 'relative rounded-md' : ''} {addon ? 'flex' : ''}"> - {#if icon} - <div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3"> - <svelte:component this={icon} class={errorText ? "text-red-500" : "text-gray-400"} /> - </div> - {:else if addon} - <div class="inline-flex items-center rounded-l-md border border-r-0 border-gray-300 bg-gray-50 px-3 text-gray-500 sm:text-sm"> - <span class="text-gray-500 sm:text-sm">{addon}</span> - </div> - {/if} - <input - use:typeAction - use:pwKey={_pwKey} - {name} - {id} - {...attributes} - bind:value - class="block w-full rounded-md shadow-sm sm:text-sm - {colorClass} - {disabled ? 'disabled:cursor-not-allowed disabled:border-gray-200 disabled:bg-gray-50 disabled:text-gray-500' : ''} - {addon ? 'min-w-0 flex-1 rounded-none rounded-r-md' : ''} - {icon ? 'pl-10' : ''}" - {placeholder} - /> - {#if errorText} - <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3"> - <ExclamationCircleIcon class="text-red-500" /> - </div> - {/if} - </div> - {#if helpText && !errorText} - <p class="mt-2 text-sm text-gray-500"> - {helpText} - </p> - {/if} - {#if errorText || errors?.length === 1} - <p class="mt-2 text-sm text-red-600" id={ariaErrorDescribedBy}> - {errorText ?? errors[0]} - </p> - {:else if errors && errors.length} - <ul class="mt-2 list-disc" id={ariaErrorDescribedBy}> - {#each errors as error} - <li class="text-sm text-red-600">{error}</li> - {/each} - </ul> - {/if} -</div> diff --git a/code/app/src/lib/components/locale-switcher.svelte b/code/app/src/lib/components/locale-switcher.svelte deleted file mode 100644 index 3681bf5..0000000 --- a/code/app/src/lib/components/locale-switcher.svelte +++ /dev/null @@ -1,56 +0,0 @@ -<script lang="ts"> - import pwKey from "$actions/pwKey"; - import { browser } from "$app/environment"; - import { page } from "$app/stores"; - import { CookieNames } from "$lib/configuration"; - import { setLocale, locale } from "$lib/i18n/i18n-svelte"; - import type { Locales } from "$lib/i18n/i18n-types"; - import { locales } from "$lib/i18n/i18n-util"; - import { loadLocaleAsync } from "$lib/i18n/i18n-util.async"; - import Cookies from "js-cookie"; - - export let _pwKey: string | undefined = undefined; - export let tabindex: number | undefined = undefined; - let currentLocale = Cookies.get(CookieNames.locale); - - async function switch_locale(newLocale: Locales) { - if (!newLocale || $locale === newLocale) return; - await loadLocaleAsync(newLocale); - setLocale(newLocale); - document.querySelector("html")?.setAttribute("lang", newLocale); - Cookies.set(CookieNames.locale, newLocale); - currentLocale = newLocale; - console.log("Switched to: " + newLocale); - } - - function on_change(event: Event) { - const target = event.target as HTMLSelectElement; - switch_locale(target.options[target.selectedIndex].value as Locales); - } - - $: if (browser) { - switch_locale($page.params.lang as Locales); - } - - function get_locale_name(iso: string) { - switch (iso) { - case "nb": { - return "Norsk Bokmål"; - } - case "en": { - return "English"; - } - } - } -</script> - -<select - {tabindex} - use:pwKey={_pwKey} - on:change={on_change} - class="mt-1 mr-1 block border-none py-2 pl-3 pr-10 text-base rounded-md right-0 absolute focus:outline-none focus:ring-teal-500 sm:text-sm" -> - {#each locales as aLocale} - <option value={aLocale} selected={aLocale === currentLocale}>{get_locale_name(aLocale)}</option> - {/each} -</select> diff --git a/code/app/src/lib/components/project-status-badge.svelte b/code/app/src/lib/components/project-status-badge.svelte deleted file mode 100644 index 5390344..0000000 --- a/code/app/src/lib/components/project-status-badge.svelte +++ /dev/null @@ -1,24 +0,0 @@ -<script lang="ts"> - import type { ProjectStatus } from "$lib/models/projects/ProjectStatus"; - import Badge from "./badge.svelte"; - export let status: string | ProjectStatus; - - let text = ""; - let type = "default" as any; - $: switch (status) { - case "idl": - type = "tame"; - text = "IDLE"; - break; - case "exp": - type = "yellow"; - text = "EXPIRED"; - break; - case "act": - type = "green"; - text = "ACTIVE"; - break; - } -</script> - -<Badge {text} {type} uppercase /> diff --git a/code/app/src/lib/components/switch.svelte b/code/app/src/lib/components/switch.svelte deleted file mode 100644 index 79f2d67..0000000 --- a/code/app/src/lib/components/switch.svelte +++ /dev/null @@ -1,125 +0,0 @@ -<script context="module" lang="ts"> - export type SwitchType = "short" | "icon" | "default"; -</script> - -<script lang="ts"> - import pwKey from "$actions/pwKey"; - - export let enabled = false; - export let type: SwitchType = "default"; - export let srText = "Use setting"; - export let label: string | undefined = undefined; - export let description: string | undefined = undefined; - export let rightAlignedLabelDescription = false; - export let _pwKey: string | undefined = undefined; - - $: colorClass = enabled ? "bg-teal-600 focus:ring-teal-500" : "bg-gray-200 focus:ring-teal-500"; - $: translateClass = enabled ? "translate-x-5" : "translate-x-0"; - $: hasLabelOrDescription = label || description; - - function toggle() { - enabled = !enabled; - } -</script> - -<div class="{hasLabelOrDescription ? 'flex items-center' : ''} {rightAlignedLabelDescription ? '' : 'justify-between'}"> - {#if hasLabelOrDescription && !rightAlignedLabelDescription} - <span class="flex flex-grow flex-col"> - {#if label} - <span class="text-sm font-medium text-gray-900">{label}</span> - {/if} - {#if description} - <span class="text-sm text-gray-500">{description}</span> - {/if} - </span> - {/if} - {#if type === "short"} - <button - type="button" - class="group relative inline-flex h-5 w-10 flex-shrink-0 cursor-pointer items-center justify-center rounded-full focus:outline-none focus:ring-2 focus:ring-offset-2" - role="switch" - aria-checked={enabled} - use:pwKey={_pwKey} - on:click={toggle} - > - <span class="sr-only">{srText}</span> - <span aria-hidden="true" class="pointer-events-none absolute h-full w-full rounded-md" /> - <span - aria-hidden="true" - class="{colorClass} pointer-events-none absolute mx-auto h-4 w-9 rounded-full transition-colors duration-200 ease-in-out" - /> - <span - aria-hidden="true" - class="{translateClass} pointer-events-none absolute left-0 inline-block h-5 w-5 transform rounded-full border border-gray-200 bg-white shadow ring-0 transition-transform duration-200 ease-in-out" - /> - </button> - {:else if type === "icon"} - <button - type="button" - class="{colorClass} relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2" - role="switch" - aria-checked={enabled} - use:pwKey={_pwKey} - on:click={toggle} - > - <span class="sr-only">{srText}</span> - <span - class="{translateClass} pointer-events-none relative inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out" - > - <span - class="{enabled - ? 'opacity-0 ease-out duration-100' - : 'opacity-100 ease-in duration-200'} absolute inset-0 flex h-full w-full items-center justify-center transition-opacity" - aria-hidden="true" - > - <svg class="h-3 w-3 text-gray-400" fill="none" viewBox="0 0 12 12"> - <path - d="M4 8l2-2m0 0l2-2M6 6L4 4m2 2l2 2" - stroke="currentColor" - stroke-width="2" - stroke-linecap="round" - stroke-linejoin="round" - /> - </svg> - </span> - <span - class="{enabled - ? 'opacity-100 ease-in duration-200' - : 'opacity-0 ease-out duration-100'} absolute inset-0 flex h-full w-full items-center justify-center transition-opacity" - aria-hidden="true" - > - <svg class="h-3 w-3 text-indigo-600" fill="currentColor" viewBox="0 0 12 12"> - <path - d="M3.707 5.293a1 1 0 00-1.414 1.414l1.414-1.414zM5 8l-.707.707a1 1 0 001.414 0L5 8zm4.707-3.293a1 1 0 00-1.414-1.414l1.414 1.414zm-7.414 2l2 2 1.414-1.414-2-2-1.414 1.414zm3.414 2l4-4-1.414-1.414-4 4 1.414 1.414z" - /> - </svg> - </span> - </span> - </button> - {:else if type === "default"} - <button - type="button" - class="{colorClass} relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2" - role="switch" - aria-checked={enabled} - use:pwKey={_pwKey} - on:click={toggle} - > - <span class="sr-only">{srText}</span> - <span - aria-hidden="true" - class="{translateClass} pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out" - /> - </button> - {/if} - {#if hasLabelOrDescription && rightAlignedLabelDescription} - <span class="ml-3"> - {#if label} - <span class="text-sm font-medium text-gray-900">{label}</span> - {/if} - {#if description} - <span class="text-sm text-gray-500">{description}</span> - {/if} - </span> - {/if} -</div> diff --git a/code/app/src/lib/components/textarea.svelte b/code/app/src/lib/components/textarea.svelte deleted file mode 100644 index a3dd06a..0000000 --- a/code/app/src/lib/components/textarea.svelte +++ /dev/null @@ -1,81 +0,0 @@ -<script lang="ts"> - import { random_string } from "$lib/helpers"; - - export let id = "textarea-" + random_string(4); - export let disabled = false; - export let rows = 2; - export let cols = 0; - export let name = ""; - export let placeholder = ""; - export let value; - export let label = ""; - export let required = false; - export let errorText = ""; - export let errors: Array<string> | undefined = undefined; - - $: ariaErrorDescribedBy = id + "__" + "error"; - $: attributes = { - "aria-describedby": errorText || errors?.length ? ariaErrorDescribedBy : null, - "aria-invalid": errorText || errors?.length ? "true" : null, - rows: rows || null, - cols: cols || null, - name: name || null, - id: id || null, - disabled: disabled || null, - required: required || null, - } as any; - - let textareaElement; - let scrollHeight = 0; - const defaultColorClass = "border-gray-300 focus:border-teal-500 focus:ring-teal-500"; - let colorClass = defaultColorClass; - - $: if (errorText) { - colorClass = "placeholder-red-300 focus:border-red-500 focus:outline-none focus:ring-red-500 text-red-900 pr-10 border-red-300"; - } else { - colorClass = defaultColorClass; - } - - $: if (textareaElement) { - scrollHeight = textareaElement.scrollHeight; - } - - function on_input(event) { - event.target.style.height = "auto"; - event.target.style.height = this.scrollHeight + "px"; - } -</script> - -<div> - {#if label} - <label for={id} class="block text-sm font-medium text-gray-700"> - {label} - {@html required ? "<span class='text-red-500'>*</span>" : ""} - </label> - {/if} - <div class="mt-1"> - <textarea - {rows} - {name} - {id} - {...attributes} - style="overflow-y:hidden;min-height:calc(1.5em + .75rem + 2px);{scrollHeight ? 'height:{scrollHeight}px' : ''};" - bind:value - bind:this={textareaElement} - on:input={on_input} - {placeholder} - class="block w-full rounded-md {colorClass} shadow-sm sm:text-sm" - /> - {#if errorText || errors?.length === 1} - <p class="mt-2 text-sm text-red-600" id={ariaErrorDescribedBy}> - {errorText ?? errors[0]} - </p> - {:else if errors && errors.length} - <ul class="mt-2 list-disc" id={ariaErrorDescribedBy}> - {#each errors as error} - <li class="text-sm text-red-600">{error}</li> - {/each} - </ul> - {/if} - </div> -</div> |
