Convert multiple pages into SPA

This commit is contained in:
2025-10-09 15:48:23 +02:00
parent c616b2da7f
commit 06d04a1abc
110 changed files with 1245 additions and 1319 deletions

View File

@@ -1,20 +1,17 @@
<script lang="ts">
import { onMount } from "svelte";
import LoadingIndicator from "util/LoadingIndicator.svelte";
import EditWindow from "./edit_window/EditWindow.svelte";
import Toolbar from "./Toolbar.svelte";
import Breadcrumbs from "./Breadcrumbs.svelte";
import DetailsWindow from "./DetailsWindow.svelte";
import FilePreview from "./viewers/FilePreview.svelte";
import FSUploadWidget from "./upload_widget/FSUploadWidget.svelte";
import { fs_download, type FSPath } from "./FilesystemAPI";
import Menu from "./Menu.svelte";
import { fs_download, type FSPath } from "lib/FilesystemAPI";
import { FSNavigator } from "./FSNavigator"
import { writable } from "svelte/store";
import { css_from_path } from "filesystem/edit_window/Branding";
import AffiliatePrompt from "user_home/AffiliatePrompt.svelte";
import { current_page_store } from "wrap/RouterStore";
let file_viewer: HTMLDivElement
let file_preview: FilePreview
let toolbar: Toolbar
let upload_widget: FSUploadWidget
@@ -22,25 +19,37 @@ let details_visible = false
let edit_window: EditWindow
let edit_visible = false
const loading = writable(true)
const nav = new FSNavigator(true)
onMount(() => {
nav.loading = loading
nav.open_node((window as any).initial_node as FSPath, false)
if ((window as any).intial_node !== undefined) {
console.debug("Loading initial node")
nav.open_node((window as any).initial_node as FSPath, false)
} else {
console.debug("No initial node, fetching path", window.location.pathname)
nav.navigate(decodeURI(window.location.pathname).replace(/^\/d/, ""), false)
}
const page_sub = current_page_store.subscribe(() => {
console.debug("Caught page transition to", window.location.pathname)
nav.navigate(decodeURI(window.location.pathname).replace(/^\/d/, ""), false)
})
// Subscribe to navigation updates. This function returns a deconstructor
// which we can conveniently return from our mount function as well
return nav.subscribe(nav => {
const nav_sub = nav.subscribe(nav => {
if (!nav.initialized) {
return
}
// Custom CSS rules for the whole viewer
document.documentElement.style = css_from_path(nav.path)
loading.set(false)
})
return () => {
page_sub()
nav_sub()
document.documentElement.style = ""
}
})
const keydown = (e: KeyboardEvent) => {
@@ -127,50 +136,41 @@ const keydown = (e: KeyboardEvent) => {
<svelte:window on:keydown={keydown} />
<div bind:this={file_viewer} class="file_viewer">
<div class="headerbar">
<Menu/>
<Breadcrumbs nav={nav}/>
</div>
<div class="filesystem">
<Breadcrumbs nav={nav}/>
<div class="viewer_area">
<Toolbar
bind:this={toolbar}
<div class="file_preview">
<FilePreview
bind:this={file_preview}
nav={nav}
file_viewer={file_viewer}
file_preview={file_preview}
bind:details_visible={details_visible}
upload_widget={upload_widget}
edit_window={edit_window}
bind:edit_visible={edit_visible}
on:open_sibling={e => nav.open_sibling(e.detail)}
on:download={() => fs_download(nav.base)}
on:details={() => details_visible = !details_visible}
/>
<div class="file_preview">
<FilePreview
bind:this={file_preview}
nav={nav}
upload_widget={upload_widget}
edit_window={edit_window}
on:open_sibling={e => nav.open_sibling(e.detail)}
on:download={() => fs_download(nav.base)}
on:details={() => details_visible = !details_visible}
/>
</div>
</div>
<DetailsWindow nav={nav} bind:visible={details_visible} />
<EditWindow nav={nav} bind:this={edit_window} bind:visible={edit_visible} />
<!-- This one is included at the highest level so uploads can keep running
even when the user navigates to a different directory -->
<FSUploadWidget nav={nav} bind:this={upload_widget} />
<AffiliatePrompt/>
<LoadingIndicator loading={$loading}/>
<Toolbar
bind:this={toolbar}
nav={nav}
bind:details_visible={details_visible}
edit_window={edit_window}
bind:edit_visible={edit_visible}
on:download={() => fs_download(nav.base)}
/>
</div>
<DetailsWindow nav={nav} bind:visible={details_visible} />
<EditWindow nav={nav} bind:this={edit_window} bind:visible={edit_visible} />
<!-- This one is included at the highest level so uploads can keep running
even when the user navigates to a different directory -->
<FSUploadWidget nav={nav} bind:this={upload_widget} />
<AffiliatePrompt/>
<style>
:global(*) {
transition: background-color 0.2s,
@@ -183,56 +183,15 @@ const keydown = (e: KeyboardEvent) => {
}
/* Viewer container */
.file_viewer {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
.filesystem {
display: flex;
flex-direction: column;
overflow: hidden;
/* Force some variable usage that is normally out of scope */
color: var(--body_text_color);
background-image: var(--background_image, var(--background_pattern));
background-color: var(--background_pattern_color);
background-size: var(--background_image_size, initial);
background-position: var(--background_image_position, initial);
background-repeat: var(--background_image_repeat, repeat);
}
/* Headerbar (row 1) */
.headerbar {
flex: 0 0 0;
display: flex;
flex-direction: row;
text-align: left;
box-shadow: none;
background-color: var(--shaded_background);
backdrop-filter: blur(4px);
}
/* File preview area (row 2) */
.viewer_area {
flex: 1 1 0;
display: flex;
flex-direction: row;
overflow: hidden;
}
/* This max-width needs to be synced with the .toolbar max-width in
Toolbar.svelte and the .label max-width in FileStats.svelte */
@media (max-width: 1000px) {
.viewer_area {
flex-direction: column-reverse;
}
height: 100vh;
width: 100%;
}
.file_preview {
flex: 1 1 0;
flex: 1 1 auto;
overflow: auto;
border: 1px solid var(--separator);
}
</style>