style: soften settings page borders

This commit is contained in:
Haitao Pan 2026-03-30 15:33:13 +08:00
parent 9bcc4b1fac
commit 2b836c5c6e
5 changed files with 87 additions and 47 deletions

View File

@ -12,6 +12,8 @@ import '../../models/app_models.dart';
import '../../runtime/gateway_runtime.dart'; import '../../runtime/gateway_runtime.dart';
import '../../runtime/runtime_controllers.dart'; import '../../runtime/runtime_controllers.dart';
import '../../runtime/runtime_models.dart'; import '../../runtime/runtime_models.dart';
import '../../theme/app_palette.dart';
import '../../theme/app_theme.dart';
import 'codex_integration_card.dart'; import 'codex_integration_card.dart';
import 'skill_directory_authorization_card.dart'; import 'skill_directory_authorization_card.dart';
import '../../widgets/settings_page_shell.dart'; import '../../widgets/settings_page_shell.dart';
@ -207,6 +209,8 @@ class SettingsPageStateInternal extends State<SettingsPage> {
return AnimatedBuilder( return AnimatedBuilder(
animation: controller, animation: controller,
builder: (context, _) { builder: (context, _) {
final theme = Theme.of(context);
final palette = context.palette;
final featurePlatform = resolveUiFeaturePlatformFromContext(context); final featurePlatform = resolveUiFeaturePlatformFromContext(context);
final uiFeatures = controller.featuresFor(featurePlatform); final uiFeatures = controller.featuresFor(featurePlatform);
tabInternal = uiFeatures.sanitizeSettingsTab(controller.settingsTab); tabInternal = uiFeatures.sanitizeSettingsTab(controller.settingsTab);
@ -220,53 +224,80 @@ class SettingsPageStateInternal extends State<SettingsPage> {
(tabInternal != SettingsTab.gateway || (tabInternal != SettingsTab.gateway ||
integrationSubTabInternal == integrationSubTabInternal ==
GatewayIntegrationSubTabInternal.acp); GatewayIntegrationSubTabInternal.acp);
return SettingsPageBodyShell( return Theme(
padding: const EdgeInsets.fromLTRB(32, 32, 32, 8), data: theme.copyWith(
breadcrumbs: buildSettingsBreadcrumbs( inputDecorationTheme: theme.inputDecorationTheme.copyWith(
controller, border: OutlineInputBorder(
tab: tabInternal, borderRadius: BorderRadius.circular(AppRadius.input),
detail: detailInternal, borderSide: BorderSide(
navigationContext: navigationContextInternal, color: palette.strokeSoft,
), width: settingsHairlineBorderWidthInternal,
title: appText('设置', 'Settings'),
subtitle: showingDetail
? appText(
'当前正在编辑详细设置参数,保存后会回写到对应状态页。',
'You are editing detailed settings. Saved values flow back to the related status page.',
)
: appText(
'配置 $kProductBrandName 工作区、网关默认项、界面与诊断选项',
'Configure workspace, gateway defaults, appearance, and diagnostics for $kProductBrandName.',
), ),
trailing: SizedBox( ),
width: showingDetail ? 168 : 220, enabledBorder: OutlineInputBorder(
child: showingDetail borderRadius: BorderRadius.circular(AppRadius.input),
? OutlinedButton.icon( borderSide: BorderSide(
onPressed: () { color: palette.strokeSoft,
controller.closeSettingsDetail(); width: settingsHairlineBorderWidthInternal,
setState(() { ),
detailInternal = null; ),
navigationContextInternal = null; focusedBorder: OutlineInputBorder(
}); borderRadius: BorderRadius.circular(AppRadius.input),
}, borderSide: BorderSide(
icon: const Icon(Icons.arrow_back_rounded), color: palette.accent.withValues(alpha: 0.32),
label: Text(appText('返回概览', 'Back to overview')), width: settingsHairlineBorderWidthInternal,
) ),
: TextField( ),
decoration: InputDecoration( ),
hintText: appText('搜索设置', 'Search settings'),
prefixIcon: Icon(Icons.search_rounded),
),
),
), ),
globalApplyBar: showGlobalApplyBar child: SettingsPageBodyShell(
? buildGlobalApplyBarInternal(context, controller) padding: const EdgeInsets.fromLTRB(32, 32, 32, 8),
: null, breadcrumbs: buildSettingsBreadcrumbs(
bodyChildren: buildContentForCurrentStateInternal( controller,
context, tab: tabInternal,
controller, detail: detailInternal,
settings, navigationContext: navigationContextInternal,
uiFeatures, ),
title: appText('设置', 'Settings'),
subtitle: showingDetail
? appText(
'当前正在编辑详细设置参数,保存后会回写到对应状态页。',
'You are editing detailed settings. Saved values flow back to the related status page.',
)
: appText(
'配置 $kProductBrandName 工作区、网关默认项、界面与诊断选项',
'Configure workspace, gateway defaults, appearance, and diagnostics for $kProductBrandName.',
),
trailing: SizedBox(
width: showingDetail ? 168 : 220,
child: showingDetail
? OutlinedButton.icon(
onPressed: () {
controller.closeSettingsDetail();
setState(() {
detailInternal = null;
navigationContextInternal = null;
});
},
icon: const Icon(Icons.arrow_back_rounded),
label: Text(appText('返回概览', 'Back to overview')),
)
: TextField(
decoration: InputDecoration(
hintText: appText('搜索设置', 'Search settings'),
prefixIcon: Icon(Icons.search_rounded),
),
),
),
globalApplyBar: showGlobalApplyBar
? buildGlobalApplyBarInternal(context, controller)
: null,
bodyChildren: buildContentForCurrentStateInternal(
context,
controller,
settings,
uiFeatures,
),
), ),
); );
}, },

View File

@ -118,6 +118,7 @@ extension SettingsPageGatewayMixinInternal on SettingsPageStateInternal {
) )
else else
SurfaceCard( SurfaceCard(
borderWidth: settingsHairlineBorderWidthInternal,
child: Text( child: Text(
appText( appText(
'当前发布配置未开放 Vault Server 参数。', '当前发布配置未开放 Vault Server 参数。',
@ -195,6 +196,7 @@ extension SettingsPageGatewayMixinInternal on SettingsPageStateInternal {
) )
else else
SurfaceCard( SurfaceCard(
borderWidth: settingsHairlineBorderWidthInternal,
child: Text( child: Text(
appText( appText(
'当前发布配置未开放 Vault Server 参数。', '当前发布配置未开放 Vault Server 参数。',
@ -650,6 +652,7 @@ extension SettingsPageGatewayMixinInternal on SettingsPageStateInternal {
}) { }) {
final theme = Theme.of(context); final theme = Theme.of(context);
return SurfaceCard( return SurfaceCard(
borderWidth: settingsHairlineBorderWidthInternal,
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [

View File

@ -35,6 +35,7 @@ extension SettingsPageGatewayConnectionMixinInternal
SettingsSnapshot settings, SettingsSnapshot settings,
) { ) {
return SurfaceCard( return SurfaceCard(
borderWidth: settingsHairlineBorderWidthInternal,
child: buildOpenClawGatewayCardBodyInternal( child: buildOpenClawGatewayCardBodyInternal(
context, context,
controller, controller,
@ -352,6 +353,7 @@ extension SettingsPageGatewayConnectionMixinInternal
SettingsSnapshot settings, SettingsSnapshot settings,
) { ) {
return SurfaceCard( return SurfaceCard(
borderWidth: settingsHairlineBorderWidthInternal,
child: buildVaultProviderCardBodyInternal(context, controller, settings), child: buildVaultProviderCardBodyInternal(context, controller, settings),
); );
} }

View File

@ -27,6 +27,8 @@ import 'settings_page_multi_agent.dart';
import 'settings_page_support.dart'; import 'settings_page_support.dart';
import 'settings_page_device.dart'; import 'settings_page_device.dart';
const double settingsHairlineBorderWidthInternal = 0.55;
class EditableFieldInternal extends StatefulWidget { class EditableFieldInternal extends StatefulWidget {
const EditableFieldInternal({ const EditableFieldInternal({
super.key, super.key,

View File

@ -12,6 +12,7 @@ class SurfaceCard extends StatefulWidget {
this.padding = const EdgeInsets.all(AppSpacing.md), this.padding = const EdgeInsets.all(AppSpacing.md),
this.onTap, this.onTap,
this.borderRadius = AppRadius.card, this.borderRadius = AppRadius.card,
this.borderWidth = 1,
this.color, this.color,
this.tone = SurfaceCardTone.standard, this.tone = SurfaceCardTone.standard,
}); });
@ -20,6 +21,7 @@ class SurfaceCard extends StatefulWidget {
final EdgeInsetsGeometry padding; final EdgeInsetsGeometry padding;
final VoidCallback? onTap; final VoidCallback? onTap;
final double borderRadius; final double borderRadius;
final double borderWidth;
final Color? color; final Color? color;
final SurfaceCardTone tone; final SurfaceCardTone tone;
@ -49,7 +51,7 @@ class _SurfaceCardState extends State<SurfaceCard> {
SurfaceCardTone.standard => BoxDecoration( SurfaceCardTone.standard => BoxDecoration(
color: (_hovered && widget.onTap != null ? hoveredColor : baseColor) color: (_hovered && widget.onTap != null ? hoveredColor : baseColor)
.withValues(alpha: 0.98), .withValues(alpha: 0.98),
border: Border.all(color: borderColor), border: Border.all(color: borderColor, width: widget.borderWidth),
borderRadius: BorderRadius.circular(widget.borderRadius), borderRadius: BorderRadius.circular(widget.borderRadius),
boxShadow: widget.onTap != null && _hovered boxShadow: widget.onTap != null && _hovered
? [palette.chromeShadowAmbient] ? [palette.chromeShadowAmbient]
@ -58,7 +60,7 @@ class _SurfaceCardState extends State<SurfaceCard> {
SurfaceCardTone.chrome => BoxDecoration( SurfaceCardTone.chrome => BoxDecoration(
color: (_hovered && widget.onTap != null ? hoveredColor : baseColor) color: (_hovered && widget.onTap != null ? hoveredColor : baseColor)
.withValues(alpha: 0.98), .withValues(alpha: 0.98),
border: Border.all(color: borderColor), border: Border.all(color: borderColor, width: widget.borderWidth),
borderRadius: BorderRadius.circular(widget.borderRadius), borderRadius: BorderRadius.circular(widget.borderRadius),
boxShadow: [ boxShadow: [
if (_hovered && widget.onTap != null) palette.chromeShadowAmbient, if (_hovered && widget.onTap != null) palette.chromeShadowAmbient,