add configurable simple theme defaults
This commit is contained in:
parent
098d9a2b19
commit
febdbedbfb
33
docs/architecture/simple-theme-default.md
Normal file
33
docs/architecture/simple-theme-default.md
Normal file
@ -0,0 +1,33 @@
|
||||
# Simple Theme Default
|
||||
|
||||
This document records the default `simple` theme token set for `XWorkmate.svc.plus`.
|
||||
|
||||
## Typography
|
||||
|
||||
- `section` title: `13/14 + 600`
|
||||
- `compact body`: `13/15 + 400`
|
||||
- `bodyMedium`: `13/15 + 400`
|
||||
- emphasized body and button labels: `13/14 + 600`
|
||||
|
||||
## Spacing
|
||||
|
||||
- page outer spacing: `0`
|
||||
- standard section spacing: `8`
|
||||
- compact spacing: `6`
|
||||
|
||||
## Radius
|
||||
|
||||
- card radius: `6`
|
||||
- input radius: `8`
|
||||
- button radius: `8`
|
||||
- dialog radius: `5`
|
||||
|
||||
## Size
|
||||
|
||||
- input height: `36`
|
||||
- button height: `16`
|
||||
|
||||
## Source Of Truth
|
||||
|
||||
- theme tokens live in [lib/theme/app_theme.dart](/Users/shenlan/workspaces/cloud-neutral-toolkit/XWorkmate.svc.plus/lib/theme/app_theme.dart)
|
||||
- token family name: `simple`
|
||||
@ -3,32 +3,36 @@ import 'package:flutter/material.dart';
|
||||
|
||||
import 'app_palette.dart';
|
||||
|
||||
class AppSpacing {
|
||||
AppSpacing._();
|
||||
// Default theme token set: simple
|
||||
class SimpleSpacing {
|
||||
SimpleSpacing._();
|
||||
|
||||
static const double page = 0.0;
|
||||
static const double compact = 6.0;
|
||||
static const double section = 8.0;
|
||||
static const double xxs = 4.0;
|
||||
static const double xs = 8.0;
|
||||
static const double sm = 12.0;
|
||||
static const double md = 16.0;
|
||||
static const double lg = 24.0;
|
||||
static const double xl = 32.0;
|
||||
static const double xs = compact;
|
||||
static const double sm = section;
|
||||
static const double md = section;
|
||||
static const double lg = section;
|
||||
static const double xl = 12.0;
|
||||
}
|
||||
|
||||
class AppRadius {
|
||||
AppRadius._();
|
||||
class SimpleRadius {
|
||||
SimpleRadius._();
|
||||
|
||||
static const double card = 16.0;
|
||||
static const double button = 12.0;
|
||||
static const double input = 16.0;
|
||||
static const double card = 6.0;
|
||||
static const double button = 8.0;
|
||||
static const double input = 8.0;
|
||||
static const double chip = 999.0;
|
||||
static const double badge = 999.0;
|
||||
static const double dialog = 16.0;
|
||||
static const double sidebar = 20.0;
|
||||
static const double icon = 12.0;
|
||||
static const double dialog = 5.0;
|
||||
static const double sidebar = 8.0;
|
||||
static const double icon = 8.0;
|
||||
}
|
||||
|
||||
class AppTypography {
|
||||
AppTypography._();
|
||||
class SimpleTypography {
|
||||
SimpleTypography._();
|
||||
|
||||
static const double displaySize = 28.0;
|
||||
static const FontWeight displayWeight = FontWeight.w600;
|
||||
@ -42,25 +46,25 @@ class AppTypography {
|
||||
static const FontWeight sectionWeight = FontWeight.w600;
|
||||
static const double sectionHeight = 14 / 13;
|
||||
|
||||
static const double bodySize = 14.0;
|
||||
static const double bodySize = 13.0;
|
||||
static const FontWeight bodyWeight = FontWeight.w400;
|
||||
static const double bodyHeight = 20 / 14;
|
||||
static const double bodyHeight = 15 / 13;
|
||||
|
||||
static const double compactBodySize = 13.0;
|
||||
static const FontWeight compactBodyWeight = FontWeight.w400;
|
||||
static const double compactBodyHeight = 15 / 13;
|
||||
|
||||
static const double emphasizedBodySize = 14.0;
|
||||
static const double emphasizedBodySize = 13.0;
|
||||
static const FontWeight emphasizedBodyWeight = FontWeight.w600;
|
||||
static const double emphasizedBodyHeight = 14 / 14;
|
||||
static const double emphasizedBodyHeight = 14 / 13;
|
||||
|
||||
static const double captionSize = 12.0;
|
||||
static const FontWeight captionWeight = FontWeight.w400;
|
||||
static const double captionHeight = 16 / 12;
|
||||
}
|
||||
|
||||
class AppSizes {
|
||||
AppSizes._();
|
||||
class SimpleSizes {
|
||||
SimpleSizes._();
|
||||
|
||||
static const double sidebarItemHeight = 40.0;
|
||||
static const double sidebarIconSize = 20.0;
|
||||
@ -68,11 +72,91 @@ class AppSizes {
|
||||
static const double sidebarExpandedWidth = 212.0;
|
||||
static const double sidebarCollapsedWidth = 72.0;
|
||||
|
||||
static const double textareaHeight = 48.0;
|
||||
static const double textareaHeight = 36.0;
|
||||
static const double toolbarHeight = 40.0;
|
||||
|
||||
static const double buttonHeightDesktop = 40.0;
|
||||
static const double buttonHeightMobile = 40.0;
|
||||
static const double inputHeight = 36.0;
|
||||
static const double buttonHeightDesktop = 16.0;
|
||||
static const double buttonHeightMobile = 16.0;
|
||||
}
|
||||
|
||||
class AppSpacing {
|
||||
AppSpacing._();
|
||||
|
||||
static const double page = SimpleSpacing.page;
|
||||
static const double compact = SimpleSpacing.compact;
|
||||
static const double section = SimpleSpacing.section;
|
||||
static const double xxs = SimpleSpacing.xxs;
|
||||
static const double xs = SimpleSpacing.xs;
|
||||
static const double sm = SimpleSpacing.sm;
|
||||
static const double md = SimpleSpacing.md;
|
||||
static const double lg = SimpleSpacing.lg;
|
||||
static const double xl = SimpleSpacing.xl;
|
||||
}
|
||||
|
||||
class AppRadius {
|
||||
AppRadius._();
|
||||
|
||||
static const double card = SimpleRadius.card;
|
||||
static const double button = SimpleRadius.button;
|
||||
static const double input = SimpleRadius.input;
|
||||
static const double chip = SimpleRadius.chip;
|
||||
static const double badge = SimpleRadius.badge;
|
||||
static const double dialog = SimpleRadius.dialog;
|
||||
static const double sidebar = SimpleRadius.sidebar;
|
||||
static const double icon = SimpleRadius.icon;
|
||||
}
|
||||
|
||||
class AppTypography {
|
||||
AppTypography._();
|
||||
|
||||
static const double displaySize = SimpleTypography.displaySize;
|
||||
static const FontWeight displayWeight = SimpleTypography.displayWeight;
|
||||
static const double displayHeight = SimpleTypography.displayHeight;
|
||||
|
||||
static const double titleSize = SimpleTypography.titleSize;
|
||||
static const FontWeight titleWeight = SimpleTypography.titleWeight;
|
||||
static const double titleHeight = SimpleTypography.titleHeight;
|
||||
|
||||
static const double sectionSize = SimpleTypography.sectionSize;
|
||||
static const FontWeight sectionWeight = SimpleTypography.sectionWeight;
|
||||
static const double sectionHeight = SimpleTypography.sectionHeight;
|
||||
|
||||
static const double bodySize = SimpleTypography.bodySize;
|
||||
static const FontWeight bodyWeight = SimpleTypography.bodyWeight;
|
||||
static const double bodyHeight = SimpleTypography.bodyHeight;
|
||||
|
||||
static const double compactBodySize = SimpleTypography.compactBodySize;
|
||||
static const FontWeight compactBodyWeight =
|
||||
SimpleTypography.compactBodyWeight;
|
||||
static const double compactBodyHeight = SimpleTypography.compactBodyHeight;
|
||||
|
||||
static const double emphasizedBodySize = SimpleTypography.emphasizedBodySize;
|
||||
static const FontWeight emphasizedBodyWeight =
|
||||
SimpleTypography.emphasizedBodyWeight;
|
||||
static const double emphasizedBodyHeight =
|
||||
SimpleTypography.emphasizedBodyHeight;
|
||||
|
||||
static const double captionSize = SimpleTypography.captionSize;
|
||||
static const FontWeight captionWeight = SimpleTypography.captionWeight;
|
||||
static const double captionHeight = SimpleTypography.captionHeight;
|
||||
}
|
||||
|
||||
class AppSizes {
|
||||
AppSizes._();
|
||||
|
||||
static const double sidebarItemHeight = SimpleSizes.sidebarItemHeight;
|
||||
static const double sidebarIconSize = SimpleSizes.sidebarIconSize;
|
||||
static const double sidebarTextSize = SimpleSizes.sidebarTextSize;
|
||||
static const double sidebarExpandedWidth = SimpleSizes.sidebarExpandedWidth;
|
||||
static const double sidebarCollapsedWidth = SimpleSizes.sidebarCollapsedWidth;
|
||||
|
||||
static const double textareaHeight = SimpleSizes.textareaHeight;
|
||||
static const double toolbarHeight = SimpleSizes.toolbarHeight;
|
||||
|
||||
static const double inputHeight = SimpleSizes.inputHeight;
|
||||
static const double buttonHeightDesktop = SimpleSizes.buttonHeightDesktop;
|
||||
static const double buttonHeightMobile = SimpleSizes.buttonHeightMobile;
|
||||
}
|
||||
|
||||
class AppTheme {
|
||||
@ -152,6 +236,7 @@ class AppTheme {
|
||||
surfaceTintColor: Colors.transparent,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(AppRadius.card),
|
||||
side: BorderSide(color: palette.strokeSoft),
|
||||
),
|
||||
),
|
||||
chipTheme: base.chipTheme.copyWith(
|
||||
@ -184,8 +269,8 @@ class AppTheme {
|
||||
: AppSizes.buttonHeightMobile,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: AppSpacing.md,
|
||||
vertical: AppSpacing.sm,
|
||||
horizontal: AppSpacing.sm,
|
||||
vertical: 0,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(AppRadius.button),
|
||||
@ -209,13 +294,13 @@ class AppTheme {
|
||||
: AppSizes.buttonHeightMobile,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: AppSpacing.md,
|
||||
vertical: AppSpacing.sm,
|
||||
horizontal: AppSpacing.sm,
|
||||
vertical: 0,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(AppRadius.button),
|
||||
),
|
||||
side: BorderSide.none,
|
||||
side: BorderSide(color: palette.strokeSoft),
|
||||
),
|
||||
),
|
||||
textButtonTheme: TextButtonThemeData(
|
||||
@ -224,10 +309,15 @@ class AppTheme {
|
||||
textStyle: tunedTextTheme.labelLarge?.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
minimumSize: Size(0, isDesktop ? 32 : 34),
|
||||
minimumSize: Size(
|
||||
0,
|
||||
isDesktop
|
||||
? AppSizes.buttonHeightDesktop
|
||||
: AppSizes.buttonHeightMobile,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: AppSpacing.md,
|
||||
vertical: AppSpacing.xs,
|
||||
horizontal: AppSpacing.xs,
|
||||
vertical: 0,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(AppRadius.button),
|
||||
@ -247,6 +337,7 @@ class AppTheme {
|
||||
),
|
||||
),
|
||||
inputDecorationTheme: InputDecorationTheme(
|
||||
isDense: true,
|
||||
filled: true,
|
||||
fillColor: palette.surfacePrimary,
|
||||
hintStyle: tunedTextTheme.bodyMedium?.copyWith(
|
||||
@ -259,16 +350,17 @@ class AppTheme {
|
||||
color: palette.textSecondary,
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: AppSpacing.md,
|
||||
vertical: AppSpacing.sm,
|
||||
horizontal: AppSpacing.sm,
|
||||
vertical: AppSpacing.compact,
|
||||
),
|
||||
constraints: const BoxConstraints(minHeight: AppSizes.inputHeight),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(AppRadius.input),
|
||||
borderSide: const BorderSide(color: Colors.transparent),
|
||||
borderSide: BorderSide(color: palette.strokeSoft),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(AppRadius.input),
|
||||
borderSide: const BorderSide(color: Colors.transparent),
|
||||
borderSide: BorderSide(color: palette.strokeSoft),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(AppRadius.input),
|
||||
@ -293,7 +385,7 @@ class AppTheme {
|
||||
padding: const WidgetStatePropertyAll(
|
||||
EdgeInsets.symmetric(
|
||||
horizontal: AppSpacing.sm,
|
||||
vertical: AppSpacing.xs,
|
||||
vertical: AppSpacing.compact,
|
||||
),
|
||||
),
|
||||
shape: WidgetStatePropertyAll(
|
||||
|
||||
@ -70,7 +70,7 @@ class _GatewayConnectDialogState extends State<GatewayConnectDialog> {
|
||||
final willUseStoredGatewayToken =
|
||||
typedGatewayToken.isEmpty && hasStoredGatewayToken;
|
||||
final body = SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(24),
|
||||
padding: const EdgeInsets.all(AppSpacing.page),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@ -79,7 +79,7 @@ class _GatewayConnectDialogState extends State<GatewayConnectDialog> {
|
||||
appText('Gateway 访问', 'Gateway Access'),
|
||||
style: theme.textTheme.headlineSmall,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const SizedBox(height: AppSpacing.section),
|
||||
Text(
|
||||
appText(
|
||||
'通过配置码或手动 Host / TLS 将 XWorkmate 连接到 OpenClaw Gateway。',
|
||||
@ -87,7 +87,7 @@ class _GatewayConnectDialogState extends State<GatewayConnectDialog> {
|
||||
),
|
||||
style: theme.textTheme.bodyMedium,
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
const SizedBox(height: AppSpacing.section),
|
||||
SectionTabs(
|
||||
items: [appText('配置码', 'Setup Code'), appText('手动配置', 'Manual')],
|
||||
value: _mode == 'setup'
|
||||
@ -100,9 +100,9 @@ class _GatewayConnectDialogState extends State<GatewayConnectDialog> {
|
||||
: 'manual',
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
const SizedBox(height: AppSpacing.section),
|
||||
_StatusBanner(controller: widget.controller),
|
||||
const SizedBox(height: 18),
|
||||
const SizedBox(height: AppSpacing.section),
|
||||
if (_mode == 'setup') ...[
|
||||
TextField(
|
||||
controller: _setupCodeController,
|
||||
@ -144,12 +144,12 @@ class _GatewayConnectDialogState extends State<GatewayConnectDialog> {
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const SizedBox(height: AppSpacing.section),
|
||||
TextField(
|
||||
controller: _hostController,
|
||||
decoration: InputDecoration(labelText: appText('主机', 'Host')),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const SizedBox(height: AppSpacing.section),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
@ -161,7 +161,7 @@ class _GatewayConnectDialogState extends State<GatewayConnectDialog> {
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
const SizedBox(width: AppSpacing.section),
|
||||
Expanded(
|
||||
child: SwitchListTile.adaptive(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
@ -175,7 +175,7 @@ class _GatewayConnectDialogState extends State<GatewayConnectDialog> {
|
||||
],
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 18),
|
||||
const SizedBox(height: AppSpacing.section),
|
||||
TextField(
|
||||
controller: _tokenController,
|
||||
obscureText: _obscureSharedToken,
|
||||
@ -203,7 +203,7 @@ class _GatewayConnectDialogState extends State<GatewayConnectDialog> {
|
||||
onChanged: (_) => setState(() {}),
|
||||
),
|
||||
if (willUseStoredGatewayToken || typedGatewayToken.isNotEmpty) ...[
|
||||
const SizedBox(height: 8),
|
||||
const SizedBox(height: AppSpacing.section),
|
||||
_SharedTokenStatusCard(
|
||||
hasStoredGatewayToken: hasStoredGatewayToken,
|
||||
storedGatewayTokenMask: storedGatewayTokenMask,
|
||||
@ -220,7 +220,7 @@ class _GatewayConnectDialogState extends State<GatewayConnectDialog> {
|
||||
: null,
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 12),
|
||||
const SizedBox(height: AppSpacing.section),
|
||||
TextField(
|
||||
controller: _passwordController,
|
||||
obscureText: true,
|
||||
@ -229,10 +229,10 @@ class _GatewayConnectDialogState extends State<GatewayConnectDialog> {
|
||||
hintText: appText('可选:共享密码', 'Optional shared password'),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
const SizedBox(height: AppSpacing.section),
|
||||
Wrap(
|
||||
spacing: 12,
|
||||
runSpacing: 12,
|
||||
spacing: AppSpacing.section,
|
||||
runSpacing: AppSpacing.section,
|
||||
alignment: WrapAlignment.end,
|
||||
children: [
|
||||
if (widget.controller.connection.status ==
|
||||
@ -270,6 +270,7 @@ class _GatewayConnectDialogState extends State<GatewayConnectDialog> {
|
||||
}
|
||||
|
||||
return Dialog(
|
||||
insetPadding: const EdgeInsets.all(AppSpacing.page),
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 560),
|
||||
child: body,
|
||||
@ -373,10 +374,11 @@ class _SharedTokenStatusCard extends StatelessWidget {
|
||||
);
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(12),
|
||||
padding: const EdgeInsets.all(AppSpacing.section),
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.surfaceContainerHighest,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(color: theme.dividerColor),
|
||||
borderRadius: BorderRadius.circular(AppRadius.card),
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@ -387,7 +389,7 @@ class _SharedTokenStatusCard extends StatelessWidget {
|
||||
: Icons.inventory_2_rounded,
|
||||
size: 18,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
const SizedBox(width: AppSpacing.compact),
|
||||
Expanded(child: Text(message, style: theme.textTheme.bodySmall)),
|
||||
if (onClearStoredToken != null)
|
||||
TextButton(
|
||||
@ -419,29 +421,30 @@ class _StatusBanner extends StatelessWidget {
|
||||
};
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.all(AppSpacing.section),
|
||||
decoration: BoxDecoration(
|
||||
color: tone,
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
border: Border.all(color: theme.dividerColor),
|
||||
borderRadius: BorderRadius.circular(AppRadius.card),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(connection.status.label, style: theme.textTheme.titleMedium),
|
||||
const SizedBox(height: 6),
|
||||
const SizedBox(height: AppSpacing.compact),
|
||||
Text(
|
||||
connection.remoteAddress ?? 'No active gateway target',
|
||||
style: theme.textTheme.bodyMedium,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const SizedBox(height: AppSpacing.section),
|
||||
Text(
|
||||
appText('认证诊断', 'Auth Diagnostics'),
|
||||
style: theme.textTheme.labelLarge,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
const SizedBox(height: AppSpacing.compact),
|
||||
Text(connection.connectAuthSummary, style: theme.textTheme.bodySmall),
|
||||
if (connection.pairingRequired) ...[
|
||||
const SizedBox(height: 8),
|
||||
const SizedBox(height: AppSpacing.section),
|
||||
Text(
|
||||
appText(
|
||||
'当前设备需要先完成配对审批。请在已授权设备上批准该请求后重试。',
|
||||
@ -450,7 +453,7 @@ class _StatusBanner extends StatelessWidget {
|
||||
style: theme.textTheme.bodySmall,
|
||||
),
|
||||
if ((connection.deviceId ?? '').isNotEmpty) ...[
|
||||
const SizedBox(height: 6),
|
||||
const SizedBox(height: AppSpacing.compact),
|
||||
Text(
|
||||
appText(
|
||||
'当前设备 ID: ${connection.deviceId}',
|
||||
@ -460,7 +463,7 @@ class _StatusBanner extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
] else if (connection.gatewayTokenMissing) ...[
|
||||
const SizedBox(height: 8),
|
||||
const SizedBox(height: AppSpacing.section),
|
||||
Text(
|
||||
appText(
|
||||
'首次连接请提供共享 Token;配对完成后可继续使用本机 device token。',
|
||||
@ -470,7 +473,7 @@ class _StatusBanner extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
if ((connection.lastError ?? '').isNotEmpty) ...[
|
||||
const SizedBox(height: 8),
|
||||
const SizedBox(height: AppSpacing.section),
|
||||
Text(connection.lastError!, style: theme.textTheme.bodySmall),
|
||||
],
|
||||
],
|
||||
|
||||
@ -25,11 +25,11 @@ class SectionTabs extends StatelessWidget {
|
||||
final padding = switch (size) {
|
||||
SectionTabsSize.small => const EdgeInsets.symmetric(
|
||||
horizontal: AppSpacing.sm,
|
||||
vertical: 6,
|
||||
vertical: AppSpacing.compact,
|
||||
),
|
||||
SectionTabsSize.medium => const EdgeInsets.symmetric(
|
||||
horizontal: AppSpacing.sm,
|
||||
vertical: AppSpacing.xs,
|
||||
vertical: AppSpacing.compact,
|
||||
),
|
||||
};
|
||||
|
||||
@ -38,13 +38,7 @@ class SectionTabs extends StatelessWidget {
|
||||
decoration: BoxDecoration(
|
||||
color: palette.surfaceSecondary,
|
||||
borderRadius: BorderRadius.circular(AppRadius.chip),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: palette.shadow.withValues(alpha: 0.04),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
border: Border.all(color: palette.strokeSoft),
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
@ -104,15 +98,9 @@ class _SectionTabChipState extends State<_SectionTabChip> {
|
||||
? palette.surfaceTertiary
|
||||
: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(AppRadius.button),
|
||||
boxShadow: widget.selected
|
||||
? [
|
||||
BoxShadow(
|
||||
color: palette.shadow.withValues(alpha: 0.06),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
]
|
||||
: const [],
|
||||
border: Border.all(
|
||||
color: widget.selected ? palette.stroke : Colors.transparent,
|
||||
),
|
||||
),
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
@ -127,7 +115,9 @@ class _SectionTabChipState extends State<_SectionTabChip> {
|
||||
color: widget.selected
|
||||
? palette.textPrimary
|
||||
: palette.textSecondary,
|
||||
fontWeight: widget.selected ? FontWeight.w600 : FontWeight.w500,
|
||||
fontWeight: widget.selected
|
||||
? FontWeight.w600
|
||||
: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@ -38,13 +38,16 @@ class _SurfaceCardState extends State<SurfaceCard> {
|
||||
duration: const Duration(milliseconds: 180),
|
||||
curve: Curves.easeInOut,
|
||||
decoration: BoxDecoration(
|
||||
color: _hovered && widget.onTap != null ? palette.surfaceSecondary : baseColor,
|
||||
color: _hovered && widget.onTap != null
|
||||
? palette.surfaceSecondary
|
||||
: baseColor,
|
||||
border: Border.all(color: palette.strokeSoft),
|
||||
borderRadius: BorderRadius.circular(widget.borderRadius),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: palette.shadow.withValues(alpha: _hovered ? 0.10 : 0.06),
|
||||
blurRadius: _hovered ? 12 : 8,
|
||||
offset: const Offset(0, 2),
|
||||
color: palette.shadow.withValues(alpha: _hovered ? 0.04 : 0.02),
|
||||
blurRadius: _hovered ? 6 : 4,
|
||||
offset: const Offset(0, 1),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user