Repository navigation
UI Library Migration
The app is moving onto its own component library, screen by screen. When it is done, every screen is built only from library components, with no CSS of its own, so the design is the same everywhere and the native apps can follow the same tokens. This page explains how the app uses the library, how progress is measured and what a migrated file must look like. The library itself is described in UI-Library.md.
Before the migration each screen drew its own buttons, rows and fields with its own CSS. The same thing came out in slightly different sizes in different places (13 dialog widths, for example), and a change to the look meant editing many files. With the library, a token change updates every screen, and a screen file holds only what the screen does.
ui/web is a package named @nibtree/ui (ui/web/package.json). The root package.json lists it as a Bun workspace and depends on it with "@nibtree/ui": "workspace:*", so bun install links it into node_modules. The app imports it by name, like any package:
import Button from "@nibtree/ui/components/Button.svelte";
import { icons } from "@nibtree/ui/icons";The package exports its components, logic, editor helpers, token CSS, icons and toasts. CodeMirror, xterm.js, markdown-it and Svelte are peer dependencies, so the app and the library share one copy of each. src/routes/+layout.svelte loads @nibtree/ui/styles/tokens.css, base.css and code.css; the app has no CSS file of its own. The icon set lives in the package; the app has no copy.
flowchart LR
A["bun run ui:migration"] --> B["each app .svelte file"]
B --> C["CSS lines + raw elements +<br/>inline styles + classes +<br/>wide lines + over 300 lines"]
C --> D{"zero?"}
D -->|"yes"| E["listed in ui/web/migrated.json"]
D -->|"no"| F["still to migrate"]
E --> G["migration.test.ts keeps it at zero"]
ui/web/scripts/migration.ts counts, for every app .svelte file, what it still owns instead of taking from the library: lines of its own CSS, raw HTML elements, inline styles, class attributes, lines over 120 columns, and whether it is longer than 300 lines. bun run ui:migration prints the table, worst first, and the total. --update adds every file now at zero to ui/web/migrated.json. A gap in the library is simply whatever stops a screen from reaching zero; it is added to the library (component, doc, story, tokens) and the screen moves on.
- Only library components and app components in the markup;
Stacklays things out andTextwrites words. - No
<style>, noclass, nostyle. Sizes are the library's named presets. - At most 300 lines of at most 120 columns. Pure logic moves to a tested
.tsmodule next to the component (for examplerebaseStart.ts,branchListItemsinbranchPopup.ts). - Shortcut hints come from
localKeysorcommandKeys, never typed in.
| Path | What it holds |
|---|---|
ui/web/package.json |
The package: name, exports, peer dependencies |
ui/web/scripts/migration.ts |
bun run ui:migration |
ui/web/migrated.json |
The files already at zero |
ui/web/scripts/migration.test.ts |
Migrated files stay at zero; parity reads no migrated file |
- Snap, do not copy. When a screen used a size the library does not have, it snaps to the nearest preset instead of adding one. The Git dialogs' ten widths became the library's five (460, 520, 560, 620 and 760 px).
-
Retire parity for migrated screens. A parity case compares a library component with the app's own CSS. Once a screen is migrated that CSS is gone, because the app now draws the library itself, so its cases are removed. A test fails if a case still reads a migrated or deleted file. With every screen migrated, the last two cases (app.css's old
.icon-btnand.input) went with those classes, and the list is empty. - Migrate a whole family at once. The Git dialogs shared one frame that styled their bodies through global classes, so the frame and all its dialogs moved together and the frame was deleted.
migration.test.ts checks the counting on a sample, that every listed file is at zero and exists, and that no parity case reads a migrated file. bun run check and bun run test must stay clean after every screen.
The migration test failed on Windows.
-
The issue: the Windows frontend CI failed "lists only files that exist" with every file in
migrated.json, while macOS passed. -
Why it happened:
appDebtsnamed each file with Node'srelative(), which uses\on Windows, butmigrated.jsonlists paths with/, so no name matched. -
The fix and why we chose it:
repoPathjoins the parts with/on every platform, the same rule the app uses for paths, so the list stays one file for all platforms. A test checks that no name holds a\.
- Run
bun run ui:migration --updateafter migrating a screen, and commitmigrated.jsonwith it. - Update this page when the package's exports or the rules for a migrated file change.
These pages are generated from docs/wiki. To correct something, open a pull request against the source file; edits made here are overwritten.
Using Nibtree
- Getting Started
- Welcome Screen
- Workspaces
- Files Panel
- File Operations
- File Icons
- Rounded Panels
- Editor and Tabs
- Pin Reorder and Wrap Tabs
- Single Tab Title
- Split Editor
- New File and Unsaved Changes
- Unload Hidden Tabs
- Editing Code
- Code Appearance
- Markdown Editor
- Image and PDF Preview
- Search Everywhere
- Recent Files
- Navigation Bar
- Find and Replace
- Changes and Commits
- Sign In Prompts
- Commit Box Layout
- Repository Actions
- Commit Options
- Ignoring Files
- Diffs
- Inline Diffs
- Staging View
- Revert a Change
- Resolving Conflicts
- Merge Tool
- Blame
- History and Log
- Merge Commits
- Branches and Tags
- Branches Popup
- Remotes
- Stashes
- Shelf
- Git Menu
- Git Dialogs
- Interactive Rebase
- Worktrees
- AI Agents
- AI Tasks
- AI Usage
- Keep Computer Awake
- Submodules
- Git LFS
- GitHub
- Git Console
- Terminal
- Terminal Features
- Scripts
- Navigation
- Menus
- Settings
- Settings Search
- Color Themes
- Settings Terminal and Automation
- Settings Files
- Updates
- Status Bar and Help
- Notifications
- Memory Use
- Clear Cache
- MCP and CLI
- Git Mergetool
- Keyboard Shortcuts
- Keyboard Shortcuts Editor
- Troubleshooting
- Troubleshooting Git
Developers
- Developer Guide
- Architecture
- Project Layout
- Backend
- How Folder Watching Works
- Folder Watching Bugs We Fixed
- How Workspace Files Work
- How the Preview Scheme Works
- Backend Services
- How Terminal Features Work
- Terminal Bugs We Fixed
- Frontend
- How the Rich Markdown Editor Works
- Rich Markdown Bugs We Fixed
- Git Menu Links
- Menu Keys and Routing
- Frontend Modules
- Blame Bugs We Fixed
- Project Color And Title Bar
- One Diff View
- Diff Bugs We Fixed
- Merge Tool Layouts
- Merge Tool Bugs We Fixed
- Color Theme Bugs We Fixed
- How the Connected Diff Works
- Rounded Panels Bugs We Fixed
- Update Bugs We Fixed
- Status Bar Bugs We Fixed
- MCP and CLI Bugs We Fixed
- Repository Actions Bugs We Fixed
- How the Changes Tab Works
- CodeMirror Patterns
- How the Cursor Works
- How Editor Features Work
- How the Path Bar Works
- Commands and Events
- Settings Reference
- Commands Workspace and Changes
- Commands Branches and Remotes
- Commands History and Extras
- Commands App and Tools
- Testing
- Test Suites
- Debugging
- Debugging with MCP
- Measuring Setting Memory
- How Terminal Memory Is Measured
- How Markdown Diagrams Work
- Releases and CI
- Publishing the Wiki
- Versioning and Changelog
- Browser Version Packages
- Browser Release Checks
- Docker Image
- Platforms and Signing
- Windows Support
- Windows Bugs We Fixed
- Windows MCP and CLI
- Docs and Screenshots
- UI Library
- UI Library MCP
- UI Library Bugs
- UI Library Migration
- Contributing
How features work
- Welcome screen
- Workspaces and folders
- Files panel
- File operations
- File icons
- Editor and tabs
- Pin, reorder and wrap tabs
- Single tab title
- Split editor
- New File and unsaved changes
- Unload hidden tabs
- Editing code
- Code appearance
- Markdown editor
- Image and PDF preview
- Search Everywhere
- Recent Files
- Navigation Bar
- Find and replace
- Changes and commits
- Sign-in prompts
- Commit box layout
- Repository actions
- Commit options
- Ignoring files
- Diffs
- Inline diffs
- Staging view
- Revert a change
- Resolving conflicts
- Merge tool
- Blame
- History and log
- Merge commits
- Commit tabs
- Branches and tags
- Branches popup
- Remotes
- Stashes
- Shelf
- Git menu
- Git dialogs
- Interactive rebase
- Worktrees
- AI agents
- AI usage
- Keep computer awake
- AI tasks
- Submodules
- Git LFS
- GitHub account
- Git Console
- Back and Forward
- Integrated terminal
- Scripts tool window
- Menu bar
- Settings
- Search in Settings
- Color themes
- Rounded panels
- Updates and release channels
- Status bar and help links
- Notifications
- Memory readout and memory log
- Clear Cache
- MCP server and command line tool
- git mergetool mode