* 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>
3.9 KiB
3.9 KiB
Plan
1) Dynamic Window Title (web + desktop)
- Add
packages/ui/src/hooks/useWindowTitle.tsand call it frompackages/ui/src/App.tsx. - Title parts:
[projectName] | [instanceName if non-local] | OpenChamber. projectName: fromuseProjectsStoreactive project; preferlabel, else basename ofpath.instanceName(desktop only): reusedesktopHostsGet + locationMatchesHostlogic (same asHeader.tsx), omit when local.- Apply:
- always set
document.title - if Tauri:
@tauri-apps/api/window→getCurrentWindow().setTitle(title)(best-effort)
- always set
2) Custom Project Icons (PNG/JPEG/SVG) stored on server + persisted in settings.json
- Extend project schema:
packages/ui/src/lib/api/types.tsProjectEntryaddiconImage?: { mime: string; updatedAt: number; source: 'custom' | 'auto' } | null- Update UI+server sanitizers to preserve it:
packages/ui/src/stores/useProjectsStore.tssanitizeProjectspackages/ui/src/lib/persistence.tssanitizeProjectspackages/web/server/index.jssanitizeProjects
- Server storage + API (Express):
- Add JSON parsing for
req.path.startsWith('/api/projects')in the existing body-parser gate (packages/web/server/index.jsaround theexpress.jsonmiddleware switch). - Store icon files under
~/.config/openchamber/project-icons/(i.e.OPENCHAMBER_DATA_DIR/project-icons), filename based onsha1(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: immutablewith?v=updatedAt)PUT /api/projects/:projectId/iconbody{ dataUrl: string }→ validate mime, decode, write file, updateprojects[].iconImageinsettings.jsonviapersistSettingsDELETE /api/projects/:projectId/icon→ delete file(s), cleariconImage, persistPOST /api/projects/:projectId/icon/discover→ best-effort “try this first”: search project dir forfavicon.(ico|png|svg|jpg|jpeg|webp)using existingsearchFilesystemFiles(), pick shortest match, store it assource:'auto'(skip ifsource:'custom'unlessforce=true)
- Add JSON parsing for
- UI wiring:
- Add async actions in
packages/ui/src/stores/useProjectsStore.ts:uploadProjectIcon(id, file),removeProjectIcon(id),discoverProjectIcon(id) - Update renderers to prefer
iconImageoverPROJECT_ICON_MAP:packages/ui/src/components/layout/NavRail.tsxpackages/ui/src/components/sections/projects/ProjectsSidebar.tsxpackages/ui/src/components/chat/MobileSessionStatusBar.tsx
- Add upload/remove/(discover) UI controls:
packages/ui/src/components/sections/projects/ProjectsPage.tsxpackages/ui/src/components/layout/ProjectEditDialog.tsx
<img src={/api/projects/${encodeURIComponent(id)}/icon?v=${updatedAt}}>(small size, fits existing tile layout)
- Add async actions in
3) File Tree File-Type Icons (full icon pack)
- Vendor the full directory from
/tmp/opencode/packages/ui/src/assets/icons/file-typesintopackages/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_lightvariant selection based onuseThemeSystem().currentTheme.metadata.variant) - fallback to
document.svg
- build an icon URL map with
- 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.tsxpackages/ui/src/components/views/FilesView.tsxpackages/ui/src/components/chat/ServerFilePicker.tsx
Verification (end of build mode)
bun run type-checkbun run lintbun run build