Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@
}
}
/* terminal: widths and indents in character cells */
@utility indent-* {
@utility pl-cells-* {
padding-inline-start: calc(--value(integer) * 1ch);
}
@utility cell-wide {
Expand Down
2 changes: 1 addition & 1 deletion registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@
}
},
"css": {
"@utility indent-*": {
"@utility pl-cells-*": {
"padding-inline-start": "calc(--value(integer) * 1ch)"
},
"@utility cell-wide": {
Expand Down
75 changes: 49 additions & 26 deletions registry/winlab/blocks/claude-code/claude-code.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -735,30 +735,52 @@ function Marketplace({
)
}

// A search field in a menu, such as the one above /plugins > Discover: a
// round box drawn with box characters, as wide as the screen.
// How many monospace cells fit across `ref`: a terminal box is drawn to the
// window's width, one character per cell. The probe holds 10 cells.
function useColumns(ref: React.RefObject<HTMLDivElement | null>) {
const [columns, setColumns] = React.useState(0)
React.useEffect(() => {
const row = ref.current
const probe = row?.querySelector("[data-probe]")
if (!row || !probe) return
const measure = () =>
setColumns(
Math.floor(row.clientWidth / (probe.getBoundingClientRect().width / 10))
)
// The observer reports the first size as soon as it starts; the web font
// can arrive later and change the cell width.
const observer = new ResizeObserver(measure)
observer.observe(row)
document.fonts.ready.then(measure)
return () => observer.disconnect()
}, [ref])
return columns
}

// A search field in a menu, such as the one in /plugins > Discover: a round
// box as wide as the screen. Each row is one string, the way the terminal
// prints it, so the box copies whole.
function SearchBox({ placeholder = "Search…" }: { placeholder?: string }) {
const edge = (left: string, right: string) => (
<Line indent={2} className="flex whitespace-nowrap">
<T tone="inactive">{left}</T>
<T tone="inactive" className="min-w-0 flex-1 overflow-hidden">
{"─".repeat(240)}
</T>
<T tone="inactive">{right}</T>
</Line>
)
const row = React.useRef<HTMLDivElement>(null)
const columns = useColumns(row)
const inner = Math.max(0, columns - 2)
const text = ` ⌕ ${placeholder}`.slice(0, inner).padEnd(inner)
return (
<div className="pb-5">
{edge("╭", "╮")}
<Line indent={2} className="flex">
<T tone="inactive">│</T>
<T tone="inactive" className="min-w-0 flex-1">
{" ⌕ "}
{placeholder}
</T>
<T tone="inactive">│</T>
</Line>
{edge("╰", "╯")}
<div className="pl-cells-2 pb-5">
<div ref={row} className="relative">
<span data-probe aria-hidden className="invisible absolute">
0000000000
</span>
<Line>
<T tone="inactive">{columns > 1 && `╭${"─".repeat(inner)}╮`}</T>
</Line>
<Line>
<T tone="inactive">{columns > 1 && `│${text}│`}</T>
</Line>
<Line>
<T tone="inactive">{columns > 1 && `╰${"─".repeat(inner)}╯`}</T>
</Line>
</div>
</div>
)
}
Expand All @@ -776,9 +798,9 @@ function cut(text: string, width: number) {
return text.length > width ? `${text.slice(0, width - 1)}…` : text
}

// The plugin list of /plugins > Discover: a count, then one row per plugin
// with its description cut to `width` cells and its version. `shown` rows
// are drawn; the rest sit under "more below".
// The plugin list of /plugins > Discover: a count, the search box, then one
// row per plugin with its description cut to `width` cells and its version.
// `shown` rows are drawn; the rest sit under "more below".
function PluginList({
items,
choice,
Expand All @@ -792,12 +814,13 @@ function PluginList({
}) {
return (
<>
<Line indent={2} className="pb-5">
<Line indent={2}>
<T bold>Install Plugins</T>{" "}
<T tone="inactive">
({choice + 1}/{items.length})
</T>
</Line>
<SearchBox />
{items.slice(0, shown).map((item, index) => {
const on = index === choice
return (
Expand Down
12 changes: 6 additions & 6 deletions registry/winlab/ui/terminal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -195,12 +195,12 @@ function TerminalLine({
}) {
const pad = [
"",
"indent-1",
"indent-2",
"indent-3",
"indent-4",
"indent-5",
"indent-6",
"pl-cells-1",
"pl-cells-2",
"pl-cells-3",
"pl-cells-4",
"pl-cells-5",
"pl-cells-6",
]
return (
<div
Expand Down
Loading