master @ 79 LINES
[ HISTORY ] [ UP ]
┌─ TS ───────────────────────────────────────────────────────────────────────┐
│ // Clickable file path, github-style: repo / dir / dir / leaf. Every │
│ // segment but the last links to its tree page; long paths wrap at │
│ // segment boundaries. │
│ 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 { │
│ repo: { name: string; slug: string }; │
│ branch: string; │
│ /** Path within the repo; the leaf gets no link. */ │
│ path: string; │
│ /** Link the leaf too (tree pages: current dir is the leaf). */ │
│ linkLeaf?: boolean; │
│ } │
│ │
│ export function pathSegs( │
│ repo: { name: string; slug: string }, │
│ branch: string, │
│ path: string, │
│ linkLeaf = false, │
│ ): PathSeg[] { │
│ const segs: PathSeg[] = [{ label: repo.name, href: `/git/${repo.slug}/` }]; │
│ const parts = path.split("/").filter(Boolean); │
│ parts.forEach((part, i) => { │
│ const isLeaf = i === parts.length - 1; │
│ const sub = parts.slice(0, i + 1).join("/"); │
│ segs.push({ │
│ label: part, │
│ href: !isLeaf || linkLeaf ? `/git/${repo.slug}/tree/${branch}/${sub}/` : und │
│ efined, │
│ }); │
│ }); │
│ if (!linkLeaf && segs.length > 1) delete segs[segs.length - 1].href; │
│ return segs; │
│ } │
│ │
│ /** 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 pieces) { │
│ checkGrid(s.label, width, "git path segment"); │
│ 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 { │
│ row.push(s); │
│ used += w; │
│ } │
│ } │
│ return rows; │
│ } │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ TS ─────────────────────────────────┐
│ // Clickable file path, github-style: repo / │
│ dir / dir / leaf. Every │
│ // segment but the last links to its tree pa │
│ ge; long paths wrap at │
│ // segment boundaries. │
│ import { checkGrid, len } from "../../lib/as │
│ cii"; │
│ │
│ 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 { │
│ repo: { name: string; slug: string }; │
│ branch: string; │
│ /** Path within the repo; the leaf gets no │
│ link. */ │
│ path: string; │
│ /** Link the leaf too (tree pages: current │
│ dir is the leaf). */ │
│ linkLeaf?: boolean; │
│ } │
│ │
│ export function pathSegs( │
│ repo: { name: string; slug: string }, │
│ branch: string, │
│ path: string, │
│ linkLeaf = false, │
│ ): PathSeg[] { │
│ const segs: PathSeg[] = [{ label: repo.nam │
│ e, href: `/git/${repo.slug}/` }]; │
│ const parts = path.split("/").filter(Boole │
│ an); │
│ parts.forEach((part, i) => { │
│ const isLeaf = i === parts.length - 1; │
│ const sub = parts.slice(0, i + 1).join(" │
│ /"); │
│ segs.push({ │
│ label: part, │
│ href: !isLeaf || linkLeaf ? `/git/${re │
│ po.slug}/tree/${branch}/${sub}/` : undefined │
│ , │
│ }); │
│ }); │
│ if (!linkLeaf && segs.length > 1) delete s │
│ egs[segs.length - 1].href; │
│ return segs; │
│ } │
│ │
│ /** Rows of segments fitting `width`; each c │
│ osts " / " after the │
│ * first. Segments wider than the frame (re │
│ al 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 += max │
│ Seg) { │
│ 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 pieces) { │
│ checkGrid(s.label, width, "git path segm │
│ ent"); │
│ 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 { │
│ row.push(s); │
│ used += w; │
│ } │
│ } │
│ return rows; │
│ } │
└──────────────────────────────────────────────┘
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET