Add lazy thumbnail loading, restore scroll position when navigating to directory

This commit is contained in:
2026-09-02 00:12:25 +02:00
parent 22d7b98794
commit 2dafceb304
5 changed files with 36 additions and 27 deletions

View File

@@ -28,7 +28,7 @@ let {
class:node_selected={child.fm_selected}
class:hidden={child.name.startsWith(".") && !show_hidden}
>
<img src={fs_node_icon(child, 64, 64)} class="node_icon" class:large_icons alt="icon"/>
<img src={fs_node_icon(child, 64, 64)} class="node_icon" class:large_icons loading="lazy" alt="icon"/>
<div class="node_name">
{child.name}
</div>
@@ -69,6 +69,8 @@ let {
/* backdrop-filter: blur(4px); */
border-radius: 4px;
gap: 6px;
content-visibility: auto;
contain-intrinsic-size: auto 2.4em;
}
.node:hover:not(.node_selected) {
background: var(--input_hover_background);

View File

@@ -1,6 +1,11 @@
<script lang="ts" module>
// Scroll offset per directory path. The file manager is destroyed when a file
// is opened, so the positions are kept here to survive the remount
const scroll_positions = new Map<string, number>()
</script>
<script lang="ts">
import { fs_rename, fs_trash, FSNode } from "lib/FilesystemAPI.svelte"
import { onMount } from "svelte"
import CreateDirectory from "./CreateDirectory.svelte"
import ListView from "./ListView.svelte"
import GalleryView from "./GalleryView.svelte"
@@ -22,7 +27,7 @@ let {
upload_widget,
edit_window = $bindable(),
search_bar = $bindable(),
directory_view = $bindable(""),
directory_view = $bindable(localStorage.getItem("directory_view") || "list"),
children
}: {
nav: FSNavigator;
@@ -33,12 +38,15 @@ let {
children?: import('svelte').Snippet;
} = $props();
let large_icons = $state(false)
let large_icons = $state(localStorage.getItem("large_icons") === "true")
let uploader!: FsUploadWidget
let mode = $state("viewing")
let creating_dir = $state(false)
let show_hidden = $state(false)
let file_menu!: FileMenu
$effect(() => {
window.scrollTo(0, scroll_positions.get($nav.base.path) ?? 0)
})
export const upload = (files: File[]) => {
return uploader.upload_files(files)
@@ -270,18 +278,13 @@ const move_here = async () => {
}
}
onMount(() => {
if(typeof Storage !== "undefined") {
directory_view = localStorage.getItem("directory_view")
large_icons = localStorage.getItem("large_icons") === "true"
}
if (directory_view === "" || directory_view === null) {
directory_view = "list"
}
})
</script>
<svelte:window onkeydown={keypress} onkeyup={keypress} />
<svelte:window
onkeydown={keypress}
onkeyup={keypress}
onscroll={() => scroll_positions.set(nav.base.path, window.scrollY)}
/>
<div
class="container"
@@ -407,9 +410,8 @@ onMount(() => {
<style>
.container {
padding: 0;
overflow: auto;
display: block;
height: 100%; /* Used for drop target */
min-height: 100%; /* Used for drop target */
}
.width_container {
position: sticky;

View File

@@ -27,11 +27,13 @@ let {
class:large_icons
title={child.name}
>
<div
<img
class="node_icon"
class:cover={fs_node_type(child) === "image" || fs_node_type(child) === "video"}
style='background-image: url("{fs_node_icon(child, 256, 256)}");'>
</div>
src={fs_node_icon(child, 256, 256)}
loading="lazy"
alt=""
/>
<div class="node_name">
{child.name}
</div>
@@ -51,6 +53,10 @@ let {
aspect-ratio: 1;
width: 150px;
height: 150px;
/* Skips style, layout and paint for nodes which are off-screen. The
intrinsic size keeps the scrollbar accurate while they're skipped */
content-visibility: auto;
contain-intrinsic-size: auto 150px;
overflow: hidden;
background: var(--body_background);
/* backdrop-filter: blur(4px); */
@@ -65,6 +71,7 @@ let {
.file.large_icons {
width: 200px;
height: 200px;
contain-intrinsic-size: auto 200px;
}
/* On very small screens we switch to grid layout */
@@ -93,13 +100,13 @@ let {
}
.node_icon {
flex: 1 1 0;
min-height: 0;
width: 100%;
border-radius: 4px;
background-position: center;
background-size: contain;
background-repeat: no-repeat;
object-fit: contain;
}
.node_icon.cover {
background-size: cover;
object-fit: cover;
}
.node_name {
flex: 0 0 auto;

View File

@@ -100,7 +100,7 @@ onMount(load_settings)
class:hidden={child.name.startsWith(".") && !show_hidden}
>
<td>
<img src={fs_node_icon(child, 64, 64)} class="node_icon" class:large_icons alt="icon"/>
<img src={fs_node_icon(child, 64, 64)} class="node_icon" class:large_icons loading="lazy" alt="icon"/>
</td>
<td class="node_name">
<a class="title_link" href={"/d"+fs_encode_path(child.path)}>
@@ -133,7 +133,7 @@ onMount(load_settings)
{/if}
</td>
<td class="node_size hide_small" class:hidden={!config.id}>
<CopyButton text={$nav.base.id} onclick={prevent} />
<CopyButton text={child.id} onclick={prevent} />
<a href="/d/{child.id}" onclick={prevent}>{child.id}</a>
</td>
<td class="node_icons">
@@ -187,7 +187,6 @@ onMount(load_settings)
background: var(--body_background);
border-collapse: collapse;
backdrop-filter: blur(4px);
max-width: 1200px;
margin: auto; /* center */
}
td {