feat(studio): rich theme picker (presets + custom colour) + editor 0.11.0
Some checks failed
Security / Security check (push) Failing after 1s

Settings dialog's Theme Plugin section is now a grid of
swatched tiles:

- Built-in (none) — falls back to FaiTheme.light/.dark
- One tile per installed studio.theme.* plugin, each
  showing the plugin's primary/secondary/tertiary as
  live colour dots. Tile loads its preview lazily so a
  dozen installed themes don't block the picker.
- Custom — opens a colour-picker dialog with 12 curated
  Material presets + a hex input + live preview. Selecting
  applies ColorScheme.fromSeed for both brightnesses.

main.dart's _pluginThemes parses a 'custom:#RRGGBB' sigil
in the same notifier slot as plugin capability ids, so the
existing persistence + restoration paths cover the custom
case with no new state.

Bumps editor to 0.11.0 (type-checked port connections +
dynamic card width fix + card-height border allowance) and
Studio to 0.58.0.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
flemming-it 2026-06-02 01:29:34 +02:00
parent 69864da934
commit c1c60d5434
30 changed files with 1280 additions and 846 deletions

View file

@ -33,10 +33,7 @@ class FaiTheme {
fontWeight: FontWeight.w600,
letterSpacing: 0,
),
titleSmall: GoogleFonts.inter(
fontSize: 13,
fontWeight: FontWeight.w500,
),
titleSmall: GoogleFonts.inter(fontSize: 13, fontWeight: FontWeight.w500),
bodyLarge: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.w400,
@ -52,10 +49,7 @@ class FaiTheme {
fontWeight: FontWeight.w400,
height: 1.4,
),
labelMedium: GoogleFonts.inter(
fontSize: 12,
fontWeight: FontWeight.w500,
),
labelMedium: GoogleFonts.inter(fontSize: 12, fontWeight: FontWeight.w500),
labelSmall: GoogleFonts.inter(
fontSize: 11,
fontWeight: FontWeight.w500,
@ -70,13 +64,12 @@ class FaiTheme {
double size = 12,
FontWeight weight = FontWeight.w400,
Color? color,
}) =>
GoogleFonts.jetBrainsMono(
fontSize: size,
fontWeight: weight,
color: color,
height: 1.4,
);
}) => GoogleFonts.jetBrainsMono(
fontSize: size,
fontWeight: weight,
color: color,
height: 1.4,
);
/// Shared markdown style used by every inline doc renderer
/// (Welcome DocReaderSheet, Store module-detail DocsPanel,
@ -107,9 +100,7 @@ class FaiTheme {
code: mono(
size: 12,
color: theme.colorScheme.onSurface,
).copyWith(
backgroundColor: Colors.transparent,
),
).copyWith(backgroundColor: Colors.transparent),
codeblockDecoration: BoxDecoration(
color: theme.colorScheme.surfaceContainerHigh,
borderRadius: BorderRadius.circular(FaiRadius.sm),
@ -123,10 +114,7 @@ class FaiTheme {
color: theme.colorScheme.surfaceContainer,
borderRadius: BorderRadius.circular(FaiRadius.sm),
border: Border(
left: BorderSide(
color: theme.colorScheme.primary,
width: 3,
),
left: BorderSide(color: theme.colorScheme.primary, width: 3),
),
),
blockquotePadding: const EdgeInsets.fromLTRB(
@ -282,20 +270,22 @@ class FaiTheme {
),
),
iconButtonTheme: IconButtonThemeData(
style: IconButton.styleFrom(
foregroundColor: scheme.onSurfaceVariant,
),
style: IconButton.styleFrom(foregroundColor: scheme.onSurfaceVariant),
),
navigationRailTheme: NavigationRailThemeData(
backgroundColor: scheme.surfaceContainerLow,
indicatorColor: scheme.primaryContainer,
selectedIconTheme: IconThemeData(color: scheme.primary, size: 22),
unselectedIconTheme:
IconThemeData(color: scheme.onSurfaceVariant, size: 22),
selectedLabelTextStyle:
textTheme.labelMedium?.copyWith(color: scheme.primary),
unselectedLabelTextStyle: textTheme.labelMedium
?.copyWith(color: scheme.onSurfaceVariant),
unselectedIconTheme: IconThemeData(
color: scheme.onSurfaceVariant,
size: 22,
),
selectedLabelTextStyle: textTheme.labelMedium?.copyWith(
color: scheme.primary,
),
unselectedLabelTextStyle: textTheme.labelMedium?.copyWith(
color: scheme.onSurfaceVariant,
),
useIndicator: true,
),
dividerColor: scheme.outlineVariant,
@ -306,8 +296,9 @@ class FaiTheme {
),
snackBarTheme: SnackBarThemeData(
backgroundColor: scheme.surfaceContainerHigh,
contentTextStyle:
textTheme.bodyMedium?.copyWith(color: scheme.onSurface),
contentTextStyle: textTheme.bodyMedium?.copyWith(
color: scheme.onSurface,
),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(FaiRadius.sm),