From e04915882eebbf5aa5158c8339368f78a58ae826 Mon Sep 17 00:00:00 2001 From: Kjell Tore Guttormsen Date: Sun, 10 May 2026 16:17:13 +0200 Subject: [PATCH] feat(voyage): add webkitdirectory primary project-loader --- .../voyage/playground/voyage-playground.html | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/plugins/voyage/playground/voyage-playground.html b/plugins/voyage/playground/voyage-playground.html index 3b064b7..65e8b90 100644 --- a/plugins/voyage/playground/voyage-playground.html +++ b/plugins/voyage/playground/voyage-playground.html @@ -506,6 +506,18 @@
+ + +
'; } + // ---- v4.3 Step 11 — webkitdirectory project-loader ---------------- + // Wire the [data-action="open-project-picker"] button (rendered by + // renderTopbar) to the hidden [data-load-input] file picker. On change, + // pipe files to loadProjectDirectory (Step 13). If webkitdirectory is + // unsupported, render a guide-panel--warn near the dropzone area. + function wireProjectLoader() { + var input = document.querySelector('[data-load-input]'); + if (!input) return; + // Browser-support detection (Firefox <50, very old Safari) + if (!('webkitdirectory' in input) && !('directory' in input)) { + var warn = document.createElement('section'); + warn.className = 'guide-panel guide-panel--warn'; + warn.setAttribute('role', 'status'); + warn.innerHTML = + '
Nettleseren støtter ikke mappevalg
' + + '
Bruk paste-import nedenfor for å laste inn ' + + 'brief.md, plan.md eller review.md.
'; + var main = document.getElementById('main-content'); + if (main) main.insertBefore(warn, main.firstChild); + return; + } + + // Click-delegation: clicking the visible button programmatically clicks the hidden input. + document.addEventListener('click', function (e) { + var btn = e.target && e.target.closest && e.target.closest('[data-action="open-project-picker"]'); + if (!btn) return; + e.preventDefault(); + input.click(); + }); + + // Change-handler: derive basePath from first file's webkitRelativePath. + input.addEventListener('change', function (e) { + var files = e.target.files; + if (!files || !files.length) return; + var first = files[0].webkitRelativePath || ''; + var basePath = first.split('/')[0] || ''; + if (typeof loadProjectDirectory === 'function') { + loadProjectDirectory(files, basePath); + } else { + // Step 13 not yet wired — log-only fallback for incremental delivery. + try { console.log('[voyage] project-loader: ' + files.length + ' files in ' + basePath); } catch (_) {} + } + }); + } + // ---- v4.3 Step 9 — renderPageShell -------------------------------- // Universal page-header for dashboard + artifact-detail flater. // Returns an HTML string wrapping body content with DS Tier 3 @@ -1589,6 +1646,10 @@ playground first-run shows a complete round-trip-able artifact. // Step 8 (v4.3) — initial topbar render with single-crumb (voyage root). // renderDashboard / drill-down (Wave 3) re-renders with deeper crumbs. renderTopbar([{ label: 'Hjem' }]); + + // Step 11 (v4.3) — webkitdirectory project-loader wiring (button + + // hidden file-input + browser-support detection). + wireProjectLoader(); } function setThemeLabel(theme) {