CodeView
A whole source file to read and cite.
View code
let path = "src/lexer/identifier.ts";
let selected = parseLineRange(url.searchParams.get("L"));
let { lines, loc, bytes } = codeStats(source);
<CodeView
path={path}
language="ts"
code={source}
selected={selected}
permalink={`/acme/delta/blob/4f2a9c1/${path}`}
issueHref="/acme/delta/issues/new"
labels={labels}
>
<CodeView.Header meta={`${lines} lines (${loc} loc) · ${formatBytes(bytes)}`}>
<LinkButton href={`/acme/delta/raw/main/${path}`} variant="outline" size="sm">Raw</LinkButton>
<LinkButton href={`/acme/delta/blame/main/${path}`} variant="outline" size="sm">Blame</LinkButton>
</CodeView.Header>
</CodeView>Demo apps
Whole pages built only from @sdxc/ui, each for an invented product with its own palette and type. They open in a new tab.
- Issue trackerCairnCairn, an invented issue tracker: grouped issue lists with filters in the address, a drag-and-drop board, projects on a roadmap, cycles with burn-up charts and an inbox./demo/apps/cairn
- Social networkChorusChorus, an invented social network: a live timeline with pictures, link cards, polls and threads, profiles, grouped notifications, search and messages./demo/apps/chorus
- Code hostDeltaDelta, a code host whose one repository is its own source: a file tree beside the code, line links, blame and the commits list, every file and commit read from git when the site is built./demo/apps/delta
- CMSInkwellInkwell, a demo CMS built from @sdxc/ui/app: posts with count tabs and quick edit, an editor with a quiet save status and a loud Publish, media and settings./demo/apps/inkwell
- Ops dashboardPulsePulse, an invented ops dashboard: Northwind's services with live filters, a peek sheet and a bulk bar, metrics that switch one chart, incidents, deploys and settings./demo/apps/pulse
- Support inboxRelayRelay, an invented support inbox: mailboxes, conversations and the open conversation on one screen, with contacts, reports and settings./demo/apps/relay
- Chat assistantTernTern, an invented chat assistant: conversations with streamed replies, code and tables, projects, a canvas, sharing and settings./demo/apps/tern
Every demo, landings and docs sites alike, is listed in the demo gallery.
Installation
An ordinary dependency: install it, import the theme once, and import the component where it is used.
npm add @sdxc/ui remiximport "@sdxc/ui/theme.css";Usage
import { CodeView } from "@sdxc/ui/app";Without script selected and #Ln paint the cited lines, and each number links to ?L=n#Ln;
mapping @sdxc/ui/app/code-view runs CodeViewSelection for ranges, the menu and y.
Set --code-view-font-size, -line-height, -blame-width, -selected and --code-age-1–5.
Composition
The parts the component publishes, each a static property of the host.
CodeViewCodeView.HeaderRenders the file's header: its facts (lines, size) on the start side in tabular figures, and its actions on the end side, wrapping under the facts on a narrow view.CodeView.AgeLegendRenders the age strip's legend: the older label, one swatch per step in the strip's own colors, and the newer label.
Examples
With blame
| Split chars out of the lexerana | import type { Token } from "./tokens.js"; | |
| import { isIdentifierStart, isIdentifierPart } from "./chars.js"; | ||
| Read identifiers with Unicode startssergio | ||
| /** Reads one identifier starting at `offset`, or nothing when none starts there. */ | ||
| export function readIdentifier(source: string, offset: number): Token | undefined { | ||
| if (!isIdentifierStart(source.charCodeAt(offset))) return undefined; | ||
| let end = offset + 1; | ||
| while (end < source.length && isIdentifierPart(source.charCodeAt(end))) end++; | ||
| Give every token a spanmei | return { | |
| kind: "identifier", | ||
| value: source.slice(offset, end), | ||
| span: { start: offset, end }, | ||
| }; | ||
| } | ||
| Add skipWhitespace for the parserana | ||
| /** Skips spaces, tabs and line breaks, returning the first offset past them. */ | ||
| export function skipWhitespace(source: string, offset: number): number { | ||
| let end = offset; | ||
| while (end < source.length && /\s/.test(source[end] ?? "")) end++; | ||
| return end; | ||
| } |
View code
<CodeView path="src/lexer/identifier.ts" language="ts" code={source} blame={hunks} labels={labels}>
<CodeView.Header meta={meta}>
<CodeView.AgeLegend labels={{ older: "Older", newer: "Newer" }} />
</CodeView.Header>
</CodeView>Props
Read from the component's own types, so every prop, every default and every allowed value is listed.
| Prop | Type | Required | Description |
|---|---|---|---|
code | string | Yes | The file's source; a single trailing newline is dropped. |
language | string | No | Language the code highlights as (ts, css); omitted, the code draws plain. |
path | string | Yes | The file's path, which names the table for assistive technology. |
tokens | readonly Token[] | No | Runs already painted for code, which skip highlighting here. |
selected | LineRange | No | The lines the page's address cites as ?L=3-8, painted on the server so the band shows without script. Read it with parseLineRange(url.searchParams.get("L")). |
lineHref | (line: number) => string | No | The address each line number links to. @default lineLink(line), ?L=n#Ln |
blame | readonly BlameHunk[] | No | Blame hunks; when set, each hunk draws its commit and age in a leading column. |
permalink | string | No | The address of this file at a fixed commit, which y and "Copy permalink" use. |
issueHref | string | No | Where "Reference in new issue" goes; the permalink arrives as its body parameter. |
labels | Labels | Yes | Every string the view shows or announces, so it reads in any language. |
now | RelativeTimeFormat.DateInput | No | The moment blame ages count from. @default the current time |
locale | string | No | The locale blame ages are written in. @default the runtime's locale |
chunkSize | number | No | Lines per chunk. @default DEFAULT_CHUNK_SIZE |
children | RemixNode | No | A CodeView.Header drawn above the lines. |
Also accepts everything in TagProps<"div">.
CodeView.Header
| Prop | Type | Required | Description |
|---|---|---|---|
meta | RemixNode | No | The file's facts, such as "49 lines (42 loc) · 1.75 KB", built from codeStats. |
children | RemixNode | No | Actions at the header's end: Raw, Copy, Download, a Code | Blame switch. |
Also accepts everything in TagProps<"div">.
CodeView.AgeLegend
| Prop | Type | Required | Description |
|---|---|---|---|
labels | { older: string; newer: string } | Yes | The legend's ends, such as { older: "Older", newer: "Newer" }. |
Also accepts everything in TagProps<"div">.
Also exported
Other components this module publishes.
codeStats