diff --git a/apps/web/components/claude/claude-header.tsx b/apps/web/components/claude/claude-header.tsx index e4767cc..db8508f 100644 --- a/apps/web/components/claude/claude-header.tsx +++ b/apps/web/components/claude/claude-header.tsx @@ -20,7 +20,7 @@ const LOGO_BITS = [ "000010100001010000", ]; -export const ClaudeLogo = ({ +const ClaudeLogo = ({ scale = 4, color = ROSE, className, diff --git a/apps/web/components/claude/claude-message.tsx b/apps/web/components/claude/claude-message.tsx deleted file mode 100644 index fcb1c99..0000000 --- a/apps/web/components/claude/claude-message.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { cn } from "@/lib/utils"; - -/** - * ClaudeMessage — a conversation turn. User turns render as Claude Code's - * full-width prompt row (`❯` + one cell of space, dark background across the - * row, white text); assistant turns are plain text. - */ -export const ClaudeMessage = ({ - messageRole = "assistant", - className, - children, -}: { - messageRole?: "user" | "assistant"; - className?: string; - children: React.ReactNode; -}) => { - if (messageRole === "user") { - return ( -
- - ❯ - - {/* one terminal cell between caret and text — a trailing space inside - a flex child collapses, so use an explicit width */} - - - {children} - -
- ); - } - return ( -
- {children} -
- ); -}; diff --git a/apps/web/components/claude/claude-permission.tsx b/apps/web/components/claude/claude-permission.tsx deleted file mode 100644 index 2251beb..0000000 --- a/apps/web/components/claude/claude-permission.tsx +++ /dev/null @@ -1,107 +0,0 @@ -/* eslint-disable jsx-a11y/prefer-tag-over-role */ -"use client"; - -import type { KeyboardEvent } from "react"; -import { useState } from "react"; - -import { cn } from "@/lib/utils"; - -/** - * ClaudePermission — Claude Code's "Do you want to proceed?" approval box. - * - * In the terminal it's a numbered list you drive with arrow keys; here it's a - * real radiogroup — arrow keys move selection, Enter/Space choose, and each - * option is a proper radio for assistive tech. - */ -const ROSE = "#cd694a"; - -const DEFAULT_OPTIONS = [ - "Yes", - "Yes, and don't ask again this session", - "No, and tell Claude what to do (esc)", -]; - -export const ClaudePermission = ({ - title = "Bash command", - command = "rm -rf node_modules", - question = "Do you want to proceed?", - options = DEFAULT_OPTIONS, - defaultSelected = 0, - onChooseAction, - className, -}: { - title?: string; - command?: string; - question?: string; - options?: string[]; - defaultSelected?: number; - onChooseAction?: (index: number) => void; - className?: string; -}) => { - const [sel, setSel] = useState(defaultSelected); - - const onKey = (e: KeyboardEvent, i: number) => { - if (e.key === "ArrowDown" || e.key === "ArrowUp") { - e.preventDefault(); - const next = - e.key === "ArrowDown" - ? (i + 1) % options.length - : (i - 1 + options.length) % options.length; - setSel(next); - (e.currentTarget.parentElement?.children[next] as HTMLElement)?.focus(); - } else if (e.key === "Enter" || e.key === " ") { - e.preventDefault(); - setSel(i); - onChooseAction?.(i); - } - }; - - return ( -
- - {title} - -
{command}
-
{question}
-
- {options.map((opt, i) => { - const active = sel === i; - return ( -
onKey(e, i)} - onClick={() => { - setSel(i); - onChooseAction?.(i); - }} - className="flex cursor-pointer items-baseline gap-2 rounded px-1 py-0.5 outline-none focus-visible:ring-1 focus-visible:ring-[#7dcfff]/60" - style={{ background: active ? `${ROSE}1f` : "transparent" }} - > - - ❯ - - - {i + 1}. {opt} - -
- ); - })} -
-
- ); -}; diff --git a/apps/web/components/claude/claude-prompt.tsx b/apps/web/components/claude/claude-prompt.tsx deleted file mode 100644 index 7a8822c..0000000 --- a/apps/web/components/claude/claude-prompt.tsx +++ /dev/null @@ -1,181 +0,0 @@ -"use client"; - -import type { ChangeEventHandler, KeyboardEventHandler } from "react"; - -import { cn } from "@/lib/utils"; - -/** - * ClaudePrompt — Claude Code's input composer. - * - * Dual CSS rules around a real text input (❯ prefix), effort chip above, and a - * mode line below. Mode colors/glyphs match shift+tab captures: - * auto ⏵⏵ gold - * manual ⏸ gray - * accept-edits ⏵⏵ lavender - * plan ⏸ teal - * - * Effort chips match `/effort` captures (glyph fills as effort rises): - * low ○ · medium ◐ · high ● · xhigh ◉ · max ◈ · ultracode ✦ - * Ultracode also paints the prompt rules as a rainbow cycle. - */ -export type ClaudeMode = "auto" | "manual" | "accept-edits" | "plan"; - -export type ClaudeEffort = - | "low" - | "medium" - | "high" - | "xhigh" - | "max" - | "ultracode"; - -const FG = "#c0caf5"; -const GRAY = "#949494"; -// 38;5;244 -const RULE = "#808080"; - -/** Ultracode prompt-rule cycle from live captures (38;5;146→182→210→216→222→151). */ -const ULTRACODE_RAINBOW = - "linear-gradient(90deg,#afafd7,#d7afd7,#ff87af,#ffaf87,#ffd787,#afd787,#afafd7)"; - -const MODES: Record< - ClaudeMode, - { glyph: string; label: string; color: string; hint: string } -> = { - "accept-edits": { - // 38;5;147 - color: "#afafd7", - glyph: "⏵⏵", - hint: "(shift+tab to cycle) · ← for agents", - label: "accept edits on", - }, - auto: { - // 38;5;220 - color: "#ffd700", - glyph: "⏵⏵", - hint: "(shift+tab to cycle) · ← for agents", - label: "auto mode on", - }, - manual: { - color: GRAY, - glyph: "⏸", - hint: "· ? for shortcuts · ← for agents", - label: "manual mode on", - }, - plan: { - // 38;5;73 - color: "#5fafaf", - glyph: "⏸", - hint: "(shift+tab to cycle) · ← for agents", - label: "plan mode on", - }, -}; - -const EFFORTS: Record< - ClaudeEffort, - { glyph: string; label: string; rainbow?: boolean } -> = { - high: { glyph: "●", label: "high · /effort" }, - low: { glyph: "○", label: "low · /effort" }, - max: { glyph: "◈", label: "max · /effort" }, - medium: { glyph: "◐", label: "medium · /effort" }, - ultracode: { - glyph: "✦", - label: - "ultracode · xhigh effort + dynamic workflows for maximum thoroughness", - rainbow: true, - }, - xhigh: { glyph: "◉", label: "xhigh · /effort" }, -}; - -export const ClaudePrompt = ({ - value, - defaultValue = "", - onChangeAction, - onKeyDownAction, - placeholder = "", - mode = "auto", - effort = "xhigh", - className, - inputClassName, -}: { - value?: string; - defaultValue?: string; - onChangeAction?: ChangeEventHandler; - onKeyDownAction?: KeyboardEventHandler; - placeholder?: string; - mode?: ClaudeMode; - /** Effort chip above the prompt. Pass `false` to hide. */ - effort?: ClaudeEffort | false; - className?: string; - inputClassName?: string; -}) => { - const m = MODES[mode]; - const e = effort === false ? null : EFFORTS[effort]; - const controlled = value !== undefined; - const rainbow = Boolean(e?.rainbow); - - return ( -
- {e ? ( -
- - {e.glyph} {e.label} - -
- ) : null} - -
- - ❯ - - -
- -
- - {m.glyph} - {m.label} - - {m.hint ? {m.hint} : null} -
-
- ); -}; diff --git a/apps/web/components/claude/claude-session.tsx b/apps/web/components/claude/claude-session.tsx deleted file mode 100644 index f7f8d1e..0000000 --- a/apps/web/components/claude/claude-session.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import { ClaudeDiff } from "@/components/claude/claude-diff"; -import { ClaudeHeader } from "@/components/claude/claude-header"; -import { ClaudeMessage } from "@/components/claude/claude-message"; -import { ClaudePermission } from "@/components/claude/claude-permission"; -import { ClaudePrompt } from "@/components/claude/claude-prompt"; -import { ClaudeThinking } from "@/components/claude/claude-thinking"; -import { ClaudeTodoList } from "@/components/claude/claude-todo-list"; -import { ClaudeToolCall } from "@/components/claude/claude-tool-call"; - -/** - * ClaudeSession — a complete Claude Code screen: welcome header, a full turn - * (prompt → plan → tool calls → diff → approval → working line) and the pinned - * input composer. Everything a Claude Code session shows, as one block. - */ -export const ClaudeSession = () => ( -
- - -
- 3 MCP servers need authentication · run /mcp -
- -
- - add a dark-mode toggle to the settings page and run the tests - - - - I'll add the toggle, wire it into the theme provider, then run the - suite. - - - - - - - {sections}", type: "del" }, - { n: 12, text: " return (", type: "add" }, - { - n: 13, - text: " }>", - type: "add", - }, - { n: 14, text: " {sections}", type: "add" }, - { n: 15, text: " ", type: "ctx" }, - ]} - /> - - - {`bun test v1.2.21 -✓ settings > renders the theme toggle -✓ theme > persists across reloads - 12 pass - 0 fail`} - - - - - -
- -
- -
-
-); diff --git a/apps/web/components/claude/claude-tool-call.tsx b/apps/web/components/claude/claude-tool-call.tsx deleted file mode 100644 index 34cdd87..0000000 --- a/apps/web/components/claude/claude-tool-call.tsx +++ /dev/null @@ -1,101 +0,0 @@ -import * as React from "react"; - -import { cn } from "@/lib/utils"; - -/** - * ClaudeToolCall — Claude Code's collapsed tool/result line. - * - * In the terminal this is faked with box-drawing glyphs and a "ctrl+o to - * expand" hint. Here it's a real
disclosure: keyboard-operable, - * announced to screen readers, and it keeps the exact ⏺ / ⎿ visual grammar. - */ -type Status = "success" | "error" | "pending"; - -const STATUS_COLOR: Record = { - error: "#f7768e", - pending: "#e0af68", - success: "#4ea96f", -}; - -export const ClaudeToolCall = ({ - tool, - arg, - result, - status = "success", - defaultOpen = false, - className, - children, -}: { - tool: string; - arg?: string; - result: string; - status?: Status; - defaultOpen?: boolean; - className?: string; - children?: React.ReactNode; -}) => { - const expandable = Boolean(children); - - return ( -
- - - - ⏺ - - - {tool} - {arg === undefined ? null : ( - <> - ( - {arg} - ) - - )} - - - - {/* invisible status glyph spacer: aligns ⎿ under the tool name */} - - ⏺ - - - - ⎿ - - - {result} - {expandable ? ( - - (ctrl+o to expand) - - ) : null} - - - - - - {expandable ? ( -
- {children} -
- ) : null} -
- ); -}; diff --git a/apps/web/components/icons/claude-code.tsx b/apps/web/components/icons/claude-code.tsx deleted file mode 100644 index f30f4c2..0000000 --- a/apps/web/components/icons/claude-code.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import type { SVGProps } from "react"; - -export const ClaudeCode = ({ ...props }: SVGProps) => ( - - - - -); diff --git a/apps/web/components/sections/architecture.tsx b/apps/web/components/sections/architecture.tsx index bdd66ef..e8f4d8e 100644 --- a/apps/web/components/sections/architecture.tsx +++ b/apps/web/components/sections/architecture.tsx @@ -272,8 +272,8 @@ export const Architecture = async () => { the engine - - + + diff --git a/apps/web/components/sections/hero.tsx b/apps/web/components/sections/hero.tsx index 7e1003f..87a5d31 100644 --- a/apps/web/components/sections/hero.tsx +++ b/apps/web/components/sections/hero.tsx @@ -35,8 +35,8 @@ export const Hero = () => ( diagnostics - - + + @@ -62,8 +62,8 @@ export const Hero = () => ( opinionated - - + +