diff options
| author | Fuwn <[email protected]> | 2024-04-21 19:51:49 -0700 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2024-04-21 19:51:49 -0700 |
| commit | eebeaa378d49cc8adb597d00fd05bcc314779888 (patch) | |
| tree | d2862e4f952525280a341e44810c261548a07a3f /src/lib/Layout | |
| parent | refactor(TextTransition): move to Layout (diff) | |
| download | due.moe-eebeaa378d49cc8adb597d00fd05bcc314779888.tar.xz due.moe-eebeaa378d49cc8adb597d00fd05bcc314779888.zip | |
refactor(lib): move componenets to modules
Diffstat (limited to 'src/lib/Layout')
| -rw-r--r-- | src/lib/Layout/Dropdown.svelte | 127 | ||||
| -rw-r--r-- | src/lib/Layout/Popup.svelte | 59 |
2 files changed, 186 insertions, 0 deletions
diff --git a/src/lib/Layout/Dropdown.svelte b/src/lib/Layout/Dropdown.svelte new file mode 100644 index 00000000..dd48af45 --- /dev/null +++ b/src/lib/Layout/Dropdown.svelte @@ -0,0 +1,127 @@ +<script lang="ts"> + interface Item { + name: string; + url: string; + onClick?: () => void; + preventDefault?: boolean; + } + + export let items: Item[] = []; + export let title: string | undefined = undefined; + export let header = true; + export let center = false; + + 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" + style={`--dropdown-left: ${center ? '50%' : 'unset'}; --dropdown-transform: ${ + center ? 'translateX(-50%)' : 'unset' + };`} +> + <span + class={`${header ? 'header-item' : ''} dropdown-toggle`} + id="dropdown-toggle" + on:click|preventDefault={() => (open = !open)} + on:keydown={() => {}} + role="button" + tabindex="0" + > + {#if title} + {title} + {:else} + <slot name="title" /> + {/if} + </span> + + <div class={`dropdown-content card card-small ${open ? 'dropdown-open' : ''}`}> + {#each items as item} + <a + href={item.url} + class="header-item" + on:click={(e) => { + if (item.preventDefault) e.preventDefault(); + if (item.onClick) item.onClick(); + }} + > + {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: var(--dropdown-left); + transform: var(--dropdown-transform); + z-index: 1; + } + + .dropdown-open { + opacity: 1; + transform: translateY(0); + visibility: visible; + transition-delay: 0s, 0s, 0s; + left: var(--dropdown-left); + transform: var(--dropdown-transform); + } + + .dropdown:hover .dropdown-content { + opacity: 1; + transform: translateY(0); + visibility: visible; + transition-delay: 0s, 0s, 0s; + left: var(--dropdown-left); + transform: var(--dropdown-transform); + } + + .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/lib/Layout/Popup.svelte b/src/lib/Layout/Popup.svelte new file mode 100644 index 00000000..be55adf0 --- /dev/null +++ b/src/lib/Layout/Popup.svelte @@ -0,0 +1,59 @@ +<script lang="ts"> + import { browser } from '$app/environment'; + import { onMount } from 'svelte'; + + export let onLeave = () => { + return; + }; + export let card = true; + export let smallCard = false; + export let fullscreen = false; + export let show = true; + export let locked = false; + export let center = false; + + const handleClickOutside = (event: any) => { + if (!locked && event.target.classList.contains('popup')) { + show = false; + + onLeave(); + } + }; + + onMount(() => { + if (browser) document.body.style.overflow = 'auto'; + }); + + $: { + if (browser) { + document.body.style.overflow = 'auto'; + + if (show) document.body.style.overflow = 'hidden'; + else document.body.style.overflow = 'auto'; + } + } +</script> + +<svelte:window on:click={handleClickOutside} /> + +{#if show} + <div class={`popup ${fullscreen ? 'popup-fullscreen' : ''}`}> + <span + class={`${card ? `card ${smallCard ? 'card-small' : ''}` : ''} ${center ? 'centered' : ''}`} + > + <slot /> + </span> + </div> +{/if} + +<style> + .popup { + z-index: 3; + } + + .centered { + display: flex; + justify-content: center; + align-items: center; + } +</style> |