Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

Move desktop UI components to shadcn/ui (Radix) and Pierre Diffs

Cerrado
#191 0 comentarios 0 reacciones 1 asignado Ver en GitHub

Los mantenedores suelen responder en 1 día

@GoDiao ya está trabajando en esto.

Desde el 26/10/2026.

Evaluación

Este issue todavía no se ha evaluado.

Descripción

area:desktop area:ux enhancement

Summary

Replace the hand-written desktop components in desktop/src/components/shared (about 2,500 lines) and the hand-rolled chat pieces with shadcn/ui components on Radix, plus Pierre Diffs for code review. Everything is restyled through our own theme tokens, so all seven themes keep working.

This lands as one PR, so the whole change can be judged at once. Commits inside it follow the order below.

The per-component picks were made on a side-by-side comparison of our components against shadcn, AI Elements, prompt-kit, ReUI, Kibo UI and Pierre Diffs.

Why

  • Behavior, not just looks. A few examples from the current code:

    • Dropdown opens from a clickable div, so the keyboard can't open it. Arrow keys don't move through items, and the menu isn't repositioned near the window edge.
    • Modal handles Escape, but it doesn't keep focus inside the dialog and doesn't return focus to the trigger when it closes.
    • Toast uses animate-in slide-in-from-right classes that nothing in the project defines, so toasts have no enter animation. Its close button is a bare × with no accessible name.
    • The workspace file tree has no arrow-key navigation.

    Radix provides all of this.

  • One place for UI. Today the same patterns are written several times:

    • Button.tsx carries its own copy of Spinner.
    • The workspace panel tabs are a separate implementation from SegmentedControl.
    • Popovers and menus outside shared are hand-built (9 files set role="dialog" or role="menu" themselves).
    • Icons mix lucide with Material Symbols (142 uses in 41 files).
  • The chat UI we want already exists. shadcn now ships Trace, Code Block, Message and Bubble in its core registry. It also has an AI Elements section (tool, reasoning, file tree, …) built only from those parts, with no AI SDK dependency, so it fits our server-owned session state.

  • It unblocks #189. The browser panel has to hide its native view while any overlay is open. That is simple when every dialog, menu and popover is a Radix primitive, and messy with the current mix. #189 also injects theme tokens into agent pages, so token names should be settled first.

Component mapping

Ours Becomes Source
Button Button shadcn
Input, Textarea, SearchField Input, Textarea, Field, InputGroup shadcn
Switch Switch shadcn
SegmentedControl, workspace panel tabs ToggleGroup, Tabs shadcn
Dropdown and hand-built menus DropdownMenu, Select, ContextMenu (file tree right-click), Popover (composer "+" menu) shadcn
Modal Dialog shadcn
ConfirmDialog AlertDialog shadcn
Toast Sonner shadcn
MobileBottomSheet Drawer shadcn
CommandPalette Command shadcn
UserMessage Message + Bubble shadcn
ThinkingBlock, ToolCallBlock Trace lines, with shimmer on the running line shadcn (AI Elements reasoning / tool)
CodeViewer, code in tool output Code Block shadcn
DiffViewer Pierre Diffs @pierre/diffs
Workspace file tree File Tree (Collapsible + Button), plus tree keyboard navigation (up/down, left/right to collapse/expand, Home/End, async expand) shadcn (AI Elements file tree)
AppShell panel resize Resizable (react-resizable-panels) shadcn
title tooltips (~30 components) Tooltip shadcn
ShortcutsDialog keys Kbd shadcn
Panel empty and loading states Empty, Skeleton shadcn
ContextUsageIndicator Context shadcn (AI Elements)
SessionTaskBar, InlineTaskSummary Plan / Task shadcn (AI Elements)

Kept as ours, with their inner buttons and cards swapped for the new components:

  • PermissionDialog. Its content (tool icon, pending state, "allow for this session", raw input) is richer than Confirmation.
  • The composer (ComposerShell / ChatInput). Its logic (slash commands, @-file search, pasted images) is untouched.
  • AskUserQuestion. shadcn's Questionnaire needs @shadcn/react/questionnaire (not Radix), and its free-text answer is a single-line input where Enter confirms the question. Ours keeps multi-line answers, IME composition and Ctrl/Cmd+Enter to submit.
  • CurrentTurnChangeCard. Checkpoint is a marker and a button that trims client-side messages. Our card shows the per-file changes and runs the server-side rewind (confirm, stop generation if needed, rewind, reload history, restore the input). Checkpoint's marker style can be borrowed.

Behavior that stays: consecutive thinking and tool calls are still grouped into one block (ToolCallGroup). Only each line inside the group changes to the Trace style. Bash calls keep showing $ command instead of JSON input.

Rules for the code that comes in

  • One primitive layer: Radix only, through the radix-ui package. Generate components with the shadcn CLI (bunx shadcn add) using the Radix base, not by copying registry source (it contains template placeholders), then switch icons, tokens and paths to ours.
  • Sonner follows our theme store instead of next-themes.
  • Our tokens only: map shadcn's variables (--background, --primary, --border, --radius, …) onto the existing tokens in desktop/src/theme/globals.css and aurora.css. Then replace any hard-coded color, radius or shadow in copied code. Check all seven themes.
  • One component per concept: one Button, one Dialog, one menu. Copied code uses our components, never a second copy.
  • One icon set: lucide. Material Symbols goes away, and so does its font.
  • One highlighter: shiki, for code blocks, diffs and the file preview. Code uses shiki's own light/dark theme rather than our code tokens. prism-react-renderer and react-diff-viewer-continued are removed. While shiki loads, or if it fails, code shows as plain text.
  • Project rules still apply to copied code:
    • no comments;
    • i18n for every visible string;
    • store selectors, not whole objects;
    • tests select by role and label.

Dependencies

Added:

  • radix-ui;
  • react-resizable-panels;
  • sonner, vaul, cmdk;
  • class-variance-authority, clsx, tailwind-merge;
  • @pierre/diffs.

Removed:

  • prism-react-renderer;
  • react-diff-viewer-continued;
  • the Material Symbols font.

Build target: safari15 → safari17.5 in desktop/vite.config.ts, because Pierre Diffs needs Safari 17.5+ (Chromium 123+). This only affects the H5 page on older iPhones; the old-Safari fallback in CodeViewer is removed, and there is no separate plain-text diff path.

Upgraded: React and React DOM 18 → 19, with their types. Current shadcn components are written for React 19 (refs as props, no forwardRef), so the copied code stays close to upstream.

Plan inside the PR

  1. React 19. Upgrade React and fix what breaks. All three checks must pass before any component work.
  2. Foundation. Add components.json, the cn helper and the token mapping. Nothing should change visually at this step.
  3. Base components. Swap the internals of each shared component, keeping its props where possible so call sites change little. Delete what is replaced.
  4. Overlays. Move every hand-built dialog, menu and popover onto Dialog, DropdownMenu, ContextMenu and Popover. Add Tooltip.
  5. Chat. Port Message/Bubble, the Trace lines inside ToolCallGroup and Code Block. Swap the inner parts of PermissionDialog, AskUserQuestion, CurrentTurnChangeCard and the composer.
  6. Developer views. Port Pierre Diffs, the file tree and Resizable. Views that move into Pierre's Shadow DOM get new selection handling for line comments and selection quotes. Remove prism and the old diff viewer.
  7. Cleanup. Remove Material Symbols, the dead classes and the unused shared files. Write a short components/README listing each component and where it came from.

Out of scope

  • A visual redesign beyond what the new components bring. That is a separate step on top of this one.
  • #189 features (browser panel, inline UI). They build on this.
  • New components without a current use, such as Terminal, StackTrace or Commit. Add them when a feature needs them.

How to check

  • bun test, bun run lint and bun run test -- --run pass.
  • Every overlay works by keyboard alone: open, move, select, Escape, focus returns.
  • All seven themes, in both languages, in the desktop app and in the H5 page at phone width.
  • A long session mounts and streams no slower than on main, with the benchmark from #172 (0/200/1,000 history messages, a 60,000-character reply written 80 characters every 50 ms, three runs each; mount, React and forced-layout time), same Electron version, window width and build mode.
  • Installer size before and after (same architecture and packaging config), with the frontend asset size listed separately.

Resolved during review

  • Pierre Diffs theming. Pierre inherits CSS variables from its host, so no per-color injection is needed. Syntax colors come from shiki's light/dark theme; diff backgrounds, line numbers, fonts and surrounding UI map to our tokens through Pierre's --diffs-…-override variables. Light or dark follows the app theme, not the system: dark, midnight and aurora are dark, the other four are light. Checked in all seven themes before the old viewer is removed.
  • Checkpoint: not used; see "Kept as ours".
  • Questionnaire: not used; see "Kept as ours".
Lenguaje dominante
TypeScript
Estrellas
490
Forks
47
Merge medio
9 h 31 min
PR fusionados (30 d)
76

Preparar el entorno

Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de GoDiao/dreamcoder

Todos los issues de GoDiao/dreamcoder

Issues similares

Más issues de TypeScript

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.