claude-code-memory-explorer 0.7.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/public/app.js +75 -24
- package/public/style.css +4 -1
package/package.json
CHANGED
package/public/app.js
CHANGED
|
@@ -137,7 +137,7 @@ function buildThemeMenu() {
|
|
|
137
137
|
const menu = document.getElementById('themeMenu');
|
|
138
138
|
menu.innerHTML = COLOR_THEMES.map(
|
|
139
139
|
([id, label]) =>
|
|
140
|
-
`<button type="button" class="theme-menu-item" data-theme-id="${id}"
|
|
140
|
+
`<button type="button" class="theme-menu-item theme-swatch-${id}" data-theme-id="${id}"
|
|
141
141
|
onclick="event.stopPropagation(); setColorTheme('${id}'); toggleThemeMenu()">
|
|
142
142
|
<span class="theme-swatch theme-swatch-${id}"><i class="sw-bg"></i><i class="sw-accent"></i><i class="sw-ink"></i></span>${label}
|
|
143
143
|
</button>`,
|
|
@@ -194,6 +194,20 @@ async function loadProject() {
|
|
|
194
194
|
document.getElementById('projectBtn').title = projectData.path;
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
+
// Shared by the project picker, the boot restore, and the hub project shim. Throws with the
|
|
198
|
+
// server's error message so callers can surface it directly.
|
|
199
|
+
async function putProject(dirPath) {
|
|
200
|
+
const res = await fetch('/api/project', {
|
|
201
|
+
method: 'PUT',
|
|
202
|
+
headers: { 'Content-Type': 'application/json' },
|
|
203
|
+
body: JSON.stringify({ path: dirPath }),
|
|
204
|
+
});
|
|
205
|
+
if (!res.ok) {
|
|
206
|
+
const err = await res.json().catch(() => ({}));
|
|
207
|
+
throw new Error(err.error || `${res.status}`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
197
211
|
function changeProject() {
|
|
198
212
|
const current = document.getElementById('projectBtn').title;
|
|
199
213
|
document.getElementById('projectPathInput').value = current;
|
|
@@ -209,20 +223,10 @@ async function submitProjectPicker() {
|
|
|
209
223
|
btn.disabled = true;
|
|
210
224
|
btn.textContent = 'Switching...';
|
|
211
225
|
try {
|
|
212
|
-
|
|
213
|
-
method: 'PUT',
|
|
214
|
-
headers: { 'Content-Type': 'application/json' },
|
|
215
|
-
body: JSON.stringify({ path: dirPath }),
|
|
216
|
-
});
|
|
217
|
-
if (!res.ok) {
|
|
218
|
-
const err = await res.json();
|
|
219
|
-
showToast(err.error, 'error');
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
226
|
+
await putProject(dirPath);
|
|
222
227
|
closeModal('projectPickerModal');
|
|
223
228
|
addRecentProject(dirPath);
|
|
224
|
-
await loadProject();
|
|
225
|
-
await loadData();
|
|
229
|
+
await Promise.all([loadProject(), loadData()]);
|
|
226
230
|
showToast('Project switched', 'success');
|
|
227
231
|
} catch (err) {
|
|
228
232
|
showToast(err.message, 'error');
|
|
@@ -977,14 +981,24 @@ document.addEventListener('keydown', (e) => {
|
|
|
977
981
|
.catch(() => ({}));
|
|
978
982
|
if (!cfg.enabled) return;
|
|
979
983
|
window.__HUB__ = cfg;
|
|
984
|
+
const fwd = (e) =>
|
|
985
|
+
window.parent?.postMessage(
|
|
986
|
+
{ type: 'hub:keydown', key: e.key, ctrl: e.ctrlKey, alt: e.altKey, shift: e.shiftKey },
|
|
987
|
+
'*',
|
|
988
|
+
);
|
|
980
989
|
document.addEventListener('keydown', (e) => {
|
|
981
990
|
if (e.ctrlKey && e.altKey && (e.key === 'ArrowLeft' || e.key === 'ArrowRight')) {
|
|
982
991
|
e.preventDefault();
|
|
983
|
-
|
|
992
|
+
fwd(e);
|
|
993
|
+
}
|
|
994
|
+
// Its own branch: the Alt+digit case below requires !ctrlKey.
|
|
995
|
+
if (e.ctrlKey && e.altKey && !e.shiftKey && !e.metaKey && e.key.toLowerCase() === 'p') {
|
|
996
|
+
e.preventDefault();
|
|
997
|
+
fwd(e);
|
|
984
998
|
}
|
|
985
999
|
if (e.altKey && !e.ctrlKey && !e.shiftKey && !e.metaKey && /^[1-9]$/.test(e.key)) {
|
|
986
1000
|
e.preventDefault();
|
|
987
|
-
|
|
1001
|
+
fwd(e);
|
|
988
1002
|
}
|
|
989
1003
|
});
|
|
990
1004
|
})();
|
|
@@ -994,10 +1008,12 @@ function _hubNavigate(app, url) {
|
|
|
994
1008
|
window.parent?.postMessage({ type: 'hub:navigate', app, url }, '*');
|
|
995
1009
|
}
|
|
996
1010
|
|
|
1011
|
+
// Hoisted out of initHubTheme so initHubProject can share it.
|
|
1012
|
+
const hubOrigin = () => (window.__HUB__?.url ? new URL(window.__HUB__.url).origin : null);
|
|
1013
|
+
|
|
997
1014
|
(function initHubTheme() {
|
|
998
1015
|
const getTheme = () => (document.body.classList.contains('light') ? 'light' : 'dark');
|
|
999
1016
|
const getColorTheme = () => document.body.dataset.colorTheme || 'ember';
|
|
1000
|
-
const hubOrigin = () => (window.__HUB__?.url ? new URL(window.__HUB__.url).origin : null);
|
|
1001
1017
|
// lastTheme/lastColorTheme are updated synchronously when applying a hub
|
|
1002
1018
|
// message, so the (async) observer sees no diff and doesn't echo it back.
|
|
1003
1019
|
let lastTheme = getTheme();
|
|
@@ -1028,6 +1044,36 @@ function _hubNavigate(app, url) {
|
|
|
1028
1044
|
});
|
|
1029
1045
|
})();
|
|
1030
1046
|
|
|
1047
|
+
// Set synchronously when the hub pushes a project, so the DOMContentLoaded restore below can't
|
|
1048
|
+
// let a stale localStorage recent win the race against the hub's choice.
|
|
1049
|
+
let hubProjectPath = null;
|
|
1050
|
+
|
|
1051
|
+
(function initHubProject() {
|
|
1052
|
+
let lastApplied = null;
|
|
1053
|
+
window.addEventListener('message', async (e) => {
|
|
1054
|
+
if (e.source !== window.parent || e.origin !== hubOrigin()) return;
|
|
1055
|
+
if (e.data?.type !== 'hub:project') return;
|
|
1056
|
+
const dirPath = e.data.project;
|
|
1057
|
+
if (typeof dirPath !== 'string' || !dirPath) return;
|
|
1058
|
+
hubProjectPath = dirPath;
|
|
1059
|
+
// Dedupes against the last applied value, not just an in-flight one: the hub re-posts on
|
|
1060
|
+
// every iframe load, so without this each load would PUT and reload twice.
|
|
1061
|
+
if (lastApplied === dirPath) return;
|
|
1062
|
+
lastApplied = dirPath;
|
|
1063
|
+
try {
|
|
1064
|
+
await putProject(dirPath);
|
|
1065
|
+
// The hub does not persist its own scope, so a hub-pushed project must become the recent
|
|
1066
|
+
// head here: after a hard refresh the boot path PUTs getRecentProjects()[0], which would
|
|
1067
|
+
// otherwise clobber the server's hub-scoped project with the previous one.
|
|
1068
|
+
addRecentProject(dirPath);
|
|
1069
|
+
await Promise.all([loadProject(), loadData()]);
|
|
1070
|
+
} catch (err) {
|
|
1071
|
+
lastApplied = null;
|
|
1072
|
+
console.warn('hub:project failed:', err.message);
|
|
1073
|
+
}
|
|
1074
|
+
});
|
|
1075
|
+
})();
|
|
1076
|
+
|
|
1031
1077
|
// #endregion HUB_INTEGRATION
|
|
1032
1078
|
|
|
1033
1079
|
// #region RESIZE
|
|
@@ -1086,16 +1132,21 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|
|
1086
1132
|
// Handle ?project= query param, else restore last-used project from localStorage
|
|
1087
1133
|
const params = new URLSearchParams(location.search);
|
|
1088
1134
|
let desiredProject = params.get('project');
|
|
1089
|
-
|
|
1135
|
+
// A hub-pushed project outranks the localStorage recent: initHub() is fire-and-forget at script
|
|
1136
|
+
// eval, so hub:project can land before or during this block.
|
|
1137
|
+
if (!desiredProject) desiredProject = hubProjectPath || getRecentProjects()[0] || null;
|
|
1090
1138
|
if (desiredProject) {
|
|
1091
1139
|
try {
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1140
|
+
await putProject(desiredProject);
|
|
1141
|
+
} catch {
|
|
1142
|
+
if (params.has('project')) showToast('Failed to switch project', 'error');
|
|
1143
|
+
}
|
|
1144
|
+
// A push that arrived while the PUT above was in flight must still win.
|
|
1145
|
+
if (hubProjectPath && hubProjectPath !== desiredProject) {
|
|
1146
|
+
try {
|
|
1147
|
+
await putProject(hubProjectPath);
|
|
1148
|
+
} catch {}
|
|
1149
|
+
}
|
|
1099
1150
|
}
|
|
1100
1151
|
if (params.has('project')) {
|
|
1101
1152
|
params.delete('project');
|
package/public/style.css
CHANGED
|
@@ -202,8 +202,11 @@ body {
|
|
|
202
202
|
background: var(--bg-hover);
|
|
203
203
|
color: var(--text-primary);
|
|
204
204
|
}
|
|
205
|
+
/* Highlighted with the row's *own* theme accent rather than the active theme's, so the selected
|
|
206
|
+
row previews the theme it names. --sw-accent comes from the theme-swatch-<id> class on the row. */
|
|
205
207
|
.theme-menu-item.on {
|
|
206
|
-
color: var(--accent-text);
|
|
208
|
+
color: var(--sw-accent, var(--accent-text));
|
|
209
|
+
background: color-mix(in srgb, var(--sw-accent, var(--accent-text)) 16%, transparent);
|
|
207
210
|
}
|
|
208
211
|
/* 3-dot palette preview: surface, accent, ink (colors from themes.css vars) */
|
|
209
212
|
.theme-swatch {
|