feat: ui theming & improved clickOutside handler (for modals)
This commit is contained in:
parent
a950da9412
commit
b3b897be85
@ -13,7 +13,7 @@
|
||||
:root {
|
||||
--light-background: #f5f5f5;
|
||||
--light-foreground: #e0e0e0;
|
||||
--light-accent: #303052;
|
||||
--light-accent: #2e2e88;
|
||||
--light-text: rgb(34, 40, 49);
|
||||
--light-highlight-text: #c28e4a;
|
||||
--light-error-text: #4b0000;
|
||||
@ -910,6 +910,14 @@
|
||||
@apply fixed inset-0 z-40 flex items-center justify-center backdrop-blur-xs;
|
||||
}
|
||||
|
||||
.modal-exit-button {
|
||||
@apply flex h-8 w-8 items-center justify-center rounded-lg border border-[var(--light-accent)] bg-transparent p-0 text-[var(--light-text)] hover:bg-[var(--light-foreground)]/80;
|
||||
}
|
||||
|
||||
.dark .modal-exit-button {
|
||||
@apply hover:bg-[var(--dark-foreground)]/80;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
@apply mx-4 max-h-[90vh] w-full max-w-[90vw] overflow-y-auto rounded-lg border-2 border-[var(--light-accent)]/10 bg-[var(--light-background)] shadow-lg;
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
import { onMount } from "svelte"
|
||||
import type { User } from "$lib/logic/model"
|
||||
import Delete from "$lib/icons/sidebar/Delete.svelte"
|
||||
import { formatDateShort } from "$lib/util/contentVisual"
|
||||
import { clickOutside, formatDateShort } from "$lib/util/contentVisual"
|
||||
|
||||
// props
|
||||
export let onClose: () => void
|
||||
@ -46,14 +46,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
// close the modal if user clicks outside of it
|
||||
const target = event.target as HTMLElement
|
||||
if (target.classList.contains("modal-backdrop")) {
|
||||
onClose()
|
||||
}
|
||||
}
|
||||
|
||||
const handleModalContentKeydown = (_event: KeyboardEvent) => {
|
||||
// accessibility compliance handler, actual handling is done by the global keydown handler
|
||||
}
|
||||
@ -71,13 +63,13 @@
|
||||
|
||||
<div
|
||||
class="modal-backdrop"
|
||||
on:click={handleClickOutside}
|
||||
on:keydown={handleKeydown}
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
tabindex="-1"
|
||||
>
|
||||
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
||||
<div use:clickOutside={() => onClose()}>
|
||||
<div
|
||||
bind:this={modalContent}
|
||||
class="modal-content max-w-xl"
|
||||
@ -89,7 +81,7 @@
|
||||
<!-- Header (title + close button) -->
|
||||
<div class="modal-section flex items-center justify-between" role="heading" aria-level="1">
|
||||
<h2 class="text-xl font-bold">Administration</h2>
|
||||
<button on:click={onClose} class="sidebar-button" aria-label="Close settings">
|
||||
<button on:click={onClose} class="modal-exit-button" aria-label="Close settings">
|
||||
<Close />
|
||||
</button>
|
||||
</div>
|
||||
@ -139,4 +131,5 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -3,7 +3,7 @@
|
||||
import Close from "$lib/icons/Close.svelte"
|
||||
import { isPasswordValid } from "$lib/util/authValidation"
|
||||
import { onMount } from "svelte"
|
||||
import { formatDateLong } from "$lib/util/contentVisual"
|
||||
import { clickOutside, formatDateLong } from "$lib/util/contentVisual"
|
||||
|
||||
// props
|
||||
export let onClose: () => void
|
||||
@ -103,14 +103,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
// close the modal if user clicks outside of it
|
||||
const target = event.target as HTMLElement
|
||||
if (target.classList.contains("modal-backdrop")) {
|
||||
onClose()
|
||||
}
|
||||
}
|
||||
|
||||
const handleModalContentKeydown = (_event: KeyboardEvent) => {
|
||||
// accessibility compliance handler, actual handling is done by the global keydown handler
|
||||
}
|
||||
@ -126,13 +118,13 @@
|
||||
|
||||
<div
|
||||
class="modal-backdrop"
|
||||
on:click={handleClickOutside}
|
||||
on:keydown={handleKeydown}
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
tabindex="-1"
|
||||
>
|
||||
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
||||
<div use:clickOutside={() => onClose()}>
|
||||
<div
|
||||
bind:this={modalContent}
|
||||
class="modal-content max-w-xl"
|
||||
@ -144,7 +136,7 @@
|
||||
<!-- Header (title + close button) -->
|
||||
<div class="modal-section flex items-center justify-between" role="heading" aria-level="1">
|
||||
<h2 class="text-xl font-bold">Settings</h2>
|
||||
<button on:click={onClose} class="sidebar-button" aria-label="Close settings">
|
||||
<button on:click={onClose} class="modal-exit-button" aria-label="Close settings">
|
||||
<Close />
|
||||
</button>
|
||||
</div>
|
||||
@ -246,8 +238,8 @@
|
||||
|
||||
<div class="space-y-4">
|
||||
<p class="text-sm">
|
||||
Deleting your account will permanently remove all your notes and account information. This
|
||||
action cannot be undone.
|
||||
Deleting your account will permanently remove all your notes and account information.
|
||||
This action cannot be undone.
|
||||
</p>
|
||||
|
||||
<!-- Confirm Password -->
|
||||
@ -283,4 +275,5 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -12,7 +12,12 @@
|
||||
import AdminWrench from "$lib/icons/sidebar/AdminShield.svelte"
|
||||
import Exit from "$lib/icons/sidebar/Exit.svelte"
|
||||
import ThemeToggle from "./ThemeToggle.svelte"
|
||||
import { formatDateLong, formatDateShort, parseExpirationPrefix } from "$lib/util/contentVisual"
|
||||
import {
|
||||
clickOutside,
|
||||
formatDateLong,
|
||||
formatDateShort,
|
||||
parseExpirationPrefix
|
||||
} from "$lib/util/contentVisual"
|
||||
import type { FullNote, NoteMetadata } from "$lib/logic/model"
|
||||
|
||||
// props
|
||||
@ -210,6 +215,13 @@
|
||||
|
||||
<!-- User section (single button) with dropdown -->
|
||||
<div class="relative flex flex-col px-2 py-3">
|
||||
<div
|
||||
use:clickOutside={() => {
|
||||
if (isUserMenuOpen) {
|
||||
isUserMenuOpen = false
|
||||
}
|
||||
}}
|
||||
>
|
||||
<button
|
||||
on:click={toggleUserMenu}
|
||||
class="sidebar-action-button flex-wrap justify-between px-4 py-4"
|
||||
@ -260,5 +272,6 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
|
@ -50,3 +50,25 @@ export const formatTitleWithHighlight = (title: string): string => {
|
||||
|
||||
return `<span class="note-title-exp-highlight">${expirationPrefix}</span> ${cleanTitle}`
|
||||
}
|
||||
|
||||
export const clickOutside = (
|
||||
node: HTMLElement,
|
||||
callbackFunction: () => void
|
||||
): {
|
||||
destroy: () => void
|
||||
} => {
|
||||
const handleClick = (event: MouseEvent): void => {
|
||||
if (node && !node.contains(event.target as Node) && !event.defaultPrevented) {
|
||||
callbackFunction()
|
||||
}
|
||||
}
|
||||
|
||||
// event listener with capture phase to ensure it runs before other click handlers
|
||||
document.addEventListener("click", handleClick, true)
|
||||
|
||||
return {
|
||||
destroy: () => {
|
||||
document.removeEventListener("click", handleClick, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user