Skip to content

Commit c51df79

Browse files
committed
feat: modernize UI styling, add lightweight theme, and improve demo embedding with videos and responsive updates
1 parent ad90ca5 commit c51df79

File tree

13 files changed

+344
-188
lines changed

13 files changed

+344
-188
lines changed

packages/demo/lib/embed_wrapper.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ class EmbedContext extends InheritedWidget {
142142
///
143143
/// Shows just the raw example content without any navigation,
144144
/// control panel, or header chrome. Handles deferred loading automatically.
145+
/// Uses a transparent background to allow the host page's background to show through.
145146
class EmbedWrapper extends StatelessWidget {
146147
final Example example;
147148

@@ -150,6 +151,7 @@ class EmbedWrapper extends StatelessWidget {
150151
@override
151152
Widget build(BuildContext context) {
152153
return Scaffold(
154+
backgroundColor: Colors.transparent,
153155
body: EmbedContext(
154156
isEmbed: true,
155157
child: DeferredExampleLoader(example: example),

packages/demo/lib/examples/hero_showcase.dart

Lines changed: 107 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class _HeroShowcaseExampleState extends State<HeroShowcaseExample>
4040
'https://images.unsplash.com/photo-1433086966358-54859d0ed716?w=256&h=256&fit=crop&q=80',
4141
];
4242

43-
// Available colors
43+
// Available colors (saturated for color overlay swatches)
4444
static const _colors = [
4545
Color(0xFF6366F1), // Indigo
4646
Color(0xFFEC4899), // Pink
@@ -50,21 +50,22 @@ class _HeroShowcaseExampleState extends State<HeroShowcaseExample>
5050
Color(0xFFEF4444), // Red
5151
];
5252

53-
// Custom theme with glowing dash connections
53+
// Custom lightweight modern theme
5454
late final NodeFlowTheme _theme;
5555

56-
// Port themes for type-based coloring (grey when disconnected, colored when connected)
57-
static final _imagePortTheme = PortTheme.light.copyWith(
58-
color: const Color(0xFF9CA3AF), // Grey when disconnected
59-
connectedColor: const Color(0xFF3B82F6), // Blue when connected
56+
// Minimal port themes - subtle when disconnected, accent when connected
57+
static final _basePortTheme = PortTheme.light.copyWith(
58+
size: const Size(8, 8), // Smaller ports for cleaner look
59+
color: const Color(0xFFD1D5DB), // Light grey when disconnected
6060
);
61-
static final _colorPortTheme = PortTheme.light.copyWith(
62-
color: const Color(0xFF9CA3AF), // Grey when disconnected
63-
connectedColor: const Color(0xFFEC4899), // Pink when connected
61+
static final _imagePortTheme = _basePortTheme.copyWith(
62+
connectedColor: const Color(0xFF60A5FA), // Soft blue when connected
6463
);
65-
static final _effectPortTheme = PortTheme.light.copyWith(
66-
color: const Color(0xFF9CA3AF), // Grey when disconnected
67-
connectedColor: const Color(0xFF10B981), // Green when connected
64+
static final _colorPortTheme = _basePortTheme.copyWith(
65+
connectedColor: const Color(0xFFF472B6), // Soft pink when connected
66+
);
67+
static final _effectPortTheme = _basePortTheme.copyWith(
68+
connectedColor: const Color(0xFF34D399), // Soft green when connected
6869
);
6970

7071
@override
@@ -74,22 +75,47 @@ class _HeroShowcaseExampleState extends State<HeroShowcaseExample>
7475
void initState() {
7576
super.initState();
7677

77-
// Create custom theme with bezier style and glowing flowing dash effect
78+
// Create modern lightweight theme with minimal visual weight
7879
final baseTheme = NodeFlowTheme.light;
7980
_theme = baseTheme.copyWith(
81+
backgroundColor: Colors.transparent,
82+
gridTheme: GridTheme.light.copyWith(style: GridStyles.none),
83+
// Lightweight node styling - 1px borders, subtle colors
84+
nodeTheme: baseTheme.nodeTheme.copyWith(
85+
backgroundColor: Colors.white,
86+
selectedBackgroundColor: const Color(0xFFFAFAFA),
87+
highlightBackgroundColor: const Color(0xFFF8FAFC),
88+
borderColor: const Color(0xFFCBD5E1), // Slate-300 for better visibility
89+
selectedBorderColor: const Color(0xFF818CF8), // Soft indigo selection
90+
highlightBorderColor: const Color(0xFFA5B4FC),
91+
borderWidth: 1.0, // Thin 1px border
92+
selectedBorderWidth: 1.0,
93+
borderRadius: const BorderRadius.all(Radius.circular(10.0)),
94+
),
95+
// Subtle connection lines with flowing animation
8096
connectionTheme: baseTheme.connectionTheme.copyWith(
8197
style: ConnectionStyles.bezier,
82-
strokeWidth: 1,
98+
color: const Color(0xFFD1D5DB), // Light grey
99+
selectedColor: const Color(0xFF818CF8), // Soft indigo
100+
strokeWidth: 1.5,
101+
selectedStrokeWidth: 2,
83102
animationEffect: FlowingDashEffect(
84-
dashLength: 8,
85-
gapLength: 6,
103+
dashLength: 6,
104+
gapLength: 4,
86105
speed: 2,
87106
),
88107
),
89-
// Temporary connection also uses bezier style
108+
// Temporary connection styling
90109
temporaryConnectionTheme: baseTheme.temporaryConnectionTheme.copyWith(
91110
style: ConnectionStyles.bezier,
92-
strokeWidth: 1,
111+
strokeWidth: 1.5,
112+
color: const Color(0xFFA5B4FC),
113+
),
114+
// Smaller, subtler ports
115+
portTheme: baseTheme.portTheme.copyWith(
116+
size: const Size(8, 8),
117+
color: const Color(0xFFD1D5DB),
118+
connectedColor: const Color(0xFF9CA3AF),
93119
),
94120
);
95121

@@ -123,7 +149,7 @@ class _HeroShowcaseExampleState extends State<HeroShowcaseExample>
123149
data: ImageSourceData(
124150
title: 'Image Source',
125151
icon: Icons.image_outlined,
126-
color: const Color(0xFF3B82F6),
152+
color: const Color(0xFF60A5FA),
127153
selectedImage: _selectedImage,
128154
images: _images,
129155
),
@@ -148,7 +174,7 @@ class _HeroShowcaseExampleState extends State<HeroShowcaseExample>
148174
data: ColorOverlayData(
149175
title: 'Color Overlay',
150176
icon: Icons.palette_outlined,
151-
color: const Color(0xFFEC4899),
177+
color: const Color(0xFFF472B6),
152178
selectedColor: _selectedColor,
153179
opacity: _colorOpacity,
154180
colors: _colors,
@@ -174,7 +200,7 @@ class _HeroShowcaseExampleState extends State<HeroShowcaseExample>
174200
data: EffectsData(
175201
title: 'Effects',
176202
icon: Icons.blur_on,
177-
color: const Color(0xFF10B981),
203+
color: const Color(0xFF34D399),
178204
blurRadius: _blurRadius,
179205
saturation: _saturation,
180206
),
@@ -199,7 +225,7 @@ class _HeroShowcaseExampleState extends State<HeroShowcaseExample>
199225
data: OutputData(
200226
title: 'Output',
201227
icon: Icons.auto_awesome,
202-
color: const Color(0xFFF59E0B),
228+
color: const Color(0xFF818CF8),
203229
controller: _controller,
204230
selectedImage: _selectedImage,
205231
selectedColor: _selectedColor,
@@ -269,8 +295,9 @@ class _HeroShowcaseExampleState extends State<HeroShowcaseExample>
269295

270296
Widget _buildNode(BuildContext context, Node<HeroNodeData> node) {
271297
final data = node.data;
298+
final isDark = Theme.of(context).brightness == Brightness.dark;
272299

273-
// Get border radius and width from theme
300+
// Get border radius from theme
274301
final nodeTheme = _theme.nodeTheme;
275302
final outerRadius = nodeTheme.borderRadius;
276303
final borderWidth = node.isSelected
@@ -280,33 +307,45 @@ class _HeroShowcaseExampleState extends State<HeroShowcaseExample>
280307
// Inner radius = outer radius - border width
281308
final innerRadiusValue = (outerRadius.topLeft.x - borderWidth);
282309

310+
// Theme-aware colors
311+
final backgroundColor = isDark ? const Color(0xFF1E293B) : Colors.white;
312+
final headerColor = isDark
313+
? data.color.withValues(alpha: 0.15)
314+
: data.color.withValues(alpha: 0.06);
315+
283316
return Container(
284317
clipBehavior: Clip.antiAlias,
285318
decoration: BoxDecoration(
319+
color: backgroundColor,
286320
borderRadius: BorderRadius.circular(innerRadiusValue),
287321
),
288322
child: Column(
289323
mainAxisSize: MainAxisSize.min,
290324
crossAxisAlignment: CrossAxisAlignment.stretch,
291325
children: [
292-
// Very thin header - inner radius accounts for border width
326+
// Modern minimal header - just subtle tinted background
293327
Container(
294-
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
295-
decoration: BoxDecoration(color: data.color),
328+
decoration: BoxDecoration(color: headerColor),
329+
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
296330
child: Row(
297331
children: [
298-
Icon(data.icon, size: 12, color: Colors.white),
299-
const SizedBox(width: 4),
332+
Icon(data.icon, size: 13, color: data.color),
333+
const SizedBox(width: 6),
300334
Expanded(
301335
child: Text(
302336
data.title,
303-
style: const TextStyle(fontSize: 10, color: Colors.white),
337+
style: TextStyle(
338+
fontSize: 11,
339+
fontWeight: FontWeight.w600,
340+
color: data.color.withValues(alpha: 0.9),
341+
letterSpacing: 0.2,
342+
),
304343
),
305344
),
306345
],
307346
),
308347
),
309-
// Content
348+
// Content with refined padding
310349
Expanded(
311350
child: Padding(
312351
padding: const EdgeInsets.all(10),
@@ -614,9 +653,9 @@ class _ColorSelector extends StatelessWidget {
614653
builder: (_) => Column(
615654
crossAxisAlignment: CrossAxisAlignment.stretch,
616655
children: [
617-
// Color swatches - just tick mark for selection, fixed size
656+
// Color swatches - checkmark for selection
618657
SizedBox(
619-
height: 32,
658+
height: 24,
620659
child: Row(
621660
children: colors.map((color) {
622661
final isSelected = selectedColor.value == color;
@@ -625,11 +664,11 @@ class _ColorSelector extends StatelessWidget {
625664
onTap: () => runInAction(() => selectedColor.value = color),
626665
child: Container(
627666
margin: const EdgeInsets.symmetric(horizontal: 2),
667+
alignment: Alignment.center,
628668
decoration: BoxDecoration(
629669
color: color,
630-
borderRadius: BorderRadius.circular(6),
670+
borderRadius: BorderRadius.circular(4),
631671
),
632-
alignment: Alignment.center,
633672
child: isSelected
634673
? const Icon(
635674
Icons.check,
@@ -663,19 +702,25 @@ class _ColorSelector extends StatelessWidget {
663702
Expanded(
664703
child: SliderTheme(
665704
data: SliderTheme.of(context).copyWith(
666-
trackHeight: 3,
705+
trackHeight: 2,
706+
activeTrackColor: selectedColor.value.withValues(
707+
alpha: 0.8,
708+
),
709+
inactiveTrackColor: selectedColor.value.withValues(
710+
alpha: 0.15,
711+
),
667712
thumbShape: const RoundSliderThumbShape(
668-
enabledThumbRadius: 6,
713+
enabledThumbRadius: 5,
669714
),
670715
overlayShape: const RoundSliderOverlayShape(
671-
overlayRadius: 12,
716+
overlayRadius: 10,
672717
),
718+
thumbColor: selectedColor.value,
673719
),
674720
child: Slider(
675721
value: opacity.value,
676722
min: 0.1,
677723
max: 1.0,
678-
activeColor: selectedColor.value,
679724
onChanged: (v) => runInAction(() => opacity.value = v),
680725
),
681726
),
@@ -730,27 +775,33 @@ class _EffectsPanel extends StatelessWidget {
730775
children: [
731776
Icon(
732777
Icons.blur_on,
733-
size: 14,
734-
color: isDark ? Colors.white54 : Colors.black45,
778+
size: 13,
779+
color: isDark ? Colors.white54 : Colors.black38,
735780
),
736781
const SizedBox(width: 4),
737782
Text('Blur', style: labelStyle),
738783
Expanded(
739784
child: SliderTheme(
740785
data: SliderTheme.of(context).copyWith(
741-
trackHeight: 3,
786+
trackHeight: 2,
787+
activeTrackColor: const Color(
788+
0xFF34D399,
789+
).withValues(alpha: 0.8),
790+
inactiveTrackColor: const Color(
791+
0xFF34D399,
792+
).withValues(alpha: 0.15),
742793
thumbShape: const RoundSliderThumbShape(
743-
enabledThumbRadius: 6,
794+
enabledThumbRadius: 5,
744795
),
745796
overlayShape: const RoundSliderOverlayShape(
746-
overlayRadius: 12,
797+
overlayRadius: 10,
747798
),
799+
thumbColor: const Color(0xFF34D399),
748800
),
749801
child: Slider(
750802
value: blurRadius.value,
751803
min: 0,
752804
max: 10,
753-
activeColor: const Color(0xFF10B981),
754805
onChanged: (v) => runInAction(() => blurRadius.value = v),
755806
),
756807
),
@@ -769,27 +820,33 @@ class _EffectsPanel extends StatelessWidget {
769820
children: [
770821
Icon(
771822
Icons.tune,
772-
size: 14,
773-
color: isDark ? Colors.white54 : Colors.black45,
823+
size: 13,
824+
color: isDark ? Colors.white54 : Colors.black38,
774825
),
775826
const SizedBox(width: 4),
776827
Text('Saturation', style: labelStyle),
777828
Expanded(
778829
child: SliderTheme(
779830
data: SliderTheme.of(context).copyWith(
780-
trackHeight: 3,
831+
trackHeight: 2,
832+
activeTrackColor: const Color(
833+
0xFF34D399,
834+
).withValues(alpha: 0.8),
835+
inactiveTrackColor: const Color(
836+
0xFF34D399,
837+
).withValues(alpha: 0.15),
781838
thumbShape: const RoundSliderThumbShape(
782-
enabledThumbRadius: 6,
839+
enabledThumbRadius: 5,
783840
),
784841
overlayShape: const RoundSliderOverlayShape(
785-
overlayRadius: 12,
842+
overlayRadius: 10,
786843
),
844+
thumbColor: const Color(0xFF34D399),
787845
),
788846
child: Slider(
789847
value: saturation.value,
790848
min: 0,
791849
max: 1,
792-
activeColor: const Color(0xFF10B981),
793850
onChanged: (v) => runInAction(() => saturation.value = v),
794851
),
795852
),
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{{flutter_js}}
2+
{{flutter_build_config}}
3+
4+
(function() {
5+
var loader = document.getElementById('loader');
6+
var progressBar = document.getElementById('progress-bar');
7+
var progressText = document.getElementById('progress-text');
8+
9+
function updateProgress(progress, text) {
10+
if (progressBar) {
11+
progressBar.style.width = Math.round(progress * 100) + '%';
12+
}
13+
if (progressText && text) {
14+
progressText.textContent = text;
15+
}
16+
}
17+
18+
function hideLoader() {
19+
if (loader) {
20+
loader.classList.add('fade-out');
21+
setTimeout(function() { loader.remove(); }, 500);
22+
}
23+
}
24+
25+
// Start with initial progress
26+
updateProgress(0.2, 'Loading');
27+
28+
_flutter.loader.load({
29+
onEntrypointLoaded: async function(engineInitializer) {
30+
updateProgress(0.5, 'Initializing');
31+
32+
var appRunner = await engineInitializer.initializeEngine();
33+
34+
updateProgress(0.8, 'Starting');
35+
36+
await appRunner.runApp();
37+
38+
updateProgress(1, 'Ready');
39+
setTimeout(hideLoader, 300);
40+
}
41+
});
42+
})();

0 commit comments

Comments
 (0)