Polish official plugin workbench UI

This commit is contained in:
mirivlad 2026-07-02 00:49:29 +08:00
parent 0e079e8290
commit d6b8ab17f1
9 changed files with 458 additions and 219 deletions

View File

@ -26,6 +26,27 @@
'browser.capture.file', 'browser.capture.file',
'browser.capture.converted' '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() { function injectStyles() {
if (document.getElementById('activity-style-injected')) return; if (document.getElementById('activity-style-injected')) return;
@ -36,33 +57,36 @@
} }
var STYLES = [ 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-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;padding:.5rem .75rem;border-bottom:1px solid #16213e;background:#12122a;flex-shrink:0;flex-wrap:wrap}', '.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:#e0e0e0}', '.activity-title{font-size:.84rem;font-weight:600;color:var(--vt-color-text-primary,#f4f7fb)}',
'.activity-count{font-size:.72rem;color:#8b8ba8}', '.activity-count{font-size:.72rem;color:var(--vt-color-text-muted,#7f8aa3)}',
'.activity-spacer{flex:1}', '.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{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:#2a2a4e;border-color:#4ecca3}', '.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:disabled{opacity:.45;cursor:default}',
'.activity-btn.danger{border-color:#633;color:#ff9a9a}', '.activity-btn.danger{border-color:rgba(233,69,96,.42);color:#ff9a9a}',
'.activity-status{font-size:.72rem;color:#8b8ba8;white-space:nowrap}', '.activity-status{font-size:.72rem;color:var(--vt-color-text-muted,#7f8aa3);white-space:nowrap}',
'.activity-status.error{color:#e74c3c}', '.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(22,33,62,.65);background:#111126;padding:.55rem .75rem;display:grid;gap:.5rem}', '.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:#8b8ba8;text-transform:uppercase;letter-spacing:.04em}', '.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:.55rem .65rem;border:1px solid rgba(78,204,163,.25);border-radius:4px;background:#14142c}', '.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:#e0e0e0;font-weight:600;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}', '.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:#aaa;line-height:1.4;white-space:pre-wrap;overflow-wrap:anywhere}', '.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:#4ecca3;white-space:nowrap}', '.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:#101020}', '.activity-list{flex:1;min-height:0;overflow:auto;background:var(--vt-color-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-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-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-empty-title{color:var(--vt-color-text-secondary,#b7c0d4);font-weight:650}',
'.activity-time{font-size:.72rem;color:#777;white-space:nowrap}', '.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-main{min-width:0}',
'.activity-row-head{display:flex;align-items:center;gap:.45rem;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-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:#e0e0e0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}', '.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:#aaa;white-space:pre-wrap;overflow-wrap:anywhere}', '.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:#777}', '.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%}}' '@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'); ].join('\n');
@ -178,6 +202,11 @@
}).slice(0, MAX_EVENTS); }).slice(0, MAX_EVENTS);
} }
function isMeaningfulActivity(activity) {
var type = text(activity && activity.type).toLowerCase();
return !LOW_VALUE_EVENT_TYPES[type];
}
function eventTimeMs(activity) { function eventTimeMs(activity) {
var value = activity && (activity.occurredAt || activity.receivedAt); var value = activity && (activity.occurredAt || activity.receivedAt);
var date = value ? new Date(value) : null; var date = value ? new Date(value) : null;
@ -209,7 +238,28 @@
} }
function eventLabel(activity) { 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) { function summarizeEvents(groupEvents) {
@ -226,7 +276,7 @@
function buildWorklogSuggestions(activityList, workspaceFilter) { function buildWorklogSuggestions(activityList, workspaceFilter) {
var filter = cleanWorkspace(workspaceFilter); var filter = cleanWorkspace(workspaceFilter);
var groups = {}; var groups = {};
sortEvents(activityList || []).forEach(function (activity) { sortEvents(activityList || []).filter(isMeaningfulActivity).forEach(function (activity) {
var workspace = suggestionWorkspace(activity); var workspace = suggestionWorkspace(activity);
if (filter && workspace !== filter) return; if (filter && workspace !== filter) return;
var day = eventDay(activity); var day = eventDay(activity);
@ -271,7 +321,7 @@
globalEventKeys(settings).forEach(function (key) { globalEventKeys(settings).forEach(function (key) {
all = all.concat(normalizeStoredEvents(settings[key], key)); all = all.concat(normalizeStoredEvents(settings[key], key));
}); });
return sortEvents(all); return sortEvents(all).filter(isMeaningfulActivity);
} }
var workspaceKey = WORKSPACE_PREFIX + encodeKey(workspace); var workspaceKey = WORKSPACE_PREFIX + encodeKey(workspace);
var scopedEvents = normalizeStoredEvents(settings[workspaceKey], workspaceKey); var scopedEvents = normalizeStoredEvents(settings[workspaceKey], workspaceKey);
@ -281,7 +331,7 @@
var legacyEvents = normalizeStoredEvents(settings[LEGACY_KEY], LEGACY_KEY).filter(function (item) { var legacyEvents = normalizeStoredEvents(settings[LEGACY_KEY], LEGACY_KEY).filter(function (item) {
return item.workspaceRootPath === workspace; return item.workspaceRootPath === workspace;
}); });
return sortEvents(scopedEvents.concat(globalEvents, legacyEvents)); return sortEvents(scopedEvents.concat(globalEvents, legacyEvents)).filter(isMeaningfulActivity);
} }
function formatDate(value) { function formatDate(value) {
@ -378,7 +428,10 @@
function renderList() { function renderList() {
listEl.innerHTML = ''; listEl.innerHTML = '';
if (events.length === 0) { 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; return;
} }
events.forEach(function (activity) { events.forEach(function (activity) {
@ -389,11 +442,14 @@
el('div', { className: 'activity-time', textContent: formatDate(activity.occurredAt) || '-' }), el('div', { className: 'activity-time', textContent: formatDate(activity.occurredAt) || '-' }),
el('div', { className: 'activity-main' }, [ el('div', { className: 'activity-main' }, [
el('div', { className: 'activity-row-head' }, [ el('div', { className: 'activity-row-head' }, [
el('span', { className: 'activity-type', textContent: activity.type }), el('span', { className: 'activity-type', textContent: eventKind(activity) }),
el('span', { className: 'activity-title-text', textContent: activity.title || 'Activity event' }) el('span', { className: 'activity-title-text', textContent: humanEventTitle(activity) })
]), ]),
activity.summary ? el('div', { className: 'activity-summary', textContent: activity.summary }) : null, 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 : '') })
])
]) ])
])); ]));
}); });

View File

@ -22,35 +22,35 @@
} }
var STYLES = [ 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-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;padding:.5rem .75rem;border-bottom:1px solid #16213e;background:#12122a;flex-shrink:0;flex-wrap:wrap}', '.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:#e0e0e0}', '.browser-inbox-title{font-size:.82rem;font-weight:600;color:var(--vt-color-text-primary,#f4f7fb)}',
'.browser-inbox-count{font-size:.72rem;color:#8b8ba8}', '.browser-inbox-count{font-size:.72rem;color:var(--vt-color-text-muted,#7f8aa3)}',
'.browser-inbox-spacer{flex:1}', '.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{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:#2a2a4e;border-color:#4ecca3}', '.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:disabled{opacity:.45;cursor:default}',
'.browser-inbox-btn.danger{border-color:#633;color:#ff9a9a}', '.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:#8b8ba8;white-space:nowrap}', '.browser-inbox-status{font-size:.72rem;color:var(--vt-color-text-muted,#7f8aa3);white-space:nowrap}',
'.browser-inbox-status.error{color:#e74c3c}', '.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-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-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:#666;font-size:.86rem;padding:2rem;text-align:center}', '.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(22,33,62,.6);cursor:pointer}', '.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:#17172d}', '.browser-inbox-row:hover{background:var(--vt-color-surface-hover,#1b2440)}',
'.browser-inbox-row.selected{background:#1a2a3a}', '.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-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-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:#e0e0e0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}', '.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:#8b8ba8;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:#aaa;line-height:1.35;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}', '.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{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-empty{margin:auto;color:var(--vt-color-text-muted,#7f8aa3);font-size:.86rem}',
'.browser-inbox-detail-title{font-size:1rem;font-weight:600;color:#f0f0f0;word-break:break-word}', '.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{display:grid;grid-template-columns:7rem minmax(0,1fr);gap:.35rem .75rem;font-size:.78rem}',
'.browser-inbox-meta-label{color:#777}', '.browser-inbox-meta-label{color:var(--vt-color-text-muted,#7f8aa3)}',
'.browser-inbox-meta-value{color:#ccc;min-width:0;overflow-wrap:anywhere}', '.browser-inbox-meta-value{color:var(--vt-color-text-secondary,#b7c0d4);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-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}', '.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}}' '@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'); ].join('\n');

View File

@ -15,56 +15,63 @@
} }
var STYLES = [ 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-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:.45rem;padding:.5rem .75rem;border-bottom:1px solid #16213e;flex-shrink:0;background:#12122a;flex-wrap:wrap}', '.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-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-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-toolbar-btn{width:2rem;height:2rem;padding:0}',
'.files-row-btn{width:1.75rem;height:1.75rem;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 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: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:disabled,.files-row-btn:disabled{opacity:.45;cursor:default;border-color:#333}', '.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-breadcrumb{display:flex;align-items:center;gap:.25rem;font-size:.8rem;color:#8b8ba8;min-width:160px;flex:1;overflow:hidden}', '.files-toolbar-btn:disabled,.files-row-btn:disabled{opacity:.45;cursor:default;border-color:var(--vt-color-border,#202b46)}',
'.files-breadcrumb-item{color:#4ecca3;cursor:pointer;padding:.1rem .3rem;border-radius:3px;white-space:nowrap}', '.files-toolbar-btn.danger,.files-row-btn.danger{color:#ff9aaa;border-color:rgba(233,69,96,.42)}',
'.files-breadcrumb-item:hover{background:#1a2a3a}', '.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-current{color:#ddd;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}', '.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-sep{color:#555}', '.files-breadcrumb-item:hover{background:var(--vt-color-accent-muted,rgba(78,204,163,.14))}',
'.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-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-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-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:#4ecca3}', '.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-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,.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{font-size:.84rem;cursor:pointer}',
'.files-item:hover{background:#17172d}', '.files-item:hover{background:var(--vt-color-surface-hover,#1b2440)}',
'.files-item.selected{background:#1a2a3a}', '.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-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-icon svg{display:block;width:16px;height:16px}',
'.files-item-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}', '.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-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}', '.files-row-actions{display:flex;align-items:center;justify-content:flex-end;gap:.35rem;white-space:nowrap;opacity:.28;transition:opacity .12s ease}',
'.files-empty,.files-loading{flex:1;display:flex;align-items:center;justify-content:center;color:#666;font-size:.9rem;padding:2rem}', '.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{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-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{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:#2a2a4e;border-color:#4ecca3}', '.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-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{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:#aaa;max-width:420px;text-align:center}', '.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 #16213e;flex-shrink:0;background:#12122a}', '.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-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}', '.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%}}', '@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{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 svg{width:14px;height:14px;fill:currentColor;opacity:.9}',
'.files-ctx-menu-item:hover{background:#2a2a4e}', '.files-ctx-menu-item:hover{background:var(--vt-color-surface-hover,#1b2440)}',
'.files-ctx-menu-item.danger{color:#e74c3c}', '.files-ctx-menu-item.danger{color:#ff9aaa}',
'.files-ctx-menu-item.danger:hover{background:#2a2a4e;color:#ff6b6b}', '.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:#333;margin:4px 8px}', '.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-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{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}', '.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: 'modified-desc' }, ['Modified']),
el('option', { value: 'size-desc' }, ['Size']) el('option', { value: 'size-desc' }, ['Size'])
]); ]);
trashBtn.classList.add('danger');
toolbar.appendChild(breadcrumb); 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); containerEl.appendChild(toolbar);
var listContainer = el('div', { className: 'files-list', 'data-files-list': '' }); var listContainer = el('div', { className: 'files-list', 'data-files-list': '' });
@ -647,7 +662,9 @@
'data-file-path': entry.relativePath, 'data-file-path': entry.relativePath,
draggable: 'true', draggable: 'true',
tabindex: '0', tabindex: '0',
onClick: function (e) { selectEntry(entry, e); }, onClick: function (e) {
selectEntry(entry, e);
},
onDblclick: function () { openEntry(entry); }, onDblclick: function () { openEntry(entry); },
onDragstart: function (e) { onDragstart: function (e) {
var paths = []; var paths = [];
@ -676,7 +693,7 @@
el('div', { className: 'files-row-actions' }, [ el('div', { className: 'files-row-actions' }, [
iconButton('row-open', 'Open', 'open', function (event) { event.stopPropagation(); openEntry(entry); }, 'files-row-btn'), 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-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); listContainer.appendChild(row);

View File

@ -20,30 +20,47 @@
} }
var STYLES = [ 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-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;padding:.55rem .75rem;border-bottom:1px solid #16213e;background:#12122a;flex-shrink:0;flex-wrap:wrap}', '.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-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-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{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:hover{border-color:#4ecca3;background:#2a2a4e}', '.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-btn:disabled{opacity:.45;cursor:default}',
'.journal-status{font-size:.72rem;color:#8b8ba8}', '.journal-status{font-size:.72rem;color:var(--vt-color-text-muted,#7f8aa3)}',
'.journal-status.error{color:#e74c3c}', '.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-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 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{font-size:.8rem;padding:.38rem .5rem;border:1px solid #333;border-radius:4px;background:#0d0d1a;color:#e0e0e0;min-width:0}', '.journal-input.textarea{min-height:7rem;resize:vertical;line-height:1.4}',
'.journal-input:focus{outline:none;border-color:#4ecca3}', '.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:#aaa;white-space:nowrap}', '.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:#101020}', '.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:#666;font-size:.86rem;padding:2rem;text-align:center}', '.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;gap:.7rem;padding:.75rem .85rem;border-bottom:1px solid rgba(22,33,62,.6)}', '.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-date{font-size:.75rem;color:#8b8ba8;white-space:nowrap}', '.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-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-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:#aaa;white-space:pre-wrap;overflow-wrap:anywhere}', '.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:#777}', '.journal-meta{margin-top:.25rem;font-size:.72rem;color:var(--vt-color-text-muted,#7f8aa3)}',
'.journal-minutes{font-size:.78rem;color:#4ecca3;white-space:nowrap}', '.journal-minutes{font-size:.78rem;color:var(--vt-color-accent,#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-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'); ].join('\n');
function el(tag, attrs, children) { function el(tag, attrs, children) {
@ -52,6 +69,7 @@
Object.keys(attrs).forEach(function (key) { Object.keys(attrs).forEach(function (key) {
if (attrs[key] == null) return; if (attrs[key] == null) return;
if (key === 'className') elem.className = attrs[key]; 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 === 'textContent') elem.textContent = attrs[key];
else if (key.slice(0, 2) === 'on') elem.addEventListener(key.slice(2).toLowerCase(), attrs[key]); else if (key.slice(0, 2) === 'on') elem.addEventListener(key.slice(2).toLowerCase(), attrs[key]);
else elem.setAttribute(key, 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(); 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 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true"><path d="' + (ICONS[name] || ICONS.edit) + '" fill="currentColor"/></svg>';
}
function JournalView() {} function JournalView() {}
JournalView.mount = function (containerEl, props, api) { JournalView.mount = function (containerEl, props, api) {
@ -178,6 +206,7 @@
var entries = []; var entries = [];
var statusText = 'Loading journal...'; var statusText = 'Loading journal...';
var statusClass = ''; var statusClass = '';
var modalHost = el('div', { className: 'journal-modal-host', hidden: 'hidden' });
var toolbar = el('div', { className: 'journal-toolbar' }); var toolbar = el('div', { className: 'journal-toolbar' });
var titleEl = el('span', { className: 'journal-title', textContent: scope.mode === 'global' ? 'Journal' : 'Journal · ' + scope.label }); var titleEl = el('span', { className: 'journal-title', textContent: scope.mode === 'global' ? 'Journal' : 'Journal · ' + scope.label });
@ -189,35 +218,23 @@
textContent: 'Import Activity', textContent: 'Import Activity',
onClick: importActivity onClick: importActivity
}); });
var addBtn = el('button', {
className: 'journal-btn primary',
'data-journal-action': 'add',
innerHTML: iconSvg('add') + '<span>Add</span>',
onClick: function () { showEntryModal(); }
});
toolbar.appendChild(titleEl); toolbar.appendChild(titleEl);
toolbar.appendChild(countEl); toolbar.appendChild(countEl);
toolbar.appendChild(el('span', { className: 'journal-spacer' })); toolbar.appendChild(el('span', { className: 'journal-spacer' }));
toolbar.appendChild(statusEl); toolbar.appendChild(statusEl);
toolbar.appendChild(addBtn);
toolbar.appendChild(importBtn); 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' }); var listEl = el('div', { className: 'journal-list' });
containerEl.appendChild(toolbar); containerEl.appendChild(toolbar);
if (scope.mode === 'workspace') containerEl.appendChild(formEl);
containerEl.appendChild(listEl); containerEl.appendChild(listEl);
containerEl.appendChild(modalHost);
function persist() { function persist() {
if (scope.mode !== 'workspace') return Promise.resolve(); 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; 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) { if (!title) {
statusText = 'Title is required'; statusText = 'Title is required';
statusClass = 'error'; statusClass = 'error';
@ -264,18 +331,34 @@
return; return;
} }
var entry = normalizeEntry({ 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, workspaceRootPath: scope.workspaceRoot,
date: dateInput.value || today(), date: formValue.date || today(),
title: title, title: title,
summary: summaryInput.value, summary: formValue.summary,
minutes: Number(minutesInput.value || 0), minutes: Number(formValue.minutes || 0),
billable: billableInput.checked === true billable: formValue.billable === true,
sourceSuggestionId: existingEntry ? existingEntry.sourceSuggestionId : '',
eventIds: existingEntry ? existingEntry.eventIds : []
}, scope.key); }, scope.key);
entries = sortEntries([entry].concat(entries)); if (existingEntry) {
titleInput.value = ''; entries = entries.map(function (item) {
summaryInput.value = ''; return item.entryId === existingEntry.entryId ? entry : item;
statusText = 'Entry added'; });
} 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 = ''; statusClass = '';
persist().then(render); persist().then(render);
} }
@ -352,7 +435,11 @@
entry.summary ? el('div', { className: 'journal-summary', textContent: entry.summary }) : null, 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-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'); countEl.textContent = entries.length + ' entr' + (entries.length === 1 ? 'y' : 'ies');
statusEl.textContent = statusText; statusEl.textContent = statusText;
statusEl.className = 'journal-status' + (statusClass ? ' ' + statusClass : ''); statusEl.className = 'journal-status' + (statusClass ? ' ' + statusClass : '');
addBtn.disabled = scope.mode !== 'workspace';
importBtn.disabled = scope.mode !== 'workspace' || importBtn.disabled; importBtn.disabled = scope.mode !== 'workspace' || importBtn.disabled;
renderList(); renderList();
} }

View File

@ -15,35 +15,38 @@
} }
var STYLES = [ 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-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:.45rem;padding:.5rem .75rem;border-bottom:1px solid #16213e;flex-shrink:0;background:#12122a;flex-wrap:wrap}', '.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:.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{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:#2a2a4e;border-color:#4ecca3}', '.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:disabled{opacity:.45;cursor:default}',
'.notes-btn.primary{background:#1a3a2a;border-color:#4ecca3;color:#4ecca3}', '.notes-btn.primary{background:var(--vt-color-accent,#4ecca3);border-color:var(--vt-color-accent,#4ecca3);color:#101827}',
'.notes-btn.primary:hover{background:#2a4a3a}', '.notes-btn.primary:hover{background:#63d9b3;color:#101827}',
'.notes-filter,.notes-sort{font-size:.78rem;padding:.32rem .5rem;border:1px solid #333;border-radius:4px;background:#0d0d1a;color:#e0e0e0;outline:none}', '.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-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-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:#4ecca3}', '.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-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{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:#17172d}', '.notes-item:hover{background:var(--vt-color-surface-hover,#1b2440)}',
'.notes-item.selected{background:#1a2a3a}', '.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:#8b8ba8}', '.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-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-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: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{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:#2a2a4e;border-color:#4ecca3;color:#4ecca3}', '.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-empty{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;color:#666;font-size:.85rem;padding:2rem;gap:.5rem}', '.notes-item-btn:focus-visible{outline:0;box-shadow:var(--vt-focus-ring,0 0 0 2px rgba(78,204,163,.34))}',
'.notes-empty-hint{font-size:.75rem;color:#555}', '.notes-item-btn svg{width:14px;height:14px;display:block;fill:currentColor}',
'.notes-error{flex:1;display:flex;align-items:center;justify-content:center;color:#e74c3c;padding:1rem;font-size:.85rem}', '.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-panel{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;border-top:1px solid #16213e;flex-shrink:0;background:#12122a}', '.notes-empty-hint{font-size:.75rem;color:var(--vt-color-text-muted,#7f8aa3)}',
'.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-error{flex:1;display:flex;align-items:center;justify-content:center;color:var(--vt-color-danger,#e94560);padding:1rem;font-size:.85rem}',
'.notes-input:focus{border-color:#4ecca3}', '.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-title-bar{padding:.4rem .75rem;font-size:.72rem;color:#8b8ba8;background:#101028;border-bottom:1px solid #16213e;text-transform:uppercase;letter-spacing:.04em}', '.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-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{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}', '.notes-modal-title{font-size:.9rem;font-weight:600;margin-bottom:12px}',
@ -259,7 +262,7 @@
// ─── UI Elements ──────────────────────────────────────── // ─── UI Elements ────────────────────────────────────────
var toolbar = el('div', { className: 'notes-toolbar' }); 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 filterInput = el('input', { className: 'notes-filter', 'data-notes-filter': '', placeholder: 'Filter notes' });
var sortSelect = el('select', { className: 'notes-sort', 'data-notes-sort': '' }, [ var sortSelect = el('select', { className: 'notes-sort', 'data-notes-sort': '' }, [
el('option', { value: 'title-asc' }, ['A-Z']), el('option', { value: 'title-asc' }, ['A-Z']),
@ -402,12 +405,15 @@
el('button', { el('button', {
className: 'notes-item-btn', className: 'notes-item-btn',
title: 'Open', title: 'Open',
'aria-label': 'Open',
'data-note-action': 'open',
innerHTML: iconSvg('open'), innerHTML: iconSvg('open'),
onClick: function (e) { e.stopPropagation(); openNote(note); } onClick: function (e) { e.stopPropagation(); openNote(note); }
}), }),
el('button', { el('button', {
className: 'notes-item-btn', className: 'notes-item-btn',
title: 'Rename', title: 'Rename',
'aria-label': 'Rename',
'data-note-action': 'rename', 'data-note-action': 'rename',
innerHTML: iconSvg('rename'), innerHTML: iconSvg('rename'),
onClick: function (e) { e.stopPropagation(); beginRename(note); } onClick: function (e) { e.stopPropagation(); beginRename(note); }
@ -415,6 +421,7 @@
el('button', { el('button', {
className: 'notes-item-btn', className: 'notes-item-btn',
title: 'Move to Trash', title: 'Move to Trash',
'aria-label': 'Move to Trash',
'data-note-action': 'trash', 'data-note-action': 'trash',
innerHTML: iconSvg('trash'), innerHTML: iconSvg('trash'),
onClick: function (e) { e.stopPropagation(); confirmTrashNote(note); } onClick: function (e) { e.stopPropagation(); confirmTrashNote(note); }

View File

@ -28,23 +28,30 @@
} }
var STYLES = [ 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-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;padding:.55rem .75rem;border-bottom:1px solid #16213e;background:#12122a;flex-shrink:0;flex-wrap:wrap}', '.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 #333;border-radius:4px;background:#0d0d1a;color:#e0e0e0;outline:none}', '.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:#4ecca3}', '.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;padding:.42rem .7rem;border:1px solid #333;border-radius:4px;background:#1a1a2e;color:#ddd;cursor:pointer}', '.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:#4ecca3;background:#2a2a4e}', '.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-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-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:#8b8ba8;padding:.45rem .75rem;border-bottom:1px solid rgba(22,33,62,.55);flex-shrink:0}', '.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:#e74c3c}', '.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-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-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:.5rem;padding:.7rem .85rem;border-bottom:1px solid rgba(22,33,62,.55)}', '.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:#17172d}', '.search-result:hover{background:var(--vt-color-surface-hover,#1b2440)}',
'.search-path{font-size:.84rem;color:#4ecca3;word-break:break-word}', '.search-result-head{display:flex;align-items:center;gap:.5rem;min-width:0}',
'.search-snippet{margin-top:.25rem;font-size:.8rem;line-height:1.45;color:#cfcfe0;white-space:pre-wrap;overflow-wrap:anywhere}', '.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-meta{margin-top:.28rem;font-size:.72rem;color:#777}', '.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}}' '@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'); ].join('\n');
@ -54,7 +61,9 @@
Object.keys(attrs).forEach(function (k) { Object.keys(attrs).forEach(function (k) {
if (attrs[k] == null) return; if (attrs[k] == null) return;
if (k === 'className') elem.className = attrs[k]; 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.slice(0, 2) === 'on') elem.addEventListener(k.slice(2).toLowerCase(), attrs[k]);
else if (k === 'textContent') elem.textContent = attrs[k]; else if (k === 'textContent') elem.textContent = attrs[k];
else if (k === 'innerHTML') elem.innerHTML = attrs[k]; else if (k === 'innerHTML') elem.innerHTML = attrs[k];
@ -74,6 +83,20 @@
return String(path || '').split('/').filter(Boolean).join('/'); 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) { function extension(entry) {
var explicit = String((entry && entry.extension) || '').replace(/^\./, '').toLowerCase(); var explicit = String((entry && entry.extension) || '').replace(/^\./, '').toLowerCase();
if (explicit) return explicit; if (explicit) return explicit;
@ -281,7 +304,7 @@
mount: function (containerEl, props, api) { mount: function (containerEl, props, api) {
injectStyles(); injectStyles();
var rootPath = cleanPath(props && (props.workspaceRootPath || props.workspaceName)); 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 searchTimer = null;
var searchSeq = 0; var searchSeq = 0;
var index = null; var index = null;
@ -290,6 +313,7 @@
var input = null; var input = null;
var button = null; var button = null;
var statusEl = null; var statusEl = null;
var alertEl = null;
var resultsEl = null; var resultsEl = null;
function ensureLayout() { function ensureLayout() {
@ -322,6 +346,8 @@
statusEl = el('div', { className: 'search-status' }); statusEl = el('div', { className: 'search-status' });
containerEl.appendChild(statusEl); containerEl.appendChild(statusEl);
alertEl = el('div', { className: 'search-alert', hidden: 'hidden' });
containerEl.appendChild(alertEl);
resultsEl = el('div', { className: 'search-results' }); resultsEl = el('div', { className: 'search-results' });
containerEl.appendChild(resultsEl); containerEl.appendChild(resultsEl);
} }
@ -335,6 +361,16 @@
button.disabled = !!state.searching; button.disabled = !!state.searching;
statusEl.className = 'search-status' + (state.error ? ' error' : ''); statusEl.className = 'search-status' + (state.error ? ' error' : '');
statusEl.textContent = state.error || state.status; 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 = ''; resultsEl.innerHTML = '';
if (!state.results.length) { if (!state.results.length) {
resultsEl.appendChild(el('div', { className: 'search-empty' }, [state.searching ? 'Searching...' : 'No results'])); resultsEl.appendChild(el('div', { className: 'search-empty' }, [state.searching ? 'Searching...' : 'No results']));
@ -343,6 +379,10 @@
state.results.forEach(function (result) { state.results.forEach(function (result) {
resultsEl.appendChild(el('div', { className: 'search-result' }, [ resultsEl.appendChild(el('div', { className: 'search-result' }, [
el('div', {}, [ 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-path' }, [result.path]),
el('div', { className: 'search-snippet' }, [result.snippet]), el('div', { className: 'search-snippet' }, [result.snippet]),
el('div', { className: 'search-meta' }, [ el('div', { className: 'search-meta' }, [
@ -350,7 +390,7 @@
]) ])
]), ]),
result.openable ? el('button', { result.openable ? el('button', {
className: 'search-btn', className: 'search-btn search-open-btn',
textContent: 'Open', textContent: 'Open',
'data-search-open': result.path, 'data-search-open': result.path,
onClick: function () { onClick: function () {
@ -377,6 +417,7 @@
state.results = []; state.results = [];
state.status = 'Enter at least 2 characters.'; state.status = 'Enter at least 2 characters.';
state.error = ''; state.error = '';
state.providerErrors = [];
render(); render();
return; return;
} }
@ -393,11 +434,13 @@
state.results = []; state.results = [];
state.status = 'Enter at least 2 characters.'; state.status = 'Enter at least 2 characters.';
state.error = ''; state.error = '';
state.providerErrors = [];
render(); render();
return; return;
} }
state.searching = true; state.searching = true;
state.error = ''; state.error = '';
state.providerErrors = [];
state.status = 'Searching...'; state.status = 'Searching...';
var seq = searchSeq + 1; var seq = searchSeq + 1;
searchSeq = seq; searchSeq = seq;
@ -409,13 +452,12 @@
if (seq !== searchSeq) return; if (seq !== searchSeq) return;
state.results = results.concat(external.results); state.results = results.concat(external.results);
state.status = state.results.length + ' result' + (state.results.length === 1 ? '' : 's'); state.status = state.results.length + ' result' + (state.results.length === 1 ? '' : 's');
if (external.errors.length) { state.providerErrors = external.errors;
state.status += ' - ' + external.errors.join('; ');
}
} catch (err) { } catch (err) {
if (seq !== searchSeq) return; if (seq !== searchSeq) return;
state.results = []; state.results = [];
state.error = err && err.message ? err.message : String(err); state.error = err && err.message ? err.message : String(err);
state.providerErrors = [];
} finally { } finally {
if (seq !== searchSeq) return; if (seq !== searchSeq) return;
state.searching = false; state.searching = false;

View File

@ -19,42 +19,44 @@
} }
var STYLES = [ 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-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 #252b36;background:#11151d}', '.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:#0d0f14}', '.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;padding:.65rem .75rem;border-bottom:1px solid #252b36}', '.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-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-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{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:#56b6c2;background:#222b38}', '.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:#176b5f;border-color:#248879;color:white}', '.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-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-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{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:#171d27;border-color:#293241}', '.secrets-item:hover{background:var(--vt-color-surface-hover,#1b2440);border-color:var(--vt-color-border,#202b46)}',
'.secrets-item.active{background:#18232f;border-color:#56b6c2}', '.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-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-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:#8b949e;font-size:.84rem;text-align:center}', '.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{max-width:46rem;display:grid;gap:.8rem}',
'.secrets-card h2{font-size:1rem;margin:0;color:#f0f6fc}', '.secrets-card h2{font-size:1rem;margin:0;color:var(--vt-color-text-primary,#f4f7fb)}',
'.secrets-form{display:grid;gap:.65rem;border:1px solid #252b36;border-radius:6px;padding:.9rem;background:#11151d}', '.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-row{display:grid;grid-template-columns:8rem minmax(0,1fr);gap:.65rem;align-items:center}',
'.secrets-label{font-size:.78rem;color:#8b949e}', '.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 #303844;border-radius:4px;background:#0d1117;color:#e6edf3;font:inherit;font-size:.84rem;padding:.45rem .55rem;outline:none}', '.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-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-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-actions{display:flex;gap:.5rem;flex-wrap:wrap}',
'.secrets-status{font-size:.78rem;color:#8b949e;min-height:1rem}', '.secrets-status{font-size:.78rem;color:var(--vt-color-text-muted,#7f8aa3);min-height:1rem}',
'.secrets-status.error{color:#ff8f8f}', '.secrets-status.error{color:#ffc6ce}',
'.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-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-table{width:100%;border-collapse:collapse;border:1px solid #252b36;background:#11151d;border-radius:6px;overflow:hidden}', '.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 th,.secrets-table td{border-bottom:1px solid #252b36;padding:.55rem .65rem;text-align:left;vertical-align:top;font-size:.84rem}', '.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{width:9rem;color:#8b949e;font-weight:500;background:#151a23}', '.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 td{color:#e6edf3;overflow-wrap:anywhere}', '.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}', '.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}}' '@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'); ].join('\n');
@ -262,7 +264,7 @@
fieldRow('Group', scopeLabel(selectedRecord)), fieldRow('Group', scopeLabel(selectedRecord)),
fieldRow('ID', selectedRecord.id), fieldRow('ID', selectedRecord.id),
fieldRow('Username', selectedRecord.username || ''), fieldRow('Username', selectedRecord.username || ''),
fieldRow('Password', selectedValue ? selectedValue : 'Value hidden'), fieldRow('Password', selectedValue ? selectedValue : '••••••••••••', selectedValue ? '' : 'secrets-hidden-value'),
fieldRow('Updated', selectedRecord.updatedAt || '') fieldRow('Updated', selectedRecord.updatedAt || '')
]) ])
]), ]),
@ -280,7 +282,7 @@
onClick: function () { showEditSecret(); } onClick: function () { showEditSecret(); }
}, ['Edit']), }, ['Edit']),
el('button', { el('button', {
className: 'secrets-btn', className: 'secrets-btn danger',
type: 'button', type: 'button',
'data-secret-delete': selectedRecord.id, 'data-secret-delete': selectedRecord.id,
onClick: function () { deleteSecret(selectedRecord.id); } onClick: function () { deleteSecret(selectedRecord.id); }
@ -290,10 +292,10 @@
]); ]);
} }
function fieldRow(label, value) { function fieldRow(label, value, valueClass) {
return el('tr', {}, [ return el('tr', {}, [
el('th', {}, [label]), el('th', {}, [label]),
el('td', {}, [value || '']) el('td', {}, [valueClass ? el('span', { className: valueClass }, [value || '']) : (value || '')])
]); ]);
} }

View File

@ -344,10 +344,18 @@ async function mountWithApi(api, props = { workspaceNode: { name: 'Project' }, w
summary: 'Notes/Case.md', summary: 'Notes/Case.md',
occurredAt: '2026-06-27T01:00:00Z', occurredAt: '2026-06-27T01:00:00Z',
sourcePluginId: 'verstak.notes', 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); 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('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({ const legacyApi = makeApi({
events: [ events: [

View File

@ -200,17 +200,31 @@ function byData(container, attr, value) {
const { component, container } = await mountWithApi(api); const { component, container } = await mountWithApi(api);
const projectKey = 'worklog:workspace:Project'; 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', 'date').value = '2026-06-27';
byData(container, 'data-journal-input', 'title').value = 'Draft brief'; byData(container, 'data-journal-input', 'title').value = 'Draft brief';
byData(container, 'data-journal-input', 'summary').value = 'Reviewed docs'; byData(container, 'data-journal-input', 'summary').value = 'Reviewed docs';
byData(container, 'data-journal-input', 'minutes').value = '45'; 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(); await flush();
if (api.storedEntries(projectKey).length !== 1) throw new Error('manual journal entry was not stored'); 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('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'); 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(); byData(container, 'data-journal-action', 'import-activity').click();
await flush(); await flush();
@ -223,9 +237,14 @@ function byData(container, attr, value) {
await flush(); await flush();
if (api.storedEntries(projectKey).length !== 2) throw new Error('duplicate activity suggestion was imported'); 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, {}); 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') && !globalView.container.textContent.includes('Draft brief updated')) {
if (!globalView.container.textContent.includes('Project work on 2026-06-27')) throw new Error('global journal did not aggregate imported suggestion'); throw new Error('global journal did not aggregate remaining entries');
}
component.unmount && component.unmount(container); component.unmount && component.unmount(container);
component.unmount && component.unmount(globalView.container); component.unmount && component.unmount(globalView.container);