Add Show Modifiers toggle to menu builder outline view
Adds button in the outline modal to toggle modifier group display under each item. Each group shows a + to expand into full options with prices. Useful for debugging modifier assignments. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9000fc91fe
commit
2d3634693b
1 changed files with 90 additions and 27 deletions
|
|
@ -3391,15 +3391,14 @@
|
||||||
// Show outline modal - full menu in hierarchical text format
|
// Show outline modal - full menu in hierarchical text format
|
||||||
showOutlineModal() {
|
showOutlineModal() {
|
||||||
document.getElementById('modalTitle').textContent = 'Menu Outline';
|
document.getElementById('modalTitle').textContent = 'Menu Outline';
|
||||||
|
this._outlineShowMods = false;
|
||||||
|
|
||||||
let outline = '';
|
const buildOutline = () => {
|
||||||
const categories = this.menu.categories || [];
|
const categories = this.menu.categories || [];
|
||||||
|
if (categories.length === 0)
|
||||||
|
return '<div style="color: var(--gray-500); text-align: center; padding: 40px;">No menu items yet</div>';
|
||||||
|
|
||||||
if (categories.length === 0) {
|
let outline = '<div class="menu-outline">';
|
||||||
outline = '<div style="color: var(--gray-500); text-align: center; padding: 40px;">No menu items yet</div>';
|
|
||||||
} else {
|
|
||||||
outline = '<div class="menu-outline">';
|
|
||||||
|
|
||||||
const topLevel = categories.filter(c => !c.parentCategoryId || c.parentCategoryId === 0);
|
const topLevel = categories.filter(c => !c.parentCategoryId || c.parentCategoryId === 0);
|
||||||
const getSubcats = (parent) => categories.filter(c =>
|
const getSubcats = (parent) => categories.filter(c =>
|
||||||
c.parentCategoryId === parent.id || (parent.dbId && c.parentCategoryDbId === parent.dbId)
|
c.parentCategoryId === parent.id || (parent.dbId && c.parentCategoryDbId === parent.dbId)
|
||||||
|
|
@ -3410,7 +3409,9 @@
|
||||||
for (const item of (items || [])) {
|
for (const item of (items || [])) {
|
||||||
const itemPrice = item.price ? `$${parseFloat(item.price).toFixed(2)}` : '';
|
const itemPrice = item.price ? `$${parseFloat(item.price).toFixed(2)}` : '';
|
||||||
html += `<div class="outline-item" style="padding-left: ${indentLevel * 20}px;">${this.escapeHtml(item.name)}${itemPrice ? ' <span class="outline-price">' + itemPrice + '</span>' : ''}</div>`;
|
html += `<div class="outline-item" style="padding-left: ${indentLevel * 20}px;">${this.escapeHtml(item.name)}${itemPrice ? ' <span class="outline-price">' + itemPrice + '</span>' : ''}</div>`;
|
||||||
html += this.renderOutlineModifiers(item.modifiers || [], indentLevel + 1);
|
if (this._outlineShowMods) {
|
||||||
|
html += this.renderOutlineModifierGroups(item.modifiers || [], indentLevel + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return html;
|
return html;
|
||||||
};
|
};
|
||||||
|
|
@ -3418,24 +3419,37 @@
|
||||||
for (const cat of topLevel) {
|
for (const cat of topLevel) {
|
||||||
outline += `<div class="outline-category">${this.escapeHtml(cat.name)}</div>`;
|
outline += `<div class="outline-category">${this.escapeHtml(cat.name)}</div>`;
|
||||||
outline += renderOutlineItems(cat.items, 1);
|
outline += renderOutlineItems(cat.items, 1);
|
||||||
|
|
||||||
const subcats = getSubcats(cat);
|
const subcats = getSubcats(cat);
|
||||||
for (const subcat of subcats) {
|
for (const subcat of subcats) {
|
||||||
outline += `<div class="outline-subcategory">${this.escapeHtml(subcat.name)}</div>`;
|
outline += `<div class="outline-subcategory">${this.escapeHtml(subcat.name)}</div>`;
|
||||||
outline += renderOutlineItems(subcat.items, 2);
|
outline += renderOutlineItems(subcat.items, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
outline += '</div>';
|
outline += '</div>';
|
||||||
}
|
return outline;
|
||||||
|
};
|
||||||
|
|
||||||
|
const render = () => {
|
||||||
|
const btnLabel = this._outlineShowMods ? 'Hide Modifiers' : 'Show Modifiers';
|
||||||
document.getElementById('modalBody').innerHTML = `
|
document.getElementById('modalBody').innerHTML = `
|
||||||
<style>
|
<div style="margin-bottom: 12px;">
|
||||||
|
<button class="outline-mods-btn" onclick="MenuBuilder.toggleOutlineMods()">${btnLabel}</button>
|
||||||
|
</div>
|
||||||
|
${buildOutline()}
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Inject styles once
|
||||||
|
document.getElementById('modalBody').innerHTML = '';
|
||||||
|
if (!document.getElementById('outlineStyles')) {
|
||||||
|
const style = document.createElement('style');
|
||||||
|
style.id = 'outlineStyles';
|
||||||
|
style.textContent = `
|
||||||
.menu-outline {
|
.menu-outline {
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
max-height: 60vh;
|
max-height: 55vh;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
background: var(--bg-secondary);
|
background: var(--bg-secondary);
|
||||||
|
|
@ -3449,9 +3463,7 @@
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
.outline-category:first-child {
|
.outline-category:first-child { margin-top: 0; }
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
.outline-subcategory {
|
.outline-subcategory {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
|
@ -3464,21 +3476,72 @@
|
||||||
padding-left: 20px;
|
padding-left: 20px;
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
.outline-modifier {
|
.outline-modifier { color: var(--text-muted); }
|
||||||
|
.outline-price { color: var(--success); }
|
||||||
|
.outline-modifier .outline-price { color: var(--warning); }
|
||||||
|
.outline-mods-btn {
|
||||||
|
padding: 6px 14px;
|
||||||
|
font-size: 13px;
|
||||||
|
border: 1px solid var(--border-color, #ccc);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: var(--bg-primary, #fff);
|
||||||
|
color: var(--text-secondary);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.outline-mods-btn:hover { background: var(--bg-secondary, #f5f5f5); }
|
||||||
|
.outline-mod-group {
|
||||||
|
padding-left: 20px;
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
||||||
.outline-price {
|
.outline-mod-group:hover { color: var(--text-secondary); }
|
||||||
color: var(--success);
|
.outline-mod-expand { display: inline-block; width: 14px; font-size: 11px; color: var(--text-muted); }
|
||||||
}
|
.outline-mod-opts { display: none; }
|
||||||
.outline-modifier .outline-price {
|
.outline-mod-opts.open { display: block; }
|
||||||
color: var(--warning);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
${outline}
|
|
||||||
`;
|
`;
|
||||||
|
document.head.appendChild(style);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._outlineRender = render;
|
||||||
|
render();
|
||||||
this.showModal();
|
this.showModal();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
toggleOutlineMods() {
|
||||||
|
this._outlineShowMods = !this._outlineShowMods;
|
||||||
|
if (this._outlineRender) this._outlineRender();
|
||||||
|
},
|
||||||
|
|
||||||
|
// Render first-level modifier groups with expandable options
|
||||||
|
renderOutlineModifierGroups(modifiers, depth) {
|
||||||
|
if (!modifiers || modifiers.length === 0) return '';
|
||||||
|
let html = '';
|
||||||
|
const pad = depth * 20;
|
||||||
|
for (let i = 0; i < modifiers.length; i++) {
|
||||||
|
const mod = modifiers[i];
|
||||||
|
const modPrice = mod.price ? `+$${parseFloat(mod.price).toFixed(2)}` : '';
|
||||||
|
const opts = mod.options || [];
|
||||||
|
const uid = 'om_' + Math.random().toString(36).substring(2, 8);
|
||||||
|
const countLabel = opts.length ? ` (${opts.length})` : '';
|
||||||
|
|
||||||
|
if (opts.length > 0) {
|
||||||
|
html += `<div class="outline-mod-group" style="padding-left: ${pad}px;" onclick="var el=document.getElementById('${uid}');el.classList.toggle('open');this.querySelector('.outline-mod-expand').textContent=el.classList.contains('open')?'−':'+'">`;
|
||||||
|
html += `<span class="outline-mod-expand">+</span> ${this.escapeHtml(mod.name)}${modPrice ? ' <span class="outline-price">' + modPrice + '</span>' : ''}${countLabel}`;
|
||||||
|
html += `</div>`;
|
||||||
|
html += `<div id="${uid}" class="outline-mod-opts">`;
|
||||||
|
for (const opt of opts) {
|
||||||
|
const optPrice = opt.price ? `+$${parseFloat(opt.price).toFixed(2)}` : '';
|
||||||
|
html += `<div class="outline-modifier" style="padding-left: ${(depth + 1) * 20}px;">${this.escapeHtml(opt.name)}${optPrice ? ' <span class="outline-price">' + optPrice + '</span>' : ''}</div>`;
|
||||||
|
}
|
||||||
|
html += `</div>`;
|
||||||
|
} else {
|
||||||
|
html += `<div class="outline-modifier" style="padding-left: ${pad}px;">${this.escapeHtml(mod.name)}${modPrice ? ' <span class="outline-price">' + modPrice + '</span>' : ''}</div>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return html;
|
||||||
|
},
|
||||||
|
|
||||||
// Helper to render modifiers recursively for outline
|
// Helper to render modifiers recursively for outline
|
||||||
renderOutlineModifiers(modifiers, depth) {
|
renderOutlineModifiers(modifiers, depth) {
|
||||||
if (!modifiers || modifiers.length === 0) return '';
|
if (!modifiers || modifiers.length === 0) return '';
|
||||||
|
|
|
||||||
Reference in a new issue