From f1b0f65c865a6a9358f1d4564a76622682502023 Mon Sep 17 00:00:00 2001 From: flemming-it Date: Mon, 1 Jun 2026 10:52:38 +0200 Subject: [PATCH] fix(studio): centre Welcome page content on wide windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Welcome page used ConstrainedBox(maxWidth: 960) inside a left-aligned Column, so on the 1440x900 default window the content hugged the left edge and left ~370 px of empty space on the right. With Stefan's M4 sidebar collapsed to 72 px the asymmetry was the dominant visual in the first thing every operator sees. Wrap the ConstrainedBox in a Center widget. 960 px stays an opinionated reading width — long-form prose gets uncomfortable past ~1100 px — but the slack now splits evenly so the content sits with ~190 px breathing room on both sides instead of all on one. Bumps the editor-package lock pointer to ad2e5b5 (same 0.2.2 version, picks up the extract-with-approval test commit on top of f8138f3) as a side-effect of the flutter pub upgrade run during verification. Version 0.52.2 -> 0.52.3. Signed-off-by: flemming-it --- lib/main.dart | 2 +- lib/pages/welcome.dart | 101 ++++++++++++++++++++--------------------- pubspec.lock | 2 +- pubspec.yaml | 2 +- 4 files changed, 51 insertions(+), 56 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index d4bab05..dcad45e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -26,7 +26,7 @@ import 'widgets/widgets.dart'; /// Studio's own build version. Bump on every UI commit so the /// running app self-identifies — visible in the sidebar header /// and quick-glance proof that you're seeing the current build. -const String kStudioVersion = '0.52.2'; +const String kStudioVersion = '0.52.3'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); diff --git a/lib/pages/welcome.dart b/lib/pages/welcome.dart index 07b118f..f3201af 100644 --- a/lib/pages/welcome.dart +++ b/lib/pages/welcome.dart @@ -29,10 +29,7 @@ class WelcomePage extends StatelessWidget { final l = AppLocalizations.of(context)!; return Scaffold( backgroundColor: theme.scaffoldBackgroundColor, - appBar: AppBar( - titleSpacing: FaiSpace.xl, - title: Text(l.navWelcome), - ), + appBar: AppBar(titleSpacing: FaiSpace.xl, title: Text(l.navWelcome)), body: SingleChildScrollView( child: Padding( padding: const EdgeInsets.fromLTRB( @@ -41,27 +38,37 @@ class WelcomePage extends StatelessWidget { FaiSpace.xl, FaiSpace.xxl, ), - child: ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 960), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: const [ - _Hero(), - SizedBox(height: FaiSpace.xxl), - // Checklist comes second — operator-actionable - // path beats educational content. Auto-hides - // once the operator dismisses it. - _OnboardingChecklist(), - _PillarRow(), - SizedBox(height: FaiSpace.xxl), - _SectionLabel(textKey: _SectionLabelKey.trust), - SizedBox(height: FaiSpace.md), - _TrustPosture(), - SizedBox(height: FaiSpace.xxl), - _SectionLabel(textKey: _SectionLabelKey.docs), - SizedBox(height: FaiSpace.md), - _DocsRow(), - ], + // Center the 960-px content column on wide windows + // so the right margin matches the left rather than + // dumping all the slack onto one side. 960 px stays + // an opinionated reading width — long-form prose + // gets uncomfortable past ~1100 px — but on Stefan's + // 1440-px default it now sits with ~190 px of + // breathing room on both sides instead of 380 px + // on the right and 20 px on the left. + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 960), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: const [ + _Hero(), + SizedBox(height: FaiSpace.xxl), + // Checklist comes second — operator-actionable + // path beats educational content. Auto-hides + // once the operator dismisses it. + _OnboardingChecklist(), + _PillarRow(), + SizedBox(height: FaiSpace.xxl), + _SectionLabel(textKey: _SectionLabelKey.trust), + SizedBox(height: FaiSpace.md), + _TrustPosture(), + SizedBox(height: FaiSpace.xxl), + _SectionLabel(textKey: _SectionLabelKey.docs), + SizedBox(height: FaiSpace.md), + _DocsRow(), + ], + ), ), ), ), @@ -175,11 +182,7 @@ class _PillarRow extends StatelessWidget { Widget build(BuildContext context) { final l = AppLocalizations.of(context)!; final pillars = <(IconData, String, String)>[ - ( - Icons.hub_outlined, - l.welcomePillarHubTitle, - l.welcomePillarHubBody, - ), + (Icons.hub_outlined, l.welcomePillarHubTitle, l.welcomePillarHubBody), ( Icons.extension_outlined, l.welcomePillarModuleTitle, @@ -240,11 +243,7 @@ class _Pillar extends StatelessWidget { final String title; final String body; - const _Pillar({ - required this.icon, - required this.title, - required this.body, - }); + const _Pillar({required this.icon, required this.title, required this.body}); @override Widget build(BuildContext context) { @@ -441,7 +440,9 @@ class _OnboardingChecklistState extends State<_OnboardingChecklist> { // Vorher haben wir den Modul-Namen geprüft und damit // nie gematcht, obwohl text-extract / text-summarize / // text-translate installiert waren. - .then((m) => m.any((x) => x.capabilities.any((c) => c.startsWith('text.')))) + .then( + (m) => m.any((x) => x.capabilities.any((c) => c.startsWith('text.'))), + ) .catchError((_) => false); final flow = hub .recentEvents(limit: 100) @@ -527,10 +528,7 @@ class _OnboardingChecklistState extends State<_OnboardingChecklist> { children: [ for (var i = 0; i < items.length; i++) ...[ if (i > 0) - Divider( - height: 1, - color: theme.colorScheme.outlineVariant, - ), + Divider(height: 1, color: theme.colorScheme.outlineVariant), _ChecklistRow( done: items[i].$1, title: items[i].$2, @@ -568,9 +566,7 @@ class _AllDoneCelebration extends StatelessWidget { decoration: BoxDecoration( color: FaiColors.success.withValues(alpha: 0.08), borderRadius: BorderRadius.circular(FaiRadius.md), - border: Border.all( - color: FaiColors.success.withValues(alpha: 0.35), - ), + border: Border.all(color: FaiColors.success.withValues(alpha: 0.35)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -811,8 +807,8 @@ class _DocsRow extends StatelessWidget { Text( l.welcomeDocsBody, style: Theme.of(context).textTheme.bodySmall?.copyWith( - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), ), const SizedBox(height: FaiSpace.md), LayoutBuilder( @@ -1033,7 +1029,11 @@ class _DocReaderSheetState extends State<_DocReaderSheet> { ), child: Row( children: [ - Icon(widget.entry.icon, size: 20, color: theme.colorScheme.primary), + Icon( + widget.entry.icon, + size: 20, + color: theme.colorScheme.primary, + ), const SizedBox(width: FaiSpace.sm), Expanded( child: Text( @@ -1065,8 +1065,7 @@ class _DocReaderSheetState extends State<_DocReaderSheet> { } if (snap.hasError) { final err = snap.error; - final structured = - err is _DocReaderError ? err : null; + final structured = err is _DocReaderError ? err : null; return Padding( padding: const EdgeInsets.all(FaiSpace.xxl), child: Column( @@ -1079,11 +1078,7 @@ class _DocReaderSheetState extends State<_DocReaderSheet> { ), ), const SizedBox(height: FaiSpace.sm), - FaiErrorBox( - error: err, - isError: true, - maxHeight: 200, - ), + FaiErrorBox(error: err, isError: true, maxHeight: 200), if (structured != null) ...[ const SizedBox(height: FaiSpace.md), TextButton.icon( diff --git a/pubspec.lock b/pubspec.lock index 32bd26b..3b4c5b0 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -125,7 +125,7 @@ packages: description: path: "." ref: main - resolved-ref: f8138f3516098dc03e65fdfa52916885e7e7aeff + resolved-ref: ad2e5b50d5201c9b97329b02e2223d6e599545f1 url: "https://git.flemming.ai/fai/studio-flow-editor" source: git version: "0.2.2" diff --git a/pubspec.yaml b/pubspec.yaml index 3051b07..5711767 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: fai_studio description: "F∆I Studio — desktop GUI for the F∆I hub" publish_to: 'none' -version: 0.52.2 +version: 0.52.3 environment: sdk: ^3.11.0-200.1.beta