Settings: toggle triage labels between encouraging and classic

Add an "Encouraging to-do labels" toggle (Settings → Appearance, default on). On, badges read Max Impact / High Impact / Worthwhile / Someday; off, the classic Critical / High / Medium / Low.

TriageLevel exposes encouragingLabel + plainLabel + label(encouraging:); TriageBadge and the TriageLabelCell sizers read the new TriageLabelStyle.encouragingKey flag so the column width tracks the active set.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
2026-06-13 17:23:01 -07:00
co-authored by Claude Opus 4.8
parent ee0f58be64
commit 201404f9e3
4 changed files with 42 additions and 5 deletions
+8
View File
@@ -63,6 +63,14 @@ enum AppAppearance: String, CaseIterable, Identifiable {
}
}
/// Whether triage badges show the encouraging, opportunity-framed labels
/// (Max Impact / High Impact / Worthwhile / Someday) or the classic severity words
/// (Critical / High / Medium / Low). Toggled in Settings Appearance; defaults to
/// encouraging. Just a labeling preference the ranking and colors are unchanged.
enum TriageLabelStyle {
static let encouragingKey = "nucleic.triageEncouragingLabels"
}
/// User-selectable global text size (Settings Appearance), applied app-wide via
/// `.dynamicTypeSize` so the semantic fonts the UI uses scale together.
enum AppTextSize: String, CaseIterable, Identifiable {
+7
View File
@@ -15,6 +15,7 @@ struct SettingsView: View {
@AppStorage(AppAppearance.storageKey) private var appearanceRaw = AppAppearance.dark.rawValue
@AppStorage(TranscriptDisplay.showDebugKey) private var showDebugLines = false
@AppStorage(StreakBadge.showKey) private var showStreak = true
@AppStorage(TriageLabelStyle.encouragingKey) private var encouragingTriageLabels = true
private var choice: IntelligenceChoice { IntelligenceChoice(rawValue: choiceRaw) ?? .onDevice }
private var textSize: AppTextSize { AppTextSize(rawValue: textSizeRaw) ?? .medium }
@@ -40,6 +41,12 @@ struct SettingsView: View {
Text("Shows a day-streak badge next to the home greeting, counting consecutive days with activity.")
.font(.caption).foregroundStyle(.secondary)
.fixedSize(horizontal: false, vertical: true)
Toggle("Encouraging to-do labels", isOn: $encouragingTriageLabels)
Text(encouragingTriageLabels
? "Triage badges read as opportunities: Max Impact, High Impact, Worthwhile, Someday."
: "Triage badges use the classic severity words: Critical, High, Medium, Low.")
.font(.caption).foregroundStyle(.secondary)
.fixedSize(horizontal: false, vertical: true)
}
Section("Transcript") {
+8 -2
View File
@@ -489,11 +489,17 @@ private struct TriageLabelCell: View {
/// any level reads clearly, even on light backgrounds); the reason shows on hover.
private struct TriageBadge: View {
let item: TriageItem
// Encouraging vs classic severity wording (Settings Appearance). The hidden
// sizers in TriageLabelCell read the same key, so the column width tracks whichever
// labels are active.
@AppStorage(TriageLabelStyle.encouragingKey) private var encouraging = true
private var label: String { item.level.label(encouraging: encouraging) }
var body: some View {
HStack(spacing: 4) {
Circle().fill(item.level.tint).frame(width: 7, height: 7)
Text(item.level.label)
Text(label)
.font(.caption2.weight(.semibold))
.foregroundStyle(.secondary)
}
@@ -501,7 +507,7 @@ private struct TriageBadge: View {
.background(item.level.tint.opacity(0.14), in: .capsule)
.overlay(Capsule().strokeBorder(item.level.tint.opacity(0.35), lineWidth: 0.5))
.fixedSize()
.help(item.reason.map { "\(item.level.label): \($0)" } ?? "Impact: \(item.level.label)")
.help(item.reason.map { "\(label): \($0)" } ?? "Impact: \(label)")
}
}
+19 -3
View File
@@ -10,9 +10,9 @@ public enum TriageLevel: String, Sendable, Codable, CaseIterable {
case medium
case low
/// Short, upbeat label for the badge. Framed as opportunity, not alarm these are
/// what the user *sees*; the case names / model tokens stay the technical vocabulary.
public var label: String {
/// Upbeat label framed as opportunity, not alarm. The default badge text; the user
/// can switch to `plainLabel` in Settings. Case names / model tokens stay technical.
public var encouragingLabel: String {
switch self {
case .critical: "Max Impact"
case .high: "High Impact"
@@ -21,6 +21,22 @@ public enum TriageLevel: String, Sendable, Codable, CaseIterable {
}
}
/// Classic severity words, for users who prefer the plain ranking over the
/// encouraging framing (toggled in Settings).
public var plainLabel: String {
switch self {
case .critical: "Critical"
case .high: "High"
case .medium: "Medium"
case .low: "Low"
}
}
/// The badge text for the user's chosen labeling style.
public func label(encouraging: Bool) -> String {
encouraging ? encouragingLabel : plainLabel
}
/// Higher = more pressing. For thresholding and ordering.
public var severity: Int {
switch self {