refactor(ui): consolidate Theme.qml tokens and replace unicode glyphs with SVG icons

This commit is contained in:
jack
2026-07-06 15:42:18 -07:00
parent 0014ccc184
commit 88b0214582
17 changed files with 303 additions and 98 deletions
+1 -1
View File
@@ -404,7 +404,7 @@ Rectangle {
id: badgeLabel
anchors.centerIn: parent
text: deviceController.connectionStatus || "Disconnected"
color: "#111111"
color: Theme.statusBadgeText
font.pixelSize: Theme.font2xs
font.bold: true
}
+58 -39
View File
@@ -1,5 +1,6 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.impl
import QtQuick.Layouts
import ISC
import ISC.Wafer
@@ -124,7 +125,7 @@ Item {
Layout.fillWidth: true
implicitHeight: 38
radius: 4
color: Qt.rgba(1, 1, 1, 0.02)
color: Theme.cardWash
border.color: Theme.cardBorder
border.width: 1
@@ -232,7 +233,7 @@ Item {
Label {
text: slotBox.filePath !== ""
? root.shortName(slotBox.filePath)
: (root.activeBox === slotBox.boxIndex ? " Select file from left panel" : "Click to select")
: (root.activeBox === slotBox.boxIndex ? "<- Select file from left panel..." : "Click to select")
font.pixelSize: Theme.fontXs
color: slotBox.filePath !== "" ? Theme.headingColor : Theme.bodyColor
opacity: slotBox.filePath !== "" ? 1.0 : 0.6
@@ -248,14 +249,15 @@ Item {
onClicked: slotBox.cleared()
background: Rectangle {
radius: Theme.radiusSm
color: parent.hovered ? Qt.rgba(1, 1, 1, 0.08) : "transparent"
color: parent.hovered ? Theme.flatButtonHover : "transparent"
}
contentItem: Label {
text: "✕"
contentItem: IconImage {
source: "icons/x.svg"
width: 14; height: 14
sourceSize.width: 14
sourceSize.height: 14
color: Theme.bodyColor
font.pixelSize: Theme.fontSm
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
anchors.centerIn: parent
}
}
}
@@ -291,44 +293,54 @@ Item {
background: Rectangle {
radius: Theme.radiusSm
color: resetBtn.hovered ? Qt.rgba(1, 1, 1, 0.08) : "transparent"
color: resetBtn.hovered ? Theme.flatButtonHover : "transparent"
}
contentItem: Label {
text: "↺"
font.pixelSize: Theme.fontLg
contentItem: IconImage {
source: "icons/rotate-ccw.svg"
width: 18; height: 18
sourceSize.width: 18
sourceSize.height: 18
color: Theme.bodyColor
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
anchors.centerIn: parent
}
ToolTip.visible: resetBtn.hovered
ToolTip.text: "Reset comparison"
}
Label {
text: "Dynamic Time Warping Profile Matching"
font.pixelSize: Theme.fontSm
color: Theme.bodyColor
}
}
// ── Error Banner ───────────────────────────────────────────
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: errorLabel.implicitHeight + 16
Layout.preferredHeight: errorRow.implicitHeight + 16
visible: root.errorMessage !== ""
color: Qt.rgba(0.93, 0.27, 0.27, 0.15)
border.color: "#ef4444"
color: Theme.errorSurface
border.color: Theme.statusErrorColor
border.width: 1
radius: Theme.radiusSm
Label {
id: errorLabel
RowLayout {
id: errorRow
anchors.fill: parent
anchors.margins: 8
text: "⚠ " + root.errorMessage
color: "#fca5a5"
font.pixelSize: Theme.fontSm
wrapMode: Text.WordWrap
spacing: 8
IconImage {
source: "icons/triangle-alert.svg"
width: 16; height: 16
sourceSize.width: 16
sourceSize.height: 16
color: Theme.errorTextSoft
Layout.alignment: Qt.AlignTop
}
Label {
id: errorLabel
text: root.errorMessage
color: Theme.errorTextSoft
font.pixelSize: Theme.fontSm
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
}
}
@@ -402,9 +414,9 @@ Item {
var plotH = height - padTop - padBottom
var range = (maxV - minV) || 1
ctx.strokeStyle = Qt.rgba(1, 1, 1, 0.08)
ctx.strokeStyle = Theme.chartGridLine
ctx.lineWidth = 1
ctx.fillStyle = Qt.rgba(1, 1, 1, 0.35)
ctx.fillStyle = Theme.chartAxisText
ctx.font = "10px sans-serif"
ctx.textAlign = "right"
@@ -507,10 +519,14 @@ Item {
visible: !root.hasSeries
spacing: 8
Label {
IconImage {
Layout.alignment: Qt.AlignHCenter
text: root.comparing ? "" : "📊"
font.pixelSize: 32
visible: !root.comparing
source: "icons/bar-chart.svg"
width: 32; height: 32
sourceSize.width: 32
sourceSize.height: 32
color: Theme.sideMutedText
}
Label {
Layout.alignment: Qt.AlignHCenter
@@ -655,10 +671,13 @@ Item {
anchors.centerIn: parent
visible: root.compareSensorLayout.length === 0 || !enableOverlapCheck.checked
spacing: 4
Label {
IconImage {
Layout.alignment: Qt.AlignHCenter
text: "🗺"
font.pixelSize: 24
source: "icons/map.svg"
width: 24; height: 24
sourceSize.width: 24
sourceSize.height: 24
color: Theme.sideMutedText
}
Label {
Layout.alignment: Qt.AlignHCenter
@@ -864,7 +883,7 @@ Item {
label: "DTW ALIGNMENT DISTANCE"
value: root.warpingDistance >= 0 ? root.warpingDistance.toFixed(2) : "--"
valueColor: root.warpingDistance >= 0
? (root.warpingDistance < 50 ? "#6ee7b7" : root.warpingDistance < 100 ? "#fde047" : "#ef4444")
? (root.warpingDistance < 50 ? Theme.metricGood : root.warpingDistance < 100 ? Theme.metricWarn : Theme.metricBad)
: Theme.sideMutedText
}
ReadoutCard {
@@ -878,7 +897,7 @@ Item {
label: "MAX SENSOR DEVIATION"
value: root.maxSensorDeviation >= 0 ? root.maxSensorDeviation.toFixed(2) + "°C" : "--"
valueColor: root.maxSensorDeviation >= 0
? (root.maxSensorDeviation < 1.0 ? "#6ee7b7" : root.maxSensorDeviation < 3.0 ? "#fde047" : "#ef4444")
? (root.maxSensorDeviation < 1.0 ? Theme.metricGood : root.maxSensorDeviation < 3.0 ? Theme.metricWarn : Theme.metricBad)
: Theme.sideMutedText
}
}
+9 -1
View File
@@ -1,5 +1,6 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.impl
import QtQuick.Layouts
import Qt.labs.qmlmodels
import ISC
@@ -181,10 +182,17 @@ Dialog {
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 12
text: "✕"
implicitWidth: 32
implicitHeight: 32
onClicked: root.close()
contentItem: IconImage {
source: "icons/x.svg"
width: 14; height: 14
sourceSize.width: 14
sourceSize.height: 14
color: Theme.buttonNeutralText
anchors.centerIn: parent
}
}
}
+25 -13
View File
@@ -1,5 +1,6 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.impl
import QtQuick.Layouts
import QtQuick.Dialogs
import ISC
@@ -123,19 +124,17 @@ Item {
ColorAnimation { duration: Theme.durationFast }
}
Text {
IconImage {
anchors.centerIn: parent
text: "✓"
font.pixelSize: Theme.fontMd
font.bold: true
source: "icons/check.svg"
width: 12; height: 12
sourceSize.width: 12
sourceSize.height: 12
color: Theme.panelBackground
opacity: toggle.checked ? 1.0 : 0.0
Behavior on opacity {
NumberAnimation { duration: Theme.durationFast }
}
// Small nudge to center the checkmark perfectly
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
}
@@ -366,7 +365,7 @@ Item {
width: 22
height: 22
radius: height / 2
color: "white"
color: Theme.toggleThumb
anchors.verticalCenter: parent.verticalCenter
x: Theme.isDarkMode ? parent.width - width - 3 : 3
@@ -452,12 +451,9 @@ Item {
}
}
Label {
Row {
anchors.centerIn: parent
text: "↓ Scroll for more"
font.pixelSize: Theme.fontSm
font.bold: true
color: Theme.bodyColor
spacing: 4
opacity: (settingsScroll.ScrollBar.vertical.position <= 0 && settingsScroll.contentHeight > settingsScroll.height) ? (scrollHintTimer.running ? 1 : 0) : 0
Behavior on opacity {
@@ -465,6 +461,22 @@ Item {
duration: 400
}
}
IconImage {
anchors.verticalCenter: parent.verticalCenter
source: "icons/chevron-down.svg"
width: 14; height: 14
sourceSize.width: 14
sourceSize.height: 14
color: Theme.bodyColor
}
Label {
anchors.verticalCenter: parent.verticalCenter
text: "Scroll for more"
font.pixelSize: Theme.fontSm
font.bold: true
color: Theme.bodyColor
}
}
}
}
+8 -4
View File
@@ -1,6 +1,7 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import QtQuick.Controls.impl
import QtQuick.Dialogs
import ISC
@@ -211,7 +212,7 @@ ColumnLayout {
id: statusPillText
anchors.centerIn: parent
text: root.isConnected ? "ACTIVE" : (root.isBusy ? deviceController.connectionStatus.replace("...", "").toUpperCase() : "INACTIVE")
color: "#111111"
color: Theme.statusBadgeText
font.pixelSize: Theme.fontXs
font.weight: Font.Bold
font.family: Theme.uiFontFamily
@@ -483,9 +484,12 @@ ColumnLayout {
anchors.rightMargin: Theme.panelPadding
spacing: 8
Text {
text: "📄"
font.pixelSize: Theme.fontSm
IconImage {
source: "icons/file-text.svg"
width: 14; height: 14
sourceSize.width: 14
sourceSize.height: 14
color: Theme.bodyColor
visible: root.csvPath !== ""
Layout.alignment: Qt.AlignVCenter
}
@@ -1,5 +1,6 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.impl
import QtQuick.Layouts
import ISC
@@ -32,18 +33,17 @@ ColumnLayout {
ColorAnimation { duration: Theme.durationFast }
}
Text {
IconImage {
anchors.centerIn: parent
text: "✓"
font.pixelSize: Theme.fontSm
font.bold: true
source: "../icons/check.svg"
width: 12; height: 12
sourceSize.width: 12
sourceSize.height: 12
color: Theme.panelBackground
opacity: toggle.checked ? 1.0 : 0.0
Behavior on opacity {
NumberAnimation { duration: Theme.durationFast }
}
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
}
@@ -205,7 +205,7 @@ ColumnLayout {
Item { Layout.fillWidth: true }
Label {
text: s.diff !== undefined ? s.diff : "—"
color: Theme.isDarkMode ? "#A78BFA" : "#8B5CF6"
color: Theme.diffAccent
font.family: Theme.codeFontFamily
font.pixelSize: Theme.fontMd
font.bold: true
@@ -64,7 +64,7 @@ Dialog {
id: overrideTag
anchors.centerIn: parent
text: "OVERRIDE"
color: "white"
color: Theme.statusBadgeText
font.pixelSize: Theme.fontXs
font.bold: true
font.letterSpacing: 1
@@ -1,6 +1,7 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import QtQuick.Controls.impl
import ISC
// ===== Stream Stats Dialog =====
@@ -72,7 +73,6 @@ Popup {
}
Button {
text: "✕"
flat: true
Layout.preferredWidth: 32
Layout.preferredHeight: 32
@@ -82,11 +82,13 @@ Popup {
radius: Theme.radiusXs
color: parent.hovered ? Theme.buttonNeutralHover : "transparent"
}
contentItem: Label {
text: parent.text
contentItem: IconImage {
source: "../icons/x.svg"
width: 14; height: 14
sourceSize.width: 14
sourceSize.height: 14
color: Theme.bodyColor
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
anchors.centerIn: parent
}
}
}
+15
View File
@@ -0,0 +1,15 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<line x1="18" x2="18" y1="20" y2="10" />
<line x1="12" x2="12" y1="20" y2="4" />
<line x1="6" x2="6" y1="20" y2="14" />
</svg>

After

Width:  |  Height:  |  Size: 334 B

+13
View File
@@ -0,0 +1,13 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M20 6 9 17l-5-5" />
</svg>

After

Width:  |  Height:  |  Size: 239 B

+13
View File
@@ -0,0 +1,13 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="m6 9 6 6 6-6" />
</svg>

After

Width:  |  Height:  |  Size: 236 B

+17
View File
@@ -0,0 +1,17 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" />
<path d="M14 2v4a2 2 0 0 0 2 2h4" />
<path d="M10 9H8" />
<path d="M16 13H8" />
<path d="M16 17H8" />
</svg>

After

Width:  |  Height:  |  Size: 392 B

+13
View File
@@ -0,0 +1,13 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z" />
</svg>

After

Width:  |  Height:  |  Size: 342 B

+14
View File
@@ -0,0 +1,14 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" />
<path d="M3 3v5h5" />
</svg>

After

Width:  |  Height:  |  Size: 297 B

@@ -0,0 +1,15 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="m21.73 18-8-14a2 2 0 0 0-3.46 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z" />
<path d="M12 9v4" />
<path d="M12 17h.01" />
</svg>

After

Width:  |  Height:  |  Size: 346 B

+14
View File
@@ -0,0 +1,14 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M18 6 6 18" />
<path d="m6 6 12 12" />
</svg>

After

Width:  |  Height:  |  Size: 260 B

+73 -27
View File
@@ -7,18 +7,23 @@ import QtQuick
// =============================================================================
// Sections:
// 1. Mode flag
// 2. Typography
// 2. Typography (families, pixel sizes, weights)
// 3. Motion
// 4. Tone palette (raw tones; everything else derives from these)
// 5. Surfaces (page / card / panel / workspace backgrounds)
// 4. Tone palette (raw tones; everything else derives from these)
// 5. Surfaces (page / card / panel / workspace backgrounds)
// 6. Borders
// 7. Text (headings, body, panel titles)
// 8. Controls (fields, buttons, checkbox)
// 9. Tracks (pill toggle + scrollbar)
// 10. Tabs (footer tab bar)
// 11. Side rail
// 12. Status (success / warning / error)
// 13. Geometry (radius / border width / spacing / sizing)
// 7. Text (headings, body, panel titles)
// 8. Controls (fields, buttons, checkbox, toggle)
// 9. Interaction overlays (hover / active washes mode-aware)
// 10. Tracks (pill toggle + scrollbar)
// 11. Tabs (mode toggle pills)
// 12. Side rail
// 13. Transport / toolbar
// 14. Status & badges (success / warning / error, badge text)
// 15. Sensor bands (wafer map dots)
// 16. Wafer family badges (source list avatars + accent bars)
// 17. Comparison & charts (metric grading, diff accent, canvas grid)
// 18. Geometry (radius / border width / spacing / sizing)
// =============================================================================
// Based on Codex themes:
// Dark (oscurange): surface #0B0B0F, ink #E6E6E6
@@ -29,7 +34,10 @@ QtObject {
// 1. Mode
property bool isDarkMode: true
// 2. Typography
// 2. Typography
readonly property string uiFontFamily: "Geist, Inter, system-ui, -apple-system, BlinkMacSystemFont, sans-serif"
readonly property string codeFontFamily: "\"Geist Mono\", ui-monospace, \"SFMono-Regular\", monospace"
// pixelSize scale map to closest token, tune globally
readonly property int font2xs: 9 // tiny metadata
readonly property int fontXs: 11 // captions, micro labels
@@ -44,22 +52,20 @@ QtObject {
readonly property int fontWeightMedium: 500
readonly property int fontWeightBold: 700
// 3. Motion
// 3. Motion
readonly property int durationFast: 120 // micro-interactions (focus ring, hover flash)
readonly property int durationBase: 180 // standard transitions (pill switch, row select)
readonly property int durationSlow: 260 // larger transitions (panel open/close)
readonly property var easeStandard: Easing.OutCubic
// 4. Tone palette (Codex theme v1 inspired)
readonly property string uiFontFamily: "Geist, Inter, system-ui, -apple-system, BlinkMacSystemFont, sans-serif"
readonly property string codeFontFamily: "\"Geist Mono\", ui-monospace, \"SFMono-Regular\", monospace"
// 4. Tone palette (Codex theme v1 inspired)
readonly property color themeSurface: isDarkMode ? "#0B0B0F" : "#F9F9F7"
readonly property color themeInk: isDarkMode ? "#E6E6E6" : "#2D2D2B"
readonly property color themeAccent: isDarkMode ? "#F9B98C" : "#B87333"
readonly property color themeSkill: isDarkMode ? "#479FFA" : "#3B82F6" // blue family both modes
readonly property color themeAdded: isDarkMode ? "#40C977" : "#00C853"
readonly property color themeRemoved: isDarkMode ? "#FA423E" : "#FF5F38"
readonly property color themeViolet: isDarkMode ? "#A78BFA" : "#8B5CF6"
readonly property color tone100: themeSurface
readonly property color tone150: isDarkMode ? "#101014" : "#F3F3F1"
@@ -71,7 +77,7 @@ QtObject {
readonly property color toneMute: isDarkMode ? "#A8A8A1" : "#85857E"
readonly property color toneBorder: isDarkMode ? "#2D2D34" : "#D2D2CE"
// 3. Surfaces
// 5. Surfaces
readonly property color pageBackground: tone100
readonly property color cardBackground: tone150
readonly property color panelBackground: tone150
@@ -79,7 +85,7 @@ QtObject {
readonly property color responseBackground: tone150
readonly property color subtleSectionBackground: tone250
// 4. Borders
// 6. Borders
readonly property color cardBorder: toneBorder
readonly property color cardSurfaceBorder: isDarkMode ? "#3A3A42" : "#C7C7C2"
readonly property color responseBorder: toneBorder
@@ -88,14 +94,14 @@ QtObject {
readonly property color outerFrameBorder: isDarkMode ? "#3A3A42" : "#C7C7C2"
readonly property color softBorder: isDarkMode ? "#24242A" : "#E4E4E1"
// 5. Text
// 7. Text
readonly property color headingColor: toneText
readonly property color bodyColor: toneMute
readonly property color subheadingColor: toneMute
readonly property color panelTitleText: toneMute
readonly property color disabledText: toneMute
// 6. Controls
// 8. Controls
// Fields
readonly property color fieldBackground: isDarkMode ? "#101014" : "#FFFFFF"
readonly property color fieldText: toneText
@@ -111,32 +117,48 @@ QtObject {
readonly property color primaryAccent: themeAccent
// Checkbox
readonly property color checkboxText: toneText
// Toggle switch thumb (white knob reads on both track colors)
readonly property color toggleThumb: "#FFFFFF"
// 7. Tracks (pill toggle, scrollbar thumb)
// 9. Interaction overlays
// Mode-aware washes. Never use raw Qt.rgba(1,1,1,x) in views: a white
// overlay is invisible on light-mode surfaces.
readonly property color listHoverBackground: isDarkMode ? Qt.rgba(1, 1, 1, 0.04) : Qt.rgba(0, 0, 0, 0.03)
readonly property color listActiveBackground: isDarkMode ? Qt.rgba(1, 1, 1, 0.06) : Qt.rgba(0, 0, 0, 0.05)
readonly property color flatButtonHover: isDarkMode ? Qt.rgba(1, 1, 1, 0.08) : Qt.rgba(0, 0, 0, 0.06)
readonly property color cardWash: isDarkMode ? Qt.rgba(1, 1, 1, 0.02) : Qt.rgba(0, 0, 0, 0.02)
// 10. Tracks (pill toggle, scrollbar thumb)
readonly property color trackBackground: isDarkMode ? "#25252B" : "#E2E2DE"
// 8. Tabs (mode toggle pills)
// 11. Tabs (mode toggle pills)
readonly property color tabActiveBackground: isDarkMode ? "#25252B" : "#FFFFFF"
// 9. Side rail
// 12. Side rail
readonly property color sideRailBackground: tone150
readonly property color sidePanelBackground: isDarkMode ? "#151518" : "#F3F3F1"
readonly property color sideActiveBackground: isDarkMode ? "#25252B" : "#FFFFFF"
readonly property color sideBorder: toneBorder
readonly property color sideMutedText: toneMute
// 10a. Transport / toolbar surfaces
// 13. Transport / toolbar surfaces
readonly property color transportButtonBg: tone250
readonly property color transportButtonHover: tone300
readonly property color liveColor: themeAdded
readonly property color recordColor: themeRemoved
// 10. Status
// 14. Status & badges
readonly property color statusSuccessColor: themeAdded
readonly property color statusWarningColor: isDarkMode ? "#E8A817" : "#B8860B" // amber/yellow, separate from accent
readonly property color statusErrorColor: themeRemoved
// Text placed ON a filled status pill / saturated chip:
readonly property color statusBadgeText: "#111111" // dark ink on bright status fills, both modes
readonly property color textOnColor: "#FFFFFF" // white text on deep saturated fills (avatars etc.)
// Error banner (soft red surface + readable red text)
readonly property color errorSurface: Qt.alpha(statusErrorColor, 0.15)
readonly property color errorTextSoft: isDarkMode ? "#FCA5A5" : "#B91C1C"
// -- 10b. Sensor bands (wafer map dots)
// 15. Sensor bands (wafer map dots)
readonly property color sensorInRange: statusSuccessColor
// ponytail: high-temp shares error red semantically correct (dangerous value),
// re-hue if colorblind testing demands a different channel.
@@ -145,7 +167,31 @@ QtObject {
readonly property color waferRingColor: toneBorder
readonly property color waferAxisColor: softBorder
// 11. Geometry
// 16. Wafer family badges (SourcePanel list)
// Accent = left bar / outline shade; Fill = avatar circle behind textOnColor.
// Family grouping mirrors FileBrowser's waferType first-letter convention.
readonly property color familyBlueAccent: "#3B82F6" // A / E / P
readonly property color familyBlueFill: "#1D4ED8"
readonly property color familyGreenAccent: "#10B981" // B / C / D
readonly property color familyGreenFill: "#065F46"
readonly property color familyVioletAccent: "#8B5CF6" // Z
readonly property color familyVioletFill: "#7C3AED"
readonly property color familyNeutralFill: "#374151" // unknown family
// 17. Comparison & charts
// Metric grading for DTW readout cards (good caution bad).
// Dark values are pastel (readable on tone150); light values are deepened
// so they still pass on near-white cards.
readonly property color metricGood: isDarkMode ? "#6EE7B7" : "#059669"
readonly property color metricWarn: isDarkMode ? "#FDE047" : "#B45309"
readonly property color metricBad: isDarkMode ? "#EF4444" : "#DC2626"
// DIFF column accent in ReadoutPanel
readonly property color diffAccent: themeViolet
// Canvas chart primitives (DTW plot grid + axis labels)
readonly property color chartGridLine: isDarkMode ? Qt.rgba(1, 1, 1, 0.08) : Qt.rgba(0, 0, 0, 0.10)
readonly property color chartAxisText: isDarkMode ? Qt.rgba(1, 1, 1, 0.35) : Qt.rgba(0, 0, 0, 0.45)
// 18. Geometry
// Radius
readonly property int radiusXs: 6 // fields, tight elements
readonly property int radiusSm: 8 // buttons