summaryrefslogtreecommitdiff
path: root/vrsite/assets
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-08-02 12:36:54 -0300
committerGabriel Schneider <[email protected]>2026-08-02 17:37:58 -0300
commite16f78b255bcf46d8c6f9a4b9e76dd7a3817edeb (patch)
treede0db0c369522b5bf92ff32a8351de2224c5c9dc /vrsite/assets
parent151ea12251ed876aa87bb486da1bc337e25369e9 (diff)
downloadnotevi-e16f78b255bcf46d8c6f9a4b9e76dd7a3817edeb.tar.gz
notevi-e16f78b255bcf46d8c6f9a4b9e76dd7a3817edeb.zip
Diffstat (limited to 'vrsite/assets')
-rw-r--r--vrsite/assets/app.js20
-rw-r--r--vrsite/assets/style.css.tmpl25
2 files changed, 45 insertions, 0 deletions
diff --git a/vrsite/assets/app.js b/vrsite/assets/app.js
index 696041c..74db8d2 100644
--- a/vrsite/assets/app.js
+++ b/vrsite/assets/app.js
@@ -22,6 +22,26 @@ setMode(root.dataset.mode || "trace");
const typing = e =>
/^(INPUT|TEXTAREA|SELECT)$/.test(e.target.tagName) || e.target.isContentEditable;
+// The project hub is fully server-derived; filtering is deliberately local so
+// choosing a project does not create another piece of server state.
+const projectFind = document.getElementById("projectfind");
+if (projectFind) {
+ const apply = () => {
+ const q = projectFind.value.trim().toLowerCase();
+ for (const card of document.querySelectorAll(".project-card"))
+ card.hidden = !!q && !(card.dataset.project || "").toLowerCase().includes(q);
+ };
+ projectFind.addEventListener("input", apply);
+ projectFind.addEventListener("search", apply);
+ projectFind.addEventListener("keydown", e => {
+ if (e.key === "Escape") { projectFind.value = ""; apply(); projectFind.blur(); }
+ if (e.key === "Enter") {
+ const first = document.querySelector(".project-card:not([hidden]) a.project-action");
+ if (first) first.click();
+ }
+ });
+}
+
document.addEventListener("keydown", e => {
if (e.metaKey || e.ctrlKey || e.altKey || typing(e)) return;
if (e.key === "t") setMode(root.dataset.mode === "notes" ? "trace" : "notes");
diff --git a/vrsite/assets/style.css.tmpl b/vrsite/assets/style.css.tmpl
index 9418087..60d2a2b 100644
--- a/vrsite/assets/style.css.tmpl
+++ b/vrsite/assets/style.css.tmpl
@@ -537,6 +537,31 @@ table.changed .st { color: var(--muted); font-size: 11px; width: 7ch; }
table.changed .st-added { color: var(--accent); }
table.changed .st-deleted { color: var(--note); }
+/* ── project hub ───────────────────────────────────────────── */
+.projects-main { padding-bottom: 20vh; }
+.projects-main > section { max-width: 1200px; }
+.project-refresh { margin: 10px 0; }
+.project-refresh button, .project-card button, .project-action {
+ display: inline-block; background: var(--panel); color: var(--fg);
+ border: 1px solid var(--border); border-radius: 5px;
+ font: inherit; font-size: 12px; padding: 5px 10px; cursor: pointer;
+}
+.project-refresh button:hover, .project-card button:hover, .project-action:hover {
+ background: var(--hover); text-decoration: none;
+}
+.project-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 10px; }
+.project-card { min-width: 0; padding: 12px; border: 1px solid var(--border); border-radius: 7px; background: var(--panel); }
+.project-card > header { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
+.project-card h3 { min-width: 0; margin: 0; font: 600 14px/1.3 ui-monospace, Menlo, monospace; overflow: hidden; text-overflow: ellipsis; }
+.project-path { margin: 8px 0; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
+.project-state { flex: none; padding: 1px 6px; border: 1px solid var(--border); border-radius: 99px; color: var(--muted); font-size: 10px; text-transform: uppercase; }
+.project-state.active { border-color: var(--accent); color: var(--accent); }
+.project-state.git { color: var(--note); }
+.project-card form, .project-card .project-action { margin-top: 10px; }
+.project-message { max-width: 1168px; }
+.ok { margin: 12px 16px; padding: 8px 10px; border: 1px solid var(--accent); border-radius: 6px; color: var(--accent); }
+.project-card[hidden] { display: none; }
+
/* ── agent coverage colors ──────────────────────────────────
A bitmask is its agents' colors averaged. The blend is left to the
browser so these rules hold for any theme: a theme only has to name