From 92317e364cffb4d05c6eac7688748d439c58fe7c Mon Sep 17 00:00:00 2001 From: Jacob Fu <141651335+FuJacob@users.noreply.github.com> Date: Sat, 30 May 2026 15:40:34 -0700 Subject: [PATCH] Replace floating Clear link with a Reset button in language and rules editors The Clear control sat alone in the top-right corner of the Languages and Rules cards (the section title comes from the enclosing Section, so nothing balanced it), which read as stray. Move it to a proper bordered Reset button at the bottom-right of each editor, with an arrow.counterclockwise icon. Same behavior (restores the default set / clears rules); only the placement and affordance change. --- Cotabby/UI/CustomRulesEditor.swift | 35 +++++++++++++-------------- Cotabby/UI/LanguageTagsEditor.swift | 37 ++++++++++++++--------------- 2 files changed, 35 insertions(+), 37 deletions(-) diff --git a/Cotabby/UI/CustomRulesEditor.swift b/Cotabby/UI/CustomRulesEditor.swift index 442f6263..1367f7af 100644 --- a/Cotabby/UI/CustomRulesEditor.swift +++ b/Cotabby/UI/CustomRulesEditor.swift @@ -3,14 +3,14 @@ import SwiftUI /// File overview: /// Editor for the user's custom autocomplete rules. Rules are short imperative style directives /// (e.g. "Use British spelling") shown as removable chips, added freeform or by tapping a suggested -/// chip. "Clear" removes every rule (rules are opt-in, so the baseline is empty). +/// chip. A bottom "Reset" button removes every rule (rules are opt-in, so the baseline is empty). /// /// The chip and flow-layout primitives live in `TagChip.swift`, shared with `LanguageTagsEditor`. struct CustomRulesEditor: View { @ObservedObject var suggestionSettings: SuggestionSettingsModel /// When false, the editor drops its own "Rules" title so an enclosing `Section("Rules")` can - /// supply the heading without duplicating it. The Clear control stays in place either way. + /// supply the heading without duplicating it. The Reset control stays in place either way. /// Defaults to true so standalone uses (e.g. onboarding) keep their inline title. var showsTitleHeader: Bool = true @@ -32,22 +32,9 @@ struct CustomRulesEditor: View { var body: some View { VStack(alignment: .leading, spacing: 14) { - if showsTitleHeader || canClear { - HStack { - if showsTitleHeader { - Text("Rules") - .font(.system(size: 13, weight: .medium)) - } - Spacer() - if canClear { - Button("Clear") { - suggestionSettings.clearRules() - } - .buttonStyle(.plain) - .font(.system(size: 12)) - .foregroundStyle(.secondary) - } - } + if showsTitleHeader { + Text("Rules") + .font(.system(size: 13, weight: .medium)) } if !rules.isEmpty { @@ -87,6 +74,18 @@ struct CustomRulesEditor: View { } } } + + if canClear { + HStack { + Spacer() + Button { + suggestionSettings.clearRules() + } label: { + Label("Reset", systemImage: "arrow.counterclockwise") + } + .controlSize(.small) + } + } } } diff --git a/Cotabby/UI/LanguageTagsEditor.swift b/Cotabby/UI/LanguageTagsEditor.swift index ca23454a..550017c5 100644 --- a/Cotabby/UI/LanguageTagsEditor.swift +++ b/Cotabby/UI/LanguageTagsEditor.swift @@ -3,13 +3,13 @@ import SwiftUI /// File overview: /// Editor for the languages the user writes in. Mirrors `CustomRulesEditor`: declared languages are /// removable chips, added by tapping a suggestion (shown with its native name) or typing a custom -/// one. "Clear" removes them all. The baseline is empty, which means "just follow the surrounding -/// text." The chip and flow-layout primitives are shared via `TagChip.swift`. +/// one. A bottom "Reset" button restores the default language set. The chip and flow-layout +/// primitives are shared via `TagChip.swift`. struct LanguageTagsEditor: View { @ObservedObject var suggestionSettings: SuggestionSettingsModel /// When false, the editor drops its own "Languages" title so an enclosing `Section("Languages")` - /// can supply the heading without duplicating it. The Clear control stays in place either way. + /// can supply the heading without duplicating it. The Reset control stays in place either way. /// Defaults to true so standalone uses (e.g. onboarding) keep their inline title. var showsTitleHeader: Bool = true @@ -31,22 +31,9 @@ struct LanguageTagsEditor: View { var body: some View { VStack(alignment: .leading, spacing: 14) { - if showsTitleHeader || canClear { - HStack { - if showsTitleHeader { - Text("Languages") - .font(.system(size: 13, weight: .medium)) - } - Spacer() - if canClear { - Button("Clear") { - suggestionSettings.clearLanguages() - } - .buttonStyle(.plain) - .font(.system(size: 12)) - .foregroundStyle(.secondary) - } - } + if showsTitleHeader { + Text("Languages") + .font(.system(size: 13, weight: .medium)) } if !languages.isEmpty { @@ -93,6 +80,18 @@ struct LanguageTagsEditor: View { + "set of languages, and local models vary, so some languages may not work.") .font(.caption2) .foregroundStyle(.tertiary) + + if canClear { + HStack { + Spacer() + Button { + suggestionSettings.clearLanguages() + } label: { + Label("Reset", systemImage: "arrow.counterclockwise") + } + .controlSize(.small) + } + } } }