From df9755ddf2da2ea2634a30c3b46bde27f6ac1e0e Mon Sep 17 00:00:00 2001 From: Youwes09 Date: Sun, 14 Jun 2026 04:35:32 -0500 Subject: [PATCH] Fix: Settings Drop-down Fix V1 (WIP) (#102) --- src/lib/components/settings/Settings.svelte | 14 +++---- .../settings/sections/LibrarySettings.svelte | 20 ++++++---- .../settings/sections/ReaderSettings.svelte | 30 +++++++++----- src/lib/core/ui/selectPortal.ts | 40 +++++++------------ 4 files changed, 53 insertions(+), 51 deletions(-) diff --git a/src/lib/components/settings/Settings.svelte b/src/lib/components/settings/Settings.svelte index f2fa5f1..01c11aa 100644 --- a/src/lib/components/settings/Settings.svelte +++ b/src/lib/components/settings/Settings.svelte @@ -4,7 +4,7 @@ import { settingsState, updateSettings } from '$lib/state/settings.svelte' import { eventToKeybind } from '$lib/core/keybinds/keybindEngine' import type { Keybinds } from '$lib/core/keybinds/defaultBinds' - import { anchorToModal } from '$lib/core/ui/selectPortal' + import { selectPortal } from '$lib/core/ui/selectPortal' import GeneralSettings from './sections/GeneralSettings.svelte' import AppearanceSettings from './sections/AppearanceSettings.svelte' @@ -175,13 +175,13 @@
{#if tab === 'general'} - + {:else if tab === 'appearance'} - + {:else if tab === 'reader'} - + {:else if tab === 'library'} - + {:else if tab === 'automation'} {:else if tab === 'performance'} @@ -189,13 +189,13 @@ {:else if tab === 'keybinds'} {:else if tab === 'storage'} - + {:else if tab === 'folders'} {:else if tab === 'tracking'} {:else if tab === 'security'} - + {:else if tab === 'content'} {:else if tab === 'about'} diff --git a/src/lib/components/settings/sections/LibrarySettings.svelte b/src/lib/components/settings/sections/LibrarySettings.svelte index dc9c081..df7c95f 100644 --- a/src/lib/components/settings/sections/LibrarySettings.svelte +++ b/src/lib/components/settings/sections/LibrarySettings.svelte @@ -2,17 +2,23 @@ import { settingsState, updateSettings } from '$lib/state/settings.svelte' import { homeState } from '$lib/state/home.svelte' import type { Settings } from '$lib/types/settings' + import type { Action } from 'svelte/action' interface Props { - selectOpen: string | null - closingSelect?: string | null - toggleSelect: (id: string) => void - anims: boolean + selectOpen: string | null + closingSelect?: string | null + toggleSelect: (id: string) => void + registerTrigger: (id: string, el: HTMLElement) => void + getTrigger: (id: string) => HTMLElement | undefined + selectPortal: Action + anims: boolean } - let { selectOpen, toggleSelect, anims }: Props = $props() + let { selectOpen, closingSelect, toggleSelect, registerTrigger, getTrigger, selectPortal, anims }: Props = $props() let triggerSortDir = $state(null!) + $effect(() => { if (triggerSortDir) registerTrigger('sort-dir', triggerSortDir) }) + function clearHistory() { homeState.history = [] } @@ -54,8 +60,8 @@ {{ 'desc':'Newest first','asc':'Oldest first' }[settingsState.settings.chapterSortDir]} - {#if selectOpen === 'sort-dir'} -
+ {#if selectOpen === 'sort-dir' || closingSelect === 'sort-dir'} +
{#each [['desc','Newest first'],['asc','Oldest first']] as [v, l]} {/each} diff --git a/src/lib/components/settings/sections/ReaderSettings.svelte b/src/lib/components/settings/sections/ReaderSettings.svelte index 4891c7b..1e68343 100644 --- a/src/lib/components/settings/sections/ReaderSettings.svelte +++ b/src/lib/components/settings/sections/ReaderSettings.svelte @@ -1,18 +1,26 @@
@@ -27,8 +35,8 @@ {{ 'single':'Single page','longstrip':'Long strip' }[settingsState.settings.pageStyle === 'double' ? 'single' : settingsState.settings.pageStyle]} - {#if selectOpen === 'page-style'} -
+ {#if selectOpen === 'page-style' || closingSelect === 'page-style'} +
{#each [['single','Single page'],['longstrip','Long strip']] as [v, l]} {/each} @@ -43,8 +51,8 @@ {{ 'ltr':'Left to right','rtl':'Right to left' }[settingsState.settings.readingDirection]} - {#if selectOpen === 'reading-dir'} -
+ {#if selectOpen === 'reading-dir' || closingSelect === 'reading-dir'} +
{#each [['ltr','Left to right'],['rtl','Right to left']] as [v, l]} {/each} @@ -81,8 +89,8 @@ {{ 'width':'Fit width','height':'Fit height','screen':'Fit screen','original':'Original (1:1)' }[settingsState.settings.fitMode ?? 'width']} - {#if selectOpen === 'fit-mode'} -
+ {#if selectOpen === 'fit-mode' || closingSelect === 'fit-mode'} +
{#each [['width','Fit width'],['height','Fit height'],['screen','Fit screen'],['original','Original (1:1)']] as [v, l]} {/each} diff --git a/src/lib/core/ui/selectPortal.ts b/src/lib/core/ui/selectPortal.ts index 0313774..e02f64c 100644 --- a/src/lib/core/ui/selectPortal.ts +++ b/src/lib/core/ui/selectPortal.ts @@ -1,19 +1,13 @@ -/** - * position:fixed dropdown anchored to a trigger element. - * - * getBoundingClientRect() returns full viewport coords. - * position:fixed is also relative to the viewport. - * So we just divide by zoom — no sidebar/titlebar subtraction needed - * (those subtractions are only needed in ContextMenu because its x/y come - * from a MouseEvent which is relative to the zoomed content area, not the viewport). - */ export function selectPortal( node: HTMLElement, trigger: HTMLElement | undefined, ): { update(t: HTMLElement | undefined): void; destroy(): void } { let currentTrigger = trigger + node.style.position = 'fixed' node.style.visibility = 'hidden' + node.style.zIndex = '99999' + document.body.appendChild(node) function getZoom(): number { const raw = parseFloat(document.documentElement.style.zoom || '1') || 1 @@ -23,33 +17,26 @@ export function selectPortal( function position() { if (!currentTrigger) return - const zoom = getZoom() - const r = currentTrigger.getBoundingClientRect() - - // Convert viewport px → CSS px by dividing by zoom - const left = r.left / zoom - const top = r.top / zoom - const bottom = r.bottom / zoom - const width = r.width / zoom - - const vw = window.innerWidth / zoom - const vh = window.innerHeight / zoom + const zoom = getZoom() + const r = currentTrigger.getBoundingClientRect() + const vw = window.innerWidth + const vh = window.innerHeight const menuH = node.offsetHeight const menuW = node.offsetWidth - const above = menuH > 0 && (vh - bottom) < menuH + 8 && top > menuH + 8 + const above = menuH > 0 && (vh - r.bottom) < menuH + 8 && r.top > menuH + 8 + const cssLeft = Math.max(4, r.left + menuW > vw ? r.right - menuW : r.left) / zoom + const cssTop = (above ? r.top - menuH - 4 : r.bottom + 4) / zoom - const cssLeft = Math.min(left, vw - menuW - 4) - const cssTop = above ? top - menuH - 4 : bottom + 4 - - node.style.left = `${Math.max(4, cssLeft)}px` + node.style.left = `${cssLeft}px` node.style.top = `${cssTop}px` - node.style.minWidth = `${width}px` + node.style.minWidth = `${r.width / zoom}px` node.style.visibility = 'visible' } requestAnimationFrame(() => position()) + window.addEventListener('scroll', position, { capture: true, passive: true }) window.addEventListener('resize', position, { passive: true }) @@ -62,6 +49,7 @@ export function selectPortal( destroy() { window.removeEventListener('scroll', position, true) window.removeEventListener('resize', position) + if (document.body.contains(node)) node.remove() }, } } \ No newline at end of file