Polish desktop workbench UI
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 110 KiB |
|
|
@ -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.
|
||||||
|
|
@ -49,6 +49,15 @@ test.describe('Activity workflow', () => {
|
||||||
sourcePluginId: 'verstak.files',
|
sourcePluginId: 'verstak.files',
|
||||||
workspaceRootPath: 'Project',
|
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('.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-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-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-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('Project work on 2026-06-30');
|
||||||
await expect(activity.locator('[data-worklog-suggestion="worklog:Project:2026-06-30"]')).toContainText('50 min');
|
await expect(activity.locator('[data-worklog-suggestion="worklog:Project:2026-06-30"]')).toContainText('50 min');
|
||||||
|
|
|
||||||
|
|
@ -97,9 +97,9 @@ test.describe('UX quick wins', () => {
|
||||||
await page.goto('/');
|
await page.goto('/');
|
||||||
await page.waitForSelector('.vault-selection', { timeout: 10000 });
|
await page.waitForSelector('.vault-selection', { timeout: 10000 });
|
||||||
|
|
||||||
await expect(page.getByText('Выберите vault для начала работы')).toBeVisible();
|
await expect(page.getByText('Choose a vault to start working')).toBeVisible();
|
||||||
await expect(page.getByRole('button', { name: 'Создать vault' })).toBeVisible();
|
await expect(page.getByRole('button', { name: 'Create vault' })).toBeVisible();
|
||||||
await expect(page.getByRole('button', { name: 'Открыть существующий' })).toBeVisible();
|
await expect(page.getByRole('button', { name: 'Open existing' })).toBeVisible();
|
||||||
await page.close();
|
await page.close();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -416,6 +416,41 @@
|
||||||
box-sizing: border-box;
|
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(html),
|
||||||
:global(body),
|
:global(body),
|
||||||
:global(#app) {
|
:global(#app) {
|
||||||
|
|
@ -425,8 +460,8 @@
|
||||||
|
|
||||||
:global(body) {
|
:global(body) {
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
background: #1a1a2e;
|
background: var(--vt-color-background);
|
||||||
color: #e0e0f0;
|
color: var(--vt-color-text-primary);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -437,12 +472,12 @@
|
||||||
gap: 0.35rem;
|
gap: 0.35rem;
|
||||||
min-height: 2rem;
|
min-height: 2rem;
|
||||||
padding: 0.4rem 0.85rem;
|
padding: 0.4rem 0.85rem;
|
||||||
border: 1px solid #1a3a5c;
|
border: 1px solid var(--vt-color-border-strong);
|
||||||
border-radius: 6px;
|
border-radius: var(--vt-radius-md);
|
||||||
background: #0f3460;
|
background: var(--vt-color-surface-hover);
|
||||||
color: #e0e0f0;
|
color: var(--vt-color-text-primary);
|
||||||
font: inherit;
|
font: inherit;
|
||||||
font-size: 0.85rem;
|
font-size: var(--vt-font-sm);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
@ -450,14 +485,14 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(button:hover:not(:disabled)) {
|
:global(button:hover:not(:disabled)) {
|
||||||
background: #1a3a5c;
|
background: #203050;
|
||||||
border-color: #4ecca3;
|
border-color: var(--vt-color-accent);
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(button:focus-visible) {
|
:global(button:focus-visible) {
|
||||||
outline: 2px solid #4ecca3;
|
outline: 0;
|
||||||
outline-offset: 2px;
|
box-shadow: var(--vt-focus-ring);
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(button:disabled) {
|
:global(button:disabled) {
|
||||||
|
|
@ -466,8 +501,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.btn-primary) {
|
:global(.btn-primary) {
|
||||||
background: #4ecca3;
|
background: var(--vt-color-accent);
|
||||||
border-color: #4ecca3;
|
border-color: var(--vt-color-accent);
|
||||||
color: #101827;
|
color: #101827;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -478,14 +513,14 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.btn-secondary) {
|
:global(.btn-secondary) {
|
||||||
background: #0f3460;
|
background: var(--vt-color-surface-hover);
|
||||||
border-color: #533483;
|
border-color: var(--vt-color-border-strong);
|
||||||
color: #e0e0f0;
|
color: var(--vt-color-text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.btn-danger) {
|
:global(.btn-danger) {
|
||||||
background: #e94560;
|
background: var(--vt-color-danger);
|
||||||
border-color: #e94560;
|
border-color: var(--vt-color-danger);
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -497,13 +532,13 @@
|
||||||
:global(.btn-ghost) {
|
:global(.btn-ghost) {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
color: #a0a0b8;
|
color: var(--vt-color-text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.btn-ghost:hover:not(:disabled)) {
|
:global(.btn-ghost:hover:not(:disabled)) {
|
||||||
background: rgba(15, 52, 96, 0.55);
|
background: var(--vt-color-surface-hover);
|
||||||
border-color: #0f3460;
|
border-color: var(--vt-color-border);
|
||||||
color: #e0e0f0;
|
color: var(--vt-color-text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.btn-icon) {
|
:global(.btn-icon) {
|
||||||
|
|
@ -512,6 +547,236 @@
|
||||||
padding: 0;
|
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) {
|
:global(.scroll-surface) {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
|
|
@ -521,7 +786,7 @@
|
||||||
|
|
||||||
:global(*) {
|
:global(*) {
|
||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
scrollbar-color: #0f3460 #1a1a2e;
|
scrollbar-color: var(--vt-color-border-strong) var(--vt-color-background);
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(*::-webkit-scrollbar) {
|
:global(*::-webkit-scrollbar) {
|
||||||
|
|
@ -530,12 +795,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(*::-webkit-scrollbar-track) {
|
:global(*::-webkit-scrollbar-track) {
|
||||||
background: #1a1a2e;
|
background: var(--vt-color-background);
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(*::-webkit-scrollbar-thumb) {
|
:global(*::-webkit-scrollbar-thumb) {
|
||||||
background: #0f3460;
|
background: var(--vt-color-border-strong);
|
||||||
border-radius: 4px;
|
border-radius: var(--vt-radius-sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(*::-webkit-scrollbar-thumb:hover) {
|
:global(*::-webkit-scrollbar-thumb:hover) {
|
||||||
|
|
@ -547,8 +812,8 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
background: #1a1a2e;
|
background: var(--vt-color-background);
|
||||||
color: #a0a0b8;
|
color: var(--vt-color-text-muted);
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -556,7 +821,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: #1a1a2e;
|
background: var(--vt-color-background);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -574,7 +839,7 @@
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: clamp(1rem, 2vw, 1.5rem);
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 720px) {
|
@media (max-width: 720px) {
|
||||||
|
|
|
||||||
|
|
@ -161,7 +161,7 @@
|
||||||
next.push({
|
next.push({
|
||||||
type: 'Workspace',
|
type: 'Workspace',
|
||||||
title: workspaceTitle(node),
|
title: workspaceTitle(node),
|
||||||
subtitle: 'Рабочее пространство',
|
subtitle: 'Workspace',
|
||||||
keywords: `${node.id || ''} ${node.rootPath || ''}`,
|
keywords: `${node.id || ''} ${node.rootPath || ''}`,
|
||||||
rank: 10,
|
rank: 10,
|
||||||
action: 'workspace',
|
action: 'workspace',
|
||||||
|
|
@ -293,8 +293,8 @@
|
||||||
on:focus={handleFocus}
|
on:focus={handleFocus}
|
||||||
on:blur={() => setTimeout(() => focused = false, 120)}
|
on:blur={() => setTimeout(() => focused = false, 120)}
|
||||||
type="search"
|
type="search"
|
||||||
placeholder={loading ? 'Индексируем...' : 'Поиск'}
|
placeholder={loading ? 'Indexing...' : 'Search'}
|
||||||
aria-label="Глобальный поиск"
|
aria-label="Global search"
|
||||||
data-global-search-input
|
data-global-search-input
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -314,7 +314,7 @@
|
||||||
</button>
|
</button>
|
||||||
{/each}
|
{/each}
|
||||||
{:else}
|
{:else}
|
||||||
<div class="global-search-empty">Ничего не найдено</div>
|
<div class="global-search-empty vt-empty-title">No results</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
@ -324,7 +324,7 @@
|
||||||
.global-search {
|
.global-search {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 0.55rem 0.75rem;
|
padding: 0.55rem 0.75rem;
|
||||||
border-bottom: 1px solid #0f3460;
|
border-bottom: 1px solid var(--vt-color-border);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -334,14 +334,14 @@
|
||||||
gap: 0.35rem;
|
gap: 0.35rem;
|
||||||
height: 2rem;
|
height: 2rem;
|
||||||
padding: 0 0.55rem;
|
padding: 0 0.55rem;
|
||||||
border: 1px solid #263653;
|
border: 1px solid var(--vt-color-border-strong);
|
||||||
border-radius: 5px;
|
border-radius: var(--vt-radius-md);
|
||||||
background: #101626;
|
background: #0f1424;
|
||||||
color: #8b8ba8;
|
color: var(--vt-color-text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.global-search-icon) {
|
:global(.global-search-icon) {
|
||||||
color: #8b8ba8;
|
color: var(--vt-color-text-muted);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -351,17 +351,18 @@
|
||||||
border: 0;
|
border: 0;
|
||||||
outline: 0;
|
outline: 0;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: #e0e0f0;
|
color: var(--vt-color-text-primary);
|
||||||
font: inherit;
|
font: inherit;
|
||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.global-search input::placeholder {
|
.global-search input::placeholder {
|
||||||
color: #6f7894;
|
color: var(--vt-color-text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.global-search-box:focus-within {
|
.global-search-box:focus-within {
|
||||||
border-color: #4ecca3;
|
border-color: var(--vt-color-accent);
|
||||||
|
box-shadow: var(--vt-focus-ring);
|
||||||
}
|
}
|
||||||
|
|
||||||
.global-search-results {
|
.global-search-results {
|
||||||
|
|
@ -372,10 +373,10 @@
|
||||||
z-index: 400;
|
z-index: 400;
|
||||||
max-height: 20rem;
|
max-height: 20rem;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
border: 1px solid #28466f;
|
border: 1px solid var(--vt-color-border-strong);
|
||||||
border-radius: 6px;
|
border-radius: var(--vt-radius-md);
|
||||||
background: #101626;
|
background: var(--vt-color-surface);
|
||||||
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.45);
|
box-shadow: var(--vt-elevation-menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
.global-search-result {
|
.global-search-result {
|
||||||
|
|
@ -387,13 +388,13 @@
|
||||||
border: 0;
|
border: 0;
|
||||||
border-bottom: 1px solid rgba(40, 70, 111, 0.55);
|
border-bottom: 1px solid rgba(40, 70, 111, 0.55);
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: #d9e1ef;
|
color: var(--vt-color-text-primary);
|
||||||
text-align: left;
|
text-align: left;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.global-search-result:hover {
|
.global-search-result:hover {
|
||||||
background: rgba(78, 204, 163, 0.1);
|
background: var(--vt-color-surface-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
.global-search-result-title {
|
.global-search-result-title {
|
||||||
|
|
@ -406,7 +407,7 @@
|
||||||
|
|
||||||
.global-search-result-meta,
|
.global-search-result-meta,
|
||||||
.global-search-empty {
|
.global-search-empty {
|
||||||
color: #8b8ba8;
|
color: var(--vt-color-text-muted);
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@
|
||||||
<span class="section-label">Tools</span>
|
<span class="section-label">Tools</span>
|
||||||
{#each sidebarItems as item}
|
{#each sidebarItems as item}
|
||||||
<button
|
<button
|
||||||
class="nav-item plugin-item"
|
class="nav-item plugin-item vt-list-row"
|
||||||
on:click={() => handleSidebarItem(item)}
|
on:click={() => handleSidebarItem(item)}
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
|
|
@ -117,10 +117,10 @@
|
||||||
.sidebar {
|
.sidebar {
|
||||||
width: 220px;
|
width: 220px;
|
||||||
min-width: 220px;
|
min-width: 220px;
|
||||||
background: #16213e;
|
background: var(--vt-color-surface-muted);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
border-right: 1px solid #0f3460;
|
border-right: 1px solid var(--vt-color-border);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -129,18 +129,18 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
padding: 1rem 1.25rem;
|
padding: 1rem 1.25rem;
|
||||||
border-bottom: 1px solid #0f3460;
|
border-bottom: 1px solid var(--vt-color-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.sidebar-logo) {
|
:global(.sidebar-logo) {
|
||||||
width: 1.2rem;
|
width: 1.2rem;
|
||||||
height: 1.2rem;
|
height: 1.2rem;
|
||||||
color: #4ecca3;
|
color: var(--vt-color-accent);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-title {
|
.sidebar-title {
|
||||||
color: #e0e0f0;
|
color: var(--vt-color-text-primary);
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
@ -150,7 +150,7 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 0.45rem 0.6rem 0.55rem;
|
padding: 0.45rem 0.6rem 0.55rem;
|
||||||
gap: 0.15rem;
|
gap: 0.15rem;
|
||||||
border-bottom: 1px solid #0f3460;
|
border-bottom: 1px solid var(--vt-color-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(workspace-tree) {
|
:global(workspace-tree) {
|
||||||
|
|
@ -161,7 +161,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-label {
|
.section-label {
|
||||||
color: #a0a0b8;
|
color: var(--vt-color-text-muted);
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.05em;
|
letter-spacing: 0.05em;
|
||||||
|
|
@ -174,22 +174,22 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
gap: 0.45rem;
|
gap: 0.45rem;
|
||||||
min-height: 1.7rem;
|
min-height: 1.85rem;
|
||||||
padding: 0.15rem 0.45rem;
|
padding: 0.15rem 0.45rem;
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
color: #a0a0b8;
|
color: var(--vt-color-text-secondary);
|
||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 3px;
|
border-radius: var(--vt-radius-sm);
|
||||||
text-align: left;
|
text-align: left;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
transition: background 0.15s, color 0.15s;
|
transition: background 0.15s, color 0.15s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-item:hover {
|
.nav-item:hover {
|
||||||
background: rgba(15,52,96,0.4);
|
background: var(--vt-color-surface-hover);
|
||||||
color: #e0e0f0;
|
color: var(--vt-color-text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.nav-icon) {
|
:global(.nav-icon) {
|
||||||
|
|
@ -199,7 +199,8 @@
|
||||||
color: currentColor;
|
color: currentColor;
|
||||||
}
|
}
|
||||||
:global(.nav-icon.icon-plugin) {
|
:global(.nav-icon.icon-plugin) {
|
||||||
color: #a78bfa;
|
color: var(--vt-color-text-muted);
|
||||||
|
opacity: 0.9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-label {
|
.nav-label {
|
||||||
|
|
@ -211,7 +212,7 @@
|
||||||
.sidebar-footer {
|
.sidebar-footer {
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
padding: 0.75rem 1.25rem;
|
padding: 0.75rem 1.25rem;
|
||||||
border-top: 1px solid #0f3460;
|
border-top: 1px solid var(--vt-color-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-error {
|
.sidebar-error {
|
||||||
|
|
@ -219,11 +220,11 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.25rem;
|
gap: 0.25rem;
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
color: #e94560;
|
color: var(--vt-color-danger);
|
||||||
margin-bottom: 0.25rem;
|
margin-bottom: 0.25rem;
|
||||||
}
|
}
|
||||||
:global(.sidebar-error-icon) {
|
:global(.sidebar-error-icon) {
|
||||||
color: #e94560;
|
color: var(--vt-color-danger);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 720px) {
|
@media (max-width: 720px) {
|
||||||
|
|
@ -232,7 +233,7 @@
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
max-height: 14rem;
|
max-height: 14rem;
|
||||||
border-right: 0;
|
border-right: 0;
|
||||||
border-bottom: 1px solid #0f3460;
|
border-bottom: 1px solid var(--vt-color-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-header {
|
.sidebar-header {
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,25 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function activityTitle(item) {
|
function activityTitle(item) {
|
||||||
return item.title || item.summary || item.type || item.activityId || 'Activity event';
|
return item.title || item.summary || humanActivityType(item.type) || 'Activity event';
|
||||||
|
}
|
||||||
|
|
||||||
|
function humanActivityType(type) {
|
||||||
|
const labels = {
|
||||||
|
'workspace.selected': 'Workspace selected',
|
||||||
|
'case.selected': 'Workspace selected',
|
||||||
|
'file.opened': 'File opened',
|
||||||
|
'file.changed': 'File changed',
|
||||||
|
'note.saved': 'Note edited',
|
||||||
|
'browser.capture.received': 'Browser capture received',
|
||||||
|
'browser.capture.page': 'Page captured',
|
||||||
|
'browser.capture.selection': 'Selection captured',
|
||||||
|
'browser.capture.link': 'Link captured',
|
||||||
|
'browser.capture.file': 'File captured',
|
||||||
|
'browser.capture.converted': 'Capture converted',
|
||||||
|
'action.started': 'Work session detected'
|
||||||
|
};
|
||||||
|
return labels[String(type || '').toLowerCase()] || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function worklogTitle(item) {
|
function worklogTitle(item) {
|
||||||
|
|
@ -265,8 +283,8 @@
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
background: #101020;
|
background: var(--vt-color-background);
|
||||||
color: #e0e0f0;
|
color: var(--vt-color-text-primary);
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -276,8 +294,8 @@
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
border-bottom: 1px solid #16213e;
|
border-bottom: 1px solid var(--vt-color-border);
|
||||||
background: #12122a;
|
background: var(--vt-color-surface-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.today-header h2 {
|
.today-header h2 {
|
||||||
|
|
@ -287,7 +305,7 @@
|
||||||
|
|
||||||
.today-header p {
|
.today-header p {
|
||||||
margin: 0.25rem 0 0;
|
margin: 0.25rem 0 0;
|
||||||
color: #8b8ba8;
|
color: var(--vt-color-text-muted);
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -310,13 +328,13 @@
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 0.15rem;
|
gap: 0.15rem;
|
||||||
padding: 0.65rem 0.75rem;
|
padding: 0.65rem 0.75rem;
|
||||||
border: 1px solid rgba(78, 204, 163, 0.16);
|
border: 1px solid var(--vt-color-border);
|
||||||
border-radius: 8px;
|
border-radius: var(--vt-radius-lg);
|
||||||
background: #121a2c;
|
background: var(--vt-color-surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
.today-summary-item strong {
|
.today-summary-item strong {
|
||||||
color: #f4f7fb;
|
color: var(--vt-color-text-primary);
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
@ -326,7 +344,7 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
color: #8b8ba8;
|
color: var(--vt-color-text-muted);
|
||||||
font-size: 0.74rem;
|
font-size: 0.74rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -338,8 +356,8 @@
|
||||||
margin: 0.75rem 0.75rem 0;
|
margin: 0.75rem 0.75rem 0;
|
||||||
padding: 0.85rem 1rem;
|
padding: 0.85rem 1rem;
|
||||||
border: 1px solid rgba(78, 204, 163, 0.24);
|
border: 1px solid rgba(78, 204, 163, 0.24);
|
||||||
border-radius: 8px;
|
border-radius: var(--vt-radius-lg);
|
||||||
background: linear-gradient(135deg, rgba(78, 204, 163, 0.11), rgba(15, 52, 96, 0.14));
|
background: linear-gradient(135deg, rgba(78, 204, 163, 0.11), rgba(27, 36, 64, 0.6));
|
||||||
}
|
}
|
||||||
|
|
||||||
.today-resume-copy {
|
.today-resume-copy {
|
||||||
|
|
@ -349,7 +367,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.today-resume-copy span {
|
.today-resume-copy span {
|
||||||
color: #4ecca3;
|
color: var(--vt-color-accent);
|
||||||
font-size: 0.72rem;
|
font-size: 0.72rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
|
|
@ -361,7 +379,7 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
color: #f4f7fb;
|
color: var(--vt-color-text-primary);
|
||||||
font-size: 0.98rem;
|
font-size: 0.98rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -371,7 +389,7 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
color: #9aa4bd;
|
color: var(--vt-color-text-secondary);
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -380,9 +398,9 @@
|
||||||
min-height: 10rem;
|
min-height: 10rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
border: 1px solid #16213e;
|
border: 1px solid var(--vt-color-border);
|
||||||
border-radius: 8px;
|
border-radius: var(--vt-radius-lg);
|
||||||
background: #15152c;
|
background: var(--vt-color-surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
.today-panel-head {
|
.today-panel-head {
|
||||||
|
|
@ -392,12 +410,12 @@
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 0.75rem;
|
gap: 0.75rem;
|
||||||
padding: 0.65rem 0.75rem;
|
padding: 0.65rem 0.75rem;
|
||||||
border-bottom: 1px solid rgba(22, 33, 62, 0.8);
|
border-bottom: 1px solid var(--vt-color-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.today-panel h3 {
|
.today-panel h3 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: #f0f0ff;
|
color: var(--vt-color-text-primary);
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -416,7 +434,7 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
color: #8b8ba8;
|
color: var(--vt-color-text-muted);
|
||||||
font-size: 0.82rem;
|
font-size: 0.82rem;
|
||||||
line-height: 1.45;
|
line-height: 1.45;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
@ -433,9 +451,9 @@
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 0.2rem;
|
gap: 0.2rem;
|
||||||
padding: 0.55rem;
|
padding: 0.55rem;
|
||||||
border: 1px solid rgba(78, 204, 163, 0.16);
|
border: 1px solid var(--vt-color-border);
|
||||||
border-radius: 6px;
|
border-radius: var(--vt-radius-md);
|
||||||
background: #101827;
|
background: var(--vt-color-surface-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.today-row strong {
|
.today-row strong {
|
||||||
|
|
@ -443,7 +461,7 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
color: #f4f7fb;
|
color: var(--vt-color-text-primary);
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -452,7 +470,7 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
color: #8b8ba8;
|
color: var(--vt-color-text-muted);
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,20 +39,20 @@
|
||||||
async function createVault() {
|
async function createVault() {
|
||||||
error = '';
|
error = '';
|
||||||
if (!newVaultPath.trim()) {
|
if (!newVaultPath.trim()) {
|
||||||
error = 'Укажите или выберите папку для нового vault';
|
error = 'Choose or enter a folder for the new vault.';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
creating = true;
|
creating = true;
|
||||||
try {
|
try {
|
||||||
const createErr = await App.CreateVault(newVaultPath.trim());
|
const createErr = await App.CreateVault(newVaultPath.trim());
|
||||||
if (createErr) {
|
if (createErr) {
|
||||||
error = 'Не удалось создать vault: ' + createErr;
|
error = 'Could not create vault: ' + createErr;
|
||||||
creating = false;
|
creating = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const openErr = await App.OpenVault(newVaultPath.trim());
|
const openErr = await App.OpenVault(newVaultPath.trim());
|
||||||
if (openErr) {
|
if (openErr) {
|
||||||
error = 'Не удалось открыть vault: ' + openErr;
|
error = 'Could not open vault: ' + openErr;
|
||||||
creating = false;
|
creating = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -70,14 +70,14 @@
|
||||||
async function openExistingVault() {
|
async function openExistingVault() {
|
||||||
error = '';
|
error = '';
|
||||||
if (!openVaultPath.trim()) {
|
if (!openVaultPath.trim()) {
|
||||||
error = 'Укажите или выберите существующий vault';
|
error = 'Choose or enter an existing vault.';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
opening = true;
|
opening = true;
|
||||||
try {
|
try {
|
||||||
const openErr = await App.OpenVault(openVaultPath.trim());
|
const openErr = await App.OpenVault(openVaultPath.trim());
|
||||||
if (openErr) {
|
if (openErr) {
|
||||||
error = 'Не удалось открыть vault: ' + openErr;
|
error = 'Could not open vault: ' + openErr;
|
||||||
opening = false;
|
opening = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -98,7 +98,7 @@
|
||||||
try {
|
try {
|
||||||
const openErr = await App.OpenVault(path);
|
const openErr = await App.OpenVault(path);
|
||||||
if (openErr) {
|
if (openErr) {
|
||||||
error = 'Не удалось открыть vault: ' + openErr;
|
error = 'Could not open vault: ' + openErr;
|
||||||
opening = false;
|
opening = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -117,7 +117,7 @@
|
||||||
{#if loading}
|
{#if loading}
|
||||||
<div class="vault-selection">
|
<div class="vault-selection">
|
||||||
<div class="vault-selection-inner">
|
<div class="vault-selection-inner">
|
||||||
<p class="loading-text">Загрузка...</p>
|
<p class="loading-text">Loading...</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
|
|
@ -130,7 +130,7 @@
|
||||||
<line x1="9" y1="14" x2="15" y2="14"/>
|
<line x1="9" y1="14" x2="15" y2="14"/>
|
||||||
</svg>
|
</svg>
|
||||||
<h1>Verstak</h1>
|
<h1>Verstak</h1>
|
||||||
<p class="subtitle">Выберите vault для начала работы</p>
|
<p class="subtitle">Choose a vault to start working</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if error}
|
{#if error}
|
||||||
|
|
@ -142,43 +142,43 @@
|
||||||
|
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<div class="action-card">
|
<div class="action-card">
|
||||||
<h3>Создать новый vault</h3>
|
<h3>Create a new vault</h3>
|
||||||
<p class="hint">Создайте локальную папку vault. В ней будут храниться рабочие пространства и проекты.</p>
|
<p class="hint">Create a local vault folder for workspaces and projects.</p>
|
||||||
<div class="input-row">
|
<div class="input-row">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
bind:value={newVaultPath}
|
bind:value={newVaultPath}
|
||||||
placeholder="Выберите или введите путь..."
|
placeholder="Choose or enter a path..."
|
||||||
disabled={creating}
|
disabled={creating}
|
||||||
/>
|
/>
|
||||||
<button class="btn-secondary" on:click={browseNewVault} type="button" disabled={creating}>
|
<button class="btn-secondary" on:click={browseNewVault} type="button" disabled={creating}>
|
||||||
Выбрать…
|
Browse...
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="button-row">
|
<div class="button-row">
|
||||||
<button class="btn-primary" on:click={createVault} type="button" disabled={creating}>
|
<button class="btn-primary" on:click={createVault} type="button" disabled={creating}>
|
||||||
{creating ? 'Создаём...' : 'Создать vault'}
|
{creating ? 'Creating...' : 'Create vault'}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="action-card">
|
<div class="action-card">
|
||||||
<h3>Открыть существующий vault</h3>
|
<h3>Open an existing vault</h3>
|
||||||
<p class="hint">Используйте vault, который уже есть на этом компьютере.</p>
|
<p class="hint">Use a vault that is already on this computer.</p>
|
||||||
<div class="input-row">
|
<div class="input-row">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
bind:value={openVaultPath}
|
bind:value={openVaultPath}
|
||||||
placeholder="Выберите или введите путь..."
|
placeholder="Choose or enter a path..."
|
||||||
disabled={opening}
|
disabled={opening}
|
||||||
/>
|
/>
|
||||||
<button class="btn-secondary" on:click={browseOpenVault} type="button" disabled={opening}>
|
<button class="btn-secondary" on:click={browseOpenVault} type="button" disabled={opening}>
|
||||||
Выбрать…
|
Browse...
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="button-row">
|
<div class="button-row">
|
||||||
<button class="btn-secondary open-existing-btn" on:click={openExistingVault} type="button" disabled={opening}>
|
<button class="btn-secondary open-existing-btn" on:click={openExistingVault} type="button" disabled={opening}>
|
||||||
{opening ? 'Открываем...' : 'Открыть существующий'}
|
{opening ? 'Opening...' : 'Open existing'}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -186,7 +186,7 @@
|
||||||
|
|
||||||
{#if recentVaults.length > 0}
|
{#if recentVaults.length > 0}
|
||||||
<div class="recent-section">
|
<div class="recent-section">
|
||||||
<h3>Недавние vault</h3>
|
<h3>Recent vaults</h3>
|
||||||
<ul class="recent-list">
|
<ul class="recent-list">
|
||||||
{#each recentVaults as path}
|
{#each recentVaults as path}
|
||||||
<li>
|
<li>
|
||||||
|
|
@ -209,7 +209,7 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
background: #1a1a2e;
|
background: var(--vt-color-background);
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
}
|
}
|
||||||
.vault-selection-inner {
|
.vault-selection-inner {
|
||||||
|
|
@ -217,7 +217,7 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.loading-text {
|
.loading-text {
|
||||||
color: #a0a0b8;
|
color: var(--vt-color-text-muted);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|
@ -226,26 +226,26 @@
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
}
|
}
|
||||||
.logo h1 {
|
.logo h1 {
|
||||||
color: #e0e0f0;
|
color: var(--vt-color-text-primary);
|
||||||
font-size: 1.8rem;
|
font-size: 1.8rem;
|
||||||
margin: 0.5rem 0 0.25rem;
|
margin: 0.5rem 0 0.25rem;
|
||||||
}
|
}
|
||||||
.subtitle {
|
.subtitle {
|
||||||
color: #a0a0b8;
|
color: var(--vt-color-text-muted);
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
.error-box {
|
.error-box {
|
||||||
background: rgba(233, 69, 96, 0.1);
|
background: var(--vt-color-danger-muted);
|
||||||
border: 1px solid #e94560;
|
border: 1px solid rgba(233, 69, 96, 0.5);
|
||||||
border-radius: 8px;
|
border-radius: var(--vt-radius-lg);
|
||||||
padding: 0.75rem 1rem;
|
padding: 0.75rem 1rem;
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
color: #e94560;
|
color: #ffc6ce;
|
||||||
}
|
}
|
||||||
:global(.error-icon) { flex-shrink: 0; }
|
:global(.error-icon) { flex-shrink: 0; }
|
||||||
.error-text { word-break: break-word; }
|
.error-text { word-break: break-word; }
|
||||||
|
|
@ -256,18 +256,18 @@
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
}
|
}
|
||||||
.action-card {
|
.action-card {
|
||||||
background: #16213e;
|
background: var(--vt-color-surface);
|
||||||
border: 1px solid #0f3460;
|
border: 1px solid var(--vt-color-border);
|
||||||
border-radius: 8px;
|
border-radius: var(--vt-radius-lg);
|
||||||
padding: 1.25rem;
|
padding: 1.25rem;
|
||||||
}
|
}
|
||||||
.action-card h3 {
|
.action-card h3 {
|
||||||
color: #e0e0f0;
|
color: var(--vt-color-text-primary);
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
margin: 0 0 0.25rem;
|
margin: 0 0 0.25rem;
|
||||||
}
|
}
|
||||||
.hint {
|
.hint {
|
||||||
color: #a0a0b8;
|
color: var(--vt-color-text-muted);
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
margin: 0 0 0.75rem;
|
margin: 0 0 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
@ -278,27 +278,28 @@
|
||||||
}
|
}
|
||||||
.input-row input {
|
.input-row input {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
background: #0f3460;
|
background: #0f1424;
|
||||||
border: 1px solid #1a3a5c;
|
border: 1px solid var(--vt-color-border-strong);
|
||||||
color: #e0e0f0;
|
color: var(--vt-color-text-primary);
|
||||||
padding: 0.5rem 0.75rem;
|
padding: 0.5rem 0.75rem;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
.input-row input:focus {
|
.input-row input:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border-color: #4ecca3;
|
border-color: var(--vt-color-accent);
|
||||||
|
box-shadow: var(--vt-focus-ring);
|
||||||
}
|
}
|
||||||
.input-row input::placeholder {
|
.input-row input::placeholder {
|
||||||
color: #666;
|
color: var(--vt-color-text-muted);
|
||||||
}
|
}
|
||||||
.button-row {
|
.button-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
.btn-primary {
|
.btn-primary {
|
||||||
background: #4ecca3;
|
background: var(--vt-color-accent);
|
||||||
color: #1a1a2e;
|
color: #101827;
|
||||||
border: none;
|
border: none;
|
||||||
padding: 0.5rem 1.25rem;
|
padding: 0.5rem 1.25rem;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
|
|
@ -314,9 +315,9 @@
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
.btn-secondary {
|
.btn-secondary {
|
||||||
background: #0f3460;
|
background: var(--vt-color-surface-hover);
|
||||||
color: #a0a0b8;
|
color: var(--vt-color-text-secondary);
|
||||||
border: 1px solid #1a3a5c;
|
border: 1px solid var(--vt-color-border-strong);
|
||||||
padding: 0.5rem 0.75rem;
|
padding: 0.5rem 0.75rem;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
@ -324,21 +325,21 @@
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
.btn-secondary:hover:not(:disabled) {
|
.btn-secondary:hover:not(:disabled) {
|
||||||
background: #1a3a5c;
|
background: var(--vt-color-surface-hover);
|
||||||
color: #e0e0f0;
|
color: var(--vt-color-text-primary);
|
||||||
}
|
}
|
||||||
.btn-secondary:disabled {
|
.btn-secondary:disabled {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
.recent-section {
|
.recent-section {
|
||||||
background: #16213e;
|
background: var(--vt-color-surface);
|
||||||
border: 1px solid #0f3460;
|
border: 1px solid var(--vt-color-border);
|
||||||
border-radius: 8px;
|
border-radius: var(--vt-radius-lg);
|
||||||
padding: 1rem 1.25rem;
|
padding: 1rem 1.25rem;
|
||||||
}
|
}
|
||||||
.recent-section h3 {
|
.recent-section h3 {
|
||||||
color: #a0a0b8;
|
color: var(--vt-color-text-muted);
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.05em;
|
letter-spacing: 0.05em;
|
||||||
|
|
@ -356,14 +357,14 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
color: #e0e0f0;
|
color: var(--vt-color-text-primary);
|
||||||
padding: 0.4rem 0;
|
padding: 0.4rem 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
}
|
}
|
||||||
.recent-item:hover {
|
.recent-item:hover {
|
||||||
color: #4ecca3;
|
color: var(--vt-color-accent);
|
||||||
}
|
}
|
||||||
.recent-item:disabled {
|
.recent-item:disabled {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
|
|
|
||||||
|
|
@ -47,10 +47,13 @@
|
||||||
{#if renderError}
|
{#if renderError}
|
||||||
<div class="view-container">
|
<div class="view-container">
|
||||||
<div class="error-boundary">
|
<div class="error-boundary">
|
||||||
<div class="error-fallback">
|
<div class="error-fallback vt-inline-alert error">
|
||||||
<Icon name="warning" size={24} class="error-icon" />
|
<Icon name="warning" size={24} class="error-icon" />
|
||||||
<p class="error-title">Plugin UI failed</p>
|
<p class="error-title">Plugin UI failed</p>
|
||||||
<p class="error-text">{renderError}</p>
|
<details class="error-details">
|
||||||
|
<summary>Details</summary>
|
||||||
|
<p class="error-text">{renderError}</p>
|
||||||
|
</details>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -69,11 +72,14 @@
|
||||||
/>
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="placeholder">
|
<div class="placeholder">
|
||||||
<p class="placeholder-label">Plugin View Host</p>
|
<p class="placeholder-label">This plugin does not provide a visual view yet.</p>
|
||||||
<p class="placeholder-info"><span class="placeholder-key">Plugin:</span> <strong>{currentView.pluginId}</strong></p>
|
<details class="placeholder-details">
|
||||||
<p class="placeholder-info"><span class="placeholder-key">View ID:</span> <code>{currentView.id}</code></p>
|
<summary>Details</summary>
|
||||||
<p class="placeholder-info"><span class="placeholder-key">Component:</span> <code>{currentView.component}</code></p>
|
<p class="placeholder-info"><span class="placeholder-key">Plugin:</span> <strong>{currentView.pluginId}</strong></p>
|
||||||
<p class="placeholder-badge">frontend bundle not available</p>
|
<p class="placeholder-info"><span class="placeholder-key">View ID:</span> <code>{currentView.id}</code></p>
|
||||||
|
<p class="placeholder-info"><span class="placeholder-key">Component:</span> <code>{currentView.component}</code></p>
|
||||||
|
</details>
|
||||||
|
<p class="placeholder-badge vt-badge">Frontend bundle unavailable</p>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -81,7 +87,7 @@
|
||||||
</div>
|
</div>
|
||||||
{:else if activeView}
|
{:else if activeView}
|
||||||
<div class="view-container empty">
|
<div class="view-container empty">
|
||||||
<p>View "{activeView}" not found in contributions</p>
|
<p>View is unavailable.</p>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="view-container empty">
|
<div class="view-container empty">
|
||||||
|
|
@ -97,7 +103,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
background: #1a1a2e;
|
background: var(--vt-color-background);
|
||||||
}
|
}
|
||||||
.view {
|
.view {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
@ -107,7 +113,7 @@
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
}
|
}
|
||||||
.view.degraded {
|
.view.degraded {
|
||||||
border-left: 3px solid #ffc857;
|
border-left: 3px solid var(--vt-color-warning);
|
||||||
}
|
}
|
||||||
.view-header {
|
.view-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -115,18 +121,18 @@
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
padding-bottom: 0.75rem;
|
padding-bottom: 0.75rem;
|
||||||
border-bottom: 1px solid #16213e;
|
border-bottom: 1px solid var(--vt-color-border);
|
||||||
}
|
}
|
||||||
.view-header h2 {
|
.view-header h2 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
color: #e0e0f0;
|
color: var(--vt-color-text-primary);
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
:global(.view-icon) {
|
:global(.view-icon) {
|
||||||
width: 1.3rem;
|
width: 1.3rem;
|
||||||
height: 1.3rem;
|
height: 1.3rem;
|
||||||
color: #a78bfa;
|
color: var(--vt-color-text-muted);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
.view-content {
|
.view-content {
|
||||||
|
|
@ -134,33 +140,33 @@
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
.placeholder {
|
.placeholder {
|
||||||
color: #666;
|
color: var(--vt-color-text-muted);
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border: 1px dashed #333;
|
border: 1px dashed var(--vt-color-border-strong);
|
||||||
border-radius: 8px;
|
border-radius: var(--vt-radius-lg);
|
||||||
}
|
}
|
||||||
.placeholder-label {
|
.placeholder-label {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
color: #a0a0b8;
|
color: var(--vt-color-text-secondary);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
.placeholder-info {
|
.placeholder-info {
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
color: #666;
|
color: var(--vt-color-text-muted);
|
||||||
margin: 0.3rem 0;
|
margin: 0.3rem 0;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
.placeholder-key {
|
.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 {
|
.placeholder-info code {
|
||||||
color: #e0e0f0;
|
color: var(--vt-color-text-primary);
|
||||||
background: #16213e;
|
background: var(--vt-color-surface-muted);
|
||||||
padding: 0.1rem 0.3rem;
|
padding: 0.1rem 0.3rem;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
|
|
@ -169,8 +175,8 @@
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
padding: 0.25rem 0.75rem;
|
padding: 0.25rem 0.75rem;
|
||||||
background: #533483;
|
background: var(--vt-color-surface-muted);
|
||||||
color: #e0e0f0;
|
color: var(--vt-color-text-secondary);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
|
@ -188,16 +194,16 @@
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
}
|
}
|
||||||
:global(.error-icon) {
|
:global(.error-icon) {
|
||||||
color: #e94560;
|
color: var(--vt-color-danger);
|
||||||
}
|
}
|
||||||
.error-title {
|
.error-title {
|
||||||
color: #e94560;
|
color: var(--vt-color-danger);
|
||||||
font-size: 1.1rem;
|
font-size: 1.1rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin: 0.5rem 0;
|
margin: 0.5rem 0;
|
||||||
}
|
}
|
||||||
.error-text {
|
.error-text {
|
||||||
color: #a0a0b8;
|
color: var(--vt-color-text-secondary);
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
|
|
@ -208,9 +214,13 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
color: #555;
|
color: var(--vt-color-text-muted);
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
text-align: center;
|
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); }
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -26,24 +26,24 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="workbench-host">
|
<div class="workbench-host vt-page">
|
||||||
{#if openedResource?.status === 'no-provider'}
|
{#if openedResource?.status === 'no-provider'}
|
||||||
<div class="workbench-header">
|
<div class="workbench-header vt-page-header">
|
||||||
<span class="workbench-title">{resourcePath}</span>
|
<span class="workbench-title vt-page-title">{resourcePath}</span>
|
||||||
<span class="workbench-provider">no-provider</span>
|
<span class="workbench-provider vt-badge">No provider</span>
|
||||||
<button class="close-btn" type="button" title="Close" aria-label="Close" on:click={closeWorkbench}>
|
<button class="close-btn btn-ghost btn-icon" type="button" title="Close" aria-label="Close" on:click={closeWorkbench}>
|
||||||
<Icon name="x" size={18} />
|
<Icon name="x" size={18} />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="workbench-empty no-provider" data-workbench-status="no-provider">
|
<div class="workbench-empty no-provider vt-empty-state" data-workbench-status="no-provider">
|
||||||
<p>No viewer/editor available</p>
|
<p class="vt-empty-title">No viewer/editor available</p>
|
||||||
<p class="workbench-meta">{requestMode} · {requestContext}</p>
|
<p class="workbench-meta">{requestMode} · {requestContext}</p>
|
||||||
</div>
|
</div>
|
||||||
{:else if openedResource}
|
{:else if openedResource}
|
||||||
<div class="workbench-header">
|
<div class="workbench-header vt-page-header">
|
||||||
<span class="workbench-title">{resourcePath}</span>
|
<span class="workbench-title vt-page-title">{resourcePath}</span>
|
||||||
<span class="workbench-provider">{providerId}</span>
|
<span class="workbench-provider vt-badge accent">{providerId}</span>
|
||||||
<button class="close-btn" type="button" title="Close" aria-label="Close" on:click={closeWorkbench}>
|
<button class="close-btn btn-ghost btn-icon" type="button" title="Close" aria-label="Close" on:click={closeWorkbench}>
|
||||||
<Icon name="x" size={18} />
|
<Icon name="x" size={18} />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -57,8 +57,8 @@
|
||||||
{/key}
|
{/key}
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="workbench-empty">
|
<div class="workbench-empty vt-empty-state">
|
||||||
<p>No resource opened</p>
|
<p class="vt-empty-title">No resource opened</p>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -71,20 +71,20 @@
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
background: #1a1a2e;
|
background: var(--vt-color-background);
|
||||||
}
|
}
|
||||||
|
|
||||||
.workbench-header {
|
.workbench-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.75rem;
|
gap: 0.75rem;
|
||||||
padding: 0.75rem 1rem;
|
padding: var(--vt-space-2) var(--vt-space-4);
|
||||||
border-bottom: 1px solid #16213e;
|
border-bottom: 1px solid var(--vt-color-border);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.workbench-title {
|
.workbench-title {
|
||||||
color: #e0e0f0;
|
color: var(--vt-color-text-primary);
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
|
@ -98,21 +98,19 @@
|
||||||
height: 2rem;
|
height: 2rem;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border: 1px solid #1a3a5c;
|
border-radius: var(--vt-radius-md);
|
||||||
border-radius: 4px;
|
color: var(--vt-color-text-secondary);
|
||||||
background: #0f3460;
|
|
||||||
color: #a0a0b8;
|
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.close-btn:hover {
|
.close-btn:hover {
|
||||||
color: #e0e0f0;
|
color: var(--vt-color-text-primary);
|
||||||
background: #1a4a7a;
|
background: var(--vt-color-surface-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
.workbench-provider {
|
.workbench-provider {
|
||||||
color: #4ecca3;
|
color: var(--vt-color-accent);
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|
@ -132,7 +130,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
color: #666;
|
color: var(--vt-color-text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.workbench-empty.no-provider {
|
.workbench-empty.no-provider {
|
||||||
|
|
@ -142,7 +140,7 @@
|
||||||
|
|
||||||
.workbench-meta {
|
.workbench-meta {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: #8b8ba8;
|
color: var(--vt-color-text-muted);
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -128,12 +128,12 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="workspace-host">
|
<div class="workspace-host vt-page">
|
||||||
{#if selectedWorkspace}
|
{#if selectedWorkspace}
|
||||||
<div class="workspace-header">
|
<div class="workspace-header vt-page-header">
|
||||||
<div class="workspace-title-group">
|
<div class="workspace-title-group">
|
||||||
<span class="workspace-title">{workspaceTitle}</span>
|
<span class="workspace-title vt-page-title">{workspaceTitle}</span>
|
||||||
<span class="workspace-type">{workspaceType}</span>
|
<span class="workspace-type vt-badge accent">{workspaceType}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="workspace-search" aria-label="Workspace search">
|
<div class="workspace-search" aria-label="Workspace search">
|
||||||
<GlobalSearch />
|
<GlobalSearch />
|
||||||
|
|
@ -141,10 +141,11 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if displayedTools.length > 0}
|
{#if displayedTools.length > 0}
|
||||||
<div class="workspace-tabs" role="tablist" aria-label="Workspace tools">
|
<div class="workspace-tabs vt-tabbar" role="tablist" aria-label="Workspace tools">
|
||||||
{#each displayedTools as tool (tool.id + tool.pluginId)}
|
{#each displayedTools as tool (tool.id + tool.pluginId)}
|
||||||
<button
|
<button
|
||||||
class:active={toolKey(tool) === toolKey(activeTool)}
|
class="vt-tab"
|
||||||
|
class:is-active={toolKey(tool) === toolKey(activeTool)}
|
||||||
role="tab"
|
role="tab"
|
||||||
aria-selected={toolKey(tool) === toolKey(activeTool)}
|
aria-selected={toolKey(tool) === toolKey(activeTool)}
|
||||||
type="button"
|
type="button"
|
||||||
|
|
@ -174,15 +175,15 @@
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="workspace-empty">
|
<div class="workspace-empty vt-empty-state">
|
||||||
<p>Для этого рабочего пространства пока нет инструментов</p>
|
<p class="vt-empty-title">No workspace tools available</p>
|
||||||
<p class="workspace-hint">Включите плагины с workspace-инструментами или откройте Plugin Manager через меню настроек.</p>
|
<p class="workspace-hint">Enable plugins with workspace tools or open Plugin Manager from settings.</p>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
<div class="workspace-empty">
|
<div class="workspace-empty vt-empty-state">
|
||||||
<p>Создайте рабочее пространство или выберите существующее в боковой панели</p>
|
<p class="vt-empty-title">Select a workspace</p>
|
||||||
<p class="workspace-hint">Нажмите «+» в разделе Workspaces, чтобы добавить первый проект.</p>
|
<p class="workspace-hint">Use the + button in Workspaces to add your first project.</p>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -194,7 +195,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: #1a1a2e;
|
background: var(--vt-color-background);
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-header {
|
.workspace-header {
|
||||||
|
|
@ -202,8 +203,8 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
padding: 0.65rem 1rem;
|
padding: var(--vt-space-2) var(--vt-space-4);
|
||||||
border-bottom: 1px solid #16213e;
|
border-bottom: 1px solid var(--vt-color-border);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -215,17 +216,17 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-title {
|
.workspace-title {
|
||||||
color: #e0e0f0;
|
color: var(--vt-color-text-primary);
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-type {
|
.workspace-type {
|
||||||
color: #4ecca3;
|
color: var(--vt-color-accent);
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
padding: 0.1rem 0.4rem;
|
padding: 0.1rem 0.4rem;
|
||||||
border-radius: 3px;
|
border-radius: var(--vt-radius-sm);
|
||||||
background: #1a2a3a;
|
background: var(--vt-color-accent-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-search {
|
.workspace-search {
|
||||||
|
|
@ -240,8 +241,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-search :global(.global-search-box) {
|
.workspace-search :global(.global-search-box) {
|
||||||
background: #101626;
|
background: #0f1424;
|
||||||
border-color: #243957;
|
border-color: var(--vt-color-border-strong);
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-search :global(.global-search-results) {
|
.workspace-search :global(.global-search-results) {
|
||||||
|
|
@ -266,9 +267,9 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.25rem;
|
gap: 0.25rem;
|
||||||
padding: 0.35rem 0.75rem 0;
|
padding: var(--vt-space-1) var(--vt-space-3) 0;
|
||||||
background: #12122a;
|
background: #12162a;
|
||||||
border-bottom: 1px solid #16213e;
|
border-bottom: 1px solid var(--vt-color-border);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
scrollbar-gutter: auto;
|
scrollbar-gutter: auto;
|
||||||
|
|
@ -280,23 +281,23 @@
|
||||||
padding: 0.35rem 0.8rem;
|
padding: 0.35rem 0.8rem;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
border-radius: 6px 6px 0 0;
|
border-radius: var(--vt-radius-md) var(--vt-radius-md) 0 0;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: #8b8ba8;
|
color: var(--vt-color-text-muted);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font: inherit;
|
font: inherit;
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-tabs button:hover {
|
.workspace-tabs button:hover {
|
||||||
color: #e0e0f0;
|
color: var(--vt-color-text-primary);
|
||||||
background: rgba(15, 52, 96, 0.4);
|
background: var(--vt-color-surface-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-tabs button.active {
|
.workspace-tabs button.is-active {
|
||||||
color: #4ecca3;
|
color: var(--vt-color-accent);
|
||||||
background: #1a1a2e;
|
background: var(--vt-color-background);
|
||||||
border-color: #16213e;
|
border-color: var(--vt-color-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-tool-content {
|
.workspace-tool-content {
|
||||||
|
|
@ -311,7 +312,7 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
color: #666;
|
color: var(--vt-color-text-muted);
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
@ -319,7 +320,7 @@
|
||||||
|
|
||||||
.workspace-hint {
|
.workspace-hint {
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
color: #555;
|
color: var(--vt-color-text-muted);
|
||||||
max-width: 300px;
|
max-width: 300px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -192,7 +192,7 @@
|
||||||
<div class="wt-list">
|
<div class="wt-list">
|
||||||
{#each workspaces as workspace (wsName(workspace))}
|
{#each workspaces as workspace (wsName(workspace))}
|
||||||
{@const id = wsName(workspace)}
|
{@const id = wsName(workspace)}
|
||||||
<div class="wt-node" class:selected={id === $activeWorkspaceId}>
|
<div class="wt-node vt-list-row" class:selected={id === $activeWorkspaceId}>
|
||||||
<div class="wt-row">
|
<div class="wt-row">
|
||||||
<span class="wt-icon"><Icon name="space" size={13} class="wt-node-icon" /></span>
|
<span class="wt-icon"><Icon name="space" size={13} class="wt-node-icon" /></span>
|
||||||
{#if renamingId === id}
|
{#if renamingId === id}
|
||||||
|
|
@ -206,7 +206,7 @@
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<button class="wt-btn wt-btn-small wt-always" on:click={() => commitRename(workspace)} title="Save rename" type="button" disabled={busyId === id}>OK</button>
|
<button class="wt-btn wt-btn-small wt-always" on:click={() => commitRename(workspace)} title="Save rename" type="button" disabled={busyId === id}>OK</button>
|
||||||
<button class="wt-btn wt-btn-small wt-always" on:click={cancelRename} title="Cancel rename" type="button" disabled={busyId === id}>x</button>
|
<button class="wt-btn wt-btn-small wt-always" on:click={cancelRename} title="Cancel rename" type="button" disabled={busyId === id}>Cancel</button>
|
||||||
{:else}
|
{:else}
|
||||||
<button class="wt-label" on:click={() => selectWorkspace(workspace)} type="button">{id}</button>
|
<button class="wt-label" on:click={() => selectWorkspace(workspace)} type="button">{id}</button>
|
||||||
<button class="wt-icon-btn" on:click={() => startRename(workspace)} title="Rename workspace" type="button" disabled={busyId === id}>
|
<button class="wt-icon-btn" on:click={() => startRename(workspace)} title="Rename workspace" type="button" disabled={busyId === id}>
|
||||||
|
|
@ -225,7 +225,7 @@
|
||||||
<div class="wt-create">
|
<div class="wt-create">
|
||||||
<div class="wt-create-header">
|
<div class="wt-create-header">
|
||||||
<span>New workspace</span>
|
<span>New workspace</span>
|
||||||
<button class="wt-btn" on:click={() => { showCreate = false; newWorkspaceName = ''; }} type="button">x</button>
|
<button class="wt-btn btn-ghost" on:click={() => { showCreate = false; newWorkspaceName = ''; }} type="button">Close</button>
|
||||||
</div>
|
</div>
|
||||||
<input type="text" bind:value={newWorkspaceName} placeholder="Name..." disabled={creating} />
|
<input type="text" bind:value={newWorkspaceName} placeholder="Name..." disabled={creating} />
|
||||||
<div class="wt-create-actions">
|
<div class="wt-create-actions">
|
||||||
|
|
@ -238,35 +238,35 @@
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.wt { display: flex; flex-direction: column; flex: 1; overflow: hidden; position: relative; }
|
.wt { display: flex; flex-direction: column; flex: 1; overflow: hidden; position: relative; }
|
||||||
.wt-header { display: flex; align-items: center; justify-content: space-between; padding: 0.7rem 0.6rem 0.35rem; border-bottom: 1px solid #0f3460; flex-shrink: 0; }
|
.wt-header { display: flex; align-items: center; justify-content: space-between; padding: 0.7rem 0.6rem 0.35rem; border-bottom: 1px solid var(--vt-color-border); flex-shrink: 0; }
|
||||||
.wt-title { color: #a0a0b8; font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.05em; font-weight: 600; }
|
.wt-title { color: var(--vt-color-text-muted); font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.05em; font-weight: 600; }
|
||||||
.wt-list { min-height: 0; overflow-y: auto; padding: 0.2rem 0.6rem; }
|
.wt-list { min-height: 0; overflow-y: auto; padding: 0.2rem 0.6rem; }
|
||||||
.wt-btn { min-height: 0; background: none; border: none; color: #666; cursor: pointer; font-size: 0.85rem; padding: 0.1rem 0.3rem; border-radius: 3px; }
|
.wt-btn { min-height: 1.55rem; background: transparent; border: 1px solid transparent; color: var(--vt-color-text-muted); cursor: pointer; font-size: 0.78rem; padding: 0.12rem 0.38rem; border-radius: var(--vt-radius-sm); }
|
||||||
.wt-btn:hover:not(:disabled) { color: #4ecca3; background: rgba(78,204,163,0.1); }
|
.wt-btn:hover:not(:disabled) { color: var(--vt-color-accent); background: var(--vt-color-accent-muted); border-color: rgba(78,204,163,0.25); }
|
||||||
.wt-btn-small { font-size: 0.68rem; opacity: 0; }
|
.wt-btn-small { font-size: 0.7rem; opacity: 0; }
|
||||||
.wt-always { opacity: 1; }
|
.wt-always { opacity: 1; }
|
||||||
.wt-row:hover .wt-btn-small { opacity: 1; }
|
.wt-row:hover .wt-btn-small { opacity: 1; }
|
||||||
.wt-loading, .wt-error { padding: 0.5rem; font-size: 0.75rem; color: #666; }
|
.wt-loading, .wt-error { padding: 0.5rem; font-size: 0.75rem; color: var(--vt-color-text-muted); }
|
||||||
.wt-error { color: #e94560; }
|
.wt-error { color: var(--vt-color-danger); }
|
||||||
.wt-row { display: flex; align-items: center; gap: 0.45rem; padding: 0.15rem 0.45rem; min-height: 1.7rem; border-radius: 3px; }
|
.wt-row { display: flex; align-items: center; gap: 0.45rem; padding: 0.18rem 0.45rem; min-height: 1.85rem; border-radius: var(--vt-radius-sm); }
|
||||||
.wt-row:hover { background: rgba(15,52,96,0.4); }
|
.wt-row:hover { background: var(--vt-color-surface-hover); }
|
||||||
.wt-node.selected > .wt-row { background: rgba(78,204,163,0.1); }
|
.wt-node.selected > .wt-row { background: var(--vt-color-surface-selected); box-shadow: inset 2px 0 0 var(--vt-color-accent); }
|
||||||
.wt-icon { width: 0.9rem; height: 0.9rem; display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; color: #a0a0b8; }
|
.wt-icon { width: 0.95rem; height: 0.95rem; display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; color: var(--vt-color-text-muted); }
|
||||||
:global(.wt-node-icon) { display: block; }
|
:global(.wt-node-icon) { display: block; }
|
||||||
.wt-label { flex: 1; min-width: 0; min-height: 0; justify-content: flex-start; background: none; border: none; color: #a0a0b8; font-size: 0.78rem; text-align: left; cursor: pointer; padding: 0.1rem 0; border-radius: 3px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
.wt-label { flex: 1; min-width: 0; min-height: 0; justify-content: flex-start; background: none; border: none; color: var(--vt-color-text-secondary); font-size: 0.78rem; text-align: left; cursor: pointer; padding: 0.1rem 0; border-radius: var(--vt-radius-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
.wt-label:hover { color: #4ecca3; }
|
.wt-label:hover { color: var(--vt-color-accent); }
|
||||||
.wt-icon-btn { width: 1.25rem; height: 1.25rem; min-height: 0; padding: 0; border: none; background: transparent; color: #666; opacity: 0; flex-shrink: 0; cursor: pointer; border-radius: 3px; }
|
.wt-icon-btn { width: 1.45rem; height: 1.45rem; min-height: 0; padding: 0; border: 1px solid transparent; background: transparent; color: var(--vt-color-text-muted); opacity: 0.75; flex-shrink: 0; cursor: pointer; border-radius: var(--vt-radius-sm); }
|
||||||
.wt-row:hover .wt-icon-btn { opacity: 1; }
|
.wt-row:hover .wt-icon-btn { opacity: 1; }
|
||||||
.wt-icon-btn:hover:not(:disabled) { color: #4ecca3; background: rgba(78,204,163,0.1); }
|
.wt-icon-btn:hover:not(:disabled) { color: var(--vt-color-accent); background: var(--vt-color-accent-muted); border-color: rgba(78,204,163,0.25); }
|
||||||
.wt-icon-btn.danger:hover:not(:disabled) { color: #e94560; background: rgba(233,69,96,0.12); }
|
.wt-icon-btn.danger:hover:not(:disabled) { color: var(--vt-color-danger); background: var(--vt-color-danger-muted); border-color: rgba(233,69,96,0.35); }
|
||||||
.wt-rename { flex: 1; min-width: 0; background: #0f3460; border: 1px solid #1a3a5c; color: #e0e0f0; padding: 0.2rem 0.35rem; border-radius: 4px; font-size: 0.78rem; }
|
.wt-rename { flex: 1; min-width: 0; background: #0f1424; border: 1px solid var(--vt-color-border-strong); color: var(--vt-color-text-primary); padding: 0.2rem 0.35rem; border-radius: var(--vt-radius-sm); font-size: 0.78rem; }
|
||||||
.wt-rename:focus { outline: none; border-color: #4ecca3; }
|
.wt-rename:focus { outline: none; border-color: var(--vt-color-accent); box-shadow: var(--vt-focus-ring); }
|
||||||
.wt-create { position: absolute; bottom: 0; left: 0; right: 0; background: #16213e; border-top: 1px solid #0f3460; padding: 0.6rem; z-index: 10; }
|
.wt-create { position: absolute; bottom: 0; left: 0; right: 0; background: var(--vt-color-surface-muted); border-top: 1px solid var(--vt-color-border); padding: 0.6rem; z-index: 10; }
|
||||||
.wt-create-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.4rem; color: #a0a0b8; font-size: 0.7rem; text-transform: uppercase; }
|
.wt-create-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.4rem; color: var(--vt-color-text-muted); font-size: 0.7rem; text-transform: uppercase; }
|
||||||
.wt-create input { width: 100%; background: #0f3460; border: 1px solid #1a3a5c; color: #e0e0f0; padding: 0.35rem 0.5rem; border-radius: 4px; font-size: 0.8rem; margin-bottom: 0.4rem; box-sizing: border-box; }
|
.wt-create input { width: 100%; background: #0f1424; border: 1px solid var(--vt-color-border-strong); color: var(--vt-color-text-primary); padding: 0.35rem 0.5rem; border-radius: var(--vt-radius-sm); font-size: 0.8rem; margin-bottom: 0.4rem; box-sizing: border-box; }
|
||||||
.wt-create input:focus { outline: none; border-color: #4ecca3; }
|
.wt-create input:focus { outline: none; border-color: var(--vt-color-accent); box-shadow: var(--vt-focus-ring); }
|
||||||
.wt-create-actions { display: flex; gap: 0.4rem; justify-content: flex-end; }
|
.wt-create-actions { display: flex; gap: 0.4rem; justify-content: flex-end; }
|
||||||
.wt-btn-primary { background: #4ecca3; color: #1a1a2e; border: none; padding: 0.3rem 0.6rem; border-radius: 4px; cursor: pointer; font-size: 0.75rem; font-weight: 600; }
|
.wt-btn-primary { background: var(--vt-color-accent); color: #101827; border: none; padding: 0.3rem 0.6rem; border-radius: var(--vt-radius-sm); cursor: pointer; font-size: 0.75rem; font-weight: 600; }
|
||||||
.wt-btn-primary:hover:not(:disabled) { background: #3dbb92; }
|
.wt-btn-primary:hover:not(:disabled) { background: #3dbb92; }
|
||||||
.wt-btn-primary:disabled, .wt-btn:disabled, .wt-icon-btn:disabled { opacity: 0.5; cursor: not-allowed; }
|
.wt-btn-primary:disabled, .wt-btn:disabled, .wt-icon-btn:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1384,6 +1384,13 @@
|
||||||
function activityBundle() {
|
function activityBundle() {
|
||||||
return '(' + function () {
|
return '(' + function () {
|
||||||
var PLUGIN_ID = 'verstak.activity';
|
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() {
|
function injectStyles() {
|
||||||
if (document.getElementById('mock-activity-style')) return;
|
if (document.getElementById('mock-activity-style')) return;
|
||||||
|
|
@ -1435,6 +1442,12 @@
|
||||||
return Array.isArray(value) ? value.filter(function (item) { return item && typeof item === 'object'; }) : [];
|
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) {
|
function eventTime(value) {
|
||||||
var date = new Date(value || 0);
|
var date = new Date(value || 0);
|
||||||
return isNaN(date.getTime()) ? 0 : date.getTime();
|
return isNaN(date.getTime()) ? 0 : date.getTime();
|
||||||
|
|
@ -1576,7 +1589,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
readSettings().then(function (settings) {
|
readSettings().then(function (settings) {
|
||||||
events = rows(settings[key]);
|
events = meaningfulRows(settings[key]);
|
||||||
render();
|
render();
|
||||||
});
|
});
|
||||||
render();
|
render();
|
||||||
|
|
|
||||||