diff options
Diffstat (limited to 'code/app/src/components/switch.svelte')
| -rw-r--r-- | code/app/src/components/switch.svelte | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/code/app/src/components/switch.svelte b/code/app/src/components/switch.svelte new file mode 100644 index 0000000..1b67f80 --- /dev/null +++ b/code/app/src/components/switch.svelte @@ -0,0 +1,125 @@ +<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> |
