diff options
Diffstat (limited to 'apps/web-shared/src/components/theme-switcher.svelte')
| -rw-r--r-- | apps/web-shared/src/components/theme-switcher.svelte | 425 |
1 files changed, 425 insertions, 0 deletions
diff --git a/apps/web-shared/src/components/theme-switcher.svelte b/apps/web-shared/src/components/theme-switcher.svelte new file mode 100644 index 0000000..26ae507 --- /dev/null +++ b/apps/web-shared/src/components/theme-switcher.svelte @@ -0,0 +1,425 @@ +<script lang="ts"> + import {base_domain, CookieNames} from "$shared/lib/configuration"; + import {get_cookie, set_cookie} from "$shared/lib/helpers"; + import {onMount} from "svelte"; + + type theme = "system"|"dark"|"light"; + + export let show = false; + export let selection: theme = "system"; + export let size; + let prefers = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"; + onMount(() => { + selection = get_cookie(CookieNames.theme) as theme; + document.addEventListener("keydown", (e) => { + if (e.code === "Esc") show = false; + }); + document.addEventListener("click", (e: any) => { + if (e.target.closest("[data-theme-switcher-element]") === null) show = false; + }); + }); + let html = document.querySelector("html"); + + window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (event) => { + prefers = event.matches ? "dark" : "light"; + }); + + $: switch (selection || prefers) { + case "system": + html.dataset.theme = prefers; + break; + case "light": + html.dataset.theme = "light"; + break; + case "dark": + html.dataset.theme = "dark"; + break; + } + + function change(to: theme) { + selection = to; + set_cookie(CookieNames.theme, selection, base_domain()); + } +</script> + +<div class="ld-switch" data-theme-switcher-element> + <button class="reset ld-switch-btn" + on:click={() => show =!show}> + <span class="sr-only">{selection}</span> + <div class="ld-switch-btn__icon-wrapper ld-switch-btn__icon-wrapper--in" + aria-hidden="true"> + {#if selection === "dark"} + <svg class="icon ld-switch-btn__icon" + viewBox="0 0 20 20"> + <title>dark</title> + <g fill="currentColor"> + <path d="M11.964 3.284c.021.237.036.474.036.716a8 8 0 0 1-8 8c-.242 0-.479-.015-.716-.036a7 7 0 1 0 8.68-8.68z" + fill-opacity=".2" + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2"></path> + <path d="M7 4a.979.979 0 0 1-1-1 1 1 0 0 0-2 0 .979.979 0 0 1-1 1 1 1 0 0 0 0 2 .979.979 0 0 1 1 1 1 1 0 0 0 2 0 .979.979 0 0 1 1-1 1 1 0 0 0 0-2z"></path> + </g> + </svg> + {:else if selection === "light"} + <svg class="icon ld-switch-btn__icon" + viewBox="0 0 20 20"> + <title>light-auto</title> + <g fill="currentColor"> + <path d="M10 14a4 4 0 1 1 3.465-6" + fill-opacity=".2" + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2"></path> + <path fill="none" + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + d="M12 18l2.5-7h1l2.5 7"></path> + <path fill="none" + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + d="M12.714 16h4.572"></path> + <path fill="none" + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + d="M10 1v1.5"></path> + <path fill="none" + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + d="M16.364 3.636l-1.061 1.061"></path> + <path fill="none" + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + d="M3.636 16.364l1.061-1.061"></path> + <path fill="none" + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + d="M1 10h1.5"></path> + <path fill="none" + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + d="M3.636 3.636l1.061 1.061"></path> + </g> + </svg> + {:else } + <svg class="icon ld-switch-btn__icon" + viewBox="0 0 20 20"> + <title>dark-auto</title> + <g fill="currentColor"> + <path fill="none" + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + d="M12 18l2.5-7h1l2.5 7"></path> + <path fill="none" + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + d="M12.714 16h4.572"></path> + <path d="M12.146 10.159A2.5 2.5 0 0 1 14.5 8.5h1a2.5 2.5 0 0 1 1.412.441 7 7 0 0 0-4.948-5.657c.021.237.036.474.036.716a8 8 0 0 1-8 8c-.242 0-.479-.015-.716-.036a6.99 6.99 0 0 0 6.427 5.012z" + fill-opacity=".2"></path> + <path d="M16.71 8a7.015 7.015 0 0 0-4.746-4.716c.021.237.036.474.036.716a8 8 0 0 1-8 8c-.242 0-.479-.015-.716-.036A7.006 7.006 0 0 0 9 16.929" + fill="none" + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2"></path> + <path d="M7 4a.979.979 0 0 1-1-1 1 1 0 0 0-2 0 .979.979 0 0 1-1 1 1 1 0 0 0 0 2 .979.979 0 0 1 1 1 1 1 0 0 0 2 0 .979.979 0 0 1 1-1 1 1 0 0 0 0-2z"></path> + </g> + </svg> + {/if} + </div> + + <div class="ld-switch-btn__icon-wrapper js-ld-switch-icon" + aria-hidden="true"> + {#if selection === "dark"} + <svg class="icon ld-switch-btn__icon" + viewBox="0 0 20 20"> + <title>dark</title> + <g fill="currentColor"> + <path d="M11.964 3.284c.021.237.036.474.036.716a8 8 0 0 1-8 8c-.242 0-.479-.015-.716-.036a7 7 0 1 0 8.68-8.68z" + fill-opacity=".2" + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2"></path> + <path d="M7 4a.979.979 0 0 1-1-1 1 1 0 0 0-2 0 .979.979 0 0 1-1 1 1 1 0 0 0 0 2 .979.979 0 0 1 1 1 1 1 0 0 0 2 0 .979.979 0 0 1 1-1 1 1 0 0 0 0-2z"></path> + </g> + </svg> + {:else if selection === "light"} + <svg class="icon ld-switch-btn__icon" + viewBox="0 0 20 20"> + <title>light-auto</title> + <g fill="currentColor"> + <path d="M10 14a4 4 0 1 1 3.465-6" + fill-opacity=".2" + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2"></path> + <path fill="none" + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + d="M12 18l2.5-7h1l2.5 7"></path> + <path fill="none" + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + d="M12.714 16h4.572"></path> + <path fill="none" + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + d="M10 1v1.5"></path> + <path fill="none" + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + d="M16.364 3.636l-1.061 1.061"></path> + <path fill="none" + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + d="M3.636 16.364l1.061-1.061"></path> + <path fill="none" + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + d="M1 10h1.5"></path> + <path fill="none" + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + d="M3.636 3.636l1.061 1.061"></path> + </g> + </svg> + {:else } + <svg class="icon ld-switch-btn__icon" + viewBox="0 0 20 20"> + <title>dark-auto</title> + <g fill="currentColor"> + <path fill="none" + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + d="M12 18l2.5-7h1l2.5 7"></path> + <path fill="none" + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + d="M12.714 16h4.572"></path> + <path d="M12.146 10.159A2.5 2.5 0 0 1 14.5 8.5h1a2.5 2.5 0 0 1 1.412.441 7 7 0 0 0-4.948-5.657c.021.237.036.474.036.716a8 8 0 0 1-8 8c-.242 0-.479-.015-.716-.036a6.99 6.99 0 0 0 6.427 5.012z" + fill-opacity=".2"></path> + <path d="M16.71 8a7.015 7.015 0 0 0-4.746-4.716c.021.237.036.474.036.716a8 8 0 0 1-8 8c-.242 0-.479-.015-.716-.036A7.006 7.006 0 0 0 9 16.929" + fill="none" + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2"></path> + <path d="M7 4a.979.979 0 0 1-1-1 1 1 0 0 0-2 0 .979.979 0 0 1-1 1 1 1 0 0 0 0 2 .979.979 0 0 1 1 1 1 1 0 0 0 2 0 .979.979 0 0 1 1-1 1 1 0 0 0 0-2z"></path> + </g> + </svg> + {/if} + </div> + </button> +</div> + +<div class="bg-light position-fixed margin-top-xxs padding-x-xs padding-bottom-xs padding-top-xxxs radius-md inner-glow shadow-xs" + class:is-hidden={!show} + style="right: 15px" + data-theme-switcher-element + role="listbox"> + <div class="flex flex-wrap flex-column" + role="group"> + <div class="margin-bottom-xs flex-grow"> + <span class="text-xs color-contrast-medium">Appearance</span> + </div> + <div class="flex gap-xs flex-row"> + <div class="ld-switch-popover__option" + aria-selected="{selection === 'dark' ? 'true' : 'false'}" + role="option"> + <figure class="radius-md inner-glow" + on:click={() => change("dark")}> + <svg id="Layer_1" + class="block radius-inherit" + data-name="Layer 1" + xmlns="http://www.w3.org/2000/svg" + width="70" + height="50" + viewBox="0 0 70 50"> + <rect width="70" + height="50" + fill="#22232a"/> + <path d="M14,10H70V50H10V14A4,4,0,0,1,14,10Z" + fill="#5a5c63"/> + <circle cx="18" + cy="18" + r="3" + fill="#22232a"/> + <circle cx="27" + cy="18" + r="3" + fill="#22232a"/> + <circle cx="36" + cy="18" + r="3" + fill="#22232a"/> + <rect x="17" + y="28" + width="46" + height="3" + rx="1" + fill="#fafaff"/> + <rect x="17" + y="34" + width="46" + height="3" + rx="1" + fill="#fafaff"/> + <rect x="17" + y="40" + width="30" + height="3" + rx="1" + fill="#fafaff"/> + </svg> + </figure> + <div class="text-xs margin-top-xxxs padding-x-xxxxs">Dark</div> + </div> + <div class="ld-switch-popover__option" + aria-selected="{selection === 'light' ? 'true' : 'false'}" + role="option"> + <figure class="radius-md inner-glow" + on:click={() => change("light")}> + <svg id="Layer_1" + class="block radius-inherit" + data-name="Layer 1" + xmlns="http://www.w3.org/2000/svg" + width="70" + height="50" + viewBox="0 0 70 50"> + <rect width="70" + height="50" + fill="#e5e5e6"/> + <path d="M14,10H70a0,0,0,0,1,0,0V50a0,0,0,0,1,0,0H10a0,0,0,0,1,0,0V14A4,4,0,0,1,14,10Z" + fill="#fff"/> + <circle cx="18" + cy="18" + r="3" + fill="#e5e5e6"/> + <circle cx="27" + cy="18" + r="3" + fill="#e5e5e6"/> + <circle cx="36" + cy="18" + r="3" + fill="#e5e5e6"/> + <rect x="17" + y="28" + width="46" + height="3" + rx="1" + fill="#38393e"/> + <rect x="17" + y="34" + width="46" + height="3" + rx="1" + fill="#38393e"/> + <rect x="17" + y="40" + width="30" + height="3" + rx="1" + fill="#38393e"/> + </svg> + </figure> + <div class="text-xs margin-top-xxxs padding-x-xxxxs">Light</div> + </div> + <div class="ld-switch-popover__option" + aria-selected="{selection === 'system' ? 'true' : 'false'}" + role="option"> + <figure class="radius-md inner-glow" + on:click={() => change("system")}> + <svg id="Layer_1" + class="block radius-inherit" + data-name="Layer 1" + xmlns="http://www.w3.org/2000/svg" + width="70" + height="50" + viewBox="0 0 70 50"> + <rect width="35" + height="50" + fill="#e5e5e6"/> + <path d="M14,10H35a0,0,0,0,1,0,0V50a0,0,0,0,1,0,0H10a0,0,0,0,1,0,0V14A4,4,0,0,1,14,10Z" + fill="#fff"/> + <circle cx="18" + cy="18" + r="3" + fill="#e5e5e6"/> + <circle cx="27" + cy="18" + r="3" + fill="#e5e5e6"/> + <path d="M18,28H35a0,0,0,0,1,0,0v3a0,0,0,0,1,0,0H18a1,1,0,0,1-1-1V29A1,1,0,0,1,18,28Z" + fill="#38393e"/> + <path d="M18,34H35a0,0,0,0,1,0,0v3a0,0,0,0,1,0,0H18a1,1,0,0,1-1-1V35A1,1,0,0,1,18,34Z" + fill="#38393e"/> + <path d="M18,40H35a0,0,0,0,1,0,0v3a0,0,0,0,1,0,0H18a1,1,0,0,1-1-1V41A1,1,0,0,1,18,40Z" + fill="#38393e"/> + <rect x="35" + width="35" + height="50" + fill="#22232a"/> + <path d="M49,10H70V50H45V14A4,4,0,0,1,49,10Z" + fill="#5a5c63"/> + <circle cx="53" + cy="18" + r="3" + fill="#22232a"/> + <circle cx="62" + cy="18" + r="3" + fill="#22232a"/> + <path d="M53,28H70a0,0,0,0,1,0,0v3a0,0,0,0,1,0,0H53a1,1,0,0,1-1-1V29A1,1,0,0,1,53,28Z" + fill="#fafaff"/> + <path d="M53,34H70a0,0,0,0,1,0,0v3a0,0,0,0,1,0,0H53a1,1,0,0,1-1-1V35A1,1,0,0,1,53,34Z" + fill="#fafaff"/> + <path d="M53,40H70a0,0,0,0,1,0,0v3a0,0,0,0,1,0,0H53a1,1,0,0,1-1-1V41A1,1,0,0,1,53,40Z" + fill="#fafaff"/> + </svg> + </figure> + <div class="text-xs margin-top-xxxs padding-x-xxxxs">System</div> + </div> + </div> + </div> +</div> |
