Architektura

System studia projektowego i konwencje UI

DataFlow AI Platform prezentuje rozbudowany, bogaty w funkcje produkt ETL — projektowanie potoków danych, monitorowanie, zarządzanie, migrację i administrację — poprzez jeden spójny system wizualny. Ta strona dokumentuje język projektowy: model tokenów semantycznych, ciemny motyw amber/zinc, powłokę adaptującą się do person, współdzieloną bibliotekę komponentów oraz konwencje dostępności i responsywności, których przestrzega każdy ekran.


Zasady projektowe

Interfejs jest zbudowany z myślą o inżynierach danych telekomunikacyjnych, analitykach, administratorach i opiekunach danych pracujących przez długie sesje na gęstych ekranach operacyjnych. Cztery zasady kształtują każdą decyzję dotyczącą komponentów.

ZasadaCo oznacza w praktyce
Semantyczne, nie dosłowneKomponenty odwołują się do klas tokenów (bg-surface-1, text-heading) zamiast surowych kolorów, więc zmiana motywu nigdy nie dotyka kodu komponentów.
Najpierw ciemnyDomyślnym motywem jest ciemny; jasny jest w pełni wspieraną alternatywą. Oba wynikają z tego samego zestawu tokenów.
Adaptacja do personyPowłoka — głównie pasek boczny — pokazuje tylko funkcje istotne dla aktywnej persony.
Podzielony kod i odpornośćKażda strona jest ładowana leniwie i opakowana w granicę błędu; awaria jednego ekranu nigdy nie psuje powłoki.

Model tokenów

Stylizacja korzysta z Tailwind CSS 4, podłączonego przez @tailwindcss/vite. Platforma nie rozsiewa wartości heksadecymalnych po komponentach. Zamiast tego definiuje warstwę semantycznych tokenów projektowych — nazwanych ról takich jak „surface" czy „heading" — a komponenty korzystają wyłącznie z nich.

Tokeny powierzchni

Powierzchnie są warstwowe. Powierzchnie o wyższych numerach znajdują się wizualnie bliżej użytkownika i są używane dla wyniesionych elementów, takich jak karty, panele i okna modalne.

Klasa tokenuRola
bg-surface-0Tło strony — najgłębsza warstwa
bg-surface-1Karty, panele, pasek boczny
bg-surface-2Wyniesione elementy — popovery, okna modalne, listy rozwijane

Tokeny tekstu

Tokeny tekstu wyrażają hierarchię, a nie kolor. Nagłówek to text-heading niezależnie od motywu.

Klasa tokenuRola
text-headingTytuły stron i sekcji
text-bodyGłówny tekst do czytania
text-secondaryTekst pomocniczy, etykiety
text-mutedTekst odznaczony, podpowiedzi, placeholdery

Obramowanie i akcent

Klasa tokenuRola
border-primaryDomyślne separatory i kontury komponentów
amber-500Akcent marki — akcje główne, aktywna nawigacja, podświetlenia fokusu
 SURFACE LAYERING (dark theme)

  ┌─ bg-surface-0  (page) ────────────────────────────────┐
  │                                                       │
  │   ┌─ bg-surface-1  (card / panel) ─────────────────┐   │
  │   │  text-heading   Pipeline summary               │   │
  │   │  text-body      14 runs in the last 24 hours   │   │
  │   │  text-muted     last updated 2 minutes ago     │   │
  │   │                              ┌──────────────┐  │   │
  │   │                              │ bg-surface-2 │  │   │
  │   │                              │  (popover)   │  │   │
  │   │                              └──────────────┘  │   │
  │   │   [ amber-500 primary action ]                 │   │
  │   └─────────────────────────────────────────────────┘   │
  └───────────────────────────────────────────────────────┘

Dlaczego tokeny semantyczne

Ponieważ komponenty odwołują się do klas tokenów, a nie do dosłownych kolorów, przełączanie między motywem ciemnym i jasnym — lub późniejsza korekta palety — jest zmianą na poziomie warstwy tokenów. Żaden plik komponentu nie jest edytowany.


Referencja palety kolorów

Za tokenami semantycznymi kryje się konkretna paleta. Platforma jest produktem nastawionym na motyw ciemny, a kanonicznym akcentem jest złoty/bursztynowy #ffd200. Poniższe tabele podają dosłowne wartości, do których rozwiązywany jest każdy token.

Motyw ciemny — tła

RolaHexTailwindZastosowanie
Bazowe#09090bzinc-950Główne tło strony — najgłębsza warstwa
Powierzchnia#0c0c0fwłasnyPrzemienne tło sekcji, karty
Wyniesione#18181bzinc-900Pasek boczny, panele, okna modalne
Nakładkargba(255,255,255,0.03)white/3Subtelne nakładki kart
Nakładka przy najechaniurgba(255,255,255,0.05)white/5Stan najechania na kartę
Nakładka aktywnargba(255,255,255,0.06)white/6Stan aktywny / wybrany

Motyw ciemny — tekst

RolaHexTailwindZastosowanie
Główny#ffffffwhiteNagłówki, wyróżnienia
Drugorzędny#f1f5f9slate-100Tekst główny
Stłumiony#d1d5dcgray-300Etykiety drugorzędne
Subtelny#6a7282gray-500Placeholdery, podpowiedzi
Wyłączony#4a5565gray-600Stan wyłączony

Motyw ciemny — obramowania

RolaHexTailwindZastosowanie
Domyślnergba(255,255,255,0.08)white/8Obramowania kart, separatory
Subtelnergba(255,255,255,0.06)white/6Subtelne separatory
Mocnergba(255,255,255,0.15)white/15Obramowanie przycisku drugorzędnego

Akcent — główny (złoty/bursztynowy)

RolaHexZastosowanie
Akcent główny#ffd200Główny kolor marki, CTA
Akcent główny przy najechaniu#e6bd00Stan najechania
Tekst na akcencie głównym#101828Tekst na tle akcentowym

Akcent — paleta semantyczna

Akcent bursztynowy jest zarezerwowany dla akcji i marki. Znaczenie statusu i kategorii przekazuje stała paleta semantyczna.

KolorHexTailwindZastosowanie
Szmaragdowy#10b981emerald-500Sukces, online, zdrowy
Niebieski#3b82f6blue-500Informacja, linki, akcje drugorzędne
Cyjan#06b6d4cyan-500Dane, metryki
Fioletowy#8b5cf6violet-500Funkcje AI, specjalne
Purpurowy#c084fcpurple-400Kreatywne, projektowe
Bursztynowy#f59e0bamber-500Ostrzeżenia
Czerwony#ef4444red-500Błędy, destrukcyjne, krytyczne
Pomarańczowy#f97316orange-500Uwaga, alerty
Różowy#ec4899pink-500Wyróżnienia

Ciemny motyw amber/zinc

Charakterystyczny wygląd to ciemny motyw amber/zinc: głębokie neutralne powierzchnie zinc niosące ciepły akcent bursztynowy. Zinc nadaje ekranom przeznaczonym na długie sesje bazę o niskim olśnieniu i niskim zmęczeniu; bursztyn (amber-500) oznacza nieliczne rzeczy, na które użytkownik powinien zareagować — przyciski główne, aktywny element nawigacji, pierścienie fokusu i kluczowe podświetlenia statusu.

Motyw ten jest domyślny. Jest kanonicznym wyrazem języka projektowego; motyw jasny to ten sam zestaw tokenów przemapowany dla jasnych środowisk.

MotywPowierzchnie bazoweAkcentDomyślny
CiemnyNeutralne tony zinc, od głębokich do wyniesionychBursztynowy (amber-500)Tak
JasnyJasne tony neutralne, takie samo warstwowanieBursztynowy (amber-500)Nie

Motywy jasny i ciemny

Stan motywu jest własnością magazynu Zustand themeStore, utrwalanego w localStorage pod kluczem dataflow-theme. Jego wartość to 'dark' | 'light', domyślnie 'dark'.

Mechanizm to pojedyncze przełączanie klasy. Gdy motyw się zmienia, magazyn ustawia lub usuwa klasę dark na document.documentElement (<html>). Tailwind CSS 4 rozwiązuje każdy token semantyczny względem tej klasy, więc jedno przełączenie klasy zmienia motyw całej aplikacji.

  themeStore.theme  ──────────────►  <html class="dark">
       │                                    │
   persisted to                      Tailwind 4 resolves
   localStorage                      every semantic token
   'dataflow-theme'                   against the class
       │                                    │
   restored on load                  components re-render
                                     with no code change

App.tsx odczytuje theme z useThemeStore przy montowaniu i natychmiast synchronizuje klasę <html>, więc poprawny motyw jest stosowany przed pierwszym renderowaniem i nie ma migotania niewłaściwego motywu.

Mapowanie motywu

Ta sama rola semantyczna rozwiązuje się do innej konkretnej wartości w zależności od motywu. Akcent i CTA pozostają stałe — przemapowywane są tylko tony neutralne.

ElementTryb ciemnyTryb jasny
Tło strony#09090b (zinc-950)#f8fafc (slate-50)
Powierzchnia#0c0c0f#ffffff
Pasek boczny#18181b (zinc-900)#ffffff
Tekst główny#ffffff#101828
Tekst drugorzędny#d1d5dc (gray-300)#4a5565 (gray-600)
Tekst stłumiony#6a7282 (gray-500)#6a7282 (gray-500)
Obramowaniewhite/8gray-200 (#e5e7eb)
Akcent#ffd200#ffd200
Przycisk CTAZłoty gradientZłoty gradient
Tekst CTA#101828#101828

Powłoka adaptująca się do person

Aplikacja działa wewnątrz jednej trwałej powłoki — components/shell/AppShell.tsx — a powłoka ta adaptuje się do aktywnej persony. Istnieją cztery persony: engineer, analyst, admin i steward.

Jak persony są rozwiązywane

W produkcji persona jest wyprowadzana z ról Keycloak za pośrednictwem ROLE_PERSONA_MAP w auth/keycloak.ts. W trybie deweloperskim pochodzi z personaStore (activePersona, domyślnie engineer, utrwalana pod dataflow-persona).

Jak powłoka się adaptuje

Model nawigacji paska bocznego znajduje się w data/navigation.ts jako navigationItems. Każdy element deklaruje id, label, icon (nazwę ikony lucide), path, listę widoczności personas[] oraz opcjonalne children[]. Pasek boczny filtruje elementy według activePersona i dodatkowo uwzględnia flagę funkcji MIGRATION_CENTER_ENABLED z config/env.ts.

  ENGINEER persona              ANALYST persona              ADMIN persona
  ┌──────────────┐             ┌──────────────┐             ┌──────────────┐
  │ ▸ Home       │             │ ▸ Home       │             │ ▸ Home       │
  │ ▸ Design     │             │ ▸ Data       │             │ ▸ Monitor    │
  │   Studio     │             │   Browser    │             │ ▸ Governance │
  │ ▸ Monitor    │             │ ▸ Monitor    │             │ ▸ Migration  │
  │ ▸ My         │             │ ▸ Marketplace│             │ ▸ Admin (6)  │
  │   Pipelines  │             │ ▸ Templates  │             │   ─ Users    │
  │ ▸ Connections│             │              │             │   ─ Security │
  └──────────────┘             └──────────────┘             └──────────────┘
   navigationItems filtered by activePersona  +  MIGRATION_CENTER_ENABLED flag

Poza filtrowaniem, ProtectedRoute egzekwuje dostęp persony dla każdej trasy: oblicza effectivePersona i wywołuje canAccess(persona, pathname) z data/permissions. Jeśli persona dotrze do ścieżki, której nie powinna widzieć, zamiast strony renderowany jest <AccessDenied />. Współdzielony prymityw UI PermissionGate pozwala pokazywać lub ukrywać poszczególne elementy sterujące — przyciski, akcje menu — według uprawnień w obrębie strony, która w innym przypadku jest widoczna.


Konwencje biblioteki komponentów

Komponenty są zorganizowane według obszaru funkcjonalnego w components/, z jednym współdzielonym, niezależnym od motywu zestawem UI w components/ui/.

Zestaw UI

Folder ui/ zawiera około czterdzieści prymitywów prezentacyjnych. Są one jedynym miejscem, gdzie podejmowane są decyzje o kolorze i odstępach; komponenty funkcjonalne je komponują.

KategoriaPrymitywy
Wyświetlanie danychDataTable, DataGrid, Timeline, Accordion, TreeView, CodeBlock, Badge, Avatar
FormularzeInput, Select, Checkbox, Radio, Switch, Textarea, FileInput
NawigacjaTabs, Pagination, Breadcrumbs
Informacja zwrotnaSkeleton, EmptyState, AlertBanner, ProgressBar, Toast / ToastProvider, Popover, Tooltip
WykresyLineChart, BarChart, GaugeChart
UkładStack, Show, ResponsiveGrid, Divider, List
DostępSkipNav, PermissionGate

Foldery funkcjonalne — design-studio/, monitor/, governance/, admin/, migration/, ai-copilot/, data-browser/, pipelines/, connections/ — budują komponenty specyficzne dla ekranów na bazie zestawu.

Tabele

Tabele o dużym wolumenie — uruchomienia potoków danych, wiersze katalogu, dzienniki audytu — są zbudowane na @tanstack/react-table 8 i wirtualizowane za pomocą @tanstack/react-virtual 3, więc tabela z tysiącami wierszy renderuje tylko widoczne okno.

Powierzchnie grafów i kodu

W produkcie pojawiają się dwie wyspecjalizowane powierzchnie:

  • Grafy przepływu korzystają z @xyflow/react 12 (React Flow) — kanwa potoku danych w Studiu Projektowym oraz graf pochodzenia danych w zarządzaniu.
  • Edycja kodu korzysta z @monaco-editor/react 4 dla definicji potoków danych w YAML oraz SQL.

Typografia

Platforma używa jednej rodziny bezszeryfowej dla tekstu UI i rodziny o stałej szerokości dla kodu, SQL i YAML.

/* UI text */
font-family: Inter, system-ui, -apple-system, sans-serif;
/* Code, SQL, pipeline YAML */
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;

Skala typograficzna

PoziomRozmiarGrubośćWysokość wierszaOdstęp między literamiZastosowanie
Display72px7001.1-1.8pxNagłówki hero
H148px7001.0-0.5pxNagłówki stron
H236px7001.1normalnyNagłówki sekcji
H324px6001.3normalnyNagłówki kart
H420px6001.4normalnyNagłówki podsekcji
Body Large18px4001.6normalnyAkapity wiodące
Body16px4001.5normalnyDomyślny tekst główny
Body Small14px4001.5normalnyOpisy
Caption12px5001.4normalnyEtykiety, metadane
Micro11px5001.30.5pxPlakietki, tagi
Tiny10px6001.20.5pxEtykiety nadkreślone

Grubości fontu

GrubośćWartośćZastosowanie
Regular400Tekst główny
Medium500Etykiety, podpisy
Semibold600Przyciski, podnagłówki
Bold700Nagłówki
Extrabold800Metryki wyświetlane

Skala odstępów

Odstępy są zgodne z jednostką bazową Tailwind wynoszącą 4px. Komponenty czerpią ze stałego zestawu kroków zamiast z dowolnych wartości.

TokenWartośćZastosowanie
space-14pxCiasne przerwy
space-28pxDomyślna przerwa
space-312pxWypełnienie karty (kompaktowe)
space-416pxPrzerwa sekcji
space-624pxWypełnienie sekcji, standardowe wypełnienie karty
space-832pxDuże odstępy sekcji
space-1248pxSekcje strony
space-1664pxGłówne sekcje

Promień obramowania

TokenWartośćZastosowanie
rounded-sm6pxTagi, małe plakietki
rounded8pxPrzyciski, pola wejściowe, małe karty
rounded-md12pxKarty, panele
rounded-lg16pxDuże karty, okna modalne
rounded-full9999pxPigułki, awatary, plakietki

Cienie

TokenWartośćZastosowanie
shadow-sm0 1px 2px rgba(0,0,0,0.05)Subtelne uniesienie
shadow-md0 4px 6px -1px rgba(0,0,0,0.1)Karty
shadow-lg0 10px 15px -3px rgba(0,0,0,0.1)Wyniesione karty, przyciski
shadow-xl0 20px 25px -5px rgba(0,0,0,0.1)Okna modalne, listy rozwijane
shadow-2xl0 25px 50px -12px rgba(0,0,0,0.25)Elementy hero
shadow-glow0 0 20px rgba(255,210,0,0.15)Złota poświata akcentu

Przyciski i stany interakcji

Przyciski występują w trzech wagach — złote główne CTA, drugorzędne typu ghost oraz czerwone destrukcyjne — w rozmiarze standardowym i dużym.

/* Primary CTA — standard */
background: linear-gradient(to right, #ffd200, #d4a00a);
color: #101828;
font-weight: 600;
font-size: 14px;
padding: 8px 16px;
border-radius: 8px;

/* Primary CTA — large */
font-size: 16px;
padding: 16px 32px;
border-radius: 12px;

/* Secondary (ghost) */
background: transparent;
color: #d1d5dc;
border: 0.8px solid rgba(255,255,255,0.15);

/* Destructive */
background: #ef4444;
color: #ffffff;

Stany interakcji

Każdy interaktywny prymityw rozwiązuje te same cztery stany, więc przycisk, wiersz i element nawigacji reagują spójnie.

StanEfekt
NajechanieRozjaśnienie o 10%, skala 1.02
AktywnyPrzyciemnienie o 5%, skala 0.98
WyłączonyPrzezroczystość 0.5, kursor not-allowed
FokusPierścień 2px, amber-500/50 — akcent bursztynowy pełni jednocześnie rolę podświetlenia fokusu

Gradienty

/* Gold text gradient — headlines */
background: linear-gradient(to right, #ffd200, #e6b800, #cc9e00);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;

/* Gold button gradient */
background: linear-gradient(to right, #ffd200 0%, #d4a00a 50%, #b8860b 100%);

/* Subtle gold glow — background accent */
background: radial-gradient(rgba(255,210,0,0.08) 0%, transparent 60%);

Wzorce komponentów

Prymitywy zestawu UI są zbudowane z powyższych tokenów. Poniższe powracające wzorce definiują, jak karta, element nawigacji, plakietka, pole wejściowe, tabela i pasek kart wyglądają w motywie ciemnym.

WzorzecSpecyfikacja
Kartabg white/3, border 1px white/8, promień 12px, wypełnienie 24px; najechanie → bg white/5, border white/12
Element nawigacji paska bocznegoDomyślnie text-gray-400; najechanie text-white na bg white/5; aktywny text-amber-400 na bg amber-500/10 z border-l-2 border-amber-500
Plakietka / tagbg {color}-500/10, text {color}-400, border 1px {color}-500/20, promień 6px, wypełnienie 2px 8px, 11px medium
Pole wejściowebg white/5, border 1px white/10, promień 8px, biały tekst, placeholder gray-500; fokus → border amber-500/50, pierścień 2px amber-500/20
TabelaNagłówek bg white/3, tekst nagłówka gray-400 wielkie litery 11px tracking-wider; obramowanie wiersza white/5, najechanie na wiersz white/3; tekst komórki gray-300 (dane) / biały (główny)
Pasek kartDomyślnie text-gray-400 z border-b-2 border-transparent; najechanie text-gray-200 / border-gray-600; aktywny text-amber-400 / border-amber-500

Ikonografia

  • Biblioteka — Lucide React. Ikoną logo marki jest glif Workflow z Lucide.
  • Grubość kreski — domyślnie 1.5px.
  • Rozmiary — mały 16px (h-4 w-4, w linii z tekstem); domyślny 20px (h-5 w-5, nawigacja i przyciski); duży 24px (h-6 w-6, ikony funkcji).
  • Kolor — ikony dziedziczą kolor otaczającego tekstu, więc zmieniają motyw wraz z resztą UI.

Animacja i przejścia

Ruch jest powściągliwy i spójny. Każda klasa interakcji ma stały czas trwania i wygładzenie.

WłaściwośćCzas trwaniaWygładzenie
Przejścia kolorów150msease
Tło200msease-in-out
Transformacja (najechanie)200msease-out
Otwarcie okna modalnego300msease-out
Przełączenie paska bocznego300msease-in-out
Spinner1000mslinear (nieskończony)

Punkty przełamań responsywnych

Układ jest rozwiązywany względem pięciu standardowych punktów przełamań Tailwind.

Punkt przełamaniaSzerokośćZastosowanie
sm640pxTelefon poziomo
md768pxTablet
lg1024pxPulpit
xl1280pxSzeroki pulpit
2xl1536pxBardzo szeroki

Prymitywy układu

Strony są montowane z niewielkiego zestawu prymitywów układu, tak aby odstępy, nagłówki stron i widoki dzielone wyglądały identycznie wszędzie.

PrymitywFolderRola
PageContainerlayout/Standardowe opakowanie strony ze spójnym wypełnieniem i maksymalną szerokością
PageHeaderlayout/Tytuł, opis i obszar akcji na górze strony
SplitPanelayout/Zmienne rozmiarem układy dwupanelowe (np. lista plus szczegóły)

Sama powłoka dostarcza trwałą ramę: Sidebar, TopBar, ujście <main id="main-content"> oraz wyzwalacz i pasek boczny AI Copilot. Treść główna jest przesunięta o effectiveMargin, który śledzi bieżącą szerokość paska bocznego (zwinięty 60px, rozwinięty 240px).


Dostępność

Dostępność jest wbudowana w powłokę i zestaw UI, a nie doczepiana do każdej strony osobno.

  • Pomiń nawigację. Powłoka renderuje link pomijający do #main-content; prymityw SkipNav go standaryzuje. <main> niesie cel id="main-content".
  • Powierzchnia poleceń klawiaturowych. Wyszukiwanie globalne otwiera się skrótem Ctrl/Cmd+K poprzez obsługę naciśnięcia klawisza w powłoce; paleta poleceń jest zbudowana na cmdk. Hak useKeyboardShortcut standaryzuje pozostałe skróty.
  • Widoczność fokusu. Akcent bursztynowy pełni jednocześnie rolę podświetlenia fokusu, więc fokus klawiatury jest zawsze wyraźnie widoczny na powierzchniach zinc.
  • Renderowanie świadome uprawnień. PermissionGate i ProtectedRoute zapewniają, że użytkownicy nie zobaczą — i nie mogą wejść tabulatorem do — elementów sterujących lub tras, z których nie mogą korzystać.
  • Stany ładowania i puste. Skeleton i EmptyState nadają każdej powierzchni asynchronicznej zdefiniowany, przyjazny dla czytników ekranu stan, zamiast pustego obszaru.

Odporny domyślnie

Każda strona jest opakowana w ErrorBoundary (wewnątrz SuspenseWrap), a panele używają PanelErrorFallback. Użytkownik zawsze widzi możliwą do odzyskania powierzchnię błędu, nigdy pusty ekran, gdy coś zawiedzie.


Zachowanie responsywne

Układ adaptuje się do trzech klas punktów przełamań, obliczanych przez useIsMobile, useIsTablet i useSidebarState z hooks/useResponsive (ze wspierającymi hakami useMediaQuery i useBreakpoint).

Punkt przełamaniaNawigacjaUwagi
PulpitPełny pasek boczny, zwijany 60px ⇄ 240pxTreść główna przesunięta o effectiveMargin
TabletZwinięty pasek boczny z rozwijaniem przy najechaniuKompaktowa chrom, te same trasy
TelefonNakładka MobileMenu + MobileBottomNavPasek boczny ukryty; dolna nawigacja dla głównych celów
  DESKTOP                    TABLET                     MOBILE
  ┌────┬────────────┐        ┌──┬──────────────┐        ┌──────────────┐
  │side│  content   │        │░░│   content    │        │   TopBar     │
  │bar │            │        │ho│              │        ├──────────────┤
  │240 │            │        │ve│              │        │              │
  │px  │            │        │r │              │        │   content    │
  │    │            │        │60│              │        │              │
  │    │            │        │px│              │        ├──────────────┤
  └────┴────────────┘        └──┴──────────────┘        │ ▣ ▣ ▣ ▣  nav │
                                                        └──────────────┘

Prymitywy układu ResponsiveGrid, Stack i Show pozwalają komponentom funkcjonalnym przepływać bez dedykowanego CSS z zapytaniami medialnymi, utrzymując zachowanie responsywne spójne z systemem projektowym zamiast improwizowane na każdej stronie.


Podsumowanie

System projektowy DataFlow AI opiera się na jednej idei stosowanej konsekwentnie: komponenty opisują role, a nie piksele. Semantyczne tokeny Tailwind 4 niosą znaczenie powierzchni, tekstu, obramowania i akcentu; ciemny motyw amber/zinc jest domyślnym wyrazem tych tokenów, a jasny to ten sam zestaw przemapowany; pojedyncze przełączenie klasy dark zmienia motyw wszystkiego; powłoka adaptuje się do aktywnej persony; czterdziestoelementowy zestaw UI i garść prymitywów układu utrzymują każdy ekran spójnym; a dostępność oraz zachowanie responsywne są podłączone do powłoki, tak że każda strona dziedziczy je za darmo.

Poprzednia
Aplikacja frontendowa