HASH 36a65ab48abd
DATE 2026-07-18
SUBJECT web: git path segments hard-wrap when a filename outgrows the frame
FILES 4 CHANGED
HASH 36a65ab48abd
DATE 2026-07-18
SUBJECT web: git path segments hard-wrap when
a filename outgrows the frame
FILES 4 CHANGED
┌─ .../.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json ───┐
│ diff --git a/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/re │
│ sults.json b/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/re │
│ sults.json │
│ index 7c4663b..ce2dcde 100644 │
│ --- a/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.j │
│ son │
│ +++ b/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.j │
│ son │
│ @@ -1 +1 @@ │
│ -{"version":"4.1.10","results":[[":src/components/GitPath/GitPath.test.ts",{"durat │
│ ion":0,"failed":true}]]} │
│ \ No newline at end of file │
│ +{"version":"4.1.10","results":[[":src/components/GitPath/GitPath.test.ts",{"durat │
│ ion":0,"failed":true}],[":ooknet-design/src/components/GitPath/GitPath.test.ts",{" │
│ duration":2.9634420000000006,"failed":false}]]} │
│ \ No newline at end of file │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ...95601890afd80709/results.json ───┐
│ diff --git a/node_modules/.vite/vitest/da39a │
│ 3ee5e6b4b0d3255bfef95601890afd80709/results. │
│ json b/node_modules/.vite/vitest/da39a3ee5e6 │
│ b4b0d3255bfef95601890afd80709/results.json │
│ index 7c4663b..ce2dcde 100644 │
│ --- a/node_modules/.vite/vitest/da39a3ee5e6b │
│ 4b0d3255bfef95601890afd80709/results.json │
│ +++ b/node_modules/.vite/vitest/da39a3ee5e6b │
│ 4b0d3255bfef95601890afd80709/results.json │
│ @@ -1 +1 @@ │
│ -{"version":"4.1.10","results":[[":src/compo │
│ nents/GitPath/GitPath.test.ts",{"duration":0 │
│ ,"failed":true}]]} │
│ \ No newline at end of file │
│ +{"version":"4.1.10","results":[[":src/compo │
│ nents/GitPath/GitPath.test.ts",{"duration":0 │
│ ,"failed":true}],[":ooknet-design/src/compon │
│ ents/GitPath/GitPath.test.ts",{"duration":2. │
│ 9634420000000006,"failed":false}]]} │
│ \ No newline at end of file │
└──────────────────────────────────────────────┘
┌─ ooknet-design/src/components/GitPath/GitPath.astro ───────────────────────┐
│ diff --git a/ooknet-design/src/components/GitPath/GitPath.astro b/ooknet-design/sr │
│ c/components/GitPath/GitPath.astro │
│ index f53c769..c714fc3 100644 │
│ --- a/ooknet-design/src/components/GitPath/GitPath.astro │
│ +++ b/ooknet-design/src/components/GitPath/GitPath.astro │
│ @@ -15,7 +15,7 @@ const variants: [string, PathSeg[][]][] = [ │
│ {variants.map(([cls, rows]) => │
│ rows.map((row, i) => ( │
│ <Pre class={cls}>{i > 0 ? " " : ""}{row.map((s, j) => ( │
│ - <Fragment>{j > 0 || i > 0 ? " / " : ""}{s.href │
│ + <Fragment>{(j > 0 || i > 0) && !s.cont ? " / " : ""}{s.href │
│ ? <a class="git-link" href={s.href}>{s.label}</a> │
│ : <span class="git-path-leaf">{s.label}</span>}</Fragment> │
│ ))}</Pre> │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ...ponents/GitPath/GitPath.astro ───┐
│ diff --git a/ooknet-design/src/components/Gi │
│ tPath/GitPath.astro b/ooknet-design/src/comp │
│ onents/GitPath/GitPath.astro │
│ index f53c769..c714fc3 100644 │
│ --- a/ooknet-design/src/components/GitPath/G │
│ itPath.astro │
│ +++ b/ooknet-design/src/components/GitPath/G │
│ itPath.astro │
│ @@ -15,7 +15,7 @@ const variants: [string, P │
│ athSeg[][]][] = [ │
│ {variants.map(([cls, rows]) => │
│ rows.map((row, i) => ( │
│ <Pre class={cls}>{i > 0 ? " " : ""}{ │
│ row.map((s, j) => ( │
│ - <Fragment>{j > 0 || i > 0 ? " / " : │
│ ""}{s.href │
│ + <Fragment>{(j > 0 || i > 0) && !s.c │
│ ont ? " / " : ""}{s.href │
│ ? <a class="git-link" href={s.hre │
│ f}>{s.label}</a> │
│ : <span class="git-path-leaf">{s. │
│ label}</span>}</Fragment> │
│ ))}</Pre> │
└──────────────────────────────────────────────┘
┌─ ooknet-design/src/components/GitPath/GitPath.test.ts ─────────────────────┐
│ diff --git a/ooknet-design/src/components/GitPath/GitPath.test.ts b/ooknet-design/ │
│ src/components/GitPath/GitPath.test.ts │
│ index ca68143..496f4e5 100644 │
│ --- a/ooknet-design/src/components/GitPath/GitPath.test.ts │
│ +++ b/ooknet-design/src/components/GitPath/GitPath.test.ts │
│ @@ -20,6 +20,18 @@ describe("pathSegs", () => { │
│ }); │
│ │
│ describe("layoutPath", () => { │
│ + it("hard-wraps single segments wider than the frame", () => { │
│ + const long = "death_knight_frost_race_p1_raid_cleave_burst.json"; │
│ + const segs = pathSegs(repo, "master", `web/data/${long}`); │
│ + const rows = layoutPath(segs, 48); │
│ + const joined = rows.flat().map((s) => s.label).join("").replace(/^ooknet.orgw │
│ ebdata/, ""); │
│ + expect(joined).toBe(long); │
│ + for (const row of rows) { │
│ + const width = row.reduce((n, s, j) => n + s.label.length + (j > 0 && !s.con │
│ t ? 3 : 0), 0); │
│ + expect(width).toBeLessThanOrEqual(48); │
│ + } │
│ + }); │
│ + │
│ it("wraps long paths at segment boundaries", () => { │
│ const segs = pathSegs(repo, "master", "a-long-directory/another-long-one/deep │
│ er/file.ts"); │
│ const rows = layoutPath(segs, 30); │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ...nents/GitPath/GitPath.test.ts ───┐
│ diff --git a/ooknet-design/src/components/Gi │
│ tPath/GitPath.test.ts b/ooknet-design/src/co │
│ mponents/GitPath/GitPath.test.ts │
│ index ca68143..496f4e5 100644 │
│ --- a/ooknet-design/src/components/GitPath/G │
│ itPath.test.ts │
│ +++ b/ooknet-design/src/components/GitPath/G │
│ itPath.test.ts │
│ @@ -20,6 +20,18 @@ describe("pathSegs", () = │
│ > { │
│ }); │
│ │
│ describe("layoutPath", () => { │
│ + it("hard-wraps single segments wider than │
│ the frame", () => { │
│ + const long = "death_knight_frost_race_p │
│ 1_raid_cleave_burst.json"; │
│ + const segs = pathSegs(repo, "master", ` │
│ web/data/${long}`); │
│ + const rows = layoutPath(segs, 48); │
│ + const joined = rows.flat().map((s) => s │
│ .label).join("").replace(/^ooknet.orgwebdata │
│ /, ""); │
│ + expect(joined).toBe(long); │
│ + for (const row of rows) { │
│ + const width = row.reduce((n, s, j) => │
│ n + s.label.length + (j > 0 && !s.cont ? 3 │
│ : 0), 0); │
│ + expect(width).toBeLessThanOrEqual(48) │
│ ; │
│ + } │
│ + }); │
│ + │
│ it("wraps long paths at segment boundarie │
│ s", () => { │
│ const segs = pathSegs(repo, "master", " │
│ a-long-directory/another-long-one/deeper/fil │
│ e.ts"); │
│ const rows = layoutPath(segs, 30); │
└──────────────────────────────────────────────┘
┌─ ooknet-design/src/components/GitPath/GitPath.ts ──────────────────────────┐
│ diff --git a/ooknet-design/src/components/GitPath/GitPath.ts b/ooknet-design/src/c │
│ omponents/GitPath/GitPath.ts │
│ index 5547942..a0d487a 100644 │
│ --- a/ooknet-design/src/components/GitPath/GitPath.ts │
│ +++ b/ooknet-design/src/components/GitPath/GitPath.ts │
│ @@ -6,6 +6,9 @@ import { checkGrid, len } from "../../lib/ascii"; │
│ export interface PathSeg { │
│ label: string; │
│ href?: string; │
│ + /** Continuation piece of a segment longer than the frame - rendered │
│ + * without a separator. */ │
│ + cont?: boolean; │
│ } │
│ │
│ export interface Props { │
│ @@ -37,18 +40,37 @@ export function pathSegs( │
│ return segs; │
│ } │
│ │
│ -/** Rows of segments fitting `width`; each costs " / " after the first. */ │
│ +/** Rows of segments fitting `width`; each costs " / " after the │
│ + * first. Segments wider than the frame (real filenames get there) │
│ + * hard-wrap into continuation pieces. */ │
│ export function layoutPath(segs: PathSeg[], width: number): PathSeg[][] { │
│ + const maxSeg = width - 2; │
│ + const pieces: PathSeg[] = []; │
│ + for (const s of segs) { │
│ + if (len(s.label) <= maxSeg) { │
│ + pieces.push(s); │
│ + continue; │
│ + } │
│ + const cps = [...s.label]; │
│ + for (let i = 0; i < cps.length; i += maxSeg) { │
│ + pieces.push({ │
│ + label: cps.slice(i, i + maxSeg).join(""), │
│ + href: s.href, │
│ + cont: i > 0, │
│ + }); │
│ + } │
│ + } │
│ const rows: PathSeg[][] = [[]]; │
│ let used = 0; │
│ - for (const s of segs) { │
│ + for (const s of pieces) { │
│ checkGrid(s.label, width, "git path segment"); │
│ - const w = len(s.label) + (rows[rows.length - 1].length ? 3 : 0); │
│ - if (rows[rows.length - 1].length && used + w > width) { │
│ + const row = rows[rows.length - 1]; │
│ + const w = len(s.label) + (row.length && !s.cont ? 3 : 0); │
│ + if (row.length && used + w > width) { │
│ rows.push([s]); │
│ used = len(s.label); │
│ } else { │
│ - rows[rows.length - 1].push(s); │
│ + row.push(s); │
│ used += w; │
│ } │
│ } │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ...components/GitPath/GitPath.ts ───┐
│ diff --git a/ooknet-design/src/components/Gi │
│ tPath/GitPath.ts b/ooknet-design/src/compone │
│ nts/GitPath/GitPath.ts │
│ index 5547942..a0d487a 100644 │
│ --- a/ooknet-design/src/components/GitPath/G │
│ itPath.ts │
│ +++ b/ooknet-design/src/components/GitPath/G │
│ itPath.ts │
│ @@ -6,6 +6,9 @@ import { checkGrid, len } fr │
│ om "../../lib/ascii"; │
│ export interface PathSeg { │
│ label: string; │
│ href?: string; │
│ + /** Continuation piece of a segment longe │
│ r than the frame - rendered │
│ + * without a separator. */ │
│ + cont?: boolean; │
│ } │
│ │
│ export interface Props { │
│ @@ -37,18 +40,37 @@ export function pathSegs │
│ ( │
│ return segs; │
│ } │
│ │
│ -/** Rows of segments fitting `width`; each │
│ costs " / " after the first. */ │
│ +/** Rows of segments fitting `width`; each │
│ costs " / " after the │
│ + * first. Segments wider than the frame (r │
│ eal filenames get there) │
│ + * hard-wrap into continuation pieces. */ │
│ export function layoutPath(segs: PathSeg[], │
│ width: number): PathSeg[][] { │
│ + const maxSeg = width - 2; │
│ + const pieces: PathSeg[] = []; │
│ + for (const s of segs) { │
│ + if (len(s.label) <= maxSeg) { │
│ + pieces.push(s); │
│ + continue; │
│ + } │
│ + const cps = [...s.label]; │
│ + for (let i = 0; i < cps.length; i += ma │
│ xSeg) { │
│ + pieces.push({ │
│ + label: cps.slice(i, i + maxSeg).joi │
│ n(""), │
│ + href: s.href, │
│ + cont: i > 0, │
│ + }); │
│ + } │
│ + } │
│ const rows: PathSeg[][] = [[]]; │
│ let used = 0; │
│ - for (const s of segs) { │
│ + for (const s of pieces) { │
│ checkGrid(s.label, width, "git path seg │
│ ment"); │
│ - const w = len(s.label) + (rows[rows.len │
│ gth - 1].length ? 3 : 0); │
│ - if (rows[rows.length - 1].length && use │
│ d + w > width) { │
│ + const row = rows[rows.length - 1]; │
│ + const w = len(s.label) + (row.length && │
│ !s.cont ? 3 : 0); │
│ + if (row.length && used + w > width) { │
│ rows.push([s]); │
│ used = len(s.label); │
│ } else { │
│ - rows[rows.length - 1].push(s); │
│ + row.push(s); │
│ used += w; │
│ } │
│ } │
└──────────────────────────────────────────────┘
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET