Skip to content

Commit b0ea36e

Browse files
author
DavidQ
committed
Enforce workspace palette locking and workspace-gated tool usage
- added second workspace lock overlay on actual tool surface below header - kept existing tile overlay and workspace action gating behavior - disabled Save/Save As/Close Workspace until workspace is loaded - updated Palette Browser shared-palette flow: - block reserved palette names for workspace assignment - lock shared palette after initial assignment - show explicit alert to edit swatches when palette is locked
1 parent 19ecf00 commit b0ea36e

5 files changed

Lines changed: 256 additions & 23 deletions

File tree

tools/Palette Browser/main.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ function renderPaletteList() {
234234
function renderSelectedPalette() {
235235
const palette = getSelectedPalette();
236236
const canUseInActiveTools = isWorkspaceContext();
237+
const existingSharedPalette = readSharedPaletteHandoff();
237238
if (!palette) {
238239
refs.paletteTitle.textContent = "Palette Preview";
239240
refs.paletteSummaryText.textContent = "Select a palette to inspect its swatches.";
@@ -472,6 +473,33 @@ function usePaletteInActiveTools() {
472473
refs.selectionText.textContent = "Use in Workspace Manager is available only in Workspace Manager context.";
473474
return;
474475
}
476+
if (hasReservedPaletteKeyword(palette.name)) {
477+
const message = "Reserved palette names cannot be used for workspace shared palette. Duplicate and rename first.";
478+
refs.selectionText.textContent = message;
479+
window.alert(message);
480+
return;
481+
}
482+
const existingSharedPalette = readSharedPaletteHandoff();
483+
if (
484+
existingSharedPalette
485+
&& existingSharedPalette.paletteId
486+
&& existingSharedPalette.paletteId !== palette.id
487+
) {
488+
const message = `Shared palette is locked to ${existingSharedPalette.displayName}. Edit swatches instead.`;
489+
refs.selectionText.textContent = message;
490+
window.alert(message);
491+
return;
492+
}
493+
if (
494+
existingSharedPalette
495+
&& existingSharedPalette.paletteId
496+
&& existingSharedPalette.paletteId === palette.id
497+
) {
498+
const message = "Shared palette is locked. Edit swatches instead.";
499+
refs.selectionText.textContent = message;
500+
window.alert(message);
501+
return;
502+
}
475503
const context = getSharedLaunchContext();
476504
const handoff = createPaletteHandoff({
477505
paletteId: palette.id,

tools/index.html

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,12 @@ <h2>Workspace Manager</h2>
3636

3737
<section>
3838
<h2>First-Class Tools</h2>
39-
<div class="grid" data-active-tools-grid>
40-
</div>
39+
<h3>Editors</h3>
40+
<div class="grid" data-active-tools-editors-grid></div>
41+
<h3>Utilities</h3>
42+
<div class="grid" data-active-tools-utilities-grid></div>
43+
<h3>Viewers</h3>
44+
<div class="grid" data-active-tools-viewers-grid></div>
4145
<noscript>
4246
<p class="callout"><strong>JavaScript required:</strong> the active tools list is generated from the shared
4347
tools registry.</p>

tools/renderToolsIndex.js

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,29 @@ function renderToolCard(tool) {
6161
`;
6262
}
6363

64+
function classifyToolGroup(toolId) {
65+
const viewerToolIds = new Set([
66+
"3d-asset-viewer",
67+
"state-inspector",
68+
"replay-visualizer",
69+
"performance-profiler"
70+
]);
71+
const utilityToolIds = new Set([
72+
"asset-browser",
73+
"asset-pipeline-tool",
74+
"tile-model-converter",
75+
"physics-sandbox",
76+
"3d-json-payload-normalizer"
77+
]);
78+
if (viewerToolIds.has(toolId)) {
79+
return "viewers";
80+
}
81+
if (utilityToolIds.has(toolId)) {
82+
return "utilities";
83+
}
84+
return "editors";
85+
}
86+
6487
function renderWorkspaceManagerCard() {
6588
return `
6689
<div class="card tools-platform-card">
@@ -88,16 +111,24 @@ function renderWorkspaceManagerSection() {
88111
}
89112

90113
function renderActiveToolsList() {
91-
const grid = document.querySelector("[data-active-tools-grid]");
92-
if (!grid) {
114+
const editorsGrid = document.querySelector("[data-active-tools-editors-grid]");
115+
const utilitiesGrid = document.querySelector("[data-active-tools-utilities-grid]");
116+
const viewersGrid = document.querySelector("[data-active-tools-viewers-grid]");
117+
if (!editorsGrid || !utilitiesGrid || !viewersGrid) {
93118
return;
94119
}
95-
const toolCards = getToolRegistry()
120+
const tools = getToolRegistry()
96121
.filter((entry) => entry.active === true)
97122
.filter((entry) => entry.visibleInToolsList === true)
98-
.sort((left, right) => String(left.displayName || "").localeCompare(String(right.displayName || "")))
99-
.map((tool) => renderToolCard(tool));
100-
grid.innerHTML = toolCards.join("\n");
123+
.sort((left, right) => String(left.displayName || "").localeCompare(String(right.displayName || "")));
124+
125+
const editors = tools.filter((tool) => classifyToolGroup(tool.id) === "editors").map((tool) => renderToolCard(tool));
126+
const utilities = tools.filter((tool) => classifyToolGroup(tool.id) === "utilities").map((tool) => renderToolCard(tool));
127+
const viewers = tools.filter((tool) => classifyToolGroup(tool.id) === "viewers").map((tool) => renderToolCard(tool));
128+
129+
editorsGrid.innerHTML = editors.join("\n");
130+
utilitiesGrid.innerHTML = utilities.join("\n");
131+
viewersGrid.innerHTML = viewers.join("\n");
101132
}
102133

103134
function sortPlannedCardsAlphabetically() {

tools/shared/platformShell.css

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,10 @@ body.tools-platform-surface {
196196
border-bottom: 0;
197197
}
198198

199+
.tools-platform-frame__nav-tool-row.is-disabled {
200+
opacity: 0.55;
201+
}
202+
199203
.tools-platform-frame__binding-badges {
200204
display: inline-flex;
201205
flex-wrap: wrap;
@@ -242,6 +246,54 @@ body.tools-platform-surface {
242246
width: 100%;
243247
}
244248

249+
.tools-platform-frame__nav.is-workspace-locked {
250+
position: relative;
251+
}
252+
253+
.tools-platform-frame__nav.is-workspace-locked::after {
254+
content: "Create or open a workspace to enable tools.";
255+
position: absolute;
256+
inset: 0;
257+
z-index: 20;
258+
display: flex;
259+
align-items: center;
260+
justify-content: center;
261+
text-align: center;
262+
padding: 16px;
263+
color: #ffffff;
264+
font-weight: 700;
265+
letter-spacing: 0.02em;
266+
border-radius: 12px;
267+
background: rgba(28, 13, 60, 0.52);
268+
border: 1px solid rgba(221, 214, 254, 0.26);
269+
backdrop-filter: blur(1px);
270+
pointer-events: auto;
271+
}
272+
273+
.tools-platform-lock-surface {
274+
position: relative;
275+
}
276+
277+
.tools-platform-lock-surface::after {
278+
content: attr(data-tools-platform-lock-message);
279+
position: absolute;
280+
inset: 0;
281+
z-index: 30;
282+
display: flex;
283+
align-items: center;
284+
justify-content: center;
285+
text-align: center;
286+
padding: 20px;
287+
color: #ffffff;
288+
font-weight: 700;
289+
letter-spacing: 0.02em;
290+
border-radius: 12px;
291+
background: rgba(28, 13, 60, 0.44);
292+
border: 1px solid rgba(221, 214, 254, 0.26);
293+
backdrop-filter: blur(1px);
294+
pointer-events: auto;
295+
}
296+
245297
.tools-platform-frame__nav-section {
246298
display: grid;
247299
gap: 10px;
@@ -335,6 +387,15 @@ body.tools-platform-surface {
335387
background: linear-gradient(180deg, var(--panel, rgba(76, 29, 149, 0.88)) 0%, var(--panel2, rgba(49, 17, 102, 0.94)) 100%);
336388
}
337389

390+
.tools-platform-frame__project-button:disabled,
391+
.tools-platform-frame__project-button[aria-disabled="true"] {
392+
color: #b3a7c9;
393+
border-color: rgba(179, 167, 201, 0.5);
394+
background: linear-gradient(180deg, rgba(89, 72, 126, 0.42) 0%, rgba(58, 44, 88, 0.66) 100%);
395+
cursor: not-allowed;
396+
box-shadow: none;
397+
}
398+
338399
.tools-platform-frame__project-input {
339400
display: none;
340401
}
@@ -372,6 +433,14 @@ body.tools-platform-surface {
372433
font-size: 0.88rem;
373434
}
374435

436+
.tools-platform-frame__nav-link.is-disabled {
437+
color: #b3a7c9;
438+
border-color: rgba(221, 214, 254, 0.16);
439+
background: linear-gradient(180deg, rgba(76, 29, 149, 0.55) 0%, rgba(49, 17, 102, 0.7) 100%);
440+
pointer-events: none;
441+
box-shadow: none;
442+
}
443+
375444
.tools-platform-frame__action-link {
376445
display: inline-flex;
377446
align-items: center;

0 commit comments

Comments
 (0)