OOKNET                             [ /  search the index  ]  
──────────────────────────────────────────────────────────────────────────────────────
══════════════════════════════════════════════════════════════════════════════════════
OOKNET   [ /  search  ]  
────────────────────────────────────────────────
════════════════════════════════════════════════
 
 
master @ 63 LINES
 
[ HISTORY ]  [ UP ]
 

// Nav row data and width math. Items render as [ LABEL ] buttons, so
// each is buttonWidth(label) cells regardless of active state.
import { buttonWidth } from "../Button/Button";

export interface NavItem {
  label: string;
  href: string;
}

export interface Props {
  width?: number;
  items?: NavItem[];
  /** Spaces between buttons. Defaults to NAV_GAP (4); narrower frames
   *  pass 1 to fit four bracketed labels in 48 cells. */
  gap?: number;
  /** Whether to render the EN label and reserve space for it. */
  lang?: boolean;
}

export const NAV_ITEMS: NavItem[] = [
  { label: "KB",       href: "/kb/" },
  { label: "GIT",      href: "/git/" },
  { label: "PROJECTS", href: "/projects/" },
  { label: "ABOUT",    href: "/about/" },
];

export const NAV_GAP = 4;       // spaces between buttons
export const NAV_LANG_W = 2;    // visible width of "EN"

/** Total width of all buttons + inter-button gaps. */
export function itemsWidth(items: NavItem[], gap = NAV_GAP): number {
  return items.reduce(
    (sum, it, i) => sum + buttonWidth(it.label) + (i > 0 ? gap : 0),
    0,
  );
}

/** Greedy row wrap. The first row reserves `reserved` cells (the EN
 *  label and a space) so nav grows downward instead of overflowing the
 *  narrow frame. */
export function navRows(items: NavItem[], width: number, gap = NAV_GAP, reserved =
 0): NavItem[][] {
  const rows: NavItem[][] = [[]];
  let used = reserved;
  for (const it of items) {
    const row = rows[rows.length - 1];
    const w = buttonWidth(it.label) + (row.length ? gap : 0);
    if (row.length && used + w > width) {
      rows.push([it]);
      used = buttonWidth(it.label);
    } else {
      row.push(it);
      used += w;
    }
  }
  return rows;
}

/** Active match: exact for the root, prefix elsewhere. */
export function isActive(href: string, path: string): boolean {
  if (href === "/") return path === "/";
  return path === href || path.startsWith(href);
}

// Nav row data and width math. Items render
 as [ LABEL ] buttons, so
// each is buttonWidth(label) cells regardle
ss of active state.
import { buttonWidth } from "../Button/Butto
n";

export interface NavItem {
  label: string;
  href: string;
}

export interface Props {
  width?: number;
  items?: NavItem[];
  /** Spaces between buttons. Defaults to NA
V_GAP (4); narrower frames
   *  pass 1 to fit four bracketed labels in
 48 cells. */
  gap?: number;
  /** Whether to render the EN label and res
erve space for it. */
  lang?: boolean;
}

export const NAV_ITEMS: NavItem[] = [
  { label: "KB",       href: "/kb/" },
  { label: "GIT",      href: "/git/" },
  { label: "PROJECTS", href: "/projects/" },
  { label: "ABOUT",    href: "/about/" },
];

export const NAV_GAP = 4;       // spaces be
tween buttons
export const NAV_LANG_W = 2;    // visible w
idth of "EN"

/** Total width of all buttons + inter-butto
n gaps. */
export function itemsWidth(items: NavItem[],
 gap = NAV_GAP): number {
  return items.reduce(
    (sum, it, i) => sum + buttonWidth(it.lab
el) + (i > 0 ? gap : 0),
    0,
  );
}

/** Greedy row wrap. The first row reserves 
`reserved` cells (the EN
 *  label and a space) so nav grows downward
 instead of overflowing the
 *  narrow frame. */
export function navRows(items: NavItem[], wi
dth: number, gap = NAV_GAP, reserved = 0): N
avItem[][] {
  const rows: NavItem[][] = [[]];
  let used = reserved;
  for (const it of items) {
    const row = rows[rows.length - 1];
    const w = buttonWidth(it.label) + (row.l
ength ? gap : 0);
    if (row.length && used + w > width) {
      rows.push([it]);
      used = buttonWidth(it.label);
    } else {
      row.push(it);
      used += w;
    }
  }
  return rows;
}

/** Active match: exact for the root, prefix
 elsewhere. */
export function isActive(href: string, path:
 string): boolean {
  if (href === "/") return path === "/";
  return path === href || path.startsWith(hr
ef);
}
 
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET