* feat(ui): add dynamic titles and sprite-based project/file icons * feat(files): add viewer syntax fallback and tab file icons * fix(files): restore file viewer highlighting and add diff file icons * feat(git): add file icons and async file-viewer syntax fallback * fix(files): force codemirror token colors in file viewer * feat(files): add shiki view mode for file viewer * fix(files): force codemirror parse after programmatic content updates * feat(files): support markdown frontmatter preview * feat(chat): use pierre diffs for tool previews * feat(chat): add configurable beautiful-mermaid rendering * feat(perf): virtualize chat rendering and add react-scan toggle * feat(build): enable React Compiler in Vite React apps * fix(chat): reduce rerenders from tooltips and streamed activity * fix(ui): make MessageList React Compiler safe * chore(ui): batch commit remaining pending ui updates * fix: polish chat and diff preview rendering - Keep Mermaid action buttons fixed while diagram content scrolls - Align Diff All Files headers and match Git-style path truncation - Default chat tool diffs to unified view with lightweight indicators disabled * fix: preserve file tree expansion and delay git action label collapse * fix: refine project icon controls in settings --------- Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
54 lines
3.9 KiB
Markdown
54 lines
3.9 KiB
Markdown
**Plan**
|
|
|
|
**1) Dynamic Window Title (web + desktop)**
|
|
- Add `packages/ui/src/hooks/useWindowTitle.ts` and call it from `packages/ui/src/App.tsx`.
|
|
- Title parts: `[projectName] | [instanceName if non-local] | OpenChamber`.
|
|
- `projectName`: from `useProjectsStore` active project; prefer `label`, else basename of `path`.
|
|
- `instanceName` (desktop only): reuse `desktopHostsGet + locationMatchesHost` logic (same as `Header.tsx`), omit when local.
|
|
- Apply:
|
|
- always set `document.title`
|
|
- if Tauri: `@tauri-apps/api/window` → `getCurrentWindow().setTitle(title)` (best-effort)
|
|
|
|
**2) Custom Project Icons (PNG/JPEG/SVG) stored on server + persisted in `settings.json`**
|
|
- Extend project schema:
|
|
- `packages/ui/src/lib/api/types.ts` `ProjectEntry` add `iconImage?: { mime: string; updatedAt: number; source: 'custom' | 'auto' } | null`
|
|
- Update UI+server sanitizers to preserve it:
|
|
- `packages/ui/src/stores/useProjectsStore.ts` `sanitizeProjects`
|
|
- `packages/ui/src/lib/persistence.ts` `sanitizeProjects`
|
|
- `packages/web/server/index.js` `sanitizeProjects`
|
|
- Server storage + API (Express):
|
|
- Add JSON parsing for `req.path.startsWith('/api/projects')` in the existing body-parser gate (`packages/web/server/index.js` around the `express.json` middleware switch).
|
|
- Store icon files under `~/.config/openchamber/project-icons/` (i.e. `OPENCHAMBER_DATA_DIR/project-icons`), filename based on `sha1(projectId)` + extension (prevents path traversal / odd IDs).
|
|
- New routes in `packages/web/server/index.js`:
|
|
- `GET /api/projects/:projectId/icon` → serve file (Content-Type from stored mime, `Cache-Control: immutable` with `?v=updatedAt`)
|
|
- `PUT /api/projects/:projectId/icon` body `{ dataUrl: string }` → validate mime, decode, write file, update `projects[].iconImage` in `settings.json` via `persistSettings`
|
|
- `DELETE /api/projects/:projectId/icon` → delete file(s), clear `iconImage`, persist
|
|
- `POST /api/projects/:projectId/icon/discover` → best-effort “try this first”: search project dir for `favicon.(ico|png|svg|jpg|jpeg|webp)` using existing `searchFilesystemFiles()`, pick shortest match, store it as `source:'auto'` (skip if `source:'custom'` unless `force=true`)
|
|
- UI wiring:
|
|
- Add async actions in `packages/ui/src/stores/useProjectsStore.ts`: `uploadProjectIcon(id, file)`, `removeProjectIcon(id)`, `discoverProjectIcon(id)`
|
|
- Update renderers to prefer `iconImage` over `PROJECT_ICON_MAP`:
|
|
- `packages/ui/src/components/layout/NavRail.tsx`
|
|
- `packages/ui/src/components/sections/projects/ProjectsSidebar.tsx`
|
|
- `packages/ui/src/components/chat/MobileSessionStatusBar.tsx`
|
|
- Add upload/remove/(discover) UI controls:
|
|
- `packages/ui/src/components/sections/projects/ProjectsPage.tsx`
|
|
- `packages/ui/src/components/layout/ProjectEditDialog.tsx`
|
|
- `<img src={`/api/projects/${encodeURIComponent(id)}/icon?v=${updatedAt}`}>` (small size, fits existing tile layout)
|
|
|
|
**3) File Tree File-Type Icons (full icon pack)**
|
|
- Vendor the full directory from `/tmp/opencode/packages/ui/src/assets/icons/file-types` into `packages/ui/src/assets/icons/file-types/`.
|
|
- Add `packages/ui/src/lib/fileTypeIcons.ts`:
|
|
- build an icon URL map with `import.meta.glob('../assets/icons/file-types/*.svg', { eager: true, as: 'url' })`
|
|
- map filename/extension → icon key (use `getLanguageFromExtension()` + a small alias map, plus `_light` variant selection based on `useThemeSystem().currentTheme.metadata.variant`)
|
|
- fallback to `document.svg`
|
|
- Add `packages/ui/src/components/icons/FileTypeIcon.tsx` (renders the resolved icon URL).
|
|
- Replace current generic file icons with `FileTypeIcon` (keep folder icons as-is):
|
|
- `packages/ui/src/components/layout/SidebarFilesTree.tsx`
|
|
- `packages/ui/src/components/views/FilesView.tsx`
|
|
- `packages/ui/src/components/chat/ServerFilePicker.tsx`
|
|
|
|
**Verification (end of build mode)**
|
|
- `bun run type-check`
|
|
- `bun run lint`
|
|
- `bun run build`
|