Design Systemy
Wprowadzenie
Lumos Islands ma dwa odseparowane design systemy — po jednym dla każdej aplikacji. Oba dzielą wspólne tokeny brand (kolory, typografia), ale mają niezależne komponenty dostosowane do swojego kontekstu (mobile vs web).
Wspólne Tokeny Brand
Kolory
| Token | Wartość | Zastosowanie |
|---|---|---|
brand-primary | #6366F1 (Indigo 500) | Główne akcje, linki, ikony |
brand-secondary | #8B5CF6 (Violet 500) | Akcenty, wyróżnienia |
brand-accent | #F59E0B (Amber 500) | XP, nagrody, odznaki |
success | #10B981 (Emerald 500) | Ukończone, poprawne |
warning | #F59E0B (Amber 500) | Ostrzeżenia, deadline |
error | #EF4444 (Red 500) | Błędy, niepoprawne |
surface | #FFFFFF / #1F2937 | Tło kart (light/dark) |
background | #F9FAFB / #111827 | Tło strony (light/dark) |
Typografia
| Token | Wartość | Zastosowanie |
|---|---|---|
font-display | Nunito | Nagłówki, tytuły |
font-body | Inter | Tekst body, opisy |
font-mono | JetBrains Mono | Kod, dane techniczne |
Spacing
Skala oparta na wielokrotnościach 4px:
| Token | Wartość |
|---|---|
space-1 | 4px |
space-2 | 8px |
space-3 | 12px |
space-4 | 16px |
space-6 | 24px |
space-8 | 32px |
space-12 | 48px |
space-16 | 64px |
Border Radius
| Token | Wartość | Zastosowanie |
|---|---|---|
radius-sm | 4px | Małe elementy (badge, chip) |
radius-md | 8px | Przyciski, inputy |
radius-lg | 12px | Karty |
radius-xl | 16px | Modale, panele |
radius-full | 9999px | Awatary, kółka |
Flutter App — Design System
Narzędzie: Widgetbook
Widgetbook to storybook dla Flutter — pozwala przeglądać, testować i dokumentować widgety w izolacji.
app/widgetbook/
└── lib/
├── main.dart # Entry point Widgetbook
├── components/
│ ├── buttons.dart # Warianty przycisków
│ ├── cards.dart # Karty zadań, lokacji
│ ├── inputs.dart # Pola formularzy
│ ├── navigation.dart # Bottom bar, app bar
│ └── badges.dart # Odznaki, XP badge
└── tokens/
├── colors.dart # Paleta kolorów
├── typography.dart # Style tekstowe
└── spacing.dart # Spacing previewUruchomienie Widgetbook
bash
cd app
flutter run -t widgetbook/lib/main.dartTokeny w Dart
dart
class AppColors {
static const primary = Color(0xFF6366F1);
static const secondary = Color(0xFF8B5CF6);
static const accent = Color(0xFFF59E0B);
static const success = Color(0xFF10B981);
static const warning = Color(0xFFF59E0B);
static const error = Color(0xFFEF4444);
}
class AppTypography {
static const displayLarge = TextStyle(
fontFamily: 'Nunito',
fontSize: 32,
fontWeight: FontWeight.bold,
);
static const bodyMedium = TextStyle(
fontFamily: 'Inter',
fontSize: 14,
fontWeight: FontWeight.normal,
);
}
class AppSpacing {
static const s1 = 4.0;
static const s2 = 8.0;
static const s3 = 12.0;
static const s4 = 16.0;
static const s6 = 24.0;
static const s8 = 32.0;
}Kluczowe Komponenty Flutter
| Komponent | Opis | Warianty |
|---|---|---|
LumosButton | Przycisk | primary, secondary, outline, text |
TaskCard | Kafel zadania (Netflix-style) | video, quiz, audio, game, creative |
LocationPin | Pin na mapie | locked, unlocked, completed |
XpBadge | Badge z XP | small, large |
AvatarWidget | Awatar dziecka | editable, display |
TodoItem | Element todo listy | pending, done, overdue |
NavBar | Dolna nawigacja | globe, cosmos, spaceship, profile |
Theming
dart
final lightTheme = ThemeData(
colorScheme: ColorScheme.light(
primary: AppColors.primary,
secondary: AppColors.secondary,
surface: Colors.white,
background: Color(0xFFF9FAFB),
),
fontFamily: 'Inter',
textTheme: TextTheme(
displayLarge: AppTypography.displayLarge,
bodyMedium: AppTypography.bodyMedium,
),
);
final darkTheme = ThemeData(
colorScheme: ColorScheme.dark(
primary: AppColors.primary,
secondary: AppColors.secondary,
surface: Color(0xFF1F2937),
background: Color(0xFF111827),
),
fontFamily: 'Inter',
);Manager-Content — Design System
Narzędzie: Dedykowana Strona Komponentów
Manager-content ma wbudowaną stronę /design-system dostępną w trybie development, prezentującą wszystkie komponenty UI.
Tokeny w TailwindCSS
js
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
brand: {
primary: '#6366F1',
secondary: '#8B5CF6',
accent: '#F59E0B',
},
success: '#10B981',
warning: '#F59E0B',
error: '#EF4444',
},
fontFamily: {
display: ['Nunito', 'sans-serif'],
body: ['Inter', 'sans-serif'],
mono: ['JetBrains Mono', 'monospace'],
},
borderRadius: {
sm: '4px',
md: '8px',
lg: '12px',
xl: '16px',
},
},
},
}Komponenty Go Templates
Komponenty UI jako szablony Go, wywoływane przez :
html
<!-- components/button.html -->
{{ define "button" }}
<button
class="inline-flex items-center px-4 py-2 rounded-md font-medium
bg-brand-primary text-white hover:bg-indigo-600
transition-colors duration-150"
{{ if .HxGet }}hx-get="{{ .HxGet }}"{{ end }}
{{ if .HxTarget }}hx-target="{{ .HxTarget }}"{{ end }}
>
{{ .Label }}
</button>
{{ end }}html
<!-- components/card.html -->
{{ define "card" }}
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
{{ if .Title }}
<h3 class="text-lg font-display font-semibold text-gray-900 mb-2">
{{ .Title }}
</h3>
{{ end }}
<div class="text-gray-600 font-body">
{{ .Content }}
</div>
</div>
{{ end }}Kluczowe Komponenty Manager-Content
| Komponent | Opis | Plik |
|---|---|---|
button | Przycisk (primary, secondary, danger) | button.html |
card | Karta z tytułem i treścią | card.html |
modal | Okno modalne (Alpine.js) | modal.html |
form-field | Pole formularza z labelem i błędem | form-field.html |
task-card | Kafel zadania z miniaturą | task-card.html |
todo-item | Element todo listy | todo-item.html |
stat-card | Karta statystyki (dashboard) | stat-card.html |
dropdown | Menu rozwijane (Alpine.js) | dropdown.html |
Interaktywność HTMX
html
<!-- Dynamiczna lista zadań -->
<div id="task-list"
hx-get="/content/tasks"
hx-trigger="load"
hx-swap="innerHTML">
<p>Ładowanie zadań...</p>
</div>
<!-- Usuwanie zadania z animacją -->
<div id="task-{{ .ID }}" class="task-card">
<button hx-delete="/content/tasks/{{ .ID }}"
hx-target="#task-{{ .ID }}"
hx-swap="outerHTML swap:0.3s"
hx-confirm="Usunąć to zadanie?">
Usuń
</button>
</div>Zasady Projektowe
1. Spójność wizualna
Obie aplikacje wyglądają jak część tego samego ekosystemu dzięki wspólnym tokenom brand (kolory, fonty, spacing).
2. Kontekst użycia
- Flutter App — mobile-first, dotykowy UI, animacje, duże hittable areas
- Manager-Content — desktop-first, formularze, tabele, gęstszy layout
3. Dostępność
- Kontrast kolorów zgodny z WCAG AA
- Focus states na wszystkich interaktywnych elementach
- Semantyczny HTML w manager-content
- Semantyczne widgety w Flutter (Semantics widget)
4. Dark Mode
Obie aplikacje wspierają dark mode:
- Flutter:
ThemeDatalight/dark z automatycznym przełączaniem - Manager-content: TailwindCSS
dark:variant +prefers-color-scheme
5. Responsive
- Flutter: adaptacyjne layouty (phone, tablet)
- Manager-content: responsive breakpoints TailwindCSS (sm, md, lg, xl)