diff --git a/docs/ui-polish-assets/2026-07-01/after-activity.png b/docs/ui-polish-assets/2026-07-01/after-activity.png new file mode 100644 index 0000000..e4f73b1 Binary files /dev/null and b/docs/ui-polish-assets/2026-07-01/after-activity.png differ diff --git a/docs/ui-polish-assets/2026-07-01/after-browser-inbox.png b/docs/ui-polish-assets/2026-07-01/after-browser-inbox.png new file mode 100644 index 0000000..d53fb8f Binary files /dev/null and b/docs/ui-polish-assets/2026-07-01/after-browser-inbox.png differ diff --git a/docs/ui-polish-assets/2026-07-01/after-files.png b/docs/ui-polish-assets/2026-07-01/after-files.png new file mode 100644 index 0000000..bf4028a Binary files /dev/null and b/docs/ui-polish-assets/2026-07-01/after-files.png differ diff --git a/docs/ui-polish-assets/2026-07-01/after-journal-modal.png b/docs/ui-polish-assets/2026-07-01/after-journal-modal.png new file mode 100644 index 0000000..d170e85 Binary files /dev/null and b/docs/ui-polish-assets/2026-07-01/after-journal-modal.png differ diff --git a/docs/ui-polish-assets/2026-07-01/after-mobile-workspace.png b/docs/ui-polish-assets/2026-07-01/after-mobile-workspace.png new file mode 100644 index 0000000..e5e50b9 Binary files /dev/null and b/docs/ui-polish-assets/2026-07-01/after-mobile-workspace.png differ diff --git a/docs/ui-polish-assets/2026-07-01/after-search-empty.png b/docs/ui-polish-assets/2026-07-01/after-search-empty.png new file mode 100644 index 0000000..88b8733 Binary files /dev/null and b/docs/ui-polish-assets/2026-07-01/after-search-empty.png differ diff --git a/docs/ui-polish-assets/2026-07-01/after-search-results.png b/docs/ui-polish-assets/2026-07-01/after-search-results.png new file mode 100644 index 0000000..4ace9df Binary files /dev/null and b/docs/ui-polish-assets/2026-07-01/after-search-results.png differ diff --git a/docs/ui-polish-assets/2026-07-01/after-today.png b/docs/ui-polish-assets/2026-07-01/after-today.png new file mode 100644 index 0000000..6cb7fc6 Binary files /dev/null and b/docs/ui-polish-assets/2026-07-01/after-today.png differ diff --git a/docs/ui-polish-milestone.md b/docs/ui-polish-milestone.md new file mode 100644 index 0000000..867deb7 --- /dev/null +++ b/docs/ui-polish-milestone.md @@ -0,0 +1,96 @@ +# UI Polish Milestone + +## Assumptions + +- This milestone is visual polish only: no backend API changes, no plugin contract changes, and no feature removal. +- English remains the baseline UI language for this pass. Hardcoded Russian strings that are visible in core UI should be converted to English where touched. +- Official plugins are plain JS bundles with injected CSS. Introducing a new shared UI package would be larger than this milestone, so shared primitives will be expressed as global design tokens/classes plus consistent local CSS in each bundle. +- Desktop workbench density should stay compact. The goal is consistency, not a marketing-style redesign. + +## Audit Findings + +### Existing Tokens + +- `frontend/src/App.svelte` already defines partial global button classes: `btn-primary`, `btn-secondary`, `btn-danger`, `btn-ghost`, `btn-icon`, plus global button focus/disabled behavior. +- Most shell and plugin surfaces hardcode the same dark palette directly: `#1a1a2e`, `#16213e`, `#0f3460`, `#4ecca3`, `#e94560`, `#8b8ba8`. +- There are no named CSS variables for semantic surface, selected row, border, muted text, warning, or focus ring. +- Plugin bundles repeat their own toolbar/button/list/empty/error styles instead of reusing shell-level primitives. + +### Repeated Patterns + +- Page/workspace headers: `WorkspaceHost.svelte`, `WorkbenchHost.svelte`, `ViewContainer.svelte`, plugin toolbars. +- Tab bars: workspace tabs use a custom active style separate from selected rows and sidebar active states. +- Toolbars: Files, Notes, Search, Activity, Journal, Browser Inbox, and default editor use similar but inconsistent dark toolbar rules. +- List rows: Files rows, Notes rows, Activity rows, Journal rows, Secrets list items, Browser Inbox rows, Global Search results, WorkspaceTree rows. +- Cards/panels: Today panels, worklog suggestions, Secrets detail/form, Browser Inbox detail text, plugin manager cards. +- Empty/error states: many are plain centered text or show technical details as primary text. + +### Candidate Primitives + +Implement as global classes/tokens first, then apply locally: + +- PageHeader / WorkspaceHeader: compact title, metadata, right actions/search. +- TabBar / TabButton: consistent active tab, hover, focus. +- Toolbar / ToolbarGroup: grouped controls with separators and predictable height. +- Button variants: primary, secondary, ghost, danger, icon. +- ListRow: hover, selected, disabled, metadata line, actions zone. +- Card: flat desktop panel with 6px radius and subtle border. +- SplitPane: list/detail grid with shared border and selected item states. +- EmptyState: centered title, hint, optional action. +- InlineAlert: readable message plus optional details/debug text. +- StatusBadge: compact semantic label for type, status, warning/error. +- Menu: context menu with same surface, hover, danger item, separator. + +## Implementation Plan + +1. Add semantic CSS variables and global primitive classes in `frontend/src/App.svelte`. + - Colors: background, surface, surface-muted, surface-hover, surface-selected, border, border-strong, text-primary, text-secondary, text-muted, accent, accent-muted, danger, warning, success. + - Spacing: 4/8/12/16/24/32 via variables. + - Radius, font sizes, focus ring, and modest elevation tokens. + +2. Normalize shell surfaces. + - Update `WorkspaceHost.svelte`, `WorkbenchHost.svelte`, `ViewContainer.svelte`, `Sidebar.svelte`, `WorkspaceTree.svelte`, `GlobalSearch.svelte`, and `TodaySurface.svelte` to use tokens and shared state rules. + - Convert visible Russian shell search/empty strings to English. + - Keep plugin manager architecture untouched; only global tokens should make it less visually divergent. + +3. Normalize Files. + - Group toolbar into Navigation, Create, Selection, Clipboard/More, and filter/sort areas. + - Keep existing context menu and operations, restyle menu with shared surface/hover/danger states. + - Make single row click open when no modifier is used; keep ctrl/meta/shift selection behavior and keyboard selection. + - Reduce actions column visual noise by showing secondary row actions on hover/selection and using a compact More/action group. + +4. Normalize Notes. + - Make New Note the primary page action. + - Keep filter/sort inside the toolbar group. + - Make entire note row readable and clickable; row actions remain visible enough and use icon-button states. + - Use shared empty/status/error styling. + +5. Normalize Search. + - Render results as compact rows/cards with type badge/icon, title/path, secondary match reason, and compact Open button. + - Show provider errors as inline alert-style secondary information, not as raw main status text. + +6. Normalize Activity and Journal. + - Add human-readable event labels such as "Workspace selected", "File opened", "Note edited", and "Work session detected". + - Move raw event names/source IDs into a details block or secondary metadata. + - Style plugin errors through inline alert patterns. + - Present worklog suggestions as cards with consistent title/summary/minutes actions. + +7. Normalize Secrets and Browser Inbox. + - Keep split-pane list/detail layout. + - Use shared list rows, detail card/form surfaces, and empty states. + - Render "Value hidden" as password-like hidden field state. + - Use button variants: primary for save/create, secondary for copy/edit/remove where appropriate, danger for delete/clear/remove destructive actions. + +8. Verify. + - Run desktop frontend build and relevant Playwright checks if available. + - Run official plugin smoke/check script. + - Capture before/after screenshots or save available after screenshots under `docs/ui-polish-assets/`. + +## Out of Scope + +- Backend API or Wails method changes. +- Plugin manifest/contribution contract changes. +- New heavy UI dependencies. +- Full i18n extraction. +- Redesigning the product information architecture. +- Rebuilding official plugins into Svelte packages. diff --git a/frontend/e2e/activity.spec.js b/frontend/e2e/activity.spec.js index a43e0bf..4e95537 100644 --- a/frontend/e2e/activity.spec.js +++ b/frontend/e2e/activity.spec.js @@ -49,6 +49,15 @@ test.describe('Activity workflow', () => { sourcePluginId: 'verstak.files', workspaceRootPath: 'Project', }, + { + activityId: 'activity-e2e-open', + occurredAt: '2026-06-30T08:30:00.000Z', + type: 'file.opened', + title: 'Selected file', + summary: 'Project/Notes/Research Capture.md', + sourcePluginId: 'verstak.files', + workspaceRootPath: 'Project', + }, ], }); }); @@ -59,6 +68,7 @@ test.describe('Activity workflow', () => { await expect(activity.locator('.activity-count')).toHaveText('2 events'); await expect(activity.locator('[data-activity-id="activity-e2e-capture"]')).toContainText('Research Capture'); await expect(activity.locator('[data-activity-id="activity-e2e-note"]')).toContainText('Saved note'); + await expect(activity.locator('[data-activity-id="activity-e2e-open"]')).toHaveCount(0); await expect(activity.locator('[data-activity-section="worklog-suggestions"]')).toContainText('Worklog suggestions'); await expect(activity.locator('[data-worklog-suggestion="worklog:Project:2026-06-30"]')).toContainText('Project work on 2026-06-30'); await expect(activity.locator('[data-worklog-suggestion="worklog:Project:2026-06-30"]')).toContainText('50 min'); diff --git a/frontend/e2e/ux-p0.spec.js b/frontend/e2e/ux-p0.spec.js index 77ec9fb..1c2c319 100644 --- a/frontend/e2e/ux-p0.spec.js +++ b/frontend/e2e/ux-p0.spec.js @@ -97,9 +97,9 @@ test.describe('UX quick wins', () => { await page.goto('/'); await page.waitForSelector('.vault-selection', { timeout: 10000 }); - await expect(page.getByText('Выберите vault для начала работы')).toBeVisible(); - await expect(page.getByRole('button', { name: 'Создать vault' })).toBeVisible(); - await expect(page.getByRole('button', { name: 'Открыть существующий' })).toBeVisible(); + await expect(page.getByText('Choose a vault to start working')).toBeVisible(); + await expect(page.getByRole('button', { name: 'Create vault' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'Open existing' })).toBeVisible(); await page.close(); }); }); diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte index 6357562..1e7a007 100644 --- a/frontend/src/App.svelte +++ b/frontend/src/App.svelte @@ -416,6 +416,41 @@ box-sizing: border-box; } + :global(:root) { + --vt-color-background: #101020; + --vt-color-surface: #15152c; + --vt-color-surface-muted: #111629; + --vt-color-surface-hover: #1b2440; + --vt-color-surface-selected: rgba(78, 204, 163, 0.14); + --vt-color-border: #202b46; + --vt-color-border-strong: #2c456a; + --vt-color-text-primary: #f4f7fb; + --vt-color-text-secondary: #b7c0d4; + --vt-color-text-muted: #7f8aa3; + --vt-color-accent: #4ecca3; + --vt-color-accent-muted: rgba(78, 204, 163, 0.14); + --vt-color-danger: #e94560; + --vt-color-danger-muted: rgba(233, 69, 96, 0.14); + --vt-color-warning: #ffc857; + --vt-color-warning-muted: rgba(255, 200, 87, 0.14); + --vt-color-success: #4ecca3; + --vt-space-1: 0.25rem; + --vt-space-2: 0.5rem; + --vt-space-3: 0.75rem; + --vt-space-4: 1rem; + --vt-space-6: 1.5rem; + --vt-space-8: 2rem; + --vt-radius-sm: 4px; + --vt-radius-md: 6px; + --vt-radius-lg: 8px; + --vt-font-xs: 0.72rem; + --vt-font-sm: 0.8rem; + --vt-font-md: 0.88rem; + --vt-font-lg: 1rem; + --vt-focus-ring: 0 0 0 2px rgba(78, 204, 163, 0.34); + --vt-elevation-menu: 0 14px 32px rgba(0, 0, 0, 0.42); + } + :global(html), :global(body), :global(#app) { @@ -425,8 +460,8 @@ :global(body) { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - background: #1a1a2e; - color: #e0e0f0; + background: var(--vt-color-background); + color: var(--vt-color-text-primary); overflow: hidden; } @@ -437,12 +472,12 @@ gap: 0.35rem; min-height: 2rem; padding: 0.4rem 0.85rem; - border: 1px solid #1a3a5c; - border-radius: 6px; - background: #0f3460; - color: #e0e0f0; + border: 1px solid var(--vt-color-border-strong); + border-radius: var(--vt-radius-md); + background: var(--vt-color-surface-hover); + color: var(--vt-color-text-primary); font: inherit; - font-size: 0.85rem; + font-size: var(--vt-font-sm); font-weight: 600; line-height: 1.2; cursor: pointer; @@ -450,14 +485,14 @@ } :global(button:hover:not(:disabled)) { - background: #1a3a5c; - border-color: #4ecca3; + background: #203050; + border-color: var(--vt-color-accent); color: #ffffff; } :global(button:focus-visible) { - outline: 2px solid #4ecca3; - outline-offset: 2px; + outline: 0; + box-shadow: var(--vt-focus-ring); } :global(button:disabled) { @@ -466,8 +501,8 @@ } :global(.btn-primary) { - background: #4ecca3; - border-color: #4ecca3; + background: var(--vt-color-accent); + border-color: var(--vt-color-accent); color: #101827; } @@ -478,14 +513,14 @@ } :global(.btn-secondary) { - background: #0f3460; - border-color: #533483; - color: #e0e0f0; + background: var(--vt-color-surface-hover); + border-color: var(--vt-color-border-strong); + color: var(--vt-color-text-primary); } :global(.btn-danger) { - background: #e94560; - border-color: #e94560; + background: var(--vt-color-danger); + border-color: var(--vt-color-danger); color: #ffffff; } @@ -497,13 +532,13 @@ :global(.btn-ghost) { background: transparent; border-color: transparent; - color: #a0a0b8; + color: var(--vt-color-text-secondary); } :global(.btn-ghost:hover:not(:disabled)) { - background: rgba(15, 52, 96, 0.55); - border-color: #0f3460; - color: #e0e0f0; + background: var(--vt-color-surface-hover); + border-color: var(--vt-color-border); + color: var(--vt-color-text-primary); } :global(.btn-icon) { @@ -512,6 +547,236 @@ padding: 0; } + :global(.vt-page) { + min-width: 0; + min-height: 0; + height: 100%; + display: flex; + flex-direction: column; + background: var(--vt-color-background); + color: var(--vt-color-text-primary); + } + + :global(.vt-page-header), + :global(.vt-toolbar) { + min-height: 2.75rem; + display: flex; + align-items: center; + gap: var(--vt-space-2); + padding: var(--vt-space-2) var(--vt-space-3); + border-bottom: 1px solid var(--vt-color-border); + background: var(--vt-color-surface-muted); + flex-shrink: 0; + } + + :global(.vt-page-title) { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + color: var(--vt-color-text-primary); + font-size: var(--vt-font-lg); + font-weight: 650; + } + + :global(.vt-page-subtitle) { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + color: var(--vt-color-text-muted); + font-size: var(--vt-font-sm); + } + + :global(.vt-toolbar-group) { + display: inline-flex; + align-items: center; + gap: var(--vt-space-1); + padding: 0 var(--vt-space-2) 0 0; + border-right: 1px solid var(--vt-color-border); + } + + :global(.vt-toolbar-group:last-child) { + border-right: 0; + padding-right: 0; + } + + :global(.vt-button) { + min-height: 2rem; + border-radius: var(--vt-radius-md); + } + + :global(.vt-icon-button) { + width: 2rem; + min-width: 2rem; + height: 2rem; + min-height: 2rem; + padding: 0; + } + + :global(.vt-tabbar) { + display: flex; + align-items: center; + gap: var(--vt-space-1); + padding: var(--vt-space-1) var(--vt-space-3) 0; + border-bottom: 1px solid var(--vt-color-border); + background: #12162a; + overflow-x: auto; + flex-shrink: 0; + } + + :global(.vt-tab) { + flex-shrink: 0; + min-height: 2.1rem; + padding: 0.38rem 0.78rem; + border: 1px solid transparent; + border-bottom: 0; + border-radius: var(--vt-radius-md) var(--vt-radius-md) 0 0; + background: transparent; + color: var(--vt-color-text-muted); + font-size: var(--vt-font-sm); + } + + :global(.vt-tab:hover:not(:disabled)) { + background: var(--vt-color-surface-hover); + border-color: transparent; + color: var(--vt-color-text-primary); + } + + :global(.vt-tab.is-active), + :global(.vt-tab.active) { + background: var(--vt-color-background); + border-color: var(--vt-color-border); + color: var(--vt-color-accent); + } + + :global(.vt-list-row) { + border-bottom: 1px solid rgba(32, 43, 70, 0.72); + color: var(--vt-color-text-primary); + } + + :global(.vt-list-row:hover) { + background: var(--vt-color-surface-hover); + } + + :global(.vt-list-row.selected), + :global(.vt-list-row.active), + :global(.vt-list-row.is-selected) { + background: var(--vt-color-surface-selected); + box-shadow: inset 2px 0 0 var(--vt-color-accent); + } + + :global(.vt-card) { + border: 1px solid var(--vt-color-border); + border-radius: var(--vt-radius-lg); + background: var(--vt-color-surface); + } + + :global(.vt-split-pane) { + display: grid; + grid-template-columns: minmax(16rem, 22rem) minmax(0, 1fr); + min-height: 0; + height: 100%; + background: var(--vt-color-background); + } + + :global(.vt-split-list) { + min-height: 0; + overflow: auto; + border-right: 1px solid var(--vt-color-border); + background: var(--vt-color-surface-muted); + } + + :global(.vt-split-detail) { + min-width: 0; + min-height: 0; + overflow: auto; + padding: var(--vt-space-4); + } + + :global(.vt-empty-state) { + min-height: 9rem; + display: flex; + flex: 1; + flex-direction: column; + align-items: center; + justify-content: center; + gap: var(--vt-space-2); + padding: var(--vt-space-8); + color: var(--vt-color-text-muted); + font-size: var(--vt-font-sm); + line-height: 1.45; + text-align: center; + } + + :global(.vt-empty-title) { + color: var(--vt-color-text-secondary); + font-size: var(--vt-font-md); + font-weight: 650; + } + + :global(.vt-inline-alert) { + border: 1px solid var(--vt-color-border-strong); + border-radius: var(--vt-radius-md); + background: var(--vt-color-surface-muted); + color: var(--vt-color-text-secondary); + padding: var(--vt-space-3); + font-size: var(--vt-font-sm); + line-height: 1.45; + } + + :global(.vt-inline-alert.error) { + border-color: rgba(233, 69, 96, 0.55); + background: var(--vt-color-danger-muted); + color: #ffc6ce; + } + + :global(.vt-badge) { + display: inline-flex; + align-items: center; + min-height: 1.25rem; + padding: 0.1rem 0.4rem; + border: 1px solid var(--vt-color-border); + border-radius: var(--vt-radius-sm); + background: var(--vt-color-surface-muted); + color: var(--vt-color-text-muted); + font-size: var(--vt-font-xs); + font-weight: 650; + line-height: 1; + } + + :global(.vt-badge.accent) { + border-color: rgba(78, 204, 163, 0.4); + background: var(--vt-color-accent-muted); + color: var(--vt-color-accent); + } + + :global(.vt-menu) { + border: 1px solid var(--vt-color-border-strong); + border-radius: var(--vt-radius-md); + background: var(--vt-color-surface); + color: var(--vt-color-text-primary); + box-shadow: var(--vt-elevation-menu); + } + + :global(.vt-menu-item) { + display: flex; + align-items: center; + gap: var(--vt-space-2); + padding: 0.42rem 0.7rem; + color: var(--vt-color-text-secondary); + cursor: pointer; + } + + :global(.vt-menu-item:hover) { + background: var(--vt-color-surface-hover); + color: var(--vt-color-text-primary); + } + + :global(.vt-menu-item.danger) { + color: #ff9aaa; + } + :global(.scroll-surface) { min-width: 0; min-height: 0; @@ -521,7 +786,7 @@ :global(*) { scrollbar-width: thin; - scrollbar-color: #0f3460 #1a1a2e; + scrollbar-color: var(--vt-color-border-strong) var(--vt-color-background); } :global(*::-webkit-scrollbar) { @@ -530,12 +795,12 @@ } :global(*::-webkit-scrollbar-track) { - background: #1a1a2e; + background: var(--vt-color-background); } :global(*::-webkit-scrollbar-thumb) { - background: #0f3460; - border-radius: 4px; + background: var(--vt-color-border-strong); + border-radius: var(--vt-radius-sm); } :global(*::-webkit-scrollbar-thumb:hover) { @@ -547,8 +812,8 @@ align-items: center; justify-content: center; height: 100vh; - background: #1a1a2e; - color: #a0a0b8; + background: var(--vt-color-background); + color: var(--vt-color-text-muted); font-size: 1rem; } @@ -556,7 +821,7 @@ display: flex; height: 100vh; width: 100%; - background: #1a1a2e; + background: var(--vt-color-background); overflow: hidden; } @@ -574,7 +839,7 @@ min-height: 0; display: flex; flex-direction: column; - padding: clamp(1rem, 2vw, 1.5rem); + padding: 0; } @media (max-width: 720px) { diff --git a/frontend/src/lib/shell/GlobalSearch.svelte b/frontend/src/lib/shell/GlobalSearch.svelte index 863761c..73842b0 100644 --- a/frontend/src/lib/shell/GlobalSearch.svelte +++ b/frontend/src/lib/shell/GlobalSearch.svelte @@ -161,7 +161,7 @@ next.push({ type: 'Workspace', title: workspaceTitle(node), - subtitle: 'Рабочее пространство', + subtitle: 'Workspace', keywords: `${node.id || ''} ${node.rootPath || ''}`, rank: 10, action: 'workspace', @@ -293,8 +293,8 @@ on:focus={handleFocus} on:blur={() => setTimeout(() => focused = false, 120)} type="search" - placeholder={loading ? 'Индексируем...' : 'Поиск'} - aria-label="Глобальный поиск" + placeholder={loading ? 'Indexing...' : 'Search'} + aria-label="Global search" data-global-search-input /> @@ -314,7 +314,7 @@ {/each} {:else} -
Ничего не найдено
+
No results
{/if} {/if} @@ -324,7 +324,7 @@ .global-search { position: relative; padding: 0.55rem 0.75rem; - border-bottom: 1px solid #0f3460; + border-bottom: 1px solid var(--vt-color-border); flex-shrink: 0; } @@ -334,14 +334,14 @@ gap: 0.35rem; height: 2rem; padding: 0 0.55rem; - border: 1px solid #263653; - border-radius: 5px; - background: #101626; - color: #8b8ba8; + border: 1px solid var(--vt-color-border-strong); + border-radius: var(--vt-radius-md); + background: #0f1424; + color: var(--vt-color-text-muted); } :global(.global-search-icon) { - color: #8b8ba8; + color: var(--vt-color-text-muted); flex-shrink: 0; } @@ -351,17 +351,18 @@ border: 0; outline: 0; background: transparent; - color: #e0e0f0; + color: var(--vt-color-text-primary); font: inherit; font-size: 0.78rem; } .global-search input::placeholder { - color: #6f7894; + color: var(--vt-color-text-muted); } .global-search-box:focus-within { - border-color: #4ecca3; + border-color: var(--vt-color-accent); + box-shadow: var(--vt-focus-ring); } .global-search-results { @@ -372,10 +373,10 @@ z-index: 400; max-height: 20rem; overflow: auto; - border: 1px solid #28466f; - border-radius: 6px; - background: #101626; - box-shadow: 0 12px 30px rgba(0, 0, 0, 0.45); + border: 1px solid var(--vt-color-border-strong); + border-radius: var(--vt-radius-md); + background: var(--vt-color-surface); + box-shadow: var(--vt-elevation-menu); } .global-search-result { @@ -387,13 +388,13 @@ border: 0; border-bottom: 1px solid rgba(40, 70, 111, 0.55); background: transparent; - color: #d9e1ef; + color: var(--vt-color-text-primary); text-align: left; cursor: pointer; } .global-search-result:hover { - background: rgba(78, 204, 163, 0.1); + background: var(--vt-color-surface-hover); } .global-search-result-title { @@ -406,7 +407,7 @@ .global-search-result-meta, .global-search-empty { - color: #8b8ba8; + color: var(--vt-color-text-muted); font-size: 0.7rem; } diff --git a/frontend/src/lib/shell/Sidebar.svelte b/frontend/src/lib/shell/Sidebar.svelte index 0e28991..9bf6f70 100644 --- a/frontend/src/lib/shell/Sidebar.svelte +++ b/frontend/src/lib/shell/Sidebar.svelte @@ -88,7 +88,7 @@ Tools {#each sidebarItems as item}
-

Открыть существующий vault

-

Используйте vault, который уже есть на этом компьютере.

+

Open an existing vault

+

Use a vault that is already on this computer.

@@ -186,7 +186,7 @@ {#if recentVaults.length > 0}
-

Недавние vault

+

Recent vaults

{:else if activeView}
-

View "{activeView}" not found in contributions

+

View is unavailable.

{:else}
@@ -97,7 +103,7 @@ display: flex; flex-direction: column; min-width: 0; - background: #1a1a2e; + background: var(--vt-color-background); } .view { flex: 1; @@ -107,7 +113,7 @@ padding: 1.5rem; } .view.degraded { - border-left: 3px solid #ffc857; + border-left: 3px solid var(--vt-color-warning); } .view-header { display: flex; @@ -115,18 +121,18 @@ gap: 0.5rem; margin-bottom: 1rem; padding-bottom: 0.75rem; - border-bottom: 1px solid #16213e; + border-bottom: 1px solid var(--vt-color-border); } .view-header h2 { margin: 0; font-size: 1.2rem; - color: #e0e0f0; + color: var(--vt-color-text-primary); flex: 1; } :global(.view-icon) { width: 1.3rem; height: 1.3rem; - color: #a78bfa; + color: var(--vt-color-text-muted); flex-shrink: 0; } .view-content { @@ -134,33 +140,33 @@ min-width: 0; } .placeholder { - color: #666; + color: var(--vt-color-text-muted); font-style: italic; padding: 2rem; text-align: center; - border: 1px dashed #333; - border-radius: 8px; + border: 1px dashed var(--vt-color-border-strong); + border-radius: var(--vt-radius-lg); } .placeholder-label { font-size: 1rem; - color: #a0a0b8; + color: var(--vt-color-text-secondary); font-weight: 600; margin-bottom: 1rem; font-style: normal; } .placeholder-info { font-size: 0.85rem; - color: #666; + color: var(--vt-color-text-muted); margin: 0.3rem 0; font-style: normal; } .placeholder-key { - color: #a0a0b8; + color: var(--vt-color-text-muted); } - .placeholder-info strong { color: #4ecca3; } + .placeholder-info strong { color: var(--vt-color-accent); } .placeholder-info code { - color: #e0e0f0; - background: #16213e; + color: var(--vt-color-text-primary); + background: var(--vt-color-surface-muted); padding: 0.1rem 0.3rem; border-radius: 3px; font-size: 0.8rem; @@ -169,8 +175,8 @@ display: inline-block; margin-top: 1rem; padding: 0.25rem 0.75rem; - background: #533483; - color: #e0e0f0; + background: var(--vt-color-surface-muted); + color: var(--vt-color-text-secondary); border-radius: 12px; font-size: 0.75rem; font-weight: 600; @@ -188,16 +194,16 @@ padding: 2rem; } :global(.error-icon) { - color: #e94560; + color: var(--vt-color-danger); } .error-title { - color: #e94560; + color: var(--vt-color-danger); font-size: 1.1rem; font-weight: 600; margin: 0.5rem 0; } .error-text { - color: #a0a0b8; + color: var(--vt-color-text-secondary); font-size: 0.85rem; font-family: monospace; margin-top: 0.5rem; @@ -208,9 +214,13 @@ align-items: center; justify-content: center; height: 100%; - color: #555; + color: var(--vt-color-text-muted); font-size: 1rem; text-align: center; } - .empty .sub { font-size: 0.85rem; color: #444; margin-top: 0.5rem; } + .empty .sub { font-size: 0.85rem; color: var(--vt-color-text-muted); margin-top: 0.5rem; } + .placeholder-details, + .error-details { margin-top: 0.75rem; color: var(--vt-color-text-muted); } + .placeholder-details summary, + .error-details summary { cursor: pointer; color: var(--vt-color-text-secondary); } diff --git a/frontend/src/lib/shell/WorkbenchHost.svelte b/frontend/src/lib/shell/WorkbenchHost.svelte index 37ef971..1a91687 100644 --- a/frontend/src/lib/shell/WorkbenchHost.svelte +++ b/frontend/src/lib/shell/WorkbenchHost.svelte @@ -26,24 +26,24 @@ } -
+
{#if openedResource?.status === 'no-provider'} -
- {resourcePath} - no-provider -
-
-

No viewer/editor available

+
+

No viewer/editor available

{requestMode} · {requestContext}

{:else if openedResource} -
- {resourcePath} - {providerId} -
@@ -57,8 +57,8 @@ {/key}
{:else} -
-

No resource opened

+
+

No resource opened

{/if}
@@ -71,20 +71,20 @@ height: 100%; display: flex; flex-direction: column; - background: #1a1a2e; + background: var(--vt-color-background); } .workbench-header { display: flex; align-items: center; gap: 0.75rem; - padding: 0.75rem 1rem; - border-bottom: 1px solid #16213e; + padding: var(--vt-space-2) var(--vt-space-4); + border-bottom: 1px solid var(--vt-color-border); flex-shrink: 0; } .workbench-title { - color: #e0e0f0; + color: var(--vt-color-text-primary); font-size: 0.95rem; font-weight: 600; min-width: 0; @@ -98,21 +98,19 @@ height: 2rem; min-height: 0; padding: 0; - border: 1px solid #1a3a5c; - border-radius: 4px; - background: #0f3460; - color: #a0a0b8; + border-radius: var(--vt-radius-md); + color: var(--vt-color-text-secondary); flex-shrink: 0; cursor: pointer; } .close-btn:hover { - color: #e0e0f0; - background: #1a4a7a; + color: var(--vt-color-text-primary); + background: var(--vt-color-surface-hover); } .workbench-provider { - color: #4ecca3; + color: var(--vt-color-accent); font-size: 0.75rem; margin-left: auto; } @@ -132,7 +130,7 @@ display: flex; align-items: center; justify-content: center; - color: #666; + color: var(--vt-color-text-muted); } .workbench-empty.no-provider { @@ -142,7 +140,7 @@ .workbench-meta { margin: 0; - color: #8b8ba8; + color: var(--vt-color-text-muted); font-size: 0.8rem; } diff --git a/frontend/src/lib/shell/WorkspaceHost.svelte b/frontend/src/lib/shell/WorkspaceHost.svelte index 7b3a69f..3ad8d9e 100644 --- a/frontend/src/lib/shell/WorkspaceHost.svelte +++ b/frontend/src/lib/shell/WorkspaceHost.svelte @@ -128,12 +128,12 @@ } -
+
{#if selectedWorkspace} -
+
- {workspaceTitle} - {workspaceType} + {workspaceTitle} + {workspaceType}
{#if displayedTools.length > 0} -
+
{#each displayedTools as tool (tool.id + tool.pluginId)} - + {:else} +
@@ -238,35 +238,35 @@ diff --git a/frontend/src/lib/test/wails-mock.js b/frontend/src/lib/test/wails-mock.js index fae2895..038d9c0 100644 --- a/frontend/src/lib/test/wails-mock.js +++ b/frontend/src/lib/test/wails-mock.js @@ -1384,6 +1384,13 @@ function activityBundle() { return '(' + function () { var PLUGIN_ID = 'verstak.activity'; + var LOW_VALUE_EVENT_TYPES = { + 'workspace.selected': true, + 'case.selected': true, + 'file.selected': true, + 'file.opened': true, + 'note.opened': true + }; function injectStyles() { if (document.getElementById('mock-activity-style')) return; @@ -1435,6 +1442,12 @@ return Array.isArray(value) ? value.filter(function (item) { return item && typeof item === 'object'; }) : []; } + function meaningfulRows(value) { + return rows(value).filter(function (activity) { + return !LOW_VALUE_EVENT_TYPES[String(activity.type || '').toLowerCase()]; + }); + } + function eventTime(value) { var date = new Date(value || 0); return isNaN(date.getTime()) ? 0 : date.getTime(); @@ -1576,7 +1589,7 @@ } readSettings().then(function (settings) { - events = rows(settings[key]); + events = meaningfulRows(settings[key]); render(); }); render();