diff --git a/res/static/style/layout.css b/res/static/style/layout.css index 1078c95..b6d24ba 100644 --- a/res/static/style/layout.css +++ b/res/static/style/layout.css @@ -501,7 +501,7 @@ input[type="color"]:focus { color: var(--input_text); text-decoration: none; background: var(--input_hover_background); - box-shadow: 0px 0px 0px 1px var(--highlight_color); + box-shadow: 0px 0px 0px 1px var(--highlight_color) !important; } button:active, @@ -515,8 +515,7 @@ input[type="color"]:active { } .button_highlight { - background: var(--highlight_background) !important; - color: var(--highlight_text_color) !important; + box-shadow: 0px 0px 0px 1px var(--highlight_color) !important; } .button_red { diff --git a/svelte/src/filesystem/FSNavigator.ts b/svelte/src/filesystem/FSNavigator.ts index f3180ac..677ea09 100644 --- a/svelte/src/filesystem/FSNavigator.ts +++ b/svelte/src/filesystem/FSNavigator.ts @@ -53,12 +53,19 @@ export class FSNavigator { } } + last_requested_path: string = "" navigate = async (path: string, push_history: boolean) => { + if (path === this.last_requested_path) { + console.debug("FSNavigator: Requested path is equal to current path. Debouncing") + return + } + this.last_requested_path = path + if (path[0] !== "/") { path = "/" + path } - console.debug("Navigating to path", path, push_history) + console.debug("FSNavigator: Navigating to path", path, push_history) try { loading_start() diff --git a/svelte/src/filesystem/filemanager/FileManager.svelte b/svelte/src/filesystem/filemanager/FileManager.svelte index 830dd61..a10d823 100644 --- a/svelte/src/filesystem/filemanager/FileManager.svelte +++ b/svelte/src/filesystem/filemanager/FileManager.svelte @@ -69,7 +69,7 @@ const file_event: FileActionHandler = (action: FileAction, index: number, orig: if (navigator.maxTouchPoints && navigator.maxTouchPoints > 0) { select_node(index) } else { - file_menu.open(nav.children[index], orig.target) + file_menu.open(nav.children[index], orig.target, orig) } break case FileAction.Edit: @@ -86,7 +86,7 @@ const file_event: FileActionHandler = (action: FileAction, index: number, orig: select_node(index) break case FileAction.Menu: - file_menu.open(nav.children[index], orig.target) + file_menu.open(nav.children[index], orig.target, orig) break } } diff --git a/svelte/src/filesystem/filemanager/FileMenu.svelte b/svelte/src/filesystem/filemanager/FileMenu.svelte index d7e6975..70c9f45 100644 --- a/svelte/src/filesystem/filemanager/FileMenu.svelte +++ b/svelte/src/filesystem/filemanager/FileMenu.svelte @@ -19,16 +19,23 @@ let { let dialog: Dialog = $state() let node: FSNode = $state(null) -export const open = async (n: FSNode, target: EventTarget) => { +export const open = async (n: FSNode, target: EventTarget, event: Event) => { node = n - let el: HTMLElement = (target as Element).closest("button") - if (el === null) { - el = (target as Element).closest("a") - } - // Wait for the view to update, so the dialog gets the proper measurements await tick() - dialog.open(el.getBoundingClientRect()) + + let el: HTMLElement = (target as Element).closest("button") + if (el !== null) { + dialog.open(el.getBoundingClientRect()) + return + } + + if (event instanceof MouseEvent) { + dialog.open(event) + return + } + + console.error("Cannot find suitable target for spawning dialog window") } const delete_node = async () => { diff --git a/svelte/src/layout/Dialog.svelte b/svelte/src/layout/Dialog.svelte index 3b93953..4ad0dd9 100644 --- a/svelte/src/layout/Dialog.svelte +++ b/svelte/src/layout/Dialog.svelte @@ -4,7 +4,7 @@ let { children }: { } = $props(); let dialog: HTMLDialogElement = $state() -export const open = (button_rect: DOMRect) => { +export const open = (origin: DOMRect|MouseEvent) => { // Show the window so we can get the location dialog.showModal() @@ -15,10 +15,18 @@ export const open = (button_rect: DOMRect) => { const max_left = window.innerWidth - dialog_rect.width - edge_offset const max_top = window.innerHeight - dialog_rect.height - edge_offset - // Position the dialog in horizontally in the center of the button and - // verticially below it - const min_left = Math.max((button_rect.left + (button_rect.width/2)) - (dialog_rect.width/2), edge_offset) - const min_top = Math.max(button_rect.bottom, edge_offset) + let min_left: number, min_top: number + if (origin instanceof DOMRect) { + // Position the dialog in horizontally in the center of the button and + // verticially below it + min_left = Math.max((origin.left + (origin.width/2)) - (dialog_rect.width/2), edge_offset) + min_top = Math.max(origin.bottom, edge_offset) + } else if (origin instanceof MouseEvent) { + // Place the dialog at the bottom right of the mouse pointer, like + // regular context menus + min_left = Math.max(origin.clientX, edge_offset) + min_top = Math.max(origin.clientY, edge_offset) + } // Place the window dialog.style.left = Math.round(Math.min(min_left, max_left)) + "px" @@ -35,6 +43,7 @@ export const close = () => { // the dialog itself then the click was on the dialog background const click = (e: MouseEvent) => { if (e.target === dialog) { + e.preventDefault() dialog.close() } } @@ -42,7 +51,7 @@ const click = (e: MouseEvent) => { - + {@render children?.()} diff --git a/svelte/src/wrap/Router.svelte b/svelte/src/wrap/Router.svelte index 6775791..d8b9e68 100644 --- a/svelte/src/wrap/Router.svelte +++ b/svelte/src/wrap/Router.svelte @@ -63,7 +63,11 @@ onMount(async () => { let current_page: Tab = $state(null) const load_page = (pathname: string, history: boolean): boolean => { - console.debug("Navigating to page", pathname, "log history:", history) + console.debug( + "Page router: Navigating to page", pathname, + "current path", window.location.pathname, + "log history:", history, + ) const path_decoded = decodeURIComponent(pathname) let page_by_path: Tab = null diff --git a/svelte/src/wrap/Tree.svelte b/svelte/src/wrap/Tree.svelte index 0b11a4b..d5689c1 100644 --- a/svelte/src/wrap/Tree.svelte +++ b/svelte/src/wrap/Tree.svelte @@ -1,6 +1,7 @@