90 lines
5.7 KiB
JavaScript
90 lines
5.7 KiB
JavaScript
/* ObsiGate — XLSX command bar builder (#154-A5).
|
|
*
|
|
* Pure string builder for the spreadsheet shell (sheet tabs + grouped action
|
|
* buttons + status pills). Extracted from frontend/js/viewer.js so the markup
|
|
* is testable and the viewer only wires behaviour.
|
|
*/
|
|
import { t } from '../i18n.js';
|
|
import { escapeHtml } from '../utils.js';
|
|
|
|
/**
|
|
* @param {object} ctx
|
|
* @param {Array<{name: string}>} ctx.sheets
|
|
* @param {boolean} ctx.isCsv
|
|
* @param {boolean} ctx.readOnly
|
|
* @param {boolean} ctx.editable - not a CSV and not read-only
|
|
* @returns {{ tabs: string, actionsHtml: string, statusBar: string }}
|
|
*/
|
|
export function buildCommandBar({ sheets, isCsv, readOnly, editable }) {
|
|
// Sheet tabs are always rendered (even for a single sheet) so the strip reads
|
|
// as a real affordance; an editable workbook gets an explicit “+” button.
|
|
const tabs = isCsv
|
|
? ""
|
|
: `<div class="xlsx-tabs" role="tablist">${sheets.map((s, i) =>
|
|
`<button class="xlsx-tab${i === 0 ? " active" : ""}" data-sheet="${i}" role="tab" aria-selected="${i === 0}">${escapeHtml(s.name)}</button>`
|
|
).join("")}${editable
|
|
? `<button class="xlsx-tab-add" id="xlsx-tab-add" type="button" title="${escapeHtml(t("xlsx.tabs_add_sheet"))}" aria-label="${escapeHtml(t("xlsx.tabs_add_sheet"))}"><i data-lucide="plus" style="width:14px;height:14px" aria-hidden="true"></i></button>`
|
|
: ""}</div>`;
|
|
|
|
// Status pills make the viewer's limits visible up front.
|
|
const statusPills = [
|
|
readOnly
|
|
? `<span class="xlsx-status-pill xlsx-status-readonly" title="${escapeHtml(t("xlsx.readonly_hint"))}"><i data-lucide="lock" class="xlsx-status-icon"></i>${escapeHtml(t("xlsx.readonly_badge"))}</span>`
|
|
: "",
|
|
!isCsv
|
|
? `<span class="xlsx-status-pill xlsx-status-formula" title="${escapeHtml(t("xlsx.formulas_note_title"))}"><i data-lucide="sigma" class="xlsx-status-icon"></i>${escapeHtml(t("xlsx.formulas_note"))}</span>`
|
|
: "",
|
|
].filter(Boolean).join("");
|
|
const statusBar = statusPills ? `<div class="xlsx-status-bar">${statusPills}</div>` : "";
|
|
|
|
// Command groups, separated by thin rules.
|
|
const actionGroups = [];
|
|
if (!readOnly) {
|
|
actionGroups.push(`<span class="xlsx-cmd-group" data-group="history">
|
|
<button class="btn-action" id="xlsx-undo-btn" type="button" title="${escapeHtml(t("xlsx.undo"))}" disabled>
|
|
<i data-lucide="undo-2" style="width:14px;height:14px"></i>
|
|
</button>
|
|
<button class="btn-action" id="xlsx-redo-btn" type="button" title="${escapeHtml(t("xlsx.redo"))}" disabled>
|
|
<i data-lucide="redo-2" style="width:14px;height:14px"></i>
|
|
</button>
|
|
</span>`);
|
|
actionGroups.push(`<span class="xlsx-cmd-group" data-group="formulas">
|
|
<button class="btn-action xlsx-formula-toggle" id="xlsx-formula-btn" type="button"
|
|
aria-pressed="false" title="${escapeHtml(t("xlsx.formula_toggle_title"))}">f(x)</button>
|
|
</span>`);
|
|
}
|
|
if (editable) {
|
|
actionGroups.push(`<span class="xlsx-cmd-group" data-group="insert">
|
|
<button class="btn-action" id="xlsx-format-btn" title="${escapeHtml(t("xlsx.format_btn"))}" aria-haspopup="menu" aria-expanded="false">
|
|
<i data-lucide="paintbrush" style="width:14px;height:14px"></i>
|
|
</button>
|
|
<button class="btn-action" id="xlsx-structure-btn" title="${escapeHtml(t("xlsx.structure_btn"))}" aria-haspopup="menu" aria-expanded="false">
|
|
<i data-lucide="table-properties" style="width:14px;height:14px"></i>
|
|
</button>
|
|
</span>`);
|
|
actionGroups.push(`<span class="xlsx-cmd-group" id="xlsx-view-group" data-group="view"></span>`);
|
|
}
|
|
actionGroups.push(`<span class="xlsx-cmd-group" data-group="file">
|
|
<button class="btn-action" id="xlsx-download-btn">
|
|
<i data-lucide="download" style="width:14px;height:14px"></i> ${t("viewer.download")}
|
|
</button>
|
|
<button class="btn-action" id="xlsx-csv-btn" title="${escapeHtml(t("xlsx.csv_export"))}">
|
|
<i data-lucide="file-spreadsheet" style="width:14px;height:14px"></i> CSV
|
|
</button>
|
|
<span class="export-dropdown xlsx-export-dropdown">
|
|
<button class="btn-action" id="xlsx-export-btn" type="button" title="${escapeHtml(t("xlsx.export_title"))}" aria-haspopup="menu" aria-expanded="false">
|
|
<i data-lucide="file-down" style="width:14px;height:14px"></i> ${escapeHtml(t("xlsx.export_btn"))}
|
|
</button>
|
|
<div class="export-menu xlsx-export-menu" id="xlsx-export-menu" style="display:none" role="menu">
|
|
<button class="export-menu-item" type="button" role="menuitem" data-xlsx-export="md"><i data-lucide="file-text" class="xlsx-menu-icon" aria-hidden="true"></i><span class="xlsx-menu-label">${escapeHtml(t("xlsx.export_md"))}</span></button>
|
|
<button class="export-menu-item" type="button" role="menuitem" data-xlsx-export="html"><i data-lucide="code" class="xlsx-menu-icon" aria-hidden="true"></i><span class="xlsx-menu-label">${escapeHtml(t("xlsx.export_html"))}</span></button>
|
|
<button class="export-menu-item" type="button" role="menuitem" data-xlsx-export="print"><i data-lucide="printer" class="xlsx-menu-icon" aria-hidden="true"></i><span class="xlsx-menu-label">${escapeHtml(t("xlsx.print"))}</span></button>
|
|
</div>
|
|
</span>
|
|
<button class="btn-action xlsx-save-primary" id="xlsx-save-btn" disabled><i data-lucide="save" style="width:14px;height:14px" aria-hidden="true"></i> ${t("common.save")}</button>
|
|
</span>`);
|
|
const actionsHtml = actionGroups.join('<span class="xlsx-cmd-sep" aria-hidden="true"></span>');
|
|
|
|
return { tabs, actionsHtml, statusBar };
|
|
}
|