From 1aab170290a83f39c19e955e63ec50f8507f1ad9 Mon Sep 17 00:00:00 2001 From: Haitao Pan Date: Thu, 26 Mar 2026 20:31:24 +0800 Subject: [PATCH] Adopt document workspace visual baseline --- lib/app/app_shell_desktop.dart | 86 +------- lib/app/app_shell_web.dart | 34 +-- lib/features/assistant/assistant_page.dart | 233 +++++++------------- lib/features/mobile/mobile_shell.dart | 72 +----- lib/theme/app_palette.dart | 142 ++++++------ lib/theme/app_theme.dart | 36 +-- lib/widgets/desktop_workspace_scaffold.dart | 12 +- lib/widgets/sidebar_navigation.dart | 84 +++---- lib/widgets/surface_card.dart | 18 +- 9 files changed, 212 insertions(+), 505 deletions(-) diff --git a/lib/app/app_shell_desktop.dart b/lib/app/app_shell_desktop.dart index af2a0dd9..d111f593 100644 --- a/lib/app/app_shell_desktop.dart +++ b/lib/app/app_shell_desktop.dart @@ -63,7 +63,6 @@ class _AppShellState extends State { builder: (context, constraints) { final palette = context.palette; final platform = Theme.of(context).platform; - final brightness = Theme.of(context).brightness; final isCompactMobile = (platform == TargetPlatform.iOS || platform == TargetPlatform.android) && @@ -287,75 +286,9 @@ class _AppShellState extends State { ), child: DecoratedBox( decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - palette.chromeBackground, - palette.canvas, - ], - stops: const [0.0, 0.68], - ), - ), - child: Stack( - children: [ - Positioned( - top: -180, - right: -80, - child: IgnorePointer( - child: Container( - width: 420, - height: 420, - decoration: BoxDecoration( - shape: BoxShape.circle, - gradient: RadialGradient( - colors: [ - palette.chromeHighlight - .withValues( - alpha: - brightness == - Brightness.dark - ? 0.14 - : 0.42, - ), - palette.chromeHighlight - .withValues(alpha: 0), - ], - ), - ), - ), - ), - ), - Positioned( - bottom: -220, - left: -140, - child: IgnorePointer( - child: Container( - width: 360, - height: 360, - decoration: BoxDecoration( - shape: BoxShape.circle, - gradient: RadialGradient( - colors: [ - palette.chromeInset.withValues( - alpha: - brightness == - Brightness.dark - ? 0.14 - : 0.24, - ), - palette.chromeInset.withValues( - alpha: 0, - ), - ], - ), - ), - ), - ), - ), - _buildCurrentPage(controller.openDetail), - ], + color: palette.canvas, ), + child: _buildCurrentPage(controller.openDetail), ), ), ), @@ -449,24 +382,13 @@ class _SidebarRevealRailState extends State<_SidebarRevealRail> { duration: const Duration(milliseconds: 180), width: _hovered ? 22 : 10, decoration: BoxDecoration( - gradient: _hovered - ? LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - palette.chromeHighlight.withValues(alpha: 0.92), - palette.chromeSurface, - ], - ) - : null, - color: _hovered ? null : Colors.transparent, + color: _hovered ? palette.surfacePrimary : Colors.transparent, borderRadius: const BorderRadius.horizontal( right: Radius.circular(14), ), border: Border.all( - color: _hovered ? palette.chromeStroke : Colors.transparent, + color: _hovered ? palette.strokeSoft : Colors.transparent, ), - boxShadow: _hovered ? [palette.chromeShadowLift] : const [], ), child: _hovered ? Icon( diff --git a/lib/app/app_shell_web.dart b/lib/app/app_shell_web.dart index f721b450..f4ceeee5 100644 --- a/lib/app/app_shell_web.dart +++ b/lib/app/app_shell_web.dart @@ -251,38 +251,8 @@ class _WebShellBody extends StatelessWidget { return Padding( padding: const EdgeInsets.only(top: 4, right: 4), child: DecoratedBox( - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [palette.chromeBackground, palette.canvas], - stops: const [0.0, 0.68], - ), - ), - child: Stack( - children: [ - Positioned( - top: -180, - right: -80, - child: IgnorePointer( - child: Container( - width: 420, - height: 420, - decoration: BoxDecoration( - shape: BoxShape.circle, - gradient: RadialGradient( - colors: [ - palette.chromeHighlight.withValues(alpha: 0.32), - palette.chromeHighlight.withValues(alpha: 0), - ], - ), - ), - ), - ), - ), - child, - ], - ), + decoration: BoxDecoration(color: palette.canvas), + child: child, ), ); } diff --git a/lib/features/assistant/assistant_page.dart b/lib/features/assistant/assistant_page.dart index 62e9437f..1e9b783c 100644 --- a/lib/features/assistant/assistant_page.dart +++ b/lib/features/assistant/assistant_page.dart @@ -1604,17 +1604,9 @@ class _AssistantSideTabRail extends StatelessWidget { key: const Key('assistant-side-pane'), width: 46, decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - palette.chromeHighlight.withValues(alpha: 0.96), - palette.chromeSurface, - ], - ), + color: palette.chromeSurface, borderRadius: BorderRadius.circular(8), - border: Border.all(color: palette.chromeStroke), - boxShadow: [palette.chromeShadowAmbient], + border: Border.all(color: palette.strokeSoft), ), child: Column( children: [ @@ -1636,7 +1628,7 @@ class _AssistantSideTabRail extends StatelessWidget { ), if (favoriteDestinations.isNotEmpty) ...[ const SizedBox(height: 4), - Container(width: 24, height: 1, color: palette.chromeStroke), + Container(width: 24, height: 1, color: palette.strokeSoft), const SizedBox(height: 4), Expanded( child: SingleChildScrollView( @@ -1673,9 +1665,9 @@ class _AssistantSideTabRail extends StatelessWidget { : appText('收起侧板', 'Collapse side pane'), onPressed: onToggleCollapsed, style: IconButton.styleFrom( - backgroundColor: palette.chromeSurface, + backgroundColor: palette.surfacePrimary, foregroundColor: palette.textSecondary, - side: BorderSide(color: palette.chromeStroke), + side: BorderSide(color: palette.strokeSoft), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), @@ -1734,30 +1726,17 @@ class _AssistantSideTabButtonState extends State<_AssistantSideTabButton> { width: 34, height: 34, decoration: BoxDecoration( - gradient: widget.selected || _hovered - ? LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - palette.chromeHighlight.withValues( - alpha: widget.selected ? 0.96 : 0.84, - ), - widget.selected - ? palette.chromeSurface - : palette.chromeSurfacePressed, - ], - ) - : null, - color: widget.selected || _hovered ? null : Colors.transparent, + color: widget.selected + ? palette.surfacePrimary + : _hovered + ? palette.surfaceSecondary + : Colors.transparent, borderRadius: BorderRadius.circular(8), border: Border.all( color: widget.selected || _hovered - ? palette.chromeStroke + ? palette.strokeSoft : Colors.transparent, ), - boxShadow: widget.selected - ? [palette.chromeShadowLift] - : const [], ), child: Icon( widget.icon, @@ -1903,22 +1882,20 @@ class _ConversationArea extends StatelessWidget { children: [ Padding( padding: EdgeInsets.fromLTRB(10, 8, 10 + topTrailingInset, 8), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Spacer(), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - _MessageViewModeChip( - value: messageViewMode, - onSelected: onMessageViewModeChanged, - ), - const SizedBox(width: 6), - _ConnectionChip(controller: controller), - ], - ), - ], + child: Align( + alignment: Alignment.centerRight, + child: Wrap( + spacing: 6, + runSpacing: 6, + alignment: WrapAlignment.end, + children: [ + _MessageViewModeChip( + value: messageViewMode, + onSelected: onMessageViewModeChanged, + ), + _ConnectionChip(controller: controller), + ], + ), ), ), Divider(height: 1, color: palette.strokeSoft), @@ -3248,16 +3225,16 @@ class _ComposerBarState extends State<_ComposerBar> { decoration: InputDecoration( isCollapsed: true, filled: true, - fillColor: palette.chromeSurface, + fillColor: palette.surfacePrimary, contentPadding: const EdgeInsets.fromLTRB(10, 8, 10, 8), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8), - borderSide: BorderSide(color: palette.chromeStroke), + borderSide: BorderSide(color: palette.strokeSoft), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: BorderSide( - color: palette.accent.withValues(alpha: 0.18), + color: palette.accent.withValues(alpha: 0.24), ), ), hintText: appText( @@ -3522,19 +3499,9 @@ class _ComposerIconButtonState extends State<_ComposerIconButton> { width: 34, height: 34, decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - palette.chromeHighlight.withValues(alpha: _hovered ? 0.94 : 0.88), - _hovered ? palette.chromeSurfacePressed : palette.chromeSurface, - ], - ), + color: _hovered ? palette.surfaceSecondary : palette.surfacePrimary, borderRadius: BorderRadius.circular(8), - border: Border.all(color: palette.chromeStroke), - boxShadow: [ - _hovered ? palette.chromeShadowLift : palette.chromeShadowAmbient, - ], + border: Border.all(color: palette.strokeSoft), ), child: Icon(widget.icon, size: 18, color: palette.textMuted), ), @@ -3580,21 +3547,9 @@ class _ComposerToolbarChipState extends State<_ComposerToolbarChip> { child: Container( padding: widget.padding, decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - palette.chromeHighlight.withValues( - alpha: _hovered ? 0.94 : 0.88, - ), - _hovered ? palette.chromeSurfacePressed : palette.chromeSurface, - ], - ), + color: _hovered ? palette.surfaceSecondary : palette.surfacePrimary, borderRadius: BorderRadius.circular(AppRadius.chip), - border: Border.all(color: palette.chromeStroke), - boxShadow: [ - _hovered ? palette.chromeShadowLift : palette.chromeShadowAmbient, - ], + border: Border.all(color: palette.strokeSoft), ), child: Row( mainAxisSize: MainAxisSize.min, @@ -3654,12 +3609,12 @@ class _SingleAgentProviderBadge extends StatelessWidget { decoration: BoxDecoration( color: isAuto ? palette.accent.withValues(alpha: 0.16) - : palette.chromeSurfacePressed, + : palette.surfaceSecondary, borderRadius: BorderRadius.circular(999), border: Border.all( color: isAuto ? palette.accent.withValues(alpha: 0.4) - : palette.chromeStroke, + : palette.strokeSoft, ), ), child: Text( @@ -3719,33 +3674,38 @@ class _MessageBubble extends StatelessWidget { Widget build(BuildContext context) { final theme = Theme.of(context); final palette = context.palette; - final borderColor = switch (tone) { - _BubbleTone.user => theme.colorScheme.primary.withValues(alpha: 0.10), - _BubbleTone.agent => theme.colorScheme.tertiary.withValues(alpha: 0.10), - _BubbleTone.assistant => palette.surfaceSecondary, + final backgroundColor = switch (tone) { + _BubbleTone.user => palette.surfaceSecondary, + _BubbleTone.agent => palette.surfaceTertiary.withValues(alpha: 0.78), + _BubbleTone.assistant => palette.surfacePrimary, + }; + final labelColor = switch (tone) { + _BubbleTone.user => palette.textSecondary, + _BubbleTone.agent => palette.success, + _BubbleTone.assistant => palette.textMuted, }; return Align( - alignment: alignRight ? Alignment.centerRight : Alignment.centerLeft, + alignment: Alignment.centerLeft, child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 760), child: Container( - padding: const EdgeInsets.all(12), + padding: const EdgeInsets.fromLTRB(14, 12, 14, 12), decoration: BoxDecoration( - color: alignRight ? palette.accentMuted : palette.surfacePrimary, + color: backgroundColor, borderRadius: BorderRadius.circular(AppRadius.card), - boxShadow: [ - BoxShadow( - color: borderColor.withValues(alpha: 0.24), - blurRadius: 8, - offset: const Offset(0, 2), - ), - ], + border: Border.all(color: palette.strokeSoft), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(label, style: theme.textTheme.labelLarge), + Text( + label, + style: theme.textTheme.labelMedium?.copyWith( + color: labelColor, + fontWeight: FontWeight.w600, + ), + ), const SizedBox(height: 4), _MessageBubbleBody( text: text.isEmpty ? appText('暂无内容。', 'No content yet.') : text, @@ -3793,6 +3753,7 @@ class _MessageBubbleBodyState extends State<_MessageBubbleBody> { @override Widget build(BuildContext context) { final theme = Theme.of(context); + final palette = context.palette; if (!widget.renderMarkdown) { final parsed = _PromptDebugSnapshot.fromMessage(widget.text); final canCompactMetadata = @@ -3883,7 +3844,19 @@ class _MessageBubbleBodyState extends State<_MessageBubbleBody> { final styleSheet = MarkdownStyleSheet.fromTheme(theme).copyWith( p: theme.textTheme.bodyLarge?.copyWith( color: theme.colorScheme.onSurface, - height: 1.45, + height: 1.55, + ), + h1: theme.textTheme.headlineSmall?.copyWith( + fontWeight: FontWeight.w600, + color: palette.textPrimary, + ), + h2: theme.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w600, + color: palette.textPrimary, + ), + h3: theme.textTheme.titleSmall?.copyWith( + fontWeight: FontWeight.w600, + color: palette.textPrimary, ), code: theme.textTheme.bodyMedium?.copyWith( fontFamily: 'Menlo', @@ -3892,10 +3865,12 @@ class _MessageBubbleBodyState extends State<_MessageBubbleBody> { codeblockDecoration: BoxDecoration( color: context.palette.surfaceSecondary, borderRadius: BorderRadius.circular(10), + border: Border.all(color: context.palette.strokeSoft), ), blockquoteDecoration: BoxDecoration( color: context.palette.surfaceSecondary.withValues(alpha: 0.72), borderRadius: BorderRadius.circular(10), + border: Border.all(color: context.palette.strokeSoft), ), blockquotePadding: const EdgeInsets.symmetric( horizontal: 10, @@ -4116,14 +4091,8 @@ class _TaskStatusCard extends StatelessWidget { padding: const EdgeInsets.all(AppSpacing.sm), decoration: BoxDecoration( borderRadius: BorderRadius.circular(AppRadius.card), - color: palette.surfacePrimary, - boxShadow: [ - BoxShadow( - color: palette.shadow.withValues(alpha: 0.04), - blurRadius: 8, - offset: const Offset(0, 2), - ), - ], + color: palette.surfaceSecondary.withValues(alpha: 0.82), + border: Border.all(color: palette.strokeSoft), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -4245,15 +4214,9 @@ class _ToolCallTileState extends State<_ToolCallTile> { constraints: const BoxConstraints(maxWidth: 760), child: Container( decoration: BoxDecoration( - color: palette.surfacePrimary, + color: palette.surfaceSecondary.withValues(alpha: 0.82), borderRadius: BorderRadius.circular(AppRadius.card), - boxShadow: [ - BoxShadow( - color: palette.shadow.withValues(alpha: 0.04), - blurRadius: 8, - offset: const Offset(0, 2), - ), - ], + border: Border.all(color: palette.strokeSoft), ), child: Column( children: [ @@ -4380,13 +4343,7 @@ class _StatusPill extends StatelessWidget { backgroundColor ?? Theme.of(context).colorScheme.surfaceContainerHighest, borderRadius: BorderRadius.circular(AppRadius.badge), - boxShadow: [ - BoxShadow( - color: context.palette.shadow.withValues(alpha: 0.03), - blurRadius: 6, - offset: const Offset(0, 2), - ), - ], + border: Border.all(color: context.palette.strokeSoft), ), child: Text( label, @@ -4430,13 +4387,7 @@ class _ConnectionChip extends StatelessWidget { decoration: BoxDecoration( color: color, borderRadius: BorderRadius.circular(AppRadius.chip), - boxShadow: [ - BoxShadow( - color: context.palette.shadow.withValues(alpha: 0.03), - blurRadius: 6, - offset: const Offset(0, 2), - ), - ], + border: Border.all(color: context.palette.strokeSoft), ), child: Text( '${controller.assistantConnectionStatusLabel} · ${controller.assistantConnectionTargetLabel}', @@ -4482,13 +4433,7 @@ class _MessageViewModeChip extends StatelessWidget { decoration: BoxDecoration( color: palette.surfaceSecondary, borderRadius: BorderRadius.circular(AppRadius.chip), - boxShadow: [ - BoxShadow( - color: palette.shadow.withValues(alpha: 0.03), - blurRadius: 6, - offset: const Offset(0, 2), - ), - ], + border: Border.all(color: palette.strokeSoft), ), child: Row( mainAxisSize: MainAxisSize.min, @@ -4725,13 +4670,7 @@ class _MetaPill extends StatelessWidget { decoration: BoxDecoration( color: palette.surfaceSecondary, borderRadius: BorderRadius.circular(999), - boxShadow: [ - BoxShadow( - color: palette.shadow.withValues(alpha: 0.03), - blurRadius: 6, - offset: const Offset(0, 2), - ), - ], + border: Border.all(color: palette.strokeSoft), ), child: Row( mainAxisSize: MainAxisSize.min, @@ -5084,13 +5023,7 @@ class _SkillPickerPopover extends StatelessWidget { color: palette.surfacePrimary, borderRadius: BorderRadius.circular(24), border: Border.all(color: palette.strokeSoft), - boxShadow: [ - BoxShadow( - color: palette.shadow.withValues(alpha: 0.16), - blurRadius: 24, - offset: const Offset(0, 12), - ), - ], + boxShadow: [palette.chromeShadowAmbient], ), child: Column( children: [ @@ -5213,13 +5146,7 @@ class _SkillPickerTile extends StatelessWidget { ? palette.surfaceSecondary : palette.surfacePrimary, borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: palette.shadow.withValues(alpha: 0.04), - blurRadius: 8, - offset: const Offset(0, 2), - ), - ], + border: Border.all(color: palette.strokeSoft), ), child: Row( children: [ diff --git a/lib/features/mobile/mobile_shell.dart b/lib/features/mobile/mobile_shell.dart index 2d298fee..ed9f7d5b 100644 --- a/lib/features/mobile/mobile_shell.dart +++ b/lib/features/mobile/mobile_shell.dart @@ -340,32 +340,10 @@ class _MobileShellState extends State { ); final detailPanel = widget.controller.detailPanel; final palette = context.palette; - final isDark = Theme.of(context).brightness == Brightness.dark; - return Scaffold( backgroundColor: palette.canvas, body: Stack( children: [ - Positioned( - top: 100, - left: -80, - child: _GlowOrb( - size: 180, - color: palette.accentMuted.withValues( - alpha: isDark ? 0.22 : 0.42, - ), - ), - ), - Positioned( - right: -90, - bottom: 220, - child: _GlowOrb( - size: 210, - color: palette.chromeHighlight.withValues( - alpha: isDark ? 0.12 : 0.28, - ), - ), - ), SafeArea( child: Padding( padding: const EdgeInsets.fromLTRB(12, 12, 12, 0), @@ -384,18 +362,8 @@ class _MobileShellState extends State { ), child: DecoratedBox( decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - palette.chromeHighlight.withValues( - alpha: isDark ? 0.14 : 0.72, - ), - palette.chromeSurface.withValues(alpha: 0.94), - ], - ), - border: Border.all(color: palette.chromeStroke), - boxShadow: [palette.chromeShadowAmbient], + color: palette.chromeSurface, + border: Border.all(color: palette.strokeSoft), ), child: AnimatedSwitcher( duration: const Duration(milliseconds: 220), @@ -1508,17 +1476,9 @@ class _WorkspaceHero extends StatelessWidget { width: double.infinity, padding: const EdgeInsets.all(16), decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - palette.chromeHighlight.withValues(alpha: 0.86), - palette.surfacePrimary.withValues(alpha: 0.94), - ], - ), + color: palette.surfacePrimary, borderRadius: BorderRadius.circular(AppRadius.card), border: Border.all(color: palette.strokeSoft), - boxShadow: [palette.chromeShadowAmbient], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -1629,14 +1589,7 @@ class _WorkspaceShortcutCard extends StatelessWidget { child: Ink( padding: const EdgeInsets.all(16), decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - palette.chromeHighlight.withValues(alpha: 0.84), - palette.surfacePrimary.withValues(alpha: 0.94), - ], - ), + color: palette.surfacePrimary, borderRadius: BorderRadius.circular(AppRadius.card), border: Border.all(color: palette.strokeSoft), ), @@ -1745,7 +1698,6 @@ class _BottomPillNav extends StatelessWidget { color: palette.surfacePrimary.withValues(alpha: 0.92), borderRadius: BorderRadius.circular(AppRadius.dialog), border: Border.all(color: palette.strokeSoft), - boxShadow: [palette.chromeShadowAmbient], ), child: Row( children: tabs @@ -1797,19 +1749,3 @@ class _BottomPillNav extends StatelessWidget { ); } } - -class _GlowOrb extends StatelessWidget { - const _GlowOrb({required this.size, required this.color}); - - final double size; - final Color color; - - @override - Widget build(BuildContext context) { - return Container( - width: size, - height: size, - decoration: BoxDecoration(shape: BoxShape.circle, color: color), - ); - } -} diff --git a/lib/theme/app_palette.dart b/lib/theme/app_palette.dart index cae7f18c..7e4bcb05 100644 --- a/lib/theme/app_palette.dart +++ b/lib/theme/app_palette.dart @@ -63,85 +63,85 @@ class AppPalette extends ThemeExtension { final Color hover; static const AppPalette light = AppPalette( - canvas: Color(0xFFF8F9FA), - sidebar: Color(0xFFF1F4F8), - sidebarBorder: Color(0x26A6B4C8), - chromeBackground: Color(0xFFF4F7FA), - chromeSurface: Color(0xFFFDFEFF), - chromeSurfacePressed: Color(0xFFF1F5F9), - chromeHighlight: Color(0xFFFFFFFF), - chromeStroke: Color(0x26A6B4C8), - chromeInset: Color(0xFFF4F7FA), + canvas: Color(0xFFFAF8F4), + sidebar: Color(0xFFF6F2EC), + sidebarBorder: Color(0x147E7061), + chromeBackground: Color(0xFFF6F2EC), + chromeSurface: Color(0xFFFFFDF9), + chromeSurfacePressed: Color(0xFFF8F4EE), + chromeHighlight: Color(0xFFFFFEFB), + chromeStroke: Color(0x1F7E7061), + chromeInset: Color(0xFFF3EEE7), chromeShadowAmbient: BoxShadow( - color: Color(0x140058BD), - blurRadius: 40, - offset: Offset(0, 12), + color: Color(0x0A2E2418), + blurRadius: 16, + offset: Offset(0, 3), spreadRadius: -14, ), chromeShadowLift: BoxShadow( - color: Color(0x180058BD), - blurRadius: 24, - offset: Offset(0, 10), - spreadRadius: -12, - ), - surfacePrimary: Color(0xFFFFFFFF), - surfaceSecondary: Color(0xFFF2F5F8), - surfaceTertiary: Color(0xFFE9EEF4), - stroke: Color(0x33A6B4C8), - strokeSoft: Color(0x26A6B4C8), - accent: Color(0xFF0058BD), - accentHover: Color(0xFF1A6CCE), - accentMuted: Color(0xFFE8F0FB), - idle: Color(0xFF98A1B2), - success: Color(0xFF34A853), - warning: Color(0xFF8F4A00), - danger: Color(0xFFC3655C), - textPrimary: Color(0xFF1C1B1F), - textSecondary: Color(0xFF667085), - textMuted: Color(0xFF98A1B2), - shadow: Color(0x140058BD), - hover: Color(0xFFEFF4FA), - ); - - static const AppPalette dark = AppPalette( - canvas: Color(0xFF141422), - sidebar: Color(0xFF1A1D2A), - sidebarBorder: Color(0x33CAC4D0), - chromeBackground: Color(0xFF161A26), - chromeSurface: Color(0xFF1D2230), - chromeSurfacePressed: Color(0xFF23293A), - chromeHighlight: Color(0xFF2A3145), - chromeStroke: Color(0x33CAC4D0), - chromeInset: Color(0xFF1A1F2C), - chromeShadowAmbient: BoxShadow( - color: Color(0x4D000814), - blurRadius: 36, - offset: Offset(0, 12), - spreadRadius: -14, - ), - chromeShadowLift: BoxShadow( - color: Color(0x660058BD), - blurRadius: 22, + color: Color(0x122E2418), + blurRadius: 20, offset: Offset(0, 8), spreadRadius: -12, ), - surfacePrimary: Color(0xFF171C28), - surfaceSecondary: Color(0xFF1E2433), - surfaceTertiary: Color(0xFF262D3F), - stroke: Color(0x40CAC4D0), - strokeSoft: Color(0x26CAC4D0), - accent: Color(0xFF4B8FE8), - accentHover: Color(0xFF78AFFF), - accentMuted: Color(0xFF1C3355), - idle: Color(0xFF8B95A8), - success: Color(0xFF5CB978), - warning: Color(0xFFE0AE5A), - danger: Color(0xFFEF9A9A), - textPrimary: Color(0xFFE6E1E5), - textSecondary: Color(0xFFB0B8C8), - textMuted: Color(0xFF8B95A8), + surfacePrimary: Color(0xFFFFFDF9), + surfaceSecondary: Color(0xFFF8F4EE), + surfaceTertiary: Color(0xFFF1EAE1), + stroke: Color(0x1F7E7061), + strokeSoft: Color(0x147E7061), + accent: Color(0xFF635BFF), + accentHover: Color(0xFF564EF0), + accentMuted: Color(0xFFECE9FF), + idle: Color(0xFF9D968C), + success: Color(0xFF2F7D57), + warning: Color(0xFF8A5A1F), + danger: Color(0xFFB65C4A), + textPrimary: Color(0xFF24211D), + textSecondary: Color(0xFF6E675F), + textMuted: Color(0xFF9D968C), + shadow: Color(0x102E2418), + hover: Color(0xFFF3EEE7), + ); + + static const AppPalette dark = AppPalette( + canvas: Color(0xFF171513), + sidebar: Color(0xFF1D1A17), + sidebarBorder: Color(0x14EEE3D6), + chromeBackground: Color(0xFF1D1A17), + chromeSurface: Color(0xFF24201C), + chromeSurfacePressed: Color(0xFF2B2621), + chromeHighlight: Color(0xFF2E2822), + chromeStroke: Color(0x1FEEE3D6), + chromeInset: Color(0xFF23201C), + chromeShadowAmbient: BoxShadow( + color: Color(0x22000000), + blurRadius: 22, + offset: Offset(0, 8), + spreadRadius: -14, + ), + chromeShadowLift: BoxShadow( + color: Color(0x2B000000), + blurRadius: 20, + offset: Offset(0, 8), + spreadRadius: -12, + ), + surfacePrimary: Color(0xFF24201C), + surfaceSecondary: Color(0xFF2B2621), + surfaceTertiary: Color(0xFF342E28), + stroke: Color(0x1FEEE3D6), + strokeSoft: Color(0x14EEE3D6), + accent: Color(0xFF8A83FF), + accentHover: Color(0xFF9A94FF), + accentMuted: Color(0x2E8A83FF), + idle: Color(0xFF958B80), + success: Color(0xFF66B78B), + warning: Color(0xFFD3A86C), + danger: Color(0xFFE58C79), + textPrimary: Color(0xFFF1E9DF), + textSecondary: Color(0xFFC6BAAD), + textMuted: Color(0xFF958B80), shadow: Color(0x52000000), - hover: Color(0xFF23293A), + hover: Color(0xFF2B2621), ); @override diff --git a/lib/theme/app_theme.dart b/lib/theme/app_theme.dart index 240be8a0..b87d4cff 100644 --- a/lib/theme/app_theme.dart +++ b/lib/theme/app_theme.dart @@ -21,12 +21,12 @@ class SimpleSpacing { class SimpleRadius { SimpleRadius._(); - static const double card = 16.0; + static const double card = 18.0; static const double button = 12.0; - static const double input = 14.0; - static const double chip = 12.0; + static const double input = 20.0; + static const double chip = 999.0; static const double badge = 999.0; - static const double dialog = 18.0; + static const double dialog = 20.0; static const double sidebar = 20.0; static const double icon = 12.0; } @@ -42,21 +42,21 @@ class SimpleTypography { static const FontWeight titleWeight = FontWeight.w600; static const double titleHeight = 24 / 20; - static const double sectionSize = 13.0; + static const double sectionSize = 15.0; static const FontWeight sectionWeight = FontWeight.w600; - static const double sectionHeight = 14 / 13; + static const double sectionHeight = 20 / 15; - static const double bodySize = 13.0; + static const double bodySize = 15.0; static const FontWeight bodyWeight = FontWeight.w400; - static const double bodyHeight = 15 / 13; + static const double bodyHeight = 24 / 15; - static const double compactBodySize = 13.0; + static const double compactBodySize = 14.0; static const FontWeight compactBodyWeight = FontWeight.w400; - static const double compactBodyHeight = 15 / 13; + static const double compactBodyHeight = 22 / 14; static const double emphasizedBodySize = 13.0; static const FontWeight emphasizedBodyWeight = FontWeight.w600; - static const double emphasizedBodyHeight = 14 / 13; + static const double emphasizedBodyHeight = 18 / 13; static const double captionSize = 12.0; static const FontWeight captionWeight = FontWeight.w400; @@ -78,7 +78,7 @@ class SimpleSizes { static const double toolbarHeight = 40.0; static const double inputHeight = 40.0; - static const double buttonHeightDesktop = 30.0; + static const double buttonHeightDesktop = 34.0; static const double buttonHeightMobile = 36.0; } @@ -353,7 +353,7 @@ class AppTheme { iconButtonTheme: IconButtonThemeData( style: IconButton.styleFrom( foregroundColor: palette.textSecondary, - backgroundColor: palette.surfaceSecondary.withValues(alpha: 0.88), + backgroundColor: palette.surfacePrimary.withValues(alpha: 0.94), surfaceTintColor: Colors.transparent, minimumSize: const Size(32, 32), padding: const EdgeInsets.all(7), @@ -365,7 +365,7 @@ class AppTheme { inputDecorationTheme: InputDecorationTheme( isDense: true, filled: true, - fillColor: palette.surfacePrimary.withValues(alpha: 0.92), + fillColor: palette.surfacePrimary, hintStyle: tunedTextTheme.bodyMedium?.copyWith( color: palette.textMuted, ), @@ -495,9 +495,9 @@ class AppTheme { ), titleSmall: withUiFont( base.titleSmall?.copyWith( - fontSize: AppTypography.bodySize, + fontSize: AppTypography.compactBodySize, fontWeight: FontWeight.w600, - height: AppTypography.bodyHeight, + height: AppTypography.compactBodyHeight, color: palette.textPrimary, ), ), @@ -527,9 +527,9 @@ class AppTheme { ), labelLarge: withUiFont( base.labelLarge?.copyWith( - fontSize: AppTypography.sectionSize, + fontSize: AppTypography.emphasizedBodySize, fontWeight: AppTypography.emphasizedBodyWeight, - height: AppTypography.sectionHeight, + height: AppTypography.emphasizedBodyHeight, color: palette.textPrimary, ), ), diff --git a/lib/widgets/desktop_workspace_scaffold.dart b/lib/widgets/desktop_workspace_scaffold.dart index fcc3ac49..585cbae9 100644 --- a/lib/widgets/desktop_workspace_scaffold.dart +++ b/lib/widgets/desktop_workspace_scaffold.dart @@ -106,17 +106,9 @@ class DesktopWorkspaceScaffold extends StatelessWidget { Expanded( child: DecoratedBox( decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - palette.chromeHighlight.withValues(alpha: 0.9), - palette.chromeSurface.withValues(alpha: 0.92), - ], - ), + color: palette.chromeSurface, borderRadius: BorderRadius.circular(AppRadius.card), - border: Border.all(color: palette.chromeStroke), - boxShadow: [palette.chromeShadowAmbient], + border: Border.all(color: palette.strokeSoft), ), child: ClipRRect( borderRadius: BorderRadius.circular(AppRadius.card), diff --git a/lib/widgets/sidebar_navigation.dart b/lib/widgets/sidebar_navigation.dart index 5e57c297..bb503cd2 100644 --- a/lib/widgets/sidebar_navigation.dart +++ b/lib/widgets/sidebar_navigation.dart @@ -91,17 +91,9 @@ class SidebarNavigation extends StatelessWidget { height: double.infinity, margin: marginOverride ?? const EdgeInsets.fromLTRB(4, 4, 4, 0), decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - palette.chromeHighlight.withValues(alpha: 0.9), - palette.chromeSurface.withValues(alpha: 0.92), - ], - ), + color: palette.chromeSurface, borderRadius: BorderRadius.circular(AppRadius.sidebar), - border: Border.all(color: palette.chromeStroke), - boxShadow: [palette.chromeShadowAmbient], + border: Border.all(color: palette.strokeSoft), ), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 4), @@ -265,17 +257,9 @@ class _SidebarHeaderChevron extends StatelessWidget { width: size, height: size, decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - palette.chromeHighlight.withValues(alpha: 0.9), - palette.chromeSurface, - ], - ), + color: palette.surfacePrimary, borderRadius: BorderRadius.circular(borderRadius), - border: Border.all(color: palette.chromeStroke), - boxShadow: [palette.chromeShadowAmbient], + border: Border.all(color: palette.strokeSoft), ), child: Center( child: Icon( @@ -345,8 +329,8 @@ class _SidebarSectionGroup extends StatelessWidget { WorkspaceDestination.secrets => AssistantFocusEntry.secrets, WorkspaceDestination.aiGateway => AssistantFocusEntry.aiGateway, WorkspaceDestination.settings => AssistantFocusEntry.settings, - WorkspaceDestination.assistant || WorkspaceDestination.account => - null, + WorkspaceDestination.assistant || + WorkspaceDestination.account => null, }; return Padding( padding: const EdgeInsets.only(bottom: AppSpacing.xxs), @@ -355,12 +339,16 @@ class _SidebarSectionGroup extends StatelessWidget { selected: currentSection == section, collapsed: collapsed, emphasis: emphasis, - favorite: focusEntry != null && favoriteDestinations.contains(focusEntry), + favorite: + focusEntry != null && + favoriteDestinations.contains(focusEntry), showFavoriteToggle: !collapsed && focusEntry != null && onToggleFavorite != null && - kAssistantNavigationDestinationCandidates.contains(focusEntry), + kAssistantNavigationDestinationCandidates.contains( + focusEntry, + ), labelOverride: useHomeShortcut ? appText('回到 APP首页', 'Back to app home') : null, @@ -435,28 +423,15 @@ class _SidebarNavItemState extends State<_SidebarNavItem> { child: AnimatedContainer( duration: const Duration(milliseconds: 160), decoration: BoxDecoration( - gradient: widget.selected || _hovered - ? LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - palette.chromeHighlight.withValues( - alpha: widget.selected ? 0.84 : 0.7, - ), - background.withValues( - alpha: widget.selected ? 0.96 : 0.9, - ), - ], - ) - : null, - color: widget.selected || _hovered ? null : Colors.transparent, + color: widget.selected || _hovered + ? background.withValues(alpha: widget.selected ? 1 : 0.96) + : Colors.transparent, borderRadius: BorderRadius.circular(radius), border: Border.all( color: widget.selected || _hovered - ? palette.chromeStroke + ? palette.strokeSoft : Colors.transparent, ), - boxShadow: widget.selected ? [palette.chromeShadowLift] : const [], ), child: Material( color: Colors.transparent, @@ -648,7 +623,9 @@ class SidebarFooter extends StatelessWidget { compact: true, tooltip: appText('切换语言', 'Toggle language'), onPressed: onToggleLanguage, - favorite: favoriteDestinations.contains(AssistantFocusEntry.language), + favorite: favoriteDestinations.contains( + AssistantFocusEntry.language, + ), showFavoriteToggle: onToggleFavorite != null, favoriteButtonKey: const ValueKey( 'sidebar-favorite-language', @@ -753,7 +730,9 @@ class SidebarFooter extends StatelessWidget { icon: chromeThemeToggleIcon(themeMode), tooltip: themeToggleTooltip, onPressed: onOpenThemeToggle, - favorite: favoriteDestinations.contains(AssistantFocusEntry.theme), + favorite: favoriteDestinations.contains( + AssistantFocusEntry.theme, + ), showFavoriteToggle: onToggleFavorite != null, favoriteButtonKey: const ValueKey( 'sidebar-favorite-theme', @@ -845,26 +824,15 @@ class _SidebarAccountTileState extends State<_SidebarAccountTile> { child: AnimatedContainer( duration: const Duration(milliseconds: 160), decoration: BoxDecoration( - gradient: widget.selected || _hovered - ? LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - palette.chromeHighlight.withValues( - alpha: widget.selected ? 0.96 : 0.84, - ), - background, - ], - ) - : null, - color: widget.selected || _hovered ? null : Colors.transparent, + color: widget.selected || _hovered + ? background + : Colors.transparent, borderRadius: BorderRadius.circular(AppRadius.button), border: Border.all( color: widget.selected || _hovered - ? palette.chromeStroke + ? palette.strokeSoft : Colors.transparent, ), - boxShadow: widget.selected ? [palette.chromeShadowLift] : const [], ), child: Material( color: Colors.transparent, diff --git a/lib/widgets/surface_card.dart b/lib/widgets/surface_card.dart index ba5aee6a..9f31d474 100644 --- a/lib/widgets/surface_card.dart +++ b/lib/widgets/surface_card.dart @@ -48,28 +48,20 @@ class _SurfaceCardState extends State { final decoration = switch (widget.tone) { SurfaceCardTone.standard => BoxDecoration( color: (_hovered && widget.onTap != null ? hoveredColor : baseColor) - .withValues(alpha: 0.94), + .withValues(alpha: 0.98), border: Border.all(color: borderColor), borderRadius: BorderRadius.circular(widget.borderRadius), boxShadow: widget.onTap != null && _hovered - ? [palette.chromeShadowLift] + ? [palette.chromeShadowAmbient] : const [], ), SurfaceCardTone.chrome => BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - palette.chromeHighlight.withValues(alpha: 0.92), - (_hovered && widget.onTap != null ? hoveredColor : baseColor) - .withValues(alpha: 0.9), - ], - ), + color: (_hovered && widget.onTap != null ? hoveredColor : baseColor) + .withValues(alpha: 0.98), border: Border.all(color: borderColor), borderRadius: BorderRadius.circular(widget.borderRadius), boxShadow: [ - palette.chromeShadowAmbient, - if (_hovered && widget.onTap != null) palette.chromeShadowLift, + if (_hovered && widget.onTap != null) palette.chromeShadowAmbient, ], ), };