Add component name formatters and grid-link navigation

Templates section:
- Define JS formatter functions per template (e.g. resistor, capacitor)
- First non-null result from any formatter is used as display name
- Live preview in template editor against first component
- Display names applied in component list, detail view, and inventory rows

Grid navigation:
- Grid-type inventory entries in component detail view show a '⊞' button
  to navigate directly to that grid's viewer

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-21 00:07:01 +00:00
parent 27970e74f9
commit 57c697cbfc
7 changed files with 338 additions and 5 deletions

View File

@@ -82,6 +82,7 @@
<span class="detail-inv-qty"></span>
<span class="detail-inv-notes"></span>
<span class="row-actions">
<button class="btn-icon btn-goto-grid detail-inv-goto-grid" title="View in grid" hidden></button>
<button class="btn-icon btn-edit" title="Edit"></button>
<button class="btn-icon btn-danger btn-delete" title="Delete"></button>
</span>
@@ -147,6 +148,54 @@
</tr>
</template>
<!-- ===== TEMPLATES SECTION ===== -->
<template id="t-section-templates">
<section class="section" id="section-templates">
<div class="section-toolbar">
<span class="section-note">Formatters that compute display names from component fields</span>
<button class="btn btn-primary" id="btn-add-template">+ Add template</button>
</div>
<div id="template-list" class="template-list"></div>
</section>
</template>
<template id="t-template-card">
<div class="template-card">
<div class="template-card-header">
<span class="template-card-name"></span>
<span class="row-actions">
<button class="btn-icon btn-edit" title="Edit"></button>
<button class="btn-icon btn-danger btn-delete" title="Delete"></button>
</span>
</div>
<pre class="template-card-formatter"></pre>
</div>
</template>
<template id="t-dialog-template">
<dialog id="dialog-template" class="app-dialog app-dialog-wide">
<h2 class="dialog-title"></h2>
<form method="dialog" id="form-template">
<div class="form-row">
<label for="tmpl-name">Name</label>
<input type="text" id="tmpl-name" required autocomplete="off" placeholder="e.g. Resistor">
</div>
<div class="form-row">
<label for="tmpl-formatter">Formatter <span class="label-hint">(JS arrow function, return null to skip)</span></label>
<textarea id="tmpl-formatter" rows="8" class="code-input" placeholder="(c) => {&#10; const r = c.fields?.resistance;&#10; if (!r) return null;&#10; return `Resistor ${r}`;&#10;}"></textarea>
</div>
<div class="tmpl-preview-row">
<span class="label-hint">Preview:</span>
<span id="tmpl-preview" class="tmpl-preview-value"></span>
</div>
<div class="dialog-actions">
<button type="button" class="btn btn-secondary" id="tmpl-cancel">Cancel</button>
<button type="submit" class="btn btn-primary" id="tmpl-save">Save</button>
</div>
</form>
</dialog>
</template>
<!-- ===== FIELDS SECTION ===== -->
<template id="t-section-fields">
<section class="section" id="section-fields">