From d6b8ab17f1482c8e94d58cd805b1be5588d83ef3 Mon Sep 17 00:00:00 2001 From: mirivlad Date: Thu, 2 Jul 2026 00:49:29 +0800 Subject: [PATCH] Polish official plugin workbench UI --- plugins/activity/frontend/src/index.js | 118 ++++++++---- plugins/browser-inbox/frontend/src/index.js | 46 ++--- plugins/files/frontend/src/index.js | 87 +++++---- plugins/journal/frontend/src/index.js | 192 ++++++++++++++------ plugins/notes/frontend/src/index.js | 55 +++--- plugins/search/frontend/src/index.js | 84 ++++++--- plugins/secrets/frontend/src/index.js | 62 ++++--- scripts/smoke-activity-plugin.js | 8 + scripts/smoke-journal-plugin.js | 25 ++- 9 files changed, 458 insertions(+), 219 deletions(-) diff --git a/plugins/activity/frontend/src/index.js b/plugins/activity/frontend/src/index.js index e03ad32..063790b 100644 --- a/plugins/activity/frontend/src/index.js +++ b/plugins/activity/frontend/src/index.js @@ -26,6 +26,27 @@ 'browser.capture.file', 'browser.capture.converted' ]; + var EVENT_LABELS = { + 'workspace.selected': 'Workspace selected', + 'case.selected': 'Workspace selected', + 'file.opened': 'File opened', + 'file.changed': 'File changed', + 'note.saved': 'Note edited', + 'action.started': 'Work session detected', + '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' + }; + 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('activity-style-injected')) return; @@ -36,33 +57,36 @@ } var STYLES = [ - '.activity-root{display:flex;flex-direction:column;height:100%;min-height:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif;color:#e0e0e0;background:#0d0d1a}', - '.activity-toolbar{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;border-bottom:1px solid #16213e;background:#12122a;flex-shrink:0;flex-wrap:wrap}', - '.activity-title{font-size:.84rem;font-weight:600;color:#e0e0e0}', - '.activity-count{font-size:.72rem;color:#8b8ba8}', + '.activity-root{display:flex;flex-direction:column;height:100%;min-height:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif;color:var(--vt-color-text-primary,#f4f7fb);background:var(--vt-color-background,#101020)}', + '.activity-toolbar{display:flex;align-items:center;gap:.5rem;min-height:2.75rem;padding:.5rem .75rem;border-bottom:1px solid var(--vt-color-border,#202b46);background:var(--vt-color-surface-muted,#111629);flex-shrink:0;flex-wrap:wrap}', + '.activity-title{font-size:.84rem;font-weight:600;color:var(--vt-color-text-primary,#f4f7fb)}', + '.activity-count{font-size:.72rem;color:var(--vt-color-text-muted,#7f8aa3)}', '.activity-spacer{flex:1}', - '.activity-btn{font-size:.78rem;padding:.32rem .65rem;border:1px solid #333;border-radius:4px;background:#1a1a2e;color:#ccc;cursor:pointer}', - '.activity-btn:hover{background:#2a2a4e;border-color:#4ecca3}', + '.activity-btn{font-size:.78rem;padding:.32rem .65rem;border:1px solid var(--vt-color-border-strong,#2c456a);border-radius:var(--vt-radius-md,6px);background:var(--vt-color-surface-hover,#1b2440);color:var(--vt-color-text-secondary,#b7c0d4);cursor:pointer}', + '.activity-btn:hover{background:var(--vt-color-surface-hover,#1b2440);border-color:var(--vt-color-accent,#4ecca3);color:var(--vt-color-text-primary,#f4f7fb)}', '.activity-btn:disabled{opacity:.45;cursor:default}', - '.activity-btn.danger{border-color:#633;color:#ff9a9a}', - '.activity-status{font-size:.72rem;color:#8b8ba8;white-space:nowrap}', - '.activity-status.error{color:#e74c3c}', - '.activity-suggestions{border-bottom:1px solid rgba(22,33,62,.65);background:#111126;padding:.55rem .75rem;display:grid;gap:.5rem}', - '.activity-suggestions-title{font-size:.76rem;font-weight:600;color:#8b8ba8;text-transform:uppercase;letter-spacing:.04em}', - '.activity-suggestion{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:.65rem;align-items:start;padding:.55rem .65rem;border:1px solid rgba(78,204,163,.25);border-radius:4px;background:#14142c}', - '.activity-suggestion-title{font-size:.84rem;color:#e0e0e0;font-weight:600;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}', - '.activity-suggestion-summary{margin-top:.22rem;font-size:.76rem;color:#aaa;line-height:1.4;white-space:pre-wrap;overflow-wrap:anywhere}', - '.activity-suggestion-minutes{font-size:.76rem;color:#4ecca3;white-space:nowrap}', - '.activity-list{flex:1;min-height:0;overflow:auto;background:#101020}', - '.activity-empty{height:100%;display:flex;align-items:center;justify-content:center;color:#666;font-size:.86rem;padding:2rem;text-align:center}', - '.activity-row{display:grid;grid-template-columns:9.5rem minmax(0,1fr);gap:.75rem;padding:.72rem .85rem;border-bottom:1px solid rgba(22,33,62,.6)}', - '.activity-time{font-size:.72rem;color:#777;white-space:nowrap}', + '.activity-btn.danger{border-color:rgba(233,69,96,.42);color:#ff9a9a}', + '.activity-status{font-size:.72rem;color:var(--vt-color-text-muted,#7f8aa3);white-space:nowrap}', + '.activity-status.error{display:inline-flex;border:1px solid rgba(233,69,96,.45);border-radius:var(--vt-radius-sm,4px);background:var(--vt-color-danger-muted,rgba(233,69,96,.14));color:#ffc6ce;padding:.18rem .4rem}', + '.activity-suggestions{border-bottom:1px solid rgba(32,43,70,.72);background:var(--vt-color-surface-muted,#111629);padding:.65rem .75rem;display:grid;gap:.5rem}', + '.activity-suggestions-title{font-size:.76rem;font-weight:600;color:var(--vt-color-text-muted,#7f8aa3);text-transform:uppercase;letter-spacing:.04em}', + '.activity-suggestion{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:.65rem;align-items:start;padding:.65rem .75rem;border:1px solid var(--vt-color-border,#202b46);border-radius:var(--vt-radius-lg,8px);background:var(--vt-color-surface,#15152c)}', + '.activity-suggestion-title{font-size:.84rem;color:var(--vt-color-text-primary,#f4f7fb);font-weight:600;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}', + '.activity-suggestion-summary{margin-top:.22rem;font-size:.76rem;color:var(--vt-color-text-secondary,#b7c0d4);line-height:1.4;white-space:pre-wrap;overflow-wrap:anywhere}', + '.activity-suggestion-minutes{font-size:.76rem;color:var(--vt-color-accent,#4ecca3);white-space:nowrap}', + '.activity-list{flex:1;min-height:0;overflow:auto;background:var(--vt-color-background,#101020)}', + '.activity-empty{height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.35rem;color:var(--vt-color-text-muted,#7f8aa3);font-size:.86rem;padding:2rem;text-align:center}', + '.activity-empty-title{color:var(--vt-color-text-secondary,#b7c0d4);font-weight:650}', + '.activity-row{display:grid;grid-template-columns:9.5rem minmax(0,1fr);gap:.75rem;padding:.72rem .85rem;border-bottom:1px solid rgba(32,43,70,.72)}', + '.activity-row:hover{background:var(--vt-color-surface-hover,#1b2440)}', + '.activity-time{font-size:.72rem;color:var(--vt-color-text-muted,#7f8aa3);white-space:nowrap}', '.activity-main{min-width:0}', '.activity-row-head{display:flex;align-items:center;gap:.45rem;min-width:0}', - '.activity-type{font-size:.68rem;color:#4ecca3;text-transform:uppercase;letter-spacing:.04em;flex-shrink:0}', - '.activity-title-text{font-size:.86rem;color:#e0e0e0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}', - '.activity-summary{margin-top:.25rem;font-size:.78rem;line-height:1.4;color:#aaa;white-space:pre-wrap;overflow-wrap:anywhere}', - '.activity-source{margin-top:.25rem;font-size:.72rem;color:#777}', + '.activity-type{font-size:.68rem;color:var(--vt-color-accent,#4ecca3);text-transform:uppercase;letter-spacing:.04em;flex-shrink:0}', + '.activity-title-text{font-size:.86rem;color:var(--vt-color-text-primary,#f4f7fb);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}', + '.activity-summary{margin-top:.25rem;font-size:.78rem;line-height:1.4;color:var(--vt-color-text-secondary,#b7c0d4);white-space:pre-wrap;overflow-wrap:anywhere}', + '.activity-source{margin-top:.25rem;font-size:.72rem;color:var(--vt-color-text-muted,#7f8aa3)}', + '.activity-details{margin-top:.25rem;font-size:.72rem;color:var(--vt-color-text-muted,#7f8aa3)}.activity-details summary{cursor:pointer}', '@media(max-width:760px){.activity-row,.activity-suggestion{grid-template-columns:1fr;gap:.25rem}.activity-toolbar{align-items:stretch}.activity-status{width:100%}}' ].join('\n'); @@ -178,6 +202,11 @@ }).slice(0, MAX_EVENTS); } + function isMeaningfulActivity(activity) { + var type = text(activity && activity.type).toLowerCase(); + return !LOW_VALUE_EVENT_TYPES[type]; + } + function eventTimeMs(activity) { var value = activity && (activity.occurredAt || activity.receivedAt); var date = value ? new Date(value) : null; @@ -209,7 +238,28 @@ } function eventLabel(activity) { - return text(activity && (activity.title || activity.summary || activity.type || activity.activityId)).trim(); + return humanEventTitle(activity); + } + + function humanEventType(type) { + return EVENT_LABELS[text(type).toLowerCase()] || ''; + } + + function humanEventTitle(activity) { + var explicit = text(activity && activity.title).trim(); + var type = text(activity && activity.type).trim(); + if (explicit && explicit.toLowerCase() !== type.toLowerCase()) return explicit; + return humanEventType(type) || text(activity && (activity.summary || activity.activityId)).trim() || 'Activity event'; + } + + function eventKind(activity) { + var type = text(activity && activity.type).toLowerCase(); + if (type.indexOf('browser.capture') === 0) return 'Capture'; + if (type.indexOf('file.') === 0) return 'File'; + if (type.indexOf('note.') === 0) return 'Note'; + if (type.indexOf('workspace') !== -1 || type.indexOf('case.') === 0) return 'Workspace'; + if (type.indexOf('action.') === 0) return 'Work'; + return 'Activity'; } function summarizeEvents(groupEvents) { @@ -226,7 +276,7 @@ function buildWorklogSuggestions(activityList, workspaceFilter) { var filter = cleanWorkspace(workspaceFilter); var groups = {}; - sortEvents(activityList || []).forEach(function (activity) { + sortEvents(activityList || []).filter(isMeaningfulActivity).forEach(function (activity) { var workspace = suggestionWorkspace(activity); if (filter && workspace !== filter) return; var day = eventDay(activity); @@ -271,7 +321,7 @@ globalEventKeys(settings).forEach(function (key) { all = all.concat(normalizeStoredEvents(settings[key], key)); }); - return sortEvents(all); + return sortEvents(all).filter(isMeaningfulActivity); } var workspaceKey = WORKSPACE_PREFIX + encodeKey(workspace); var scopedEvents = normalizeStoredEvents(settings[workspaceKey], workspaceKey); @@ -281,7 +331,7 @@ var legacyEvents = normalizeStoredEvents(settings[LEGACY_KEY], LEGACY_KEY).filter(function (item) { return item.workspaceRootPath === workspace; }); - return sortEvents(scopedEvents.concat(globalEvents, legacyEvents)); + return sortEvents(scopedEvents.concat(globalEvents, legacyEvents)).filter(isMeaningfulActivity); } function formatDate(value) { @@ -378,7 +428,10 @@ function renderList() { listEl.innerHTML = ''; if (events.length === 0) { - listEl.appendChild(el('div', { className: 'activity-empty', textContent: 'No activity events yet.' })); + listEl.appendChild(el('div', { className: 'activity-empty' }, [ + el('div', { className: 'activity-empty-title', textContent: 'No activity events yet' }), + el('div', { textContent: 'File changes, browser captures, and conversions will appear here.' }) + ])); return; } events.forEach(function (activity) { @@ -389,11 +442,14 @@ el('div', { className: 'activity-time', textContent: formatDate(activity.occurredAt) || '-' }), el('div', { className: 'activity-main' }, [ el('div', { className: 'activity-row-head' }, [ - el('span', { className: 'activity-type', textContent: activity.type }), - el('span', { className: 'activity-title-text', textContent: activity.title || 'Activity event' }) + el('span', { className: 'activity-type', textContent: eventKind(activity) }), + el('span', { className: 'activity-title-text', textContent: humanEventTitle(activity) }) ]), activity.summary ? el('div', { className: 'activity-summary', textContent: activity.summary }) : null, - activity.sourcePluginId ? el('div', { className: 'activity-source', textContent: activity.sourcePluginId }) : null + el('details', { className: 'activity-details' }, [ + el('summary', {}, ['Details']), + el('div', { className: 'activity-source', textContent: 'Event: ' + activity.type + (activity.sourcePluginId ? ' · Source: ' + activity.sourcePluginId : '') }) + ]) ]) ])); }); diff --git a/plugins/browser-inbox/frontend/src/index.js b/plugins/browser-inbox/frontend/src/index.js index d019909..f682387 100644 --- a/plugins/browser-inbox/frontend/src/index.js +++ b/plugins/browser-inbox/frontend/src/index.js @@ -22,35 +22,35 @@ } var STYLES = [ - '.browser-inbox-root{display:flex;flex-direction:column;height:100%;min-height:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif;color:#e0e0e0;background:#0d0d1a}', - '.browser-inbox-toolbar{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;border-bottom:1px solid #16213e;background:#12122a;flex-shrink:0;flex-wrap:wrap}', - '.browser-inbox-title{font-size:.82rem;font-weight:600;color:#e0e0e0}', - '.browser-inbox-count{font-size:.72rem;color:#8b8ba8}', + '.browser-inbox-root{display:flex;flex-direction:column;height:100%;min-height:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif;color:var(--vt-color-text-primary,#f4f7fb);background:var(--vt-color-background,#101020)}', + '.browser-inbox-toolbar{display:flex;align-items:center;gap:.5rem;min-height:2.75rem;padding:.5rem .75rem;border-bottom:1px solid var(--vt-color-border,#202b46);background:var(--vt-color-surface-muted,#111629);flex-shrink:0;flex-wrap:wrap}', + '.browser-inbox-title{font-size:.82rem;font-weight:600;color:var(--vt-color-text-primary,#f4f7fb)}', + '.browser-inbox-count{font-size:.72rem;color:var(--vt-color-text-muted,#7f8aa3)}', '.browser-inbox-spacer{flex:1}', - '.browser-inbox-btn{font-size:.78rem;padding:.32rem .65rem;border:1px solid #333;border-radius:4px;background:#1a1a2e;color:#ccc;cursor:pointer}', - '.browser-inbox-btn:hover{background:#2a2a4e;border-color:#4ecca3}', + '.browser-inbox-btn{font-size:.78rem;padding:.32rem .65rem;border:1px solid var(--vt-color-border-strong,#2c456a);border-radius:var(--vt-radius-md,6px);background:var(--vt-color-surface-hover,#1b2440);color:var(--vt-color-text-secondary,#b7c0d4);cursor:pointer}', + '.browser-inbox-btn:hover{background:var(--vt-color-surface-hover,#1b2440);border-color:var(--vt-color-accent,#4ecca3);color:var(--vt-color-text-primary,#f4f7fb)}', '.browser-inbox-btn:disabled{opacity:.45;cursor:default}', - '.browser-inbox-btn.danger{border-color:#633;color:#ff9a9a}', - '.browser-inbox-status{font-size:.72rem;color:#8b8ba8;white-space:nowrap}', - '.browser-inbox-status.error{color:#e74c3c}', + '.browser-inbox-btn.danger{border-color:rgba(233,69,96,.42);color:#ff9a9a;background:var(--vt-color-danger-muted,rgba(233,69,96,.14))}', + '.browser-inbox-status{font-size:.72rem;color:var(--vt-color-text-muted,#7f8aa3);white-space:nowrap}', + '.browser-inbox-status.error{display:inline-flex;border:1px solid rgba(233,69,96,.45);border-radius:var(--vt-radius-sm,4px);background:var(--vt-color-danger-muted,rgba(233,69,96,.14));color:#ffc6ce;padding:.18rem .4rem}', '.browser-inbox-body{display:grid;grid-template-columns:minmax(260px,360px) minmax(0,1fr);flex:1;min-height:0}', - '.browser-inbox-list{min-height:0;overflow:auto;border-right:1px solid #16213e;background:#101020}', - '.browser-inbox-empty{height:100%;display:flex;align-items:center;justify-content:center;color:#666;font-size:.86rem;padding:2rem;text-align:center}', - '.browser-inbox-row{display:flex;flex-direction:column;gap:.22rem;padding:.65rem .75rem;border-bottom:1px solid rgba(22,33,62,.6);cursor:pointer}', - '.browser-inbox-row:hover{background:#17172d}', - '.browser-inbox-row.selected{background:#1a2a3a}', + '.browser-inbox-list{min-height:0;overflow:auto;border-right:1px solid var(--vt-color-border,#202b46);background:var(--vt-color-surface-muted,#111629)}', + '.browser-inbox-empty{height:100%;display:flex;align-items:center;justify-content:center;color:var(--vt-color-text-muted,#7f8aa3);font-size:.86rem;padding:2rem;text-align:center;line-height:1.45}', + '.browser-inbox-row{display:flex;flex-direction:column;gap:.22rem;padding:.65rem .75rem;border-bottom:1px solid rgba(32,43,70,.72);cursor:pointer}', + '.browser-inbox-row:hover{background:var(--vt-color-surface-hover,#1b2440)}', + '.browser-inbox-row.selected{background:var(--vt-color-surface-selected,rgba(78,204,163,.14));box-shadow:inset 2px 0 0 var(--vt-color-accent,#4ecca3)}', '.browser-inbox-row-head{display:flex;align-items:center;gap:.45rem;min-width:0}', - '.browser-inbox-kind{font-size:.68rem;color:#4ecca3;text-transform:uppercase;letter-spacing:.04em;flex-shrink:0}', - '.browser-inbox-row-title{font-size:.86rem;color:#e0e0e0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}', - '.browser-inbox-row-url{font-size:.72rem;color:#8b8ba8;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}', - '.browser-inbox-row-text{font-size:.76rem;color:#aaa;line-height:1.35;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}', + '.browser-inbox-kind{font-size:.68rem;color:var(--vt-color-accent,#4ecca3);text-transform:uppercase;letter-spacing:.04em;flex-shrink:0}', + '.browser-inbox-row-title{font-size:.86rem;color:var(--vt-color-text-primary,#f4f7fb);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}', + '.browser-inbox-row-url{font-size:.72rem;color:var(--vt-color-text-muted,#7f8aa3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}', + '.browser-inbox-row-text{font-size:.76rem;color:var(--vt-color-text-secondary,#b7c0d4);line-height:1.35;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}', '.browser-inbox-detail{display:flex;flex-direction:column;min-width:0;min-height:0;overflow:auto;padding:1rem;gap:.75rem}', - '.browser-inbox-detail-empty{margin:auto;color:#666;font-size:.86rem}', - '.browser-inbox-detail-title{font-size:1rem;font-weight:600;color:#f0f0f0;word-break:break-word}', + '.browser-inbox-detail-empty{margin:auto;color:var(--vt-color-text-muted,#7f8aa3);font-size:.86rem}', + '.browser-inbox-detail-title{font-size:1rem;font-weight:600;color:var(--vt-color-text-primary,#f4f7fb);word-break:break-word}', '.browser-inbox-meta{display:grid;grid-template-columns:7rem minmax(0,1fr);gap:.35rem .75rem;font-size:.78rem}', - '.browser-inbox-meta-label{color:#777}', - '.browser-inbox-meta-value{color:#ccc;min-width:0;overflow-wrap:anywhere}', - '.browser-inbox-text{border:1px solid #24304f;background:#101020;border-radius:6px;padding:.75rem;font-size:.85rem;line-height:1.5;color:#ddd;white-space:pre-wrap;overflow-wrap:anywhere}', + '.browser-inbox-meta-label{color:var(--vt-color-text-muted,#7f8aa3)}', + '.browser-inbox-meta-value{color:var(--vt-color-text-secondary,#b7c0d4);min-width:0;overflow-wrap:anywhere}', + '.browser-inbox-text{border:1px solid var(--vt-color-border,#202b46);background:var(--vt-color-surface,#15152c);border-radius:var(--vt-radius-lg,8px);padding:.75rem;font-size:.85rem;line-height:1.5;color:var(--vt-color-text-primary,#f4f7fb);white-space:pre-wrap;overflow-wrap:anywhere}', '.browser-inbox-detail-actions{display:flex;gap:.5rem;flex-wrap:wrap}', '@media(max-width:760px){.browser-inbox-body{grid-template-columns:1fr}.browser-inbox-list{border-right:0;border-bottom:1px solid #16213e;max-height:45vh}.browser-inbox-meta{grid-template-columns:1fr}}' ].join('\n'); diff --git a/plugins/files/frontend/src/index.js b/plugins/files/frontend/src/index.js index 452f4dd..e10c179 100644 --- a/plugins/files/frontend/src/index.js +++ b/plugins/files/frontend/src/index.js @@ -15,56 +15,63 @@ } var STYLES = [ - '.files-root{display:flex;flex-direction:column;height:100%;min-height:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif;color:#e0e0e0;background:#0d0d1a;outline:none}', - '.files-toolbar{display:flex;align-items:center;gap:.45rem;padding:.5rem .75rem;border-bottom:1px solid #16213e;flex-shrink:0;background:#12122a;flex-wrap:wrap}', - '.files-toolbar-btn,.files-row-btn{display:inline-flex;align-items:center;justify-content:center;border:1px solid #333;border-radius:4px;background:#1a1a2e;color:#ccc;cursor:pointer;line-height:1}', + '.files-root{display:flex;flex-direction:column;height:100%;min-height:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif;color:var(--vt-color-text-primary,#f4f7fb);background:var(--vt-color-background,#101020);outline:none}', + '.files-toolbar{display:flex;align-items:center;gap:.5rem;min-height:2.75rem;padding:.5rem .75rem;border-bottom:1px solid var(--vt-color-border,#202b46);flex-shrink:0;background:var(--vt-color-surface-muted,#111629);flex-wrap:wrap}', + '.files-toolbar-group{display:inline-flex;align-items:center;gap:.25rem;padding-right:.5rem;border-right:1px solid var(--vt-color-border,#202b46)}', + '.files-toolbar-group:last-child{border-right:0;padding-right:0}', + '.files-toolbar-spacer{flex:1}', + '.files-toolbar-btn,.files-row-btn{display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--vt-color-border-strong,#2c456a);border-radius:var(--vt-radius-md,6px);background:var(--vt-color-surface-hover,#1b2440);color:var(--vt-color-text-secondary,#b7c0d4);cursor:pointer;line-height:1}', '.files-toolbar-btn{width:2rem;height:2rem;padding:0}', '.files-row-btn{width:1.75rem;height:1.75rem;padding:0}', + '.files-panel .files-toolbar-btn{width:auto;min-width:4.5rem;padding:0 .65rem}', '.files-toolbar-btn svg,.files-row-btn svg{width:16px;height:16px;display:block;fill:currentColor}', - '.files-toolbar-btn:hover,.files-row-btn:hover{background:#2a2a4e;border-color:#4ecca3}', - '.files-toolbar-btn:disabled,.files-row-btn:disabled{opacity:.45;cursor:default;border-color:#333}', - '.files-breadcrumb{display:flex;align-items:center;gap:.25rem;font-size:.8rem;color:#8b8ba8;min-width:160px;flex:1;overflow:hidden}', - '.files-breadcrumb-item{color:#4ecca3;cursor:pointer;padding:.1rem .3rem;border-radius:3px;white-space:nowrap}', - '.files-breadcrumb-item:hover{background:#1a2a3a}', - '.files-breadcrumb-current{color:#ddd;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}', - '.files-breadcrumb-sep{color:#555}', - '.files-filter,.files-sort,.files-create-input,.files-rename-input{font-size:.78rem;padding:.32rem .5rem;border:1px solid #333;border-radius:4px;background:#0d0d1a;color:#e0e0e0;outline:none}', + '.files-toolbar-btn:hover,.files-row-btn:hover{background:var(--vt-color-surface-hover,#1b2440);border-color:var(--vt-color-accent,#4ecca3);color:var(--vt-color-text-primary,#f4f7fb)}', + '.files-toolbar-btn:focus-visible,.files-row-btn:focus-visible{outline:0;box-shadow:var(--vt-focus-ring,0 0 0 2px rgba(78,204,163,.34))}', + '.files-toolbar-btn:disabled,.files-row-btn:disabled{opacity:.45;cursor:default;border-color:var(--vt-color-border,#202b46)}', + '.files-toolbar-btn.danger,.files-row-btn.danger{color:#ff9aaa;border-color:rgba(233,69,96,.42)}', + '.files-breadcrumb{display:flex;align-items:center;gap:.25rem;font-size:.8rem;color:var(--vt-color-text-muted,#7f8aa3);min-width:160px;flex:1;overflow:hidden}', + '.files-breadcrumb-item{color:var(--vt-color-accent,#4ecca3);cursor:pointer;padding:.1rem .3rem;border-radius:var(--vt-radius-sm,4px);white-space:nowrap}', + '.files-breadcrumb-item:hover{background:var(--vt-color-accent-muted,rgba(78,204,163,.14))}', + '.files-breadcrumb-current{color:var(--vt-color-text-primary,#f4f7fb);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}', + '.files-breadcrumb-sep{color:var(--vt-color-text-muted,#7f8aa3)}', + '.files-filter,.files-sort,.files-create-input,.files-rename-input{font-size:.78rem;padding:.32rem .5rem;border:1px solid var(--vt-color-border-strong,#2c456a);border-radius:var(--vt-radius-sm,4px);background:#0f1424;color:var(--vt-color-text-primary,#f4f7fb);outline:none}', '.files-filter{width:11rem}', - '.files-sort{width:9.5rem;appearance:none;background-color:#0d0d1a;background-image:linear-gradient(45deg,transparent 50%,#8b8ba8 50%),linear-gradient(135deg,#8b8ba8 50%,transparent 50%);background-position:calc(100% - 14px) 50%,calc(100% - 9px) 50%;background-size:5px 5px,5px 5px;background-repeat:no-repeat;padding-right:1.6rem}', - '.files-filter:focus,.files-sort:focus,.files-create-input:focus,.files-rename-input:focus{border-color:#4ecca3}', + '.files-sort{width:9.5rem;appearance:none;background-color:#0f1424;background-image:linear-gradient(45deg,transparent 50%,#8b8ba8 50%),linear-gradient(135deg,#8b8ba8 50%,transparent 50%);background-position:calc(100% - 14px) 50%,calc(100% - 9px) 50%;background-size:5px 5px,5px 5px;background-repeat:no-repeat;padding-right:1.6rem}', + '.files-filter:focus,.files-sort:focus,.files-create-input:focus,.files-rename-input:focus{border-color:var(--vt-color-accent,#4ecca3);box-shadow:var(--vt-focus-ring,0 0 0 2px rgba(78,204,163,.34))}', '.files-list{flex:1;overflow:auto;min-height:0}', '.files-header,.files-item{display:grid;grid-template-columns:minmax(160px,1fr) 90px 90px 150px 220px;align-items:center;gap:.5rem;padding:.38rem .75rem;border-bottom:1px solid rgba(22,33,62,.55)}', - '.files-header{position:sticky;top:0;background:#101028;color:#8b8ba8;font-size:.7rem;text-transform:uppercase;letter-spacing:.04em;z-index:1}', + '.files-header{position:sticky;top:0;background:var(--vt-color-surface-muted,#111629);color:var(--vt-color-text-muted,#7f8aa3);font-size:.7rem;text-transform:uppercase;letter-spacing:.04em;z-index:1}', '.files-item{font-size:.84rem;cursor:pointer}', - '.files-item:hover{background:#17172d}', - '.files-item.selected{background:#1a2a3a}', + '.files-item:hover{background:var(--vt-color-surface-hover,#1b2440)}', + '.files-item.selected{background:var(--vt-color-surface-selected,rgba(78,204,163,.14));box-shadow:inset 2px 0 0 var(--vt-color-accent,#4ecca3)}', '.files-namecell{display:flex;align-items:center;gap:.55rem;min-width:0}', - '.files-item-icon{width:1.25rem;height:1.25rem;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;color:#8b8ba8}', + '.files-item-icon{width:1.25rem;height:1.25rem;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;color:var(--vt-color-text-muted,#7f8aa3)}', '.files-item-icon svg{display:block;width:16px;height:16px}', '.files-item-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}', - '.files-item-meta{font-size:.74rem;color:#777;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}', - '.files-row-actions{display:flex;align-items:center;justify-content:flex-end;gap:.35rem;white-space:nowrap}', - '.files-empty,.files-loading{flex:1;display:flex;align-items:center;justify-content:center;color:#666;font-size:.9rem;padding:2rem}', + '.files-item-meta{font-size:.74rem;color:var(--vt-color-text-muted,#7f8aa3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}', + '.files-row-actions{display:flex;align-items:center;justify-content:flex-end;gap:.35rem;white-space:nowrap;opacity:.28;transition:opacity .12s ease}', + '.files-item:hover .files-row-actions,.files-item.selected .files-row-actions{opacity:1}', + '.files-empty,.files-loading{flex:1;display:flex;align-items:center;justify-content:center;color:var(--vt-color-text-muted,#7f8aa3);font-size:.9rem;padding:2rem}', '.files-empty{flex-direction:column;gap:.75rem;text-align:center}', - '.files-empty-title{color:#8b8ba8}', + '.files-empty-title{color:var(--vt-color-text-secondary,#b7c0d4);font-weight:650}', '.files-empty-actions{display:flex;align-items:center;justify-content:center;gap:.5rem;flex-wrap:wrap}', - '.files-empty-btn{display:inline-flex;align-items:center;justify-content:center;gap:.35rem;min-height:2rem;padding:.35rem .6rem;border:1px solid #333;border-radius:4px;background:#1a1a2e;color:#ccc;cursor:pointer;font-size:.78rem}', - '.files-empty-btn:hover{background:#2a2a4e;border-color:#4ecca3}', + '.files-empty-btn{display:inline-flex;align-items:center;justify-content:center;gap:.35rem;min-height:2rem;padding:.35rem .6rem;border:1px solid var(--vt-color-border-strong,#2c456a);border-radius:var(--vt-radius-md,6px);background:var(--vt-color-surface-hover,#1b2440);color:var(--vt-color-text-secondary,#b7c0d4);cursor:pointer;font-size:.78rem}', + '.files-empty-btn:hover{background:var(--vt-color-surface-hover,#1b2440);border-color:var(--vt-color-accent,#4ecca3)}', '.files-empty-btn svg{width:15px;height:15px;display:block;fill:currentColor}', - '.files-error{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;color:#e74c3c;gap:.5rem;padding:1rem}', - '.files-error-msg{font-size:.85rem;color:#aaa;max-width:420px;text-align:center}', - '.files-panel{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;border-top:1px solid #16213e;flex-shrink:0;background:#12122a}', + '.files-error{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;color:var(--vt-color-danger,#e94560);gap:.5rem;padding:1rem}', + '.files-error-msg{font-size:.85rem;color:var(--vt-color-text-secondary,#b7c0d4);max-width:420px;text-align:center}', + '.files-panel{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;border-top:1px solid var(--vt-color-border,#202b46);flex-shrink:0;background:var(--vt-color-surface-muted,#111629)}', '.files-field-stack{display:flex;flex:1;min-width:160px;flex-direction:column;gap:.25rem}', - '.files-panel-error{display:none;color:#ff8a8a;font-size:.72rem;line-height:1.2}', + '.files-panel-error{display:none;color:#ff9aaa;font-size:.72rem;line-height:1.2}', '.files-create-input,.files-rename-input{flex:1;min-width:160px}', '@media(max-width:760px){.files-header,.files-item{grid-template-columns:minmax(130px,1fr) 70px 0 0 150px}.files-header span:nth-child(3),.files-header span:nth-child(4),.files-item-meta.hide-narrow{display:none}.files-toolbar{align-items:stretch}.files-filter,.files-sort{width:100%}}', - '.files-ctx-menu{position:fixed;z-index:9999;min-width:180px;background:#1a1a2e;border:1px solid #333;border-radius:6px;padding:6px 0;box-shadow:0 8px 24px rgba(0,0,0,.5);font-size:.84rem;color:#e0e0e0;user-select:none}', + '.files-ctx-menu{position:fixed;z-index:9999;min-width:180px;background:var(--vt-color-surface,#15152c);border:1px solid var(--vt-color-border-strong,#2c456a);border-radius:var(--vt-radius-md,6px);padding:6px 0;box-shadow:var(--vt-elevation-menu,0 14px 32px rgba(0,0,0,.42));font-size:.84rem;color:var(--vt-color-text-primary,#f4f7fb);user-select:none}', '.files-ctx-menu-item{padding:6px 16px;cursor:pointer;white-space:nowrap;display:flex;align-items:center;gap:.5rem}', '.files-ctx-menu-item svg{width:14px;height:14px;fill:currentColor;opacity:.9}', - '.files-ctx-menu-item:hover{background:#2a2a4e}', - '.files-ctx-menu-item.danger{color:#e74c3c}', - '.files-ctx-menu-item.danger:hover{background:#2a2a4e;color:#ff6b6b}', - '.files-ctx-menu-sep{height:1px;background:#333;margin:4px 8px}', + '.files-ctx-menu-item:hover{background:var(--vt-color-surface-hover,#1b2440)}', + '.files-ctx-menu-item.danger{color:#ff9aaa}', + '.files-ctx-menu-item.danger:hover{background:var(--vt-color-danger-muted,rgba(233,69,96,.14));color:#ffc6ce}', + '.files-ctx-menu-sep{height:1px;background:var(--vt-color-border,#202b46);margin:4px 8px}', '.files-modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,.6);z-index:10000;display:flex;align-items:center;justify-content:center}', '.files-modal{width:400px;max-width:90vw;padding:24px;background:#1a1a2e;border:1px solid #333;border-radius:12px;color:#e0e0e0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif;box-shadow:0 12px 40px rgba(0,0,0,.5)}', '.files-modal-title{font-size:.95rem;line-height:1.5;margin-bottom:20px;word-wrap:break-word}', @@ -407,8 +414,16 @@ el('option', { value: 'modified-desc' }, ['Modified']), el('option', { value: 'size-desc' }, ['Size']) ]); + trashBtn.classList.add('danger'); toolbar.appendChild(breadcrumb); - [backBtn, forwardBtn, upBtn, refreshBtn, newFolderBtn, newMdBtn, newTextBtn, openBtn, renameBtn, trashBtn, trashViewBtn, cutBtn, copyBtn, pasteBtn, filterInput, sortSelect].forEach(function (node) { toolbar.appendChild(node); }); + [ + el('div', { className: 'files-toolbar-group', 'aria-label': 'Navigation' }, [backBtn, forwardBtn, upBtn, refreshBtn]), + el('div', { className: 'files-toolbar-group', 'aria-label': 'Create' }, [newFolderBtn, newMdBtn, newTextBtn]), + el('div', { className: 'files-toolbar-group', 'aria-label': 'Selection actions' }, [openBtn, renameBtn, trashBtn]), + el('div', { className: 'files-toolbar-group', 'aria-label': 'Clipboard and trash' }, [trashViewBtn, cutBtn, copyBtn, pasteBtn]), + el('span', { className: 'files-toolbar-spacer' }), + el('div', { className: 'files-toolbar-group', 'aria-label': 'Filter and sort' }, [filterInput, sortSelect]) + ].forEach(function (node) { toolbar.appendChild(node); }); containerEl.appendChild(toolbar); var listContainer = el('div', { className: 'files-list', 'data-files-list': '' }); @@ -647,7 +662,9 @@ 'data-file-path': entry.relativePath, draggable: 'true', tabindex: '0', - onClick: function (e) { selectEntry(entry, e); }, + onClick: function (e) { + selectEntry(entry, e); + }, onDblclick: function () { openEntry(entry); }, onDragstart: function (e) { var paths = []; @@ -676,7 +693,7 @@ el('div', { className: 'files-row-actions' }, [ iconButton('row-open', 'Open', 'open', function (event) { event.stopPropagation(); openEntry(entry); }, 'files-row-btn'), iconButton('row-rename', 'Rename', 'rename', function (event) { event.stopPropagation(); beginRename(entry); }, 'files-row-btn'), - iconButton('row-trash', 'Move to trash', 'trash', function (event) { event.stopPropagation(); trashEntry(entry); }, 'files-row-btn') + iconButton('row-trash', 'Move to trash', 'trash', function (event) { event.stopPropagation(); trashEntry(entry); }, 'files-row-btn danger') ]) ]); listContainer.appendChild(row); diff --git a/plugins/journal/frontend/src/index.js b/plugins/journal/frontend/src/index.js index dd2bc13..90d007a 100644 --- a/plugins/journal/frontend/src/index.js +++ b/plugins/journal/frontend/src/index.js @@ -20,30 +20,47 @@ } var STYLES = [ - '.journal-root{display:flex;flex-direction:column;height:100%;min-height:0;background:#0d0d1a;color:#e0e0e0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif}', - '.journal-toolbar{display:flex;align-items:center;gap:.5rem;padding:.55rem .75rem;border-bottom:1px solid #16213e;background:#12122a;flex-shrink:0;flex-wrap:wrap}', + '.journal-root{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--vt-color-background,#101020);color:var(--vt-color-text-primary,#f4f7fb);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif}', + '.journal-toolbar{display:flex;align-items:center;gap:.5rem;min-height:2.75rem;padding:.55rem .75rem;border-bottom:1px solid var(--vt-color-border,#202b46);background:var(--vt-color-surface-muted,#111629);flex-shrink:0;flex-wrap:wrap}', '.journal-title{font-size:.86rem;font-weight:600}', - '.journal-count{font-size:.72rem;color:#8b8ba8}', + '.journal-count{font-size:.72rem;color:var(--vt-color-text-muted,#7f8aa3)}', '.journal-spacer{flex:1}', - '.journal-btn{font-size:.78rem;padding:.36rem .65rem;border:1px solid #333;border-radius:4px;background:#1a1a2e;color:#ddd;cursor:pointer}', - '.journal-btn:hover{border-color:#4ecca3;background:#2a2a4e}', + '.journal-btn{font-size:.78rem;padding:.36rem .65rem;border:1px solid var(--vt-color-border-strong,#2c456a);border-radius:var(--vt-radius-md,6px);background:var(--vt-color-surface-hover,#1b2440);color:var(--vt-color-text-secondary,#b7c0d4);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;gap:.35rem}', + '.journal-btn svg{width:14px;height:14px;display:block;fill:currentColor}', + '.journal-btn:hover{border-color:var(--vt-color-accent,#4ecca3);background:var(--vt-color-surface-hover,#1b2440);color:var(--vt-color-text-primary,#f4f7fb)}', '.journal-btn:disabled{opacity:.45;cursor:default}', - '.journal-status{font-size:.72rem;color:#8b8ba8}', - '.journal-status.error{color:#e74c3c}', - '.journal-form{display:grid;grid-template-columns:8rem minmax(10rem,1fr) 7rem auto auto;gap:.45rem;padding:.65rem .75rem;border-bottom:1px solid rgba(22,33,62,.65);background:#101020;align-items:center}', - '.journal-input{font-size:.8rem;padding:.38rem .5rem;border:1px solid #333;border-radius:4px;background:#0d0d1a;color:#e0e0e0;min-width:0}', - '.journal-input:focus{outline:none;border-color:#4ecca3}', - '.journal-billable{display:flex;align-items:center;gap:.25rem;font-size:.74rem;color:#aaa;white-space:nowrap}', - '.journal-list{flex:1;min-height:0;overflow:auto;background:#101020}', - '.journal-empty{height:100%;display:flex;align-items:center;justify-content:center;color:#666;font-size:.86rem;padding:2rem;text-align:center}', - '.journal-row{display:grid;grid-template-columns:8rem minmax(0,1fr) auto;gap:.7rem;padding:.75rem .85rem;border-bottom:1px solid rgba(22,33,62,.6)}', - '.journal-date{font-size:.75rem;color:#8b8ba8;white-space:nowrap}', + '.journal-status{font-size:.72rem;color:var(--vt-color-text-muted,#7f8aa3)}', + '.journal-status.error{display:inline-flex;border:1px solid rgba(233,69,96,.45);border-radius:var(--vt-radius-sm,4px);background:var(--vt-color-danger-muted,rgba(233,69,96,.14));color:#ffc6ce;padding:.18rem .4rem}', + '.journal-input{font-size:.8rem;padding:.38rem .5rem;border:1px solid var(--vt-color-border-strong,#2c456a);border-radius:var(--vt-radius-sm,4px);background:#0f1424;color:var(--vt-color-text-primary,#f4f7fb);min-width:0;font-family:inherit}', + '.journal-input.textarea{min-height:7rem;resize:vertical;line-height:1.4}', + '.journal-input:focus{outline:none;border-color:var(--vt-color-accent,#4ecca3);box-shadow:var(--vt-focus-ring,0 0 0 2px rgba(78,204,163,.34))}', + '.journal-billable{display:flex;align-items:center;gap:.25rem;font-size:.74rem;color:var(--vt-color-text-secondary,#b7c0d4);white-space:nowrap}', + '.journal-list{flex:1;min-height:0;overflow:auto;background:var(--vt-color-background,#101020)}', + '.journal-empty{height:100%;display:flex;align-items:center;justify-content:center;color:var(--vt-color-text-muted,#7f8aa3);font-size:.86rem;padding:2rem;text-align:center}', + '.journal-row{display:grid;grid-template-columns:8rem minmax(0,1fr) auto auto;gap:.7rem;margin:.5rem .75rem 0;padding:.75rem .85rem;border:1px solid var(--vt-color-border,#202b46);border-radius:var(--vt-radius-lg,8px);background:var(--vt-color-surface,#15152c);align-items:start}', + '.journal-row:hover{background:var(--vt-color-surface-hover,#1b2440)}', + '.journal-date{font-size:.75rem;color:var(--vt-color-text-muted,#7f8aa3);white-space:nowrap}', '.journal-main{min-width:0}', - '.journal-entry-title{font-size:.88rem;color:#e0e0e0;font-weight:600;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}', - '.journal-summary{margin-top:.25rem;font-size:.78rem;line-height:1.4;color:#aaa;white-space:pre-wrap;overflow-wrap:anywhere}', - '.journal-meta{margin-top:.25rem;font-size:.72rem;color:#777}', - '.journal-minutes{font-size:.78rem;color:#4ecca3;white-space:nowrap}', - '@media(max-width:820px){.journal-form,.journal-row{grid-template-columns:1fr}.journal-btn{width:100%}.journal-toolbar{align-items:stretch}.journal-status{width:100%}}' + '.journal-entry-title{font-size:.88rem;color:var(--vt-color-text-primary,#f4f7fb);font-weight:600;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}', + '.journal-summary{margin-top:.25rem;font-size:.78rem;line-height:1.4;color:var(--vt-color-text-secondary,#b7c0d4);white-space:pre-wrap;overflow-wrap:anywhere}', + '.journal-meta{margin-top:.25rem;font-size:.72rem;color:var(--vt-color-text-muted,#7f8aa3)}', + '.journal-minutes{font-size:.78rem;color:var(--vt-color-accent,#4ecca3);white-space:nowrap}', + '.journal-row-actions{display:flex;gap:.25rem}', + '.journal-icon-btn{width:1.65rem;height:1.65rem;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--vt-color-border,#202b46);border-radius:var(--vt-radius-sm,4px);background:transparent;color:var(--vt-color-text-muted,#7f8aa3);cursor:pointer;padding:0}', + '.journal-icon-btn:hover{background:var(--vt-color-surface-hover,#1b2440);border-color:var(--vt-color-accent,#4ecca3);color:var(--vt-color-accent,#4ecca3)}', + '.journal-icon-btn.danger:hover{border-color:rgba(233,69,96,.65);color:var(--vt-color-danger,#e94560)}', + '.journal-icon-btn svg{width:14px;height:14px;display:block;fill:currentColor}', + '.journal-modal-host[hidden]{display:none}', + '.journal-modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,.58);z-index:10000;display:flex;align-items:center;justify-content:center;padding:1rem}', + '.journal-modal{width:520px;max-width:96vw;display:grid;gap:.75rem;padding:1rem;border:1px solid var(--vt-color-border-strong,#2c456a);border-radius:var(--vt-radius-lg,8px);background:var(--vt-color-surface,#15152c);box-shadow:0 18px 44px rgba(0,0,0,.38)}', + '.journal-modal-title{font-size:.95rem;font-weight:650;color:var(--vt-color-text-primary,#f4f7fb)}', + '.journal-modal-grid{display:grid;grid-template-columns:1fr 8rem;gap:.6rem}', + '.journal-field{display:grid;gap:.3rem;font-size:.72rem;color:var(--vt-color-text-muted,#7f8aa3)}', + '.journal-field.wide{grid-column:1/-1}', + '.journal-modal-actions{display:flex;justify-content:flex-end;gap:.5rem}', + '.journal-btn.primary{background:var(--vt-color-accent,#4ecca3);border-color:var(--vt-color-accent,#4ecca3);color:#101827}', + '.journal-btn.ghost{background:transparent}', + '@media(max-width:820px){.journal-row{grid-template-columns:1fr}.journal-btn{width:100%}.journal-toolbar{align-items:stretch}.journal-status{width:100%}.journal-modal-grid{grid-template-columns:1fr}}' ].join('\n'); function el(tag, attrs, children) { @@ -52,6 +69,7 @@ Object.keys(attrs).forEach(function (key) { if (attrs[key] == null) return; if (key === 'className') elem.className = attrs[key]; + else if (key === 'innerHTML') elem.innerHTML = attrs[key]; else if (key === 'textContent') elem.textContent = attrs[key]; else if (key.slice(0, 2) === 'on') elem.addEventListener(key.slice(2).toLowerCase(), attrs[key]); else elem.setAttribute(key, attrs[key]); @@ -166,6 +184,16 @@ return 'journal:' + cleanWorkspace(workspaceRoot || 'Global') + ':' + text(date) + ':' + encodeKey(title).slice(0, 48) + ':' + Date.now(); } + var ICONS = { + add: 'M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z', + edit: 'M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34a.9959.9959 0 0 0-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z', + trash: 'M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM8 9h8v10H8V9zm7.5-5-1-1h-5l-1 1H5v2h14V4z' + }; + + function iconSvg(name) { + return ''; + } + function JournalView() {} JournalView.mount = function (containerEl, props, api) { @@ -178,6 +206,7 @@ var entries = []; var statusText = 'Loading journal...'; var statusClass = ''; + var modalHost = el('div', { className: 'journal-modal-host', hidden: 'hidden' }); var toolbar = el('div', { className: 'journal-toolbar' }); var titleEl = el('span', { className: 'journal-title', textContent: scope.mode === 'global' ? 'Journal' : 'Journal · ' + scope.label }); @@ -189,35 +218,23 @@ textContent: 'Import Activity', onClick: importActivity }); + var addBtn = el('button', { + className: 'journal-btn primary', + 'data-journal-action': 'add', + innerHTML: iconSvg('add') + 'Add', + onClick: function () { showEntryModal(); } + }); toolbar.appendChild(titleEl); toolbar.appendChild(countEl); toolbar.appendChild(el('span', { className: 'journal-spacer' })); toolbar.appendChild(statusEl); + toolbar.appendChild(addBtn); toolbar.appendChild(importBtn); - var dateInput = el('input', { className: 'journal-input', type: 'date', value: today(), 'data-journal-input': 'date' }); - var titleInput = el('input', { className: 'journal-input', type: 'text', placeholder: 'Work item', 'data-journal-input': 'title' }); - var summaryInput = el('input', { className: 'journal-input', type: 'text', placeholder: 'Summary', 'data-journal-input': 'summary' }); - var minutesInput = el('input', { className: 'journal-input', type: 'number', min: '0', step: '15', value: '30', 'data-journal-input': 'minutes' }); - var billableInput = el('input', { type: 'checkbox', 'data-journal-input': 'billable' }); - var addBtn = el('button', { - className: 'journal-btn', - 'data-journal-action': 'add', - textContent: 'Add', - onClick: addManualEntry - }); - var formEl = el('div', { className: 'journal-form' }, [ - dateInput, - titleInput, - summaryInput, - minutesInput, - el('label', { className: 'journal-billable' }, [billableInput, 'Billable']), - addBtn - ]); var listEl = el('div', { className: 'journal-list' }); containerEl.appendChild(toolbar); - if (scope.mode === 'workspace') containerEl.appendChild(formEl); containerEl.appendChild(listEl); + containerEl.appendChild(modalHost); function persist() { if (scope.mode !== 'workspace') return Promise.resolve(); @@ -254,9 +271,59 @@ }); } - function addManualEntry() { + function closeEntryModal() { + modalHost.innerHTML = ''; + modalHost.setAttribute('hidden', 'hidden'); + } + + function showEntryModal(existingEntry) { if (scope.mode !== 'workspace') return; - var title = text(titleInput.value).trim(); + var editing = !!existingEntry; + var dateInput = el('input', { className: 'journal-input', type: 'date', value: editing ? existingEntry.date : today(), 'data-journal-input': 'date' }); + var titleInput = el('input', { className: 'journal-input', type: 'text', placeholder: 'Work item', value: editing ? existingEntry.title : '', 'data-journal-input': 'title' }); + var summaryInput = el('textarea', { className: 'journal-input textarea', placeholder: 'Summary', 'data-journal-input': 'summary' }); + summaryInput.value = editing ? existingEntry.summary : ''; + var minutesInput = el('input', { className: 'journal-input', type: 'number', min: '0', step: '15', value: editing ? existingEntry.minutes : '30', 'data-journal-input': 'minutes' }); + var billableInput = el('input', { type: 'checkbox', 'data-journal-input': 'billable' }); + billableInput.checked = editing ? existingEntry.billable === true : false; + + function saveEntry() { + addOrUpdateEntry(existingEntry, { + date: dateInput.value || today(), + title: titleInput.value, + summary: summaryInput.value, + minutes: minutesInput.value, + billable: billableInput.checked === true + }); + } + + modalHost.innerHTML = ''; + if (typeof modalHost.removeAttribute === 'function') modalHost.removeAttribute('hidden'); + else delete modalHost.attributes.hidden; + modalHost.appendChild(el('div', { className: 'journal-modal-overlay', onClick: function (event) { + if (event.target === event.currentTarget) closeEntryModal(); + } }, [ + el('div', { className: 'journal-modal' }, [ + el('div', { className: 'journal-modal-title', textContent: editing ? 'Edit journal entry' : 'Add journal entry' }), + el('div', { className: 'journal-modal-grid' }, [ + el('label', { className: 'journal-field' }, ['Date', dateInput]), + el('label', { className: 'journal-field' }, ['Minutes', minutesInput]), + el('label', { className: 'journal-field wide' }, ['Title', titleInput]), + el('label', { className: 'journal-field wide' }, ['Summary', summaryInput]), + el('label', { className: 'journal-billable' }, [billableInput, 'Billable']) + ]), + el('div', { className: 'journal-modal-actions' }, [ + el('button', { className: 'journal-btn ghost', type: 'button', textContent: 'Cancel', onClick: closeEntryModal }), + el('button', { className: 'journal-btn primary', type: 'button', 'data-journal-action': 'save-entry', textContent: editing ? 'Save changes' : 'Add entry', onClick: saveEntry }) + ]) + ]) + ])); + titleInput.focus && titleInput.focus(); + } + + function addOrUpdateEntry(existingEntry, formValue) { + if (scope.mode !== 'workspace') return; + var title = text(formValue && formValue.title).trim(); if (!title) { statusText = 'Title is required'; statusClass = 'error'; @@ -264,18 +331,34 @@ return; } var entry = normalizeEntry({ - entryId: entryId(scope.workspaceRoot, dateInput.value || today(), title), + entryId: existingEntry ? existingEntry.entryId : entryId(scope.workspaceRoot, formValue.date || today(), title), workspaceRootPath: scope.workspaceRoot, - date: dateInput.value || today(), + date: formValue.date || today(), title: title, - summary: summaryInput.value, - minutes: Number(minutesInput.value || 0), - billable: billableInput.checked === true + summary: formValue.summary, + minutes: Number(formValue.minutes || 0), + billable: formValue.billable === true, + sourceSuggestionId: existingEntry ? existingEntry.sourceSuggestionId : '', + eventIds: existingEntry ? existingEntry.eventIds : [] }, scope.key); - entries = sortEntries([entry].concat(entries)); - titleInput.value = ''; - summaryInput.value = ''; - statusText = 'Entry added'; + if (existingEntry) { + entries = entries.map(function (item) { + return item.entryId === existingEntry.entryId ? entry : item; + }); + } else { + entries = [entry].concat(entries); + } + entries = sortEntries(entries); + closeEntryModal(); + statusText = existingEntry ? 'Entry updated' : 'Entry added'; + statusClass = ''; + persist().then(render); + } + + function deleteEntry(entry) { + if (scope.mode !== 'workspace' || !entry) return; + entries = entries.filter(function (item) { return item.entryId !== entry.entryId; }); + statusText = 'Entry deleted'; statusClass = ''; persist().then(render); } @@ -352,7 +435,11 @@ entry.summary ? el('div', { className: 'journal-summary', textContent: entry.summary }) : null, el('div', { className: 'journal-meta', textContent: entry.workspaceRootPath + (entry.billable ? ' · billable' : ' · non-billable') }) ]), - el('div', { className: 'journal-minutes', textContent: entry.minutes + ' min' }) + el('div', { className: 'journal-minutes', textContent: entry.minutes + ' min' }), + scope.mode === 'workspace' ? el('div', { className: 'journal-row-actions' }, [ + el('button', { className: 'journal-icon-btn', type: 'button', title: 'Edit', 'aria-label': 'Edit', 'data-journal-action': 'edit', innerHTML: iconSvg('edit'), onClick: function () { showEntryModal(entry); } }), + el('button', { className: 'journal-icon-btn danger', type: 'button', title: 'Delete', 'aria-label': 'Delete', 'data-journal-action': 'delete', innerHTML: iconSvg('trash'), onClick: function () { deleteEntry(entry); } }) + ]) : null ])); }); } @@ -361,6 +448,7 @@ countEl.textContent = entries.length + ' entr' + (entries.length === 1 ? 'y' : 'ies'); statusEl.textContent = statusText; statusEl.className = 'journal-status' + (statusClass ? ' ' + statusClass : ''); + addBtn.disabled = scope.mode !== 'workspace'; importBtn.disabled = scope.mode !== 'workspace' || importBtn.disabled; renderList(); } diff --git a/plugins/notes/frontend/src/index.js b/plugins/notes/frontend/src/index.js index 83db706..909298c 100644 --- a/plugins/notes/frontend/src/index.js +++ b/plugins/notes/frontend/src/index.js @@ -15,35 +15,38 @@ } var STYLES = [ - '.notes-root{display:flex;flex-direction:column;height:100%;min-height:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif;color:#e0e0e0;background:#0d0d1a;outline:none}', - '.notes-toolbar{display:flex;align-items:center;gap:.45rem;padding:.5rem .75rem;border-bottom:1px solid #16213e;flex-shrink:0;background:#12122a;flex-wrap:wrap}', - '.notes-btn{font-size:.78rem;padding:.32rem .65rem;border:1px solid #333;border-radius:4px;background:#1a1a2e;color:#ccc;cursor:pointer;display:inline-flex;align-items:center;gap:.35rem}', - '.notes-btn:hover{background:#2a2a4e;border-color:#4ecca3}', + '.notes-root{display:flex;flex-direction:column;height:100%;min-height:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif;color:var(--vt-color-text-primary,#f4f7fb);background:var(--vt-color-background,#101020);outline:none}', + '.notes-toolbar{display:flex;align-items:center;gap:.5rem;min-height:2.75rem;padding:.5rem .75rem;border-bottom:1px solid var(--vt-color-border,#202b46);flex-shrink:0;background:var(--vt-color-surface-muted,#111629);flex-wrap:wrap}', + '.notes-btn{font-size:.78rem;padding:.36rem .7rem;border:1px solid var(--vt-color-border-strong,#2c456a);border-radius:var(--vt-radius-md,6px);background:var(--vt-color-surface-hover,#1b2440);color:var(--vt-color-text-secondary,#b7c0d4);cursor:pointer;display:inline-flex;align-items:center;gap:.35rem}', + '.notes-btn:hover{background:var(--vt-color-surface-hover,#1b2440);border-color:var(--vt-color-accent,#4ecca3);color:var(--vt-color-text-primary,#f4f7fb)}', + '.notes-btn:focus-visible{outline:0;box-shadow:var(--vt-focus-ring,0 0 0 2px rgba(78,204,163,.34))}', '.notes-btn:disabled{opacity:.45;cursor:default}', - '.notes-btn.primary{background:#1a3a2a;border-color:#4ecca3;color:#4ecca3}', - '.notes-btn.primary:hover{background:#2a4a3a}', - '.notes-filter,.notes-sort{font-size:.78rem;padding:.32rem .5rem;border:1px solid #333;border-radius:4px;background:#0d0d1a;color:#e0e0e0;outline:none}', + '.notes-btn.primary{background:var(--vt-color-accent,#4ecca3);border-color:var(--vt-color-accent,#4ecca3);color:#101827}', + '.notes-btn.primary:hover{background:#63d9b3;color:#101827}', + '.notes-filter,.notes-sort{font-size:.78rem;padding:.32rem .5rem;border:1px solid var(--vt-color-border-strong,#2c456a);border-radius:var(--vt-radius-sm,4px);background:#0f1424;color:var(--vt-color-text-primary,#f4f7fb);outline:none}', '.notes-filter{width:11rem}', - '.notes-sort{width:8rem;appearance:none;background-color:#0d0d1a;background-image:linear-gradient(45deg,transparent 50%,#8b8ba8 50%),linear-gradient(135deg,#8b8ba8 50%,transparent 50%);background-position:calc(100% - 14px) 50%,calc(100% - 9px) 50%;background-size:5px 5px,5px 5px;background-repeat:no-repeat;padding-right:1.6rem}', - '.notes-filter:focus,.notes-sort:focus{border-color:#4ecca3}', + '.notes-sort{width:8rem;appearance:none;background-color:#0f1424;background-image:linear-gradient(45deg,transparent 50%,#8b8ba8 50%),linear-gradient(135deg,#8b8ba8 50%,transparent 50%);background-position:calc(100% - 14px) 50%,calc(100% - 9px) 50%;background-size:5px 5px,5px 5px;background-repeat:no-repeat;padding-right:1.6rem}', + '.notes-filter:focus,.notes-sort:focus{border-color:var(--vt-color-accent,#4ecca3);box-shadow:var(--vt-focus-ring,0 0 0 2px rgba(78,204,163,.34))}', '.notes-list{flex:1;overflow:auto;min-height:0}', - '.notes-item{display:flex;align-items:center;gap:.5rem;padding:.45rem .75rem;border-bottom:1px solid rgba(22,33,62,.55);cursor:pointer;font-size:.85rem}', - '.notes-item:hover{background:#17172d}', - '.notes-item.selected{background:#1a2a3a}', - '.notes-item-icon{width:1.25rem;height:1.25rem;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;color:#8b8ba8}', + '.notes-item{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;border-bottom:1px solid rgba(32,43,70,.72);cursor:pointer;font-size:.85rem}', + '.notes-item:hover{background:var(--vt-color-surface-hover,#1b2440)}', + '.notes-item.selected{background:var(--vt-color-surface-selected,rgba(78,204,163,.14));box-shadow:inset 2px 0 0 var(--vt-color-accent,#4ecca3)}', + '.notes-item-icon{width:1.25rem;height:1.25rem;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;color:var(--vt-color-text-muted,#7f8aa3)}', '.notes-item-icon svg{width:16px;height:16px;display:block;fill:currentColor}', '.notes-item-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}', - '.notes-item-actions{display:flex;gap:.25rem;opacity:0;transition:opacity .15s}', + '.notes-item-actions{display:flex;gap:.25rem;opacity:.78;transition:opacity .15s}', '.notes-item:hover .notes-item-actions{opacity:1}', - '.notes-item-btn{width:1.5rem;height:1.5rem;display:inline-flex;align-items:center;justify-content:center;border:1px solid #333;border-radius:3px;background:transparent;color:#888;cursor:pointer;padding:0;font-size:.7rem}', - '.notes-item-btn:hover{background:#2a2a4e;border-color:#4ecca3;color:#4ecca3}', - '.notes-empty{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;color:#666;font-size:.85rem;padding:2rem;gap:.5rem}', - '.notes-empty-hint{font-size:.75rem;color:#555}', - '.notes-error{flex:1;display:flex;align-items:center;justify-content:center;color:#e74c3c;padding:1rem;font-size:.85rem}', - '.notes-panel{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;border-top:1px solid #16213e;flex-shrink:0;background:#12122a}', - '.notes-input{flex:1;font-size:.78rem;padding:.32rem .5rem;border:1px solid #333;border-radius:4px;background:#0d0d1a;color:#e0e0e0;outline:none;min-width:120px}', - '.notes-input:focus{border-color:#4ecca3}', - '.notes-title-bar{padding:.4rem .75rem;font-size:.72rem;color:#8b8ba8;background:#101028;border-bottom:1px solid #16213e;text-transform:uppercase;letter-spacing:.04em}', + '.notes-item-btn{width:1.65rem;height:1.65rem;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--vt-color-border,#202b46);border-radius:var(--vt-radius-sm,4px);background:transparent;color:var(--vt-color-text-muted,#7f8aa3);cursor:pointer;padding:0;font-size:.7rem}', + '.notes-item-btn:hover{background:var(--vt-color-surface-hover,#1b2440);border-color:var(--vt-color-accent,#4ecca3);color:var(--vt-color-accent,#4ecca3)}', + '.notes-item-btn:focus-visible{outline:0;box-shadow:var(--vt-focus-ring,0 0 0 2px rgba(78,204,163,.34))}', + '.notes-item-btn svg{width:14px;height:14px;display:block;fill:currentColor}', + '.notes-empty{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;color:var(--vt-color-text-muted,#7f8aa3);font-size:.85rem;padding:2rem;gap:.5rem;text-align:center}', + '.notes-empty-hint{font-size:.75rem;color:var(--vt-color-text-muted,#7f8aa3)}', + '.notes-error{flex:1;display:flex;align-items:center;justify-content:center;color:var(--vt-color-danger,#e94560);padding:1rem;font-size:.85rem}', + '.notes-panel{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;border-top:1px solid var(--vt-color-border,#202b46);flex-shrink:0;background:var(--vt-color-surface-muted,#111629)}', + '.notes-input{flex:1;font-size:.78rem;padding:.32rem .5rem;border:1px solid var(--vt-color-border-strong,#2c456a);border-radius:var(--vt-radius-sm,4px);background:#0f1424;color:var(--vt-color-text-primary,#f4f7fb);outline:none;min-width:120px}', + '.notes-input:focus{border-color:var(--vt-color-accent,#4ecca3);box-shadow:var(--vt-focus-ring,0 0 0 2px rgba(78,204,163,.34))}', + '.notes-title-bar{padding:.4rem .75rem;font-size:.72rem;color:var(--vt-color-text-muted,#7f8aa3);background:var(--vt-color-surface-muted,#111629);border-bottom:1px solid var(--vt-color-border,#202b46);text-transform:uppercase;letter-spacing:.04em}', '.notes-modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,.6);z-index:10000;display:flex;align-items:center;justify-content:center}', '.notes-modal{width:380px;max-width:90vw;padding:20px;background:#1a1a2e;border:1px solid #333;border-radius:10px;color:#e0e0e0;font-family:inherit;box-shadow:0 12px 40px rgba(0,0,0,.5)}', '.notes-modal-title{font-size:.9rem;font-weight:600;margin-bottom:12px}', @@ -259,7 +262,7 @@ // ─── UI Elements ──────────────────────────────────────── var toolbar = el('div', { className: 'notes-toolbar' }); - var createBtn = el('button', { className: 'notes-btn', 'data-action': 'create', innerHTML: iconSvg('add') + ' New Note' }); + var createBtn = el('button', { className: 'notes-btn primary', 'data-action': 'create', innerHTML: iconSvg('add') + ' New Note' }); var filterInput = el('input', { className: 'notes-filter', 'data-notes-filter': '', placeholder: 'Filter notes' }); var sortSelect = el('select', { className: 'notes-sort', 'data-notes-sort': '' }, [ el('option', { value: 'title-asc' }, ['A-Z']), @@ -402,12 +405,15 @@ el('button', { className: 'notes-item-btn', title: 'Open', + 'aria-label': 'Open', + 'data-note-action': 'open', innerHTML: iconSvg('open'), onClick: function (e) { e.stopPropagation(); openNote(note); } }), el('button', { className: 'notes-item-btn', title: 'Rename', + 'aria-label': 'Rename', 'data-note-action': 'rename', innerHTML: iconSvg('rename'), onClick: function (e) { e.stopPropagation(); beginRename(note); } @@ -415,6 +421,7 @@ el('button', { className: 'notes-item-btn', title: 'Move to Trash', + 'aria-label': 'Move to Trash', 'data-note-action': 'trash', innerHTML: iconSvg('trash'), onClick: function (e) { e.stopPropagation(); confirmTrashNote(note); } diff --git a/plugins/search/frontend/src/index.js b/plugins/search/frontend/src/index.js index 8303fe0..797ba62 100644 --- a/plugins/search/frontend/src/index.js +++ b/plugins/search/frontend/src/index.js @@ -28,23 +28,30 @@ } var STYLES = [ - '.search-root{height:100%;min-height:0;display:flex;flex-direction:column;background:#0d0d1a;color:#e0e0e0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif}', - '.search-toolbar{display:flex;align-items:center;gap:.5rem;padding:.55rem .75rem;border-bottom:1px solid #16213e;background:#12122a;flex-shrink:0;flex-wrap:wrap}', - '.search-input{flex:1;min-width:180px;font-size:.86rem;padding:.42rem .55rem;border:1px solid #333;border-radius:4px;background:#0d0d1a;color:#e0e0e0;outline:none}', - '.search-input:focus{border-color:#4ecca3}', - '.search-btn{font-size:.8rem;padding:.42rem .7rem;border:1px solid #333;border-radius:4px;background:#1a1a2e;color:#ddd;cursor:pointer}', - '.search-btn:hover{border-color:#4ecca3;background:#2a2a4e}', + '.search-root{height:100%;min-height:0;display:flex;flex-direction:column;background:var(--vt-color-background,#101020);color:var(--vt-color-text-primary,#f4f7fb);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif}', + '.search-toolbar{display:flex;align-items:center;gap:.5rem;min-height:2.75rem;padding:.55rem .75rem;border-bottom:1px solid var(--vt-color-border,#202b46);background:var(--vt-color-surface-muted,#111629);flex-shrink:0;flex-wrap:wrap}', + '.search-input{flex:1;min-width:180px;font-size:.86rem;padding:.42rem .55rem;border:1px solid var(--vt-color-border-strong,#2c456a);border-radius:var(--vt-radius-sm,4px);background:#0f1424;color:var(--vt-color-text-primary,#f4f7fb);outline:none}', + '.search-input:focus{border-color:var(--vt-color-accent,#4ecca3);box-shadow:var(--vt-focus-ring,0 0 0 2px rgba(78,204,163,.34))}', + '.search-btn{font-size:.8rem;min-height:2rem;padding:.42rem .7rem;border:1px solid var(--vt-color-border-strong,#2c456a);border-radius:var(--vt-radius-md,6px);background:var(--vt-color-surface-hover,#1b2440);color:var(--vt-color-text-secondary,#b7c0d4);cursor:pointer}', + '.search-btn:hover{border-color:var(--vt-color-accent,#4ecca3);background:var(--vt-color-surface-hover,#1b2440);color:var(--vt-color-text-primary,#f4f7fb)}', '.search-btn:disabled{opacity:.45;cursor:default}', - '.search-scope{font-size:.72rem;color:#8b8ba8;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:18rem}', - '.search-status{font-size:.78rem;color:#8b8ba8;padding:.45rem .75rem;border-bottom:1px solid rgba(22,33,62,.55);flex-shrink:0}', - '.search-status.error{color:#e74c3c}', + '.search-scope{font-size:.72rem;color:var(--vt-color-text-muted,#7f8aa3);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:18rem}', + '.search-status{font-size:.78rem;color:var(--vt-color-text-muted,#7f8aa3);padding:.45rem .75rem;border-bottom:1px solid rgba(32,43,70,.72);flex-shrink:0}', + '.search-status.error{color:var(--vt-color-danger,#e94560)}', + '.search-alert{margin:.65rem .75rem 0;border:1px solid rgba(233,69,96,.45);border-radius:var(--vt-radius-md,6px);background:var(--vt-color-danger-muted,rgba(233,69,96,.14));color:#ffc6ce;padding:.55rem .65rem;font-size:.78rem}', + '.search-alert[hidden]{display:none}', + '.search-alert summary{cursor:pointer;color:#fff}', '.search-results{flex:1;min-height:0;overflow:auto}', - '.search-empty{height:100%;display:flex;align-items:center;justify-content:center;color:#666;font-size:.9rem;padding:2rem;text-align:center}', - '.search-result{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:.5rem;padding:.7rem .85rem;border-bottom:1px solid rgba(22,33,62,.55)}', - '.search-result:hover{background:#17172d}', - '.search-path{font-size:.84rem;color:#4ecca3;word-break:break-word}', - '.search-snippet{margin-top:.25rem;font-size:.8rem;line-height:1.45;color:#cfcfe0;white-space:pre-wrap;overflow-wrap:anywhere}', - '.search-meta{margin-top:.28rem;font-size:.72rem;color:#777}', + '.search-empty{height:100%;display:flex;align-items:center;justify-content:center;color:var(--vt-color-text-muted,#7f8aa3);font-size:.9rem;padding:2rem;text-align:center}', + '.search-result{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:.75rem;align-items:center;margin:.5rem .75rem 0;padding:.7rem .8rem;border:1px solid var(--vt-color-border,#202b46);border-radius:var(--vt-radius-lg,8px);background:var(--vt-color-surface,#15152c)}', + '.search-result:hover{background:var(--vt-color-surface-hover,#1b2440)}', + '.search-result-head{display:flex;align-items:center;gap:.5rem;min-width:0}', + '.search-type{display:inline-flex;align-items:center;min-height:1.25rem;padding:.1rem .4rem;border:1px solid rgba(78,204,163,.4);border-radius:var(--vt-radius-sm,4px);background:var(--vt-color-accent-muted,rgba(78,204,163,.14));color:var(--vt-color-accent,#4ecca3);font-size:.68rem;font-weight:650;text-transform:uppercase;letter-spacing:.03em}', + '.search-title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.86rem;color:var(--vt-color-text-primary,#f4f7fb);font-weight:650}', + '.search-path{margin-top:.2rem;font-size:.76rem;color:var(--vt-color-text-muted,#7f8aa3);word-break:break-word}', + '.search-snippet{margin-top:.25rem;font-size:.8rem;line-height:1.45;color:var(--vt-color-text-secondary,#b7c0d4);white-space:pre-wrap;overflow-wrap:anywhere}', + '.search-meta{margin-top:.28rem;font-size:.72rem;color:var(--vt-color-text-muted,#7f8aa3)}', + '.search-open-btn{align-self:center;white-space:nowrap;min-width:4.5rem;padding:.35rem .65rem}', '@media(max-width:700px){.search-result{grid-template-columns:1fr}.search-toolbar{align-items:stretch}.search-btn{width:100%}.search-scope{max-width:none}}' ].join('\n'); @@ -54,7 +61,9 @@ Object.keys(attrs).forEach(function (k) { if (attrs[k] == null) return; if (k === 'className') elem.className = attrs[k]; - else if (k === 'style' && typeof attrs[k] === 'object') Object.assign(elem.style, attrs[k]); + else if (k === 'style' && typeof attrs[k] === 'object') { + if (elem.style) Object.assign(elem.style, attrs[k]); + } else if (k.slice(0, 2) === 'on') elem.addEventListener(k.slice(2).toLowerCase(), attrs[k]); else if (k === 'textContent') elem.textContent = attrs[k]; else if (k === 'innerHTML') elem.innerHTML = attrs[k]; @@ -74,6 +83,20 @@ return String(path || '').split('/').filter(Boolean).join('/'); } + function baseName(path) { + path = cleanPath(path); + var parts = path.split('/'); + return parts[parts.length - 1] || path || 'Untitled'; + } + + function resultTypeLabel(result) { + var type = String(result && result.type || 'result').toLowerCase(); + if (type === 'folder') return 'Folder'; + if (type === 'file') return 'File'; + if (type === 'external') return 'Plugin'; + return type.charAt(0).toUpperCase() + type.slice(1); + } + function extension(entry) { var explicit = String((entry && entry.extension) || '').replace(/^\./, '').toLowerCase(); if (explicit) return explicit; @@ -281,7 +304,7 @@ mount: function (containerEl, props, api) { injectStyles(); var rootPath = cleanPath(props && (props.workspaceRootPath || props.workspaceName)); - var state = { query: '', searching: false, results: [], status: 'Enter at least 2 characters.', error: '' }; + var state = { query: '', searching: false, results: [], status: 'Enter at least 2 characters.', error: '', providerErrors: [] }; var searchTimer = null; var searchSeq = 0; var index = null; @@ -290,6 +313,7 @@ var input = null; var button = null; var statusEl = null; + var alertEl = null; var resultsEl = null; function ensureLayout() { @@ -322,6 +346,8 @@ statusEl = el('div', { className: 'search-status' }); containerEl.appendChild(statusEl); + alertEl = el('div', { className: 'search-alert', hidden: 'hidden' }); + containerEl.appendChild(alertEl); resultsEl = el('div', { className: 'search-results' }); containerEl.appendChild(resultsEl); } @@ -335,6 +361,16 @@ button.disabled = !!state.searching; statusEl.className = 'search-status' + (state.error ? ' error' : ''); statusEl.textContent = state.error || state.status; + alertEl.innerHTML = ''; + if (state.providerErrors && state.providerErrors.length) { + if (typeof alertEl.removeAttribute === 'function') alertEl.removeAttribute('hidden'); + alertEl.appendChild(el('details', {}, [ + el('summary', {}, ['Some plugin search providers did not respond']), + el('div', {}, [state.providerErrors.join('; ')]) + ])); + } else if (typeof alertEl.setAttribute === 'function') { + alertEl.setAttribute('hidden', 'hidden'); + } resultsEl.innerHTML = ''; if (!state.results.length) { resultsEl.appendChild(el('div', { className: 'search-empty' }, [state.searching ? 'Searching...' : 'No results'])); @@ -343,6 +379,10 @@ state.results.forEach(function (result) { resultsEl.appendChild(el('div', { className: 'search-result' }, [ el('div', {}, [ + el('div', { className: 'search-result-head' }, [ + el('span', { className: 'search-type' }, [resultTypeLabel(result)]), + el('span', { className: 'search-title', title: result.path }, [baseName(result.path)]) + ]), el('div', { className: 'search-path' }, [result.path]), el('div', { className: 'search-snippet' }, [result.snippet]), el('div', { className: 'search-meta' }, [ @@ -350,7 +390,7 @@ ]) ]), result.openable ? el('button', { - className: 'search-btn', + className: 'search-btn search-open-btn', textContent: 'Open', 'data-search-open': result.path, onClick: function () { @@ -377,6 +417,7 @@ state.results = []; state.status = 'Enter at least 2 characters.'; state.error = ''; + state.providerErrors = []; render(); return; } @@ -393,11 +434,13 @@ state.results = []; state.status = 'Enter at least 2 characters.'; state.error = ''; + state.providerErrors = []; render(); return; } state.searching = true; state.error = ''; + state.providerErrors = []; state.status = 'Searching...'; var seq = searchSeq + 1; searchSeq = seq; @@ -409,13 +452,12 @@ if (seq !== searchSeq) return; state.results = results.concat(external.results); state.status = state.results.length + ' result' + (state.results.length === 1 ? '' : 's'); - if (external.errors.length) { - state.status += ' - ' + external.errors.join('; '); - } + state.providerErrors = external.errors; } catch (err) { if (seq !== searchSeq) return; state.results = []; state.error = err && err.message ? err.message : String(err); + state.providerErrors = []; } finally { if (seq !== searchSeq) return; state.searching = false; diff --git a/plugins/secrets/frontend/src/index.js b/plugins/secrets/frontend/src/index.js index 563a18d..49eefee 100644 --- a/plugins/secrets/frontend/src/index.js +++ b/plugins/secrets/frontend/src/index.js @@ -19,42 +19,44 @@ } var STYLES = [ - '.secrets-root{display:grid;grid-template-columns:minmax(17rem,20rem) minmax(0,1fr);height:100%;min-height:0;background:#0d0f14;color:#e6edf3;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif}', - '.secrets-panel{min-height:0;overflow:auto;border-right:1px solid #252b36;background:#11151d}', - '.secrets-main{min-width:0;min-height:0;overflow:auto;padding:1rem;background:#0d0f14}', - '.secrets-toolbar{display:flex;align-items:center;gap:.5rem;padding:.65rem .75rem;border-bottom:1px solid #252b36}', + '.secrets-root{display:grid;grid-template-columns:minmax(17rem,20rem) minmax(0,1fr);height:100%;min-height:0;background:var(--vt-color-background,#101020);color:var(--vt-color-text-primary,#f4f7fb);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif}', + '.secrets-panel{min-height:0;overflow:auto;border-right:1px solid var(--vt-color-border,#202b46);background:var(--vt-color-surface-muted,#111629)}', + '.secrets-main{min-width:0;min-height:0;overflow:auto;padding:1rem;background:var(--vt-color-background,#101020)}', + '.secrets-toolbar{display:flex;align-items:center;gap:.5rem;min-height:2.75rem;padding:.65rem .75rem;border-bottom:1px solid var(--vt-color-border,#202b46)}', '.secrets-title{font-weight:600;font-size:.88rem}', - '.secrets-count{color:#8b949e;font-size:.76rem}', + '.secrets-count{color:var(--vt-color-text-muted,#7f8aa3);font-size:.76rem}', '.secrets-spacer{flex:1}', - '.secrets-btn{height:2rem;padding:0 .65rem;border:1px solid #303844;border-radius:4px;background:#1b222d;color:#d8dee9;font:inherit;font-size:.78rem;cursor:pointer}', - '.secrets-btn:hover{border-color:#56b6c2;background:#222b38}', - '.secrets-btn.primary{background:#176b5f;border-color:#248879;color:white}', + '.secrets-btn{height:2rem;padding:0 .65rem;border:1px solid var(--vt-color-border-strong,#2c456a);border-radius:var(--vt-radius-md,6px);background:var(--vt-color-surface-hover,#1b2440);color:var(--vt-color-text-secondary,#b7c0d4);font:inherit;font-size:.78rem;cursor:pointer}', + '.secrets-btn:hover{border-color:var(--vt-color-accent,#4ecca3);background:var(--vt-color-surface-hover,#1b2440);color:var(--vt-color-text-primary,#f4f7fb)}', + '.secrets-btn.primary{background:var(--vt-color-accent,#4ecca3);border-color:var(--vt-color-accent,#4ecca3);color:#101827}', + '.secrets-btn.danger{border-color:rgba(233,69,96,.5);color:#ff9aaa;background:var(--vt-color-danger-muted,rgba(233,69,96,.14))}', '.secrets-btn:disabled{opacity:.45;cursor:default}', - '.secrets-group{padding:.6rem .55rem .25rem;color:#8b949e;font-size:.72rem;text-transform:uppercase;letter-spacing:.04em}', + '.secrets-group{padding:.6rem .55rem .25rem;color:var(--vt-color-text-muted,#7f8aa3);font-size:.72rem;text-transform:uppercase;letter-spacing:.04em}', '.secrets-list{display:grid;gap:.25rem;padding:.2rem .45rem .75rem}', - '.secrets-item{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:.45rem;align-items:center;text-align:left;border:1px solid transparent;border-radius:5px;background:transparent;color:#d8dee9;padding:.5rem .55rem;cursor:pointer}', - '.secrets-item:hover{background:#171d27;border-color:#293241}', - '.secrets-item.active{background:#18232f;border-color:#56b6c2}', + '.secrets-item{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:.45rem;align-items:center;text-align:left;border:1px solid transparent;border-radius:var(--vt-radius-md,6px);background:transparent;color:var(--vt-color-text-secondary,#b7c0d4);padding:.5rem .55rem;cursor:pointer}', + '.secrets-item:hover{background:var(--vt-color-surface-hover,#1b2440);border-color:var(--vt-color-border,#202b46)}', + '.secrets-item.active{background:var(--vt-color-surface-selected,rgba(78,204,163,.14));border-color:rgba(78,204,163,.45);box-shadow:inset 2px 0 0 var(--vt-color-accent,#4ecca3)}', '.secrets-item-title{font-size:.82rem;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}', - '.secrets-item-meta{font-size:.72rem;color:#8b949e;margin-top:.12rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}', - '.secrets-empty{padding:1.5rem;color:#8b949e;font-size:.84rem;text-align:center}', + '.secrets-item-meta{font-size:.72rem;color:var(--vt-color-text-muted,#7f8aa3);margin-top:.12rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}', + '.secrets-empty{padding:1.5rem;color:var(--vt-color-text-muted,#7f8aa3);font-size:.84rem;text-align:center}', '.secrets-card{max-width:46rem;display:grid;gap:.8rem}', - '.secrets-card h2{font-size:1rem;margin:0;color:#f0f6fc}', - '.secrets-form{display:grid;gap:.65rem;border:1px solid #252b36;border-radius:6px;padding:.9rem;background:#11151d}', + '.secrets-card h2{font-size:1rem;margin:0;color:var(--vt-color-text-primary,#f4f7fb)}', + '.secrets-form{display:grid;gap:.65rem;border:1px solid var(--vt-color-border,#202b46);border-radius:var(--vt-radius-lg,8px);padding:.9rem;background:var(--vt-color-surface,#15152c)}', '.secrets-row{display:grid;grid-template-columns:8rem minmax(0,1fr);gap:.65rem;align-items:center}', - '.secrets-label{font-size:.78rem;color:#8b949e}', - '.secrets-input,.secrets-textarea,.secrets-select{width:100%;box-sizing:border-box;border:1px solid #303844;border-radius:4px;background:#0d1117;color:#e6edf3;font:inherit;font-size:.84rem;padding:.45rem .55rem;outline:none}', + '.secrets-label{font-size:.78rem;color:var(--vt-color-text-muted,#7f8aa3)}', + '.secrets-input,.secrets-textarea,.secrets-select{width:100%;box-sizing:border-box;border:1px solid var(--vt-color-border-strong,#2c456a);border-radius:var(--vt-radius-sm,4px);background:#0f1424;color:var(--vt-color-text-primary,#f4f7fb);font:inherit;font-size:.84rem;padding:.45rem .55rem;outline:none}', '.secrets-select{appearance:none;background-color:#0d1117;background-image:linear-gradient(45deg,transparent 50%,#8b949e 50%),linear-gradient(135deg,#8b949e 50%,transparent 50%);background-position:calc(100% - 16px) 50%,calc(100% - 11px) 50%;background-size:5px 5px,5px 5px;background-repeat:no-repeat;padding-right:2rem}', '.secrets-textarea{min-height:6rem;resize:vertical;font-family:ui-monospace,SFMono-Regular,Consolas,monospace}', - '.secrets-input:focus,.secrets-textarea:focus,.secrets-select:focus{border-color:#56b6c2}', + '.secrets-input:focus,.secrets-textarea:focus,.secrets-select:focus{border-color:var(--vt-color-accent,#4ecca3);box-shadow:var(--vt-focus-ring,0 0 0 2px rgba(78,204,163,.34))}', '.secrets-actions{display:flex;gap:.5rem;flex-wrap:wrap}', - '.secrets-status{font-size:.78rem;color:#8b949e;min-height:1rem}', - '.secrets-status.error{color:#ff8f8f}', - '.secrets-secret-value{white-space:pre-wrap;overflow-wrap:anywhere;border:1px solid #303844;background:#0d1117;border-radius:4px;padding:.7rem;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:.82rem}', - '.secrets-table{width:100%;border-collapse:collapse;border:1px solid #252b36;background:#11151d;border-radius:6px;overflow:hidden}', - '.secrets-table th,.secrets-table td{border-bottom:1px solid #252b36;padding:.55rem .65rem;text-align:left;vertical-align:top;font-size:.84rem}', - '.secrets-table th{width:9rem;color:#8b949e;font-weight:500;background:#151a23}', - '.secrets-table td{color:#e6edf3;overflow-wrap:anywhere}', + '.secrets-status{font-size:.78rem;color:var(--vt-color-text-muted,#7f8aa3);min-height:1rem}', + '.secrets-status.error{color:#ffc6ce}', + '.secrets-secret-value{white-space:pre-wrap;overflow-wrap:anywhere;border:1px solid var(--vt-color-border-strong,#2c456a);background:#0f1424;border-radius:var(--vt-radius-sm,4px);padding:.7rem;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:.82rem}', + '.secrets-hidden-value{display:inline-flex;align-items:center;min-height:2rem;width:100%;border:1px solid var(--vt-color-border-strong,#2c456a);border-radius:var(--vt-radius-sm,4px);background:#0f1424;color:var(--vt-color-text-muted,#7f8aa3);padding:.35rem .55rem;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;letter-spacing:.08em}', + '.secrets-table{width:100%;border-collapse:collapse;border:1px solid var(--vt-color-border,#202b46);background:var(--vt-color-surface,#15152c);border-radius:var(--vt-radius-lg,8px);overflow:hidden}', + '.secrets-table th,.secrets-table td{border-bottom:1px solid var(--vt-color-border,#202b46);padding:.55rem .65rem;text-align:left;vertical-align:top;font-size:.84rem}', + '.secrets-table th{width:9rem;color:var(--vt-color-text-muted,#7f8aa3);font-weight:500;background:var(--vt-color-surface-muted,#111629)}', + '.secrets-table td{color:var(--vt-color-text-primary,#f4f7fb);overflow-wrap:anywhere}', '.secrets-table tr:last-child th,.secrets-table tr:last-child td{border-bottom:0}', '@media(max-width:780px){.secrets-root{grid-template-columns:1fr}.secrets-panel{border-right:0;border-bottom:1px solid #252b36;max-height:45vh}.secrets-row{grid-template-columns:1fr}}' ].join('\n'); @@ -262,7 +264,7 @@ fieldRow('Group', scopeLabel(selectedRecord)), fieldRow('ID', selectedRecord.id), fieldRow('Username', selectedRecord.username || ''), - fieldRow('Password', selectedValue ? selectedValue : 'Value hidden'), + fieldRow('Password', selectedValue ? selectedValue : '••••••••••••', selectedValue ? '' : 'secrets-hidden-value'), fieldRow('Updated', selectedRecord.updatedAt || '') ]) ]), @@ -280,7 +282,7 @@ onClick: function () { showEditSecret(); } }, ['Edit']), el('button', { - className: 'secrets-btn', + className: 'secrets-btn danger', type: 'button', 'data-secret-delete': selectedRecord.id, onClick: function () { deleteSecret(selectedRecord.id); } @@ -290,10 +292,10 @@ ]); } - function fieldRow(label, value) { + function fieldRow(label, value, valueClass) { return el('tr', {}, [ el('th', {}, [label]), - el('td', {}, [value || '']) + el('td', {}, [valueClass ? el('span', { className: valueClass }, [value || '']) : (value || '')]) ]); } diff --git a/scripts/smoke-activity-plugin.js b/scripts/smoke-activity-plugin.js index 3c69a0b..c0c00fa 100644 --- a/scripts/smoke-activity-plugin.js +++ b/scripts/smoke-activity-plugin.js @@ -344,10 +344,18 @@ async function mountWithApi(api, props = { workspaceNode: { name: 'Project' }, w summary: 'Notes/Case.md', occurredAt: '2026-06-27T01:00:00Z', sourcePluginId: 'verstak.notes', + }, { + activityId: 'persisted-open-1', + type: 'file.opened', + title: 'Selected file', + summary: 'Project/Notes/Case.md', + occurredAt: '2026-06-27T01:05:00Z', + sourcePluginId: 'verstak.files', }], }); const persisted = await mountWithApi(persistedApi); if (!persisted.container.textContent.includes('Saved note')) throw new Error('persisted activity was not rendered'); + if (persisted.container.textContent.includes('Selected file')) throw new Error('low-value file activity should not be rendered'); const legacyApi = makeApi({ events: [ diff --git a/scripts/smoke-journal-plugin.js b/scripts/smoke-journal-plugin.js index a313182..b327d52 100644 --- a/scripts/smoke-journal-plugin.js +++ b/scripts/smoke-journal-plugin.js @@ -200,17 +200,31 @@ function byData(container, attr, value) { const { component, container } = await mountWithApi(api); const projectKey = 'worklog:workspace:Project'; + byData(container, 'data-journal-action', 'add').click(); + await flush(); byData(container, 'data-journal-input', 'date').value = '2026-06-27'; byData(container, 'data-journal-input', 'title').value = 'Draft brief'; byData(container, 'data-journal-input', 'summary').value = 'Reviewed docs'; byData(container, 'data-journal-input', 'minutes').value = '45'; - byData(container, 'data-journal-action', 'add').click(); + byData(container, 'data-journal-action', 'save-entry').click(); await flush(); if (api.storedEntries(projectKey).length !== 1) throw new Error('manual journal entry was not stored'); if (!container.textContent.includes('Draft brief')) throw new Error('manual journal entry was not rendered'); if (!container.textContent.includes('45 min')) throw new Error('manual journal entry minutes were not rendered'); + byData(container, 'data-journal-action', 'edit').click(); + await flush(); + byData(container, 'data-journal-input', 'title').value = 'Draft brief updated'; + byData(container, 'data-journal-input', 'summary').value = 'Reviewed docs and drafted notes'; + byData(container, 'data-journal-input', 'minutes').value = '60'; + byData(container, 'data-journal-action', 'save-entry').click(); + await flush(); + + if (api.storedEntries(projectKey).length !== 1) throw new Error('editing journal entry created a duplicate'); + if (api.storedEntries(projectKey)[0].title !== 'Draft brief updated') throw new Error('journal entry title was not updated'); + if (!container.textContent.includes('60 min')) throw new Error('edited journal entry minutes were not rendered'); + byData(container, 'data-journal-action', 'import-activity').click(); await flush(); @@ -223,9 +237,14 @@ function byData(container, attr, value) { await flush(); if (api.storedEntries(projectKey).length !== 2) throw new Error('duplicate activity suggestion was imported'); + byData(container, 'data-journal-action', 'delete').click(); + await flush(); + if (api.storedEntries(projectKey).length !== 1) throw new Error('journal entry was not deleted'); + const globalView = await mountWithApi(api, {}); - if (!globalView.container.textContent.includes('Draft brief')) throw new Error('global journal did not aggregate manual entry'); - if (!globalView.container.textContent.includes('Project work on 2026-06-27')) throw new Error('global journal did not aggregate imported suggestion'); + if (!globalView.container.textContent.includes('Project work on 2026-06-27') && !globalView.container.textContent.includes('Draft brief updated')) { + throw new Error('global journal did not aggregate remaining entries'); + } component.unmount && component.unmount(container); component.unmount && component.unmount(globalView.container);