mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-10-14 21:20:48 +08:00
style(widget): adopt system type styles and control conventions
Replace fixed point sizes with semantic footnote/caption styles, dim unselected mode labels into a secondary tier, drop the mode track fill and capsule borders in favor of one capsule language, and reshape the toggles as borderless system-style pills. Section spacing unifies at 8pt and the error row gains a leading warning glyph. No behavior change.
This commit is contained in:
@@ -21,6 +21,12 @@ struct RoutingView: View {
|
|||||||
private var renderingMode: WidgetRenderingMode { systemRenderingMode }
|
private var renderingMode: WidgetRenderingMode { systemRenderingMode }
|
||||||
#endif
|
#endif
|
||||||
@Environment(\.colorScheme) private var colorScheme
|
@Environment(\.colorScheme) private var colorScheme
|
||||||
|
@Environment(\.colorSchemeContrast) private var systemContrast
|
||||||
|
#if DEBUG
|
||||||
|
private var contrast: ColorSchemeContrast { previewIncreaseContrast ? .increased : systemContrast }
|
||||||
|
#else
|
||||||
|
private var contrast: ColorSchemeContrast { systemContrast }
|
||||||
|
#endif
|
||||||
@Environment(\.accessibilityReduceMotion) private var systemReduceMotion
|
@Environment(\.accessibilityReduceMotion) private var systemReduceMotion
|
||||||
@Environment(\.accessibilityReduceTransparency) private var systemReduceTransparency
|
@Environment(\.accessibilityReduceTransparency) private var systemReduceTransparency
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
@@ -35,11 +41,11 @@ struct RoutingView: View {
|
|||||||
private func text(_ key: String) -> String { localized(key, language: entry.status.language) }
|
private func text(_ key: String) -> String { localized(key, language: entry.status.language) }
|
||||||
private let modes = ["rule", "global", "direct"]
|
private let modes = ["rule", "global", "direct"]
|
||||||
private var ink: Color { renderingMode == .fullColor ? (colorScheme == .dark ? .white : .black) : .primary }
|
private var ink: Color { renderingMode == .fullColor ? (colorScheme == .dark ? .white : .black) : .primary }
|
||||||
|
private var secondaryInk: Color { ink.opacity(contrast == .increased ? 0.8 : 0.6) }
|
||||||
@ViewBuilder private var selectionBackground: some View {
|
@ViewBuilder private var selectionBackground: some View {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if previewMaterial == "thin" && renderingMode == .fullColor && !reduceTransparency {
|
if previewMaterial == "thin" && renderingMode == .fullColor && !reduceTransparency {
|
||||||
Capsule().fill(.thinMaterial)
|
Capsule().fill(.thinMaterial)
|
||||||
.overlay(Capsule().strokeBorder(ink.opacity(0.15), lineWidth: 1))
|
|
||||||
} else {
|
} else {
|
||||||
automaticSelectionBackground
|
automaticSelectionBackground
|
||||||
}
|
}
|
||||||
@@ -57,11 +63,12 @@ struct RoutingView: View {
|
|||||||
.glassEffect(.regular, in: Capsule())
|
.glassEffect(.regular, in: Capsule())
|
||||||
} else {
|
} else {
|
||||||
Capsule().fill(.thinMaterial)
|
Capsule().fill(.thinMaterial)
|
||||||
.overlay(Capsule().strokeBorder(ink.opacity(0.15), lineWidth: 1))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private func modeInk(selected: Bool) -> Color {
|
private func modeInk(selected: Bool) -> Color {
|
||||||
guard selected && reduceTransparency && renderingMode == .fullColor else { return ink }
|
guard selected && reduceTransparency && renderingMode == .fullColor else {
|
||||||
|
return selected ? ink : secondaryInk
|
||||||
|
}
|
||||||
return colorScheme == .dark ? .black : .white
|
return colorScheme == .dark ? .black : .white
|
||||||
}
|
}
|
||||||
private var locale: Locale {
|
private var locale: Locale {
|
||||||
@@ -76,18 +83,17 @@ struct RoutingView: View {
|
|||||||
return Button(intent: SetRouting(action, value == true ? "false" : "true")) {
|
return Button(intent: SetRouting(action, value == true ? "false" : "true")) {
|
||||||
let label = HStack(spacing: 4) {
|
let label = HStack(spacing: 4) {
|
||||||
if !compact { Image(systemName: icon).font(.caption2) }
|
if !compact { Image(systemName: icon).font(.caption2) }
|
||||||
Text(title).font(.system(size: compact ? 11 : 12, weight: .medium))
|
Text(title).font(.caption)
|
||||||
.lineLimit(compact ? 2 : 1)
|
.lineLimit(compact ? 2 : 1)
|
||||||
.frame(height: compact ? 28 : nil, alignment: .topLeading)
|
.frame(height: compact ? 30 : nil, alignment: .topLeading)
|
||||||
}
|
}
|
||||||
let toggle = ZStack(alignment: .leading) {
|
let toggle = ZStack(alignment: .leading) {
|
||||||
Capsule().strokeBorder(ink.opacity(0.5), lineWidth: 1)
|
Capsule().fill(ink.opacity(value == true ? 0.28 : 0.08))
|
||||||
.background(ink.opacity(value == true ? 0.22 : 0.06), in: Capsule())
|
|
||||||
Circle().fill(ink)
|
Circle().fill(ink)
|
||||||
.frame(width: 12, height: 12)
|
.frame(width: 13, height: 13)
|
||||||
.offset(x: value.map { $0 ? 18.0 : 4.0 } ?? 11)
|
.offset(x: value.map { $0 ? 19.0 : 4.0 } ?? 11.5)
|
||||||
}
|
}
|
||||||
.frame(width: 34, height: 20)
|
.frame(width: 36, height: 22)
|
||||||
.environment(\.layoutDirection, .leftToRight)
|
.environment(\.layoutDirection, .leftToRight)
|
||||||
if compact {
|
if compact {
|
||||||
VStack(alignment: .leading, spacing: 8) {
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
@@ -102,7 +108,7 @@ struct RoutingView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.foregroundStyle(ink)
|
.foregroundStyle(secondaryInk)
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
.padding(8)
|
.padding(8)
|
||||||
.disabled(value == nil)
|
.disabled(value == nil)
|
||||||
@@ -126,12 +132,6 @@ struct RoutingView: View {
|
|||||||
content.padding(16)
|
content.padding(16)
|
||||||
.frame(width: family == .systemSmall ? 170 : 360, height: 170)
|
.frame(width: family == .systemSmall ? 170 : 360, height: 170)
|
||||||
.background { containerMaterial }
|
.background { containerMaterial }
|
||||||
.overlay {
|
|
||||||
if previewIncreaseContrast {
|
|
||||||
RoundedRectangle(cornerRadius: 24).strokeBorder(ink, lineWidth: 2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.contrast(previewIncreaseContrast ? 1.25 : 1)
|
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 24))
|
.clipShape(RoundedRectangle(cornerRadius: 24))
|
||||||
} else {
|
} else {
|
||||||
content.containerBackground(for: .widget) { containerMaterial }
|
content.containerBackground(for: .widget) { containerMaterial }
|
||||||
@@ -142,7 +142,7 @@ struct RoutingView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var content: some View {
|
private var content: some View {
|
||||||
VStack(alignment: .leading, spacing: family == .systemSmall ? 10 : 12) {
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
GeometryReader { geometry in
|
GeometryReader { geometry in
|
||||||
let width = (geometry.size.width - 4) / 3
|
let width = (geometry.size.width - 4) / 3
|
||||||
let orderedModes = rtl ? Array(modes.reversed()) : modes
|
let orderedModes = rtl ? Array(modes.reversed()) : modes
|
||||||
@@ -157,10 +157,7 @@ struct RoutingView: View {
|
|||||||
ForEach(orderedModes, id: \.self) { mode in
|
ForEach(orderedModes, id: \.self) { mode in
|
||||||
let selected = entry.status.mode == mode
|
let selected = entry.status.mode == mode
|
||||||
let label = Text(text("tray." + mode))
|
let label = Text(text("tray." + mode))
|
||||||
.font(.system(
|
.font(selected ? .footnote.weight(.semibold) : .footnote)
|
||||||
size: family == .systemSmall ? 12 : 13,
|
|
||||||
weight: selected ? .semibold : .regular
|
|
||||||
))
|
|
||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
.frame(height: 30)
|
.frame(height: 30)
|
||||||
@@ -175,7 +172,6 @@ struct RoutingView: View {
|
|||||||
.padding(.horizontal, 2)
|
.padding(.horizontal, 2)
|
||||||
.zIndex(1)
|
.zIndex(1)
|
||||||
}
|
}
|
||||||
.background(ink.opacity(0.04), in: Capsule())
|
|
||||||
.invalidatableContent()
|
.invalidatableContent()
|
||||||
.environment(\.layoutDirection, .leftToRight)
|
.environment(\.layoutDirection, .leftToRight)
|
||||||
}
|
}
|
||||||
@@ -188,7 +184,12 @@ struct RoutingView: View {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
if let error = entry.status.error {
|
if let error = entry.status.error {
|
||||||
Text(text(error)).font(.caption2).foregroundStyle(ink.opacity(0.8)).lineLimit(2)
|
Label {
|
||||||
|
Text(text(error)).font(.caption2).lineLimit(2)
|
||||||
|
} icon: {
|
||||||
|
Image(systemName: "exclamationmark.triangle.fill").font(.caption2)
|
||||||
|
}
|
||||||
|
.foregroundStyle(secondaryInk)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.environment(\.locale, locale)
|
.environment(\.locale, locale)
|
||||||
|
|||||||
Reference in New Issue
Block a user