web/repo: a file page draws a hundred rows of a big folder and a link to the folder's page, and the rest once the app starts
Signed-off-by: dawn <90008@klbr.net>
92 unmodified lines9394959697989910010110210310410510610710810911011111211311411591 unmodified lines2072082092102112122132142154 unmodified lines22022122222320822422522622722846 unmodified lines27527627727827928028128228328428528628728828997 unmodified lines3873883893903913923933943953963973 unmodified lines92 unmodified lines
const linkOf = (entry: TreeEntrySummary, at: string) => href ? href(at, entry.kind) : hrefFor(entry, at);
// until the app starts, a big folder draws the rows around the current one and a link to // the folder's own page, which draws them all; once it has, they are all here too const ROW_WINDOW = 100; let started = $state(false); onMount(() => { started = true; }); const rowsOf = (items: TreeEntrySummary[], dir: string): TreeEntrySummary[] => { if (started || href || onpick || items.length <= ROW_WINDOW || dir === currentPath) return items; const at = items.findIndex((entry) => within(currentPath ?? "", pathOf(dir, entry))); const start = Math.max(0, Math.min(at - ROW_WINDOW / 2, items.length - ROW_WINDOW)); return items.slice(start, start + ROW_WINDOW); };
const ensureLoaded = async (at: string) => { if (!load || at in children || fetching.has(at)) return; fetching.add(at); failed.delete(at);91 unmodified lines)}{#each name.split("/") as part, index (index)}{#if index > 0}<span class="sl">/</span >{/if}{part}{/each}{#if folder}<span class="sl">/</span>{/if}{/snippet}
{#snippet list(items: TreeEntrySummary[], dir: string, level: number)} {@const rows = rowsOf(items, dir)} <ul class="t"> {#if level === 1 && path !== ""} <li> <div class="row dir trail">4 unmodified lines > </div> </li> {/if} {#each items as entry (entry.name)} {#each rows as entry (entry.name)} {@const start = join(dir, entry.name)} {@const at = pathOf(dir, entry)} {@const name = at.slice(dir ? dir.length + 1 : 0)} {#if shown(entry, dir)}46 unmodified lines {/if} </li> {/if} {/each} {#if rows.length < items.length} <li> <a href={treeLink(dir)} class="row all" >all {items.length} in {dir.split("/").at(-1)}<span class="sl">/</span></a > </li> {/if} </ul>{/snippet}
{@render list(entries, path, 1)}97 unmodified lines } .trail a:first-child { color: var(--y-accent); } .all { color: var(--y-muted); } .note { margin: 0; padding: 0.16rem 0 0.16rem 1.35rem; color: var(--y-muted);3 unmodified lines7 unmodified lines89101112131415161766 unmodified lines848586878889909192939495969798991001011021031041051061071081091101111121131147 unmodified lines { name: "a b.md", kind: "file", size: 12 }];
const markup = (props: { entries?: TreeEntrySummary[]; href?: (path: string) => string; load?: () => Promise<TreeEntrySummary[]>; currentPath?: string; listings?: Record<string, TreeEntrySummary[]>; compact?: Record<string, string>;66 unmodified lines expect(html).toContain('href="/alice/tangled/tree/feat%2Fx/deep"'); expect(html).toContain('href="/alice/tangled/tree/feat%2Fx/deep/er"'); expect(html).toContain('href="/alice/tangled/blob/feat%2Fx/deep/er/a%20b.md"'); });
describe("a big folder", () => { const big = Array.from({ length: 300 }, (_, index) => ({ name: `${String(index).padStart(3, "0")}.json`, kind: "file" as const, size: 1 })); const rows = (html: string) => html.match(/href="[^"]*\/blob\/[^"]*"/g)?.length ?? 0;
it("draws a window around the current file and links its page for the rest", () => { const html = markup({ entries: big, load: async () => [], currentPath: "150.json" });
expect(rows(html)).toBe(100); expect(html).toContain('href="/alice/tangled/blob/feat%2Fx/100.json"'); expect(html).toContain('href="/alice/tangled/blob/feat%2Fx/199.json"'); expect(html).not.toContain("099.json"); expect(html).toContain('href="/alice/tangled/tree/feat%2Fx"'); expect(html.replace(/<[^>]+>/g, "")).toContain("all 300 in"); });
it("draws every row on the folder's own page, and in a tree that links its own way", () => { expect(rows(markup({ entries: big, load: async () => [], currentPath: "" }))).toBe(300); const diff = markup({ entries: big, href: (path) => `#${path}`, currentPath: "a" }); expect(diff.match(/href="#[^"]*"/g)).toHaveLength(300); }); });});