fusion_plating: icon picker grid + auto-icon from name (v19.0.2.0.3)
Replaced text input with a clickable 24-icon grid picker for the side panel. Icons are curated for plating (flask, blast, mask, rinse, bake, plate, inspect, etc.). When adding a new step, the icon is automatically guessed from the name via keyword matching (e.g. "Masking" → paint-brush, "Oven baking" → fire, "Acid Dip" → flask). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -33,6 +33,63 @@ const NODE_TYPE_OPTIONS = [
|
||||
{ value: "step", label: "Step" },
|
||||
];
|
||||
|
||||
// ---- Icon picker options (curated for plating / manufacturing) -----------
|
||||
const ICON_OPTIONS = [
|
||||
{ value: "fa-flask", label: "Flask / Chemistry" },
|
||||
{ value: "fa-industry", label: "Industry / Line" },
|
||||
{ value: "fa-sitemap", label: "Sitemap / Process" },
|
||||
{ value: "fa-wrench", label: "Wrench / Operation" },
|
||||
{ value: "fa-cog", label: "Gear / General" },
|
||||
{ value: "fa-cogs", label: "Gears / System" },
|
||||
{ value: "fa-paint-brush", label: "Paint / Masking" },
|
||||
{ value: "fa-eraser", label: "Eraser / De-Masking" },
|
||||
{ value: "fa-th", label: "Grid / Racking" },
|
||||
{ value: "fa-fire", label: "Fire / Bake" },
|
||||
{ value: "fa-bolt", label: "Bolt / Electric" },
|
||||
{ value: "fa-diamond", label: "Diamond / Plating" },
|
||||
{ value: "fa-tint", label: "Tint / Rinse" },
|
||||
{ value: "fa-shower", label: "Shower / Clean" },
|
||||
{ value: "fa-bullseye", label: "Target / Blast" },
|
||||
{ value: "fa-search", label: "Search / Inspect" },
|
||||
{ value: "fa-check-circle", label: "Check / Approve" },
|
||||
{ value: "fa-clock-o", label: "Clock / Wait" },
|
||||
{ value: "fa-sun-o", label: "Sun / Dry" },
|
||||
{ value: "fa-thermometer-half", label: "Temp / Heat" },
|
||||
{ value: "fa-eye", label: "Eye / Visual" },
|
||||
{ value: "fa-hand-paper-o", label: "Hand / Manual" },
|
||||
{ value: "fa-cube", label: "Cube / Part" },
|
||||
{ value: "fa-shield", label: "Shield / Protect" },
|
||||
];
|
||||
|
||||
// ---- Auto-icon: guess the best icon from the node name ------------------
|
||||
const ICON_KEYWORDS = [
|
||||
{ pattern: /mask/i, icon: "fa-paint-brush" },
|
||||
{ pattern: /de-?mask|unmask/i, icon: "fa-eraser" },
|
||||
{ pattern: /rack/i, icon: "fa-th" },
|
||||
{ pattern: /de-?rack|unrack/i, icon: "fa-th" },
|
||||
{ pattern: /blast/i, icon: "fa-bullseye" },
|
||||
{ pattern: /bake|oven/i, icon: "fa-fire" },
|
||||
{ pattern: /clean|soak|wash/i, icon: "fa-shower" },
|
||||
{ pattern: /rinse/i, icon: "fa-tint" },
|
||||
{ pattern: /dry/i, icon: "fa-sun-o" },
|
||||
{ pattern: /nickel|plate|plat/i, icon: "fa-diamond" },
|
||||
{ pattern: /strike|electro/i, icon: "fa-bolt" },
|
||||
{ pattern: /acid|dip|etch/i, icon: "fa-flask" },
|
||||
{ pattern: /inspect|check|test/i, icon: "fa-search" },
|
||||
{ pattern: /ready|wait|queue/i, icon: "fa-clock-o" },
|
||||
{ pattern: /line|process/i, icon: "fa-industry" },
|
||||
{ pattern: /heat|temp/i, icon: "fa-thermometer-half" },
|
||||
{ pattern: /porosity/i, icon: "fa-tint" },
|
||||
];
|
||||
|
||||
function guessIcon(name) {
|
||||
if (!name) return "fa-cog";
|
||||
for (const rule of ICON_KEYWORDS) {
|
||||
if (rule.pattern.test(name)) return rule.icon;
|
||||
}
|
||||
return "fa-cog";
|
||||
}
|
||||
|
||||
export class RecipeTreeEditor extends Component {
|
||||
static template = "fusion_plating.RecipeTreeEditor";
|
||||
static props = ["*"];
|
||||
@@ -205,6 +262,7 @@ export class RecipeTreeEditor extends Component {
|
||||
parent_id: this.state.addingTo,
|
||||
name: name,
|
||||
node_type: this.state.newNodeType,
|
||||
vals: { icon: guessIcon(name) },
|
||||
});
|
||||
if (result && result.ok) {
|
||||
this.notification.add(`Added "${name}"`, { type: "success" });
|
||||
@@ -391,6 +449,10 @@ export class RecipeTreeEditor extends Component {
|
||||
return NODE_TYPE_OPTIONS;
|
||||
}
|
||||
|
||||
getIconOptions() {
|
||||
return ICON_OPTIONS;
|
||||
}
|
||||
|
||||
formatDuration(minutes) {
|
||||
if (!minutes) return "";
|
||||
if (minutes < 60) return `${Math.round(minutes)}m`;
|
||||
|
||||
@@ -372,6 +372,40 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Icon picker ------------------------------------------------------------
|
||||
|
||||
.o_fp_recipe_icon_picker {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.o_fp_recipe_icon_btn {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: 6px;
|
||||
background: transparent;
|
||||
color: var(--bs-secondary-color);
|
||||
font-size: 0.9rem;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.12s, background-color 0.12s;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--o-action, var(--bs-primary));
|
||||
color: var(--bs-body-color);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: var(--o-action, var(--bs-primary));
|
||||
border-color: var(--o-action, var(--bs-primary));
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Responsive -------------------------------------------------------------
|
||||
|
||||
@media (max-width: 768px) {
|
||||
|
||||
@@ -100,14 +100,15 @@
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-bold">Icon (FA class)</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">
|
||||
<i t-att-class="'fa ' + (state.selectedNode.icon || 'fa-cog')"/>
|
||||
</span>
|
||||
<input type="text" class="form-control"
|
||||
t-att-value="state.selectedNode.icon"
|
||||
t-on-change="(ev) => { state.selectedNode.icon = ev.target.value; }"/>
|
||||
<label class="form-label fw-bold">Icon</label>
|
||||
<div class="o_fp_recipe_icon_picker">
|
||||
<t t-foreach="getIconOptions()" t-as="ic" t-key="ic.value">
|
||||
<button t-att-class="'o_fp_recipe_icon_btn' + (state.selectedNode.icon === ic.value ? ' active' : '')"
|
||||
t-on-click.stop="() => { state.selectedNode.icon = ic.value; }"
|
||||
t-att-title="ic.label">
|
||||
<i t-att-class="'fa ' + ic.value"/>
|
||||
</button>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
|
||||
Reference in New Issue
Block a user