Merge branch 'dev'
CI/CD / deploy (push) Successful in 5m39s
Details
CI/CD / deploy (push) Successful in 5m39s
Details
This commit is contained in:
commit
38582a5d12
|
|
@ -388,8 +388,9 @@ export function renderShell(opts: ShellOptions): string {
|
||||||
});
|
});
|
||||||
}).catch(() => {});
|
}).catch(() => {});
|
||||||
let refreshing = false;
|
let refreshing = false;
|
||||||
|
const hadController = !!navigator.serviceWorker.controller;
|
||||||
navigator.serviceWorker.addEventListener('controllerchange', () => {
|
navigator.serviceWorker.addEventListener('controllerchange', () => {
|
||||||
if (refreshing) return;
|
if (!hadController || refreshing) return;
|
||||||
refreshing = true;
|
refreshing = true;
|
||||||
location.reload();
|
location.reload();
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,9 @@
|
||||||
html.rspace-embedded .rstack-tab-row { display: none !important; }
|
html.rspace-embedded .rstack-tab-row { display: none !important; }
|
||||||
html.rspace-embedded #toolbar { bottom: 16px !important; }
|
html.rspace-embedded #toolbar { bottom: 16px !important; }
|
||||||
html.rspace-embedded #community-info { display: none !important; }
|
html.rspace-embedded #community-info { display: none !important; }
|
||||||
|
/* Hide module-gated toolbar items until JS confirms they're enabled */
|
||||||
|
[data-requires-module] { display: none !important; }
|
||||||
|
[data-requires-module].mod-enabled { display: revert !important; }
|
||||||
</style>
|
</style>
|
||||||
<script>if (window.self !== window.parent) document.documentElement.classList.add('rspace-embedded');</script>
|
<script>if (window.self !== window.parent) document.documentElement.classList.add('rspace-embedded');</script>
|
||||||
<style>
|
<style>
|
||||||
|
|
@ -2573,44 +2576,49 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
// Load module list for app switcher and tab bar + menu
|
// Load module list for app switcher and tab bar + menu
|
||||||
// Parallel fetch: modules + space-specific filter — setModules called once
|
// Skip fetch if shell.ts already injected module data (avoids toolbar flash)
|
||||||
let moduleList = [];
|
if (!window.__rspaceEnabledModules) {
|
||||||
const spaceSlug = window.location.pathname.split("/").filter(Boolean)[0] || "demo";
|
let moduleList = [];
|
||||||
Promise.all([
|
const spaceSlug = window.location.pathname.split("/").filter(Boolean)[0] || "demo";
|
||||||
fetch("/api/modules").then(r => r.json()),
|
Promise.all([
|
||||||
fetch(`/api/spaces/${encodeURIComponent(spaceSlug)}/modules`).then(r => r.ok ? r.json() : null),
|
fetch("/api/modules").then(r => r.json()),
|
||||||
]).then(([data, spaceData]) => {
|
fetch(`/api/spaces/${encodeURIComponent(spaceSlug)}/modules`).then(r => r.ok ? r.json() : null),
|
||||||
moduleList = data.modules || [];
|
]).then(([data, spaceData]) => {
|
||||||
window.__rspaceAllModules = moduleList;
|
moduleList = data.modules || [];
|
||||||
|
window.__rspaceAllModules = moduleList;
|
||||||
|
|
||||||
const enabledIds = spaceData?.enabledModules ?? null;
|
const enabledIds = spaceData?.enabledModules ?? null;
|
||||||
window.__rspaceEnabledModules = enabledIds;
|
window.__rspaceEnabledModules = enabledIds;
|
||||||
|
|
||||||
const visible = enabledIds
|
const visible = enabledIds
|
||||||
? moduleList.filter(m => m.id === "rspace" || new Set(enabledIds).has(m.id))
|
? moduleList.filter(m => m.id === "rspace" || new Set(enabledIds).has(m.id))
|
||||||
: moduleList;
|
: moduleList;
|
||||||
|
|
||||||
document.querySelector("rstack-app-switcher")?.setModules(visible);
|
document.querySelector("rstack-app-switcher")?.setModules(visible);
|
||||||
const tb = document.querySelector("rstack-tab-bar");
|
const tb = document.querySelector("rstack-tab-bar");
|
||||||
if (tb) tb.setModules(visible);
|
if (tb) tb.setModules(visible);
|
||||||
|
|
||||||
// Initialize folk-rapp filtering
|
// Initialize folk-rapp filtering
|
||||||
customElements.whenDefined("folk-rapp").then(() => {
|
customElements.whenDefined("folk-rapp").then(() => {
|
||||||
const FolkRApp = customElements.get("folk-rapp");
|
const FolkRApp = customElements.get("folk-rapp");
|
||||||
if (FolkRApp?.setEnabledModules) FolkRApp.setEnabledModules(enabledIds);
|
if (FolkRApp?.setEnabledModules) FolkRApp.setEnabledModules(enabledIds);
|
||||||
});
|
});
|
||||||
// Initialize rTime shape disabled states
|
// Initialize rTime shape disabled states
|
||||||
customElements.whenDefined("folk-commitment-pool").then(() => {
|
customElements.whenDefined("folk-commitment-pool").then(() => {
|
||||||
const cls = customElements.get("folk-commitment-pool");
|
const cls = customElements.get("folk-commitment-pool");
|
||||||
if (cls?.setEnabledModules) cls.setEnabledModules(enabledIds);
|
if (cls?.setEnabledModules) cls.setEnabledModules(enabledIds);
|
||||||
});
|
});
|
||||||
customElements.whenDefined("folk-task-request").then(() => {
|
customElements.whenDefined("folk-task-request").then(() => {
|
||||||
const cls = customElements.get("folk-task-request");
|
const cls = customElements.get("folk-task-request");
|
||||||
if (cls?.setEnabledModules) cls.setEnabledModules(enabledIds);
|
if (cls?.setEnabledModules) cls.setEnabledModules(enabledIds);
|
||||||
});
|
});
|
||||||
// Overlay disabled-module shapes on canvas
|
// Overlay disabled-module shapes on canvas
|
||||||
syncCanvasShapeModuleStates(enabledIds);
|
syncCanvasShapeModuleStates(enabledIds);
|
||||||
}).catch(() => {});
|
}).catch(() => {});
|
||||||
|
} else {
|
||||||
|
// Shell already set module data — just sync shape states
|
||||||
|
syncCanvasShapeModuleStates(window.__rspaceEnabledModules);
|
||||||
|
}
|
||||||
|
|
||||||
// React to runtime module toggling from app switcher
|
// React to runtime module toggling from app switcher
|
||||||
document.addEventListener("modules-changed", (e) => {
|
document.addEventListener("modules-changed", (e) => {
|
||||||
|
|
@ -2636,12 +2644,12 @@
|
||||||
syncCanvasShapeModuleStates(enabledModules);
|
syncCanvasShapeModuleStates(enabledModules);
|
||||||
|
|
||||||
document.querySelectorAll("[data-requires-module]").forEach(el => {
|
document.querySelectorAll("[data-requires-module]").forEach(el => {
|
||||||
el.style.display = enabledSet.has(el.dataset.requiresModule) ? "" : "none";
|
el.classList.toggle("mod-enabled", enabledSet.has(el.dataset.requiresModule));
|
||||||
});
|
});
|
||||||
document.querySelectorAll(".toolbar-group").forEach(group => {
|
document.querySelectorAll(".toolbar-group").forEach(group => {
|
||||||
const dropdown = group.querySelector(".toolbar-dropdown");
|
const dropdown = group.querySelector(".toolbar-dropdown");
|
||||||
if (!dropdown) return;
|
if (!dropdown) return;
|
||||||
const vis = dropdown.querySelectorAll('button:not([style*="display: none"]):not(.toolbar-dropdown-header)');
|
const vis = dropdown.querySelectorAll('button.mod-enabled, button:not([data-requires-module]):not(.toolbar-dropdown-header)');
|
||||||
group.style.display = vis.length === 0 ? "none" : "";
|
group.style.display = vis.length === 0 ? "none" : "";
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -2670,60 +2678,7 @@
|
||||||
window.__rspaceTabBar = tabBar;
|
window.__rspaceTabBar = tabBar;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register service worker for offline support
|
// Service worker registration handled by shell.ts — no duplicate here
|
||||||
if ("serviceWorker" in navigator && window.location.hostname !== "localhost") {
|
|
||||||
navigator.serviceWorker.register("/sw.js?v=4").then((reg) => {
|
|
||||||
console.log("[Canvas] Service worker registered, scope:", reg.scope);
|
|
||||||
}).catch((err) => {
|
|
||||||
console.warn("[Canvas] Service worker registration failed:", err);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update banner: detect new SW activation and prompt reload
|
|
||||||
if (navigator.serviceWorker.controller) {
|
|
||||||
navigator.serviceWorker.addEventListener("controllerchange", () => {
|
|
||||||
if (!document.getElementById("sw-update-banner")) {
|
|
||||||
showSwUpdateBanner();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
navigator.serviceWorker.getRegistration().then((reg) => {
|
|
||||||
if (!reg) return;
|
|
||||||
if (reg.waiting && navigator.serviceWorker.controller) {
|
|
||||||
showSwUpdateBanner();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
reg.addEventListener("updatefound", () => {
|
|
||||||
const nw = reg.installing;
|
|
||||||
if (!nw) return;
|
|
||||||
nw.addEventListener("statechange", () => {
|
|
||||||
if (nw.state === "installed" && navigator.serviceWorker.controller) {
|
|
||||||
showSwUpdateBanner();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
function showSwUpdateBanner() {
|
|
||||||
if (document.getElementById("sw-update-banner")) return;
|
|
||||||
const b = document.createElement("div");
|
|
||||||
b.id = "sw-update-banner";
|
|
||||||
b.setAttribute("role", "alert");
|
|
||||||
Object.assign(b.style, {
|
|
||||||
position: "fixed", top: "0", left: "0", right: "0", zIndex: "10000",
|
|
||||||
display: "flex", alignItems: "center", justifyContent: "center", gap: "12px",
|
|
||||||
padding: "10px 16px", background: "linear-gradient(135deg, #6366f1, #8b5cf6)",
|
|
||||||
color: "white", fontSize: "14px", fontWeight: "500",
|
|
||||||
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
||||||
boxShadow: "0 2px 12px rgba(0,0,0,0.3)",
|
|
||||||
animation: "sw-slide-down 0.3s ease-out",
|
|
||||||
});
|
|
||||||
b.innerHTML = '<span>New version available</span>'
|
|
||||||
+ '<button style="padding:5px 14px;border-radius:6px;border:1.5px solid rgba(255,255,255,0.5);background:rgba(255,255,255,0.15);color:white;font-size:13px;font-weight:600;cursor:pointer">Tap to update</button>'
|
|
||||||
+ '<button style="position:absolute;right:12px;top:50%;transform:translateY(-50%);background:none;border:none;color:rgba(255,255,255,0.7);font-size:20px;cursor:pointer;padding:4px 8px;line-height:1" aria-label="Dismiss">×</button>';
|
|
||||||
document.body.prepend(b);
|
|
||||||
b.querySelector("button")?.addEventListener("click", () => location.reload());
|
|
||||||
b.querySelector("[aria-label=Dismiss]")?.addEventListener("click", () => b.remove());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register custom elements
|
// Register custom elements
|
||||||
FolkShape.define();
|
FolkShape.define();
|
||||||
|
|
@ -5141,22 +5096,29 @@ Use real coordinates, YYYY-MM-DD dates, ISO currency codes. Ask clarifying quest
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Hide toolbar items for disabled modules
|
// Show/hide toolbar items based on enabled modules
|
||||||
|
// Items start hidden via CSS ([data-requires-module] { display:none }),
|
||||||
|
// enabled ones get .mod-enabled class to become visible
|
||||||
const _enabledMods = window.__rspaceEnabledModules;
|
const _enabledMods = window.__rspaceEnabledModules;
|
||||||
if (_enabledMods) {
|
if (_enabledMods) {
|
||||||
const _enabledSet = new Set(_enabledMods);
|
const _enabledSet = new Set(_enabledMods);
|
||||||
document.querySelectorAll('[data-requires-module]').forEach(el => {
|
document.querySelectorAll('[data-requires-module]').forEach(el => {
|
||||||
if (!_enabledSet.has(el.dataset.requiresModule)) {
|
if (_enabledSet.has(el.dataset.requiresModule)) {
|
||||||
el.style.display = 'none';
|
el.classList.add('mod-enabled');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Hide empty toolbar groups (all visible items hidden)
|
// Hide empty toolbar groups (all items disabled)
|
||||||
document.querySelectorAll('.toolbar-group').forEach(group => {
|
document.querySelectorAll('.toolbar-group').forEach(group => {
|
||||||
const dropdown = group.querySelector('.toolbar-dropdown');
|
const dropdown = group.querySelector('.toolbar-dropdown');
|
||||||
if (!dropdown) return;
|
if (!dropdown) return;
|
||||||
const visibleItems = dropdown.querySelectorAll('button:not([style*="display: none"]):not(.toolbar-dropdown-header)');
|
const visibleItems = dropdown.querySelectorAll('button.mod-enabled, button:not([data-requires-module]):not(.toolbar-dropdown-header)');
|
||||||
if (visibleItems.length === 0) group.style.display = 'none';
|
if (visibleItems.length === 0) group.style.display = 'none';
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
// No module filter — show all items
|
||||||
|
document.querySelectorAll('[data-requires-module]').forEach(el => {
|
||||||
|
el.classList.add('mod-enabled');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// rApp embed buttons — embed any module as a folk-rapp shape on the canvas
|
// rApp embed buttons — embed any module as a folk-rapp shape on the canvas
|
||||||
|
|
@ -6969,10 +6931,14 @@ Use real coordinates, YYYY-MM-DD dates, ISO currency codes. Ask clarifying quest
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Close panel when clicking outside toolbar + panel
|
// Close panel + collapse toolbar when clicking outside
|
||||||
document.addEventListener("click", (e) => {
|
document.addEventListener("click", (e) => {
|
||||||
if (!e.target.closest("#toolbar") && !e.target.closest("#toolbar-panel")) {
|
if (!e.target.closest("#toolbar") && !e.target.closest("#toolbar-panel")) {
|
||||||
closeToolbarPanel();
|
closeToolbarPanel();
|
||||||
|
// Collapse expanded toolbar back to wrench icon
|
||||||
|
if (!toolbarEl.classList.contains("collapsed")) {
|
||||||
|
document.getElementById("toolbar-collapse")?.click();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue