Move search bar into modal

This commit is contained in:
2026-04-01 19:38:15 +02:00
parent dbfe9ff383
commit f578f2c2c0
13 changed files with 299 additions and 202 deletions

View File

@@ -0,0 +1,4 @@
import type { Snippet } from "svelte";
import { writable } from "svelte/store";
export let breadcrumbs_store = writable(null as Snippet);

View File

@@ -17,6 +17,7 @@ import { get_user } from "lib/PixeldrainAPI";
import Tree from "./Tree.svelte";
import MenuEntry from "./MenuEntry.svelte";
import { writable } from "svelte/store";
import { breadcrumbs_store } from "./BreadcrumbStore";
// The menu swipe will be detected if it was less than this much pixels from the
// screen edge
@@ -147,100 +148,114 @@ const set_offset = (off: number) => {
<svelte:window ontouchstart={touchstart} ontouchmove={touchmove} ontouchend={touchend}/>
<button class="menu_button" onclick={toggle_menu}>
<i class="icon">menu</i>
{#if $menu_is_open}
<span>Menu</span>
{/if}
</button>
<div class="nav_container" bind:this={menu}>
<div class="scroll_container">
<nav class="nav" bind:this={nav}>
<a class="button" href="/" use:highlight_current_page>
<i class="icon">home</i>
<span>Home</span>
</a>
{#if $user.username !== undefined && $user.username !== ""}
<MenuEntry id="subscription_info" collapsed={false}>
{#snippet title()}
<div class="username">{$user.username}</div>
{/snippet}
{#snippet body()}
<div class="stats_table">
<div>Subscription</div>
<div>{$user.subscription.name}</div>
{#if $user.subscription.type === "prepaid"}
<div>Credit</div>
<div><Euro amount={$user.balance_micro_eur}/></div>
{/if}
<div>Storage used</div>
<div>{formatDataVolume($user.filesystem_storage_used, 3)}</div>
<div>Transfer used</div>
<div>{formatDataVolume($user.monthly_transfer_used, 3)}</div>
</div>
{/snippet}
</MenuEntry>
<a class="button" href="/d/me" use:highlight_current_page>
<i class="icon">folder</i>
<span>Filesystem</span>
<div class="wrap">
<div class="nav_container" bind:this={menu}>
<div class="scroll_container">
<nav class="nav" bind:this={nav}>
{#if document.documentElement.clientWidth < min_screen_size_menu_open}
<button class="button" onclick={toggle_menu}>
<i class="icon">menu</i>
Menu
</button>
{/if}
<a class="button" href="/" use:highlight_current_page>
<i class="icon">home</i>
<span>Home</span>
</a>
<a class="button" href="/user" use:highlight_current_page>
<i class="icon">person</i>
<span>Account</span>
</a>
{#if $user.is_admin}
<a class="button" href="/admin" use:highlight_current_page>
<i class="icon">admin_panel_settings</i>
<span>Admin Panel</span>
{#if $user.username !== undefined && $user.username !== ""}
<MenuEntry id="subscription_info" collapsed={false}>
{#snippet title()}
<div class="username">{$user.username}</div>
{/snippet}
{#snippet body()}
<div class="stats_table">
<div>Subscription</div>
<div>{$user.subscription.name}</div>
{#if $user.subscription.type === "prepaid"}
<div>Credit</div>
<div><Euro amount={$user.balance_micro_eur}/></div>
{/if}
<div>Storage used</div>
<div>{formatDataVolume($user.filesystem_storage_used, 3)}</div>
<div>Transfer used</div>
<div>{formatDataVolume($user.monthly_transfer_used, 3)}</div>
</div>
{/snippet}
</MenuEntry>
<a class="button" href="/d/me" use:highlight_current_page>
<i class="icon">folder</i>
<span>Filesystem</span>
</a>
<a class="button" href="/user" use:highlight_current_page>
<i class="icon">person</i>
<span>Account</span>
</a>
{#if $user.is_admin}
<a class="button" href="/admin" use:highlight_current_page>
<i class="icon">admin_panel_settings</i>
<span>Admin Panel</span>
</a>
{/if}
{:else}
<a class="button" href="/login" use:highlight_current_page>
<i class="icon">login</i>
<span>Login</span>
</a>
<a class="button" href="/register" use:highlight_current_page>
<i class="icon">how_to_reg</i>
<span>Register</span>
</a>
{/if}
{:else}
<a class="button" href="/login" use:highlight_current_page>
<i class="icon">login</i>
<span>Login</span>
<div class="separator"></div>
<a class="button" href="/speedtest" use:highlight_current_page>
<i class="icon">speed</i>
<span>Speedtest</span>
</a>
<a class="button" href="/register" use:highlight_current_page>
<i class="icon">how_to_reg</i>
<span>Register</span>
<a class="button" href="/appearance" use:highlight_current_page>
<i class="icon">palette</i>
<span>Themes</span>
</a>
{/if}
<div class="separator"></div>
<a class="button" href="/speedtest" use:highlight_current_page>
<i class="icon">speed</i>
<span>Speedtest</span>
</a>
<a class="button" href="/appearance" use:highlight_current_page>
<i class="icon">palette</i>
<span>Themes</span>
</a>
<Bookmarks menu_collapsed={false}/>
<Tree menu_collapsed={false}/>
</nav>
<Bookmarks menu_collapsed={false}/>
<Tree menu_collapsed={false}/>
</nav>
</div>
</div>
</div>
<div class="page">
<Router/>
</div>
<div class="page">
<div class="header">
<button class="menu_button" onclick={toggle_menu}>
<i class="icon">menu</i>
</button>
<div class="breadcrumbs">
{#if $breadcrumbs_store !== null}
{@render $breadcrumbs_store()}
{/if}
</div>
</div>
{#if $loading_store !== 0}
<div class="spinner">
<Spinner/>
<Router/>
</div>
{/if}
{#if $loading_store !== 0}
<div class="spinner">
<Spinner/>
</div>
{/if}
</div>
<style>
:global(body) {
.wrap {
display: flex;
flex-direction: row;
@@ -251,27 +266,13 @@ const set_offset = (off: number) => {
background-position: var(--background_image_position, initial);
background-repeat: var(--background_image_repeat, repeat);
background-attachment: fixed;
width: 100%;
min-height: 100vh;
}
.menu_button {
position: fixed;
backface-visibility: hidden;
z-index: 10;
top: 0;
left: 0;
background: none;
box-shadow: none;
margin: 0;
padding: 4px;
border-radius: 0;
border-bottom-right-radius: 4px;
backdrop-filter: blur(6px);
}
.nav_container {
flex: 0 0 auto;
border-right: 1px solid var(--separator);
background: var(--shaded_background);
backdrop-filter: blur(6px);
z-index: 9;
}
.scroll_container {
@@ -286,7 +287,6 @@ const set_offset = (off: number) => {
display: flex;
flex-direction: column;
width: 15em;
padding-top: 2em;
}
.nav > .button {
background: none;
@@ -294,8 +294,10 @@ const set_offset = (off: number) => {
}
.page {
flex: 1 1 auto;
overflow-x: hidden;
max-width: 100%;
max-width: 100vw;
min-width: 0; /* prevents overflow */
display: flex;
flex-direction: column;
}
.username {
flex: 1 1 auto;
@@ -314,6 +316,28 @@ const set_offset = (off: number) => {
margin: 5px;
}
.header {
flex: 0 0 auto;
display: flex;
flex-direction: row;
align-items: center;
justify-content: left;
background: var(--shaded_background);
border-bottom: 1px solid var(--separator);
}
.menu_button {
flex: 0 0 auto;
background: none;
box-shadow: none;
}
.breadcrumbs {
flex: 1 1 auto;
display: flex;
flex-wrap: wrap;
flex-direction: row;
align-items: center;
}
.spinner {
position: fixed;
top: 10px;

View File

@@ -11,6 +11,7 @@ import Appearance from "pages/Appearance.svelte";
import Footer from "layout/Footer.svelte";
import { current_page_store, type Tab } from "./RouterStore";
import { get_user, type User } from "lib/PixeldrainAPI";
import { breadcrumbs_store } from "./BreadcrumbStore";
let pages: Tab[] = [
{
@@ -37,6 +38,7 @@ let pages: Tab[] = [
title: "Filesystem",
component: Filesystem,
footer: false,
custom_breadcrumbs: true,
}, {
path: "/admin",
prefix: "/admin/",
@@ -107,6 +109,10 @@ const load_page = (pathname: string, history: boolean): boolean => {
window.history.pushState({}, window.document.title, pathname)
}
if (current_page.custom_breadcrumbs !== true) {
breadcrumbs_store.set(breadcrumbs)
}
// The current_page_store updates all the listening pages for navigation
// events. We first wait for a tick so that the current page gets unmounted
// before sending the event. That way a stale page will not get events which
@@ -144,6 +150,10 @@ const popstate = (e: PopStateEvent) => {
}
</script>
{#snippet breadcrumbs()}
{current_page.title}
{/snippet}
<svelte:document onclick={click}/>
<svelte:window onpopstate={popstate}/>

View File

@@ -8,5 +8,6 @@ export type Tab = {
component?: Component,
footer?: boolean,
login?: boolean,
custom_breadcrumbs?: boolean,
};
export let current_page_store = writable({} as Tab);