diff options
| author | Fuwn <[email protected]> | 2024-01-31 18:01:16 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2024-01-31 18:01:16 -0800 |
| commit | 25e25ead288af9d3cfd7843ef7cbfc773b96f6f0 (patch) | |
| tree | 6e1918807a016e21ba53bb702a28835c18bd8a6a /src | |
| parent | deps(bun): update lockfile (diff) | |
| download | due.moe-25e25ead288af9d3cfd7843ef7cbfc773b96f6f0.tar.xz due.moe-25e25ead288af9d3cfd7843ef7cbfc773b96f6f0.zip | |
refactor(layout): dropdown component
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/Dropdown.svelte | 105 | ||||
| -rw-r--r-- | src/routes/+layout.svelte | 89 |
2 files changed, 114 insertions, 80 deletions
diff --git a/src/lib/Dropdown.svelte b/src/lib/Dropdown.svelte new file mode 100644 index 00000000..efbafa1a --- /dev/null +++ b/src/lib/Dropdown.svelte @@ -0,0 +1,105 @@ +<script lang="ts"> + interface Item { + name: string; + url: string; + } + + export let items: Item[] = []; + export let title: string; + + let open = false; + + const handleClickOutside = (event: any) => { + if (!event.target.closest('.dropdown')) open = false; + }; +</script> + +<svelte:window on:click={handleClickOutside} /> + +<div class="dropdown" id="dropdown"> + <span + class="header-item dropdown-toggle" + id="dropdown-toggle" + on:click|preventDefault={() => (open = !open)} + on:keydown={() => {}} + role="button" + tabindex="0" + > + {title} + </span> + + <div class={`dropdown-content card card-small ${open ? 'dropdown-open' : ''}`}> + {#each items as item} + <a href={item.url} class="header-item"> + {item.name} + </a> + {/each} + </div> +</div> + +<style lang="scss"> + a { + color: var(--base06); + } + + .header-item { + margin: 0 0.5rem; + } + + .header-item:hover { + text-decoration: none; + } + + .header-item:active { + outline: none; + } + + .dropdown { + position: relative; + display: inline-block; + } + + .dropdown-content { + display: block; + position: absolute; + min-width: max-content; + padding: 0.5em 0; + opacity: 0; + transform: translateY(-20px); + visibility: hidden; + $delay: 0.25s; + transition: opacity $delay ease, transform $delay ease, visibility 0s linear $delay; + left: 50%; + transform: translateX(-50%); + } + + .dropdown-open { + opacity: 1; + transform: translateY(0); + visibility: visible; + transition-delay: 0s, 0s, 0s; + left: 50%; + transform: translateX(-50%); + } + + .dropdown:hover .dropdown-content { + opacity: 1; + transform: translateY(0); + visibility: visible; + transition-delay: 0s, 0s, 0s; + left: 50%; + transform: translateX(-50%); + } + + .dropdown-content a { + padding: 0.5em 0.75em; + text-decoration: none; + display: block; + } + + .dropdown-content a:hover { + border-radius: 8px; + backdrop-filter: blur(160px); + background-color: var(--base01); + } +</style> diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index a29529d7..7fb24a50 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -20,11 +20,10 @@ import locale from '$stores/locale'; import Skeleton from '$lib/Loading/Skeleton.svelte'; import subsPlease from '$stores/subsPlease'; + import Dropdown from '$lib/Dropdown.svelte'; export let data; - let dropdownOpen = false; - addMessages('en', english as unknown as LocaleDictionary); addMessages('ja', japanese as unknown as LocaleDictionary); init({ fallbackLocale: 'en', initialLocale: $settings.displayLanguage }); @@ -73,12 +72,6 @@ }); }); - const handleClickOutside = (event: any) => { - if (!event.target.closest('.dropdown')) { - dropdownOpen = false; - } - }; - $: { if ((data.url === '/' || data.url === '/completed') && !$subsPlease) fetch(root(`/api/subsplease?tz=${Intl.DateTimeFormat().resolvedOptions().timeZone}`)) @@ -87,8 +80,6 @@ } </script> -<svelte:window on:click={handleClickOutside} /> - <HeadTitle /> <div id="container"> @@ -100,27 +91,14 @@ > {$locale().navigation.completed} </a> - <div class="dropdown" id="dropdown"> - <span - class="header-item dropdown-toggle" - id="dropdown-toggle" - on:click|preventDefault={() => (dropdownOpen = !dropdownOpen)} - on:keydown={() => {}} - role="button" - tabindex="0" - > - {$locale().navigation.schedule} - </span> - - <div class={`dropdown-content card card-small ${dropdownOpen ? 'dropdown-open' : ''}`}> - <a href={root('/schedule')} class="header-item">{$locale().navigation.subtitleSchedule}</a - > - <a href={root('/updates')} class="header-item">{$locale().navigation.newReleases}</a> - <a href={root('/birthdays')} class="header-item"> - {$locale().tools.tool.characterBirthdays.short} - </a> - </div> - </div> + <Dropdown + items={[ + { name: $locale().navigation.subtitleSchedule, url: root('/schedule') }, + { name: $locale().navigation.newReleases, url: root('/updates') }, + { name: $locale().tools.tool.characterBirthdays.short, url: root('/birthdays') } + ]} + title={$locale().navigation.schedule} + /> <a href={root('/tools')} class="header-item">{$locale().navigation.tools}</a> <a href={root('/settings')} class="header-item">{$locale().navigation.settings}</a> @@ -266,53 +244,4 @@ border-radius: 8px; box-shadow: 0 1.5px 9px var(--base01), 0 0 0 4px var(--base0E), 0 4px 30px var(--base01); } - - .dropdown { - position: relative; - display: inline-block; - } - - .dropdown-content { - display: block; - position: absolute; - min-width: max-content; - padding: 0.5em 0; - opacity: 0; - transform: translateY(-20px); - visibility: hidden; - $delay: 0.25s; - transition: opacity $delay ease, transform $delay ease, visibility 0s linear $delay; - left: 50%; - transform: translateX(-50%); - } - - .dropdown-open { - opacity: 1; - transform: translateY(0); - visibility: visible; - transition-delay: 0s, 0s, 0s; - left: 50%; - transform: translateX(-50%); - } - - .dropdown:hover .dropdown-content { - opacity: 1; - transform: translateY(0); - visibility: visible; - transition-delay: 0s, 0s, 0s; - left: 50%; - transform: translateX(-50%); - } - - .dropdown-content a { - padding: 0.5em 0.75em; - text-decoration: none; - display: block; - } - - .dropdown-content a:hover { - border-radius: 8px; - backdrop-filter: blur(160px); - background-color: var(--base01); - } </style> |