feat(quality_dashboard): rewrite OWL component + template + SCSS (Task 6)
JS: single FpQualityDashboard component + BannerCard / BannerItem / SectionCard / SectionRow sibling sub-components in the same file. Fetches /fp/quality/dashboard/snapshot, 60s poll, deep-link ?tab=certificates scrolls to section-cert via scrollIntoView. XML: outer wrapper + banner + 6 sections (t-foreach over state.snapshot.sections). Each section has id='section-<type>' so the deep-link target works. SectionRow has overdue-conditional class for red subtitle highlight. SCSS: local tokens for urgent/good/section-head with light+dark via $o-webclient-color-scheme branch. 135deg gradients matching the plant kanban polish. Mobile breakpoint at 900px collapses banner grid to 1 col and stacks row Open button. OLD TABS array, selectTab, openTab, totalOpen, totalOverdue all deleted. Old template's tab tiles + per-tab panels deleted. Existing per-model kanbans untouched. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,57 +1,181 @@
|
||||
// Sub 12 Phase D — Unified Quality Dashboard styling.
|
||||
// Reuses the shopfloor SCSS tokens ($fp-page, $fp-card, $fp-border,
|
||||
// $fp-ink, $fp-accent, etc.) — they are bundled before us via the
|
||||
// fusion_plating_shopfloor dep, so no @import is needed.
|
||||
// Quality Dashboard — action surface.
|
||||
// Spec: docs/superpowers/specs/2026-05-25-quality-dashboard-redesign-design.md
|
||||
//
|
||||
// Tokens defined locally; light + dark via $o-webclient-color-scheme
|
||||
// compile-time branch (project Rule 9 — no runtime .o_dark_mode class).
|
||||
// Reuses base $plant-card-bg / $plant-bg / $plant-text / $plant-muted /
|
||||
// $plant-card-border from _plant_tokens.scss (loaded earlier in the
|
||||
// fusion_plating_shopfloor manifest — fusion_plating_quality depends
|
||||
// on shopfloor so those tokens are visible).
|
||||
|
||||
.o_fp_quality_dashboard {
|
||||
background-color: $fp-page;
|
||||
min-height: 100%;
|
||||
$o-webclient-color-scheme: bright !default;
|
||||
|
||||
.o_fp_card {
|
||||
background-color: $fp-card;
|
||||
border: 1px solid $fp-border;
|
||||
border-radius: 8px;
|
||||
$_qd-urgent-bg-hex: #fee2e2;
|
||||
$_qd-urgent-bg-end-hex: #fff;
|
||||
$_qd-urgent-border-hex: #dc2626;
|
||||
$_qd-urgent-text-hex: #7f1d1d;
|
||||
|
||||
$_qd-good-bg-hex: #d1fae5;
|
||||
$_qd-good-bg-end-hex: #ecfdf5;
|
||||
$_qd-good-border-hex: #22c55e;
|
||||
$_qd-good-text-hex: #064e3b;
|
||||
|
||||
$_qd-section-head-bg-hex: #fef3c7;
|
||||
$_qd-section-overdue-hex: #b45309;
|
||||
|
||||
@if $o-webclient-color-scheme == dark {
|
||||
$_qd-urgent-bg-hex: #3a1818 !global;
|
||||
$_qd-urgent-bg-end-hex: #1d1d1f !global;
|
||||
$_qd-urgent-text-hex: #fca5a5 !global;
|
||||
$_qd-good-bg-hex: #14281a !global;
|
||||
$_qd-good-bg-end-hex: #1d1d1f !global;
|
||||
$_qd-good-text-hex: #6ee7b7 !global;
|
||||
$_qd-section-head-bg-hex: #3a2f15 !global;
|
||||
$_qd-section-overdue-hex: #fbbf24 !global;
|
||||
}
|
||||
|
||||
$qd-urgent-bg: var(--fp-qd-urgent-bg, $_qd-urgent-bg-hex);
|
||||
$qd-urgent-bg-end: var(--fp-qd-urgent-bg-end, $_qd-urgent-bg-end-hex);
|
||||
$qd-urgent-border: var(--fp-qd-urgent-border, $_qd-urgent-border-hex);
|
||||
$qd-urgent-text: var(--fp-qd-urgent-text, $_qd-urgent-text-hex);
|
||||
$qd-good-bg: var(--fp-qd-good-bg, $_qd-good-bg-hex);
|
||||
$qd-good-bg-end: var(--fp-qd-good-bg-end, $_qd-good-bg-end-hex);
|
||||
$qd-good-border: var(--fp-qd-good-border, $_qd-good-border-hex);
|
||||
$qd-good-text: var(--fp-qd-good-text, $_qd-good-text-hex);
|
||||
$qd-section-head-bg: var(--fp-qd-section-head-bg, $_qd-section-head-bg-hex);
|
||||
$qd-section-overdue: var(--fp-qd-section-overdue, $_qd-section-overdue-hex);
|
||||
|
||||
.o_fp_qd {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
color: $plant-text;
|
||||
|
||||
.o_fp_qd_loading, .o_fp_qd_error {
|
||||
padding: 2rem; text-align: center; color: $plant-muted;
|
||||
}
|
||||
.o_fp_qd_error { color: $qd-urgent-border; }
|
||||
|
||||
.o_fp_qd_summary {
|
||||
min-width: 220px;
|
||||
// ===== Banner =====
|
||||
.o_fp_qd_banner {
|
||||
border-radius: 10px;
|
||||
padding: 14px 18px;
|
||||
margin-bottom: 16px;
|
||||
border: 1px solid $plant-card-border;
|
||||
}
|
||||
|
||||
.o_fp_qd_tile {
|
||||
cursor: pointer;
|
||||
min-width: 130px;
|
||||
text-align: left;
|
||||
transition: transform 0.08s ease-in-out, box-shadow 0.08s ease-in-out;
|
||||
|
||||
.o_fp_qd_banner_urgent {
|
||||
background: linear-gradient(135deg, $qd-urgent-bg 0%, $qd-urgent-bg-end 100%);
|
||||
border-color: $qd-urgent-border;
|
||||
}
|
||||
.o_fp_qd_banner_clear {
|
||||
background: linear-gradient(135deg, $qd-good-bg 0%, $qd-good-bg-end 100%);
|
||||
border-color: $qd-good-border;
|
||||
display: flex; align-items: center; gap: 14px;
|
||||
padding: 20px;
|
||||
}
|
||||
.o_fp_qd_banner_clear_icon {
|
||||
font-size: 32px; color: $qd-good-text; line-height: 1;
|
||||
}
|
||||
.o_fp_qd_banner_clear_text { color: $qd-good-text; font-size: 16px; }
|
||||
.o_fp_qd_banner_head {
|
||||
font-weight: 700; color: $qd-urgent-text;
|
||||
font-size: 13px; letter-spacing: 0.04em; margin-bottom: 10px;
|
||||
}
|
||||
.o_fp_qd_banner_overflow {
|
||||
font-weight: 500; opacity: 0.8; margin-left: 8px;
|
||||
}
|
||||
.o_fp_qd_banner_grid {
|
||||
display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px;
|
||||
}
|
||||
.o_fp_qd_banner_item {
|
||||
background: $plant-card-bg;
|
||||
border: 1px solid $plant-card-border;
|
||||
border-left: 3px solid $qd-urgent-border;
|
||||
border-radius: 6px;
|
||||
padding: 8px 10px;
|
||||
text-align: left; cursor: pointer;
|
||||
color: $plant-text; font-family: inherit;
|
||||
transition: transform 0.1s ease, box-shadow 0.1s ease;
|
||||
&:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
&.o_fp_qd_active {
|
||||
border: 2px solid $fp-accent;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
|
||||
box-shadow: 0 3px 6px rgba(0,0,0,0.08);
|
||||
}
|
||||
}
|
||||
|
||||
.o_fp_qd_metric_label {
|
||||
font-size: 0.85em;
|
||||
color: $fp-ink-mute;
|
||||
font-weight: 500;
|
||||
.o_fp_qd_banner_item_l1 {
|
||||
display: flex; align-items: center; gap: 6px; font-size: 13px;
|
||||
}
|
||||
.o_fp_qd_banner_item_type {
|
||||
font-size: 9px; font-weight: 700; padding: 2px 6px;
|
||||
background: $plant-bg; color: $plant-muted;
|
||||
border-radius: 4px; letter-spacing: 0.04em;
|
||||
}
|
||||
.o_fp_qd_banner_item_badge {
|
||||
font-size: 9px; font-weight: 700; padding: 2px 6px;
|
||||
background: $qd-urgent-border; color: #fff;
|
||||
border-radius: 4px; letter-spacing: 0.04em;
|
||||
}
|
||||
.o_fp_qd_banner_item_l2 {
|
||||
font-size: 11px; color: $plant-muted; margin-top: 3px;
|
||||
display: flex; gap: 6px;
|
||||
}
|
||||
.o_fp_qd_banner_item_subtitle {
|
||||
color: $qd-urgent-border; font-weight: 600;
|
||||
}
|
||||
|
||||
.o_fp_qd_metric_value {
|
||||
font-size: 1.6em;
|
||||
font-weight: 700;
|
||||
color: $fp-ink;
|
||||
line-height: 1.1;
|
||||
// ===== Section =====
|
||||
.o_fp_qd_section {
|
||||
background: $plant-card-bg;
|
||||
border: 1px solid $plant-card-border;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 12px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.o_fp_qd_section_head {
|
||||
background: linear-gradient(135deg, $qd-section-head-bg 0%, $plant-card-bg 100%);
|
||||
padding: 10px 14px;
|
||||
display: flex; justify-content: space-between; align-items: center;
|
||||
font-size: 13px;
|
||||
}
|
||||
.o_fp_qd_section_overdue { color: $qd-section-overdue; font-weight: 600; }
|
||||
.o_fp_qd_section_open {
|
||||
background: transparent; border: 0;
|
||||
color: #1d4ed8; font-weight: 500; cursor: pointer;
|
||||
font-size: 12px; font-family: inherit;
|
||||
&:hover { text-decoration: underline; }
|
||||
}
|
||||
.o_fp_qd_section_empty {
|
||||
padding: 12px 14px; color: $plant-muted; font-style: italic;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.o_fp_qd_metric_sub {
|
||||
margin-top: 0.25em;
|
||||
// ===== Row =====
|
||||
.o_fp_qd_row {
|
||||
padding: 8px 14px;
|
||||
display: flex; justify-content: space-between; align-items: center;
|
||||
gap: 10px; font-size: 13px;
|
||||
border-top: 1px solid $plant-card-border;
|
||||
transition: background 0.1s ease;
|
||||
&:hover { background: $plant-bg; }
|
||||
}
|
||||
.o_fp_qd_row_overdue .o_fp_qd_row_subtitle {
|
||||
color: $qd-urgent-border; font-weight: 600;
|
||||
}
|
||||
.o_fp_qd_row_main { flex: 1; min-width: 0; }
|
||||
.o_fp_qd_row_sep { color: $plant-muted; }
|
||||
.o_fp_qd_row_cust { color: $plant-muted; }
|
||||
.o_fp_qd_row_open {
|
||||
background: #1d4ed8; color: #fff;
|
||||
border: 0; padding: 4px 12px; border-radius: 4px;
|
||||
font-size: 11px; font-weight: 600; cursor: pointer;
|
||||
font-family: inherit; min-height: 28px;
|
||||
transition: background 0.1s ease;
|
||||
&:hover { background: #1e40af; }
|
||||
}
|
||||
|
||||
.o_fp_qd_panel {
|
||||
min-height: 200px;
|
||||
// ===== Mobile =====
|
||||
@media (max-width: 900px) {
|
||||
.o_fp_qd_banner_grid { grid-template-columns: 1fr; }
|
||||
.o_fp_qd_row {
|
||||
flex-direction: column; align-items: flex-start;
|
||||
.o_fp_qd_row_open { align-self: stretch; min-height: 32px; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user