Captures navigation structure, theming, mock data, state, and responsive (mobile + web) layout decisions agreed on during brainstorming before implementation planning starts.
11 KiB
Volana Expo App — UI-Umsetzung des Prototyps
Kontext
prototype/Volana.dc.html ist ein interaktiver HTML-Prototyp (DC-Format mit Template-Bindings à la {{ x }}, sc-if, sc-for) der Volana-Konsumenten-Oberfläche: ein dezentraler, zensurresistenter Marktplatz auf Solana (siehe docs/volana-design-brief.md für den vollständigen Produkt-Kontext). Der Prototyp enthält Homepage, Browse (Liste/Grid), Listing-Detail, My Orders, Order-Detail, Wallet-Connect-Modal, Checkout-Modal (Review/Pending/Success) und Toasts, inklusive vollständiger Mock-Daten (12 Produkte, 3 Dispute-Resolver, 3 Orders) und Farb-/Theming-Variablen für Light/Dark.
Die Expo-App (app/) ist aktuell ein leeres Grundgerüst: Expo Router mit (tabs)-Gruppe (Home/Explore), HeroUI Native, Uniwind (Tailwind v4 für React Native), React 19 / RN 0.86 / Expo SDK 57.
Ziel dieser Iteration: Das Design des Prototyps 1:1 in Seiten/Komponenten der Expo-App übertragen — mobil UND auf Web (react-native-web, in den Dependencies vorhanden) nahe am Prototyp. Keine echte Funktionalität (kein echtes Wallet, kein Backend) — Mock-Daten reichen. Styling bleibt so nah wie möglich an den HeroUI-Native-Defaults; nur Akzentfarbe, Statusfarben und Radius werden angepasst (Theming), komplexere Komponenten/Seiten bekommen zusätzlich Custom-Styles via className (Uniwind/Tailwind) bzw. StyleSheet wo nötig.
Nicht-Ziele
- Keine echte Solana-Wallet-Integration (
@solana/connectoro.ä.) — Connect/Disconnect ist gemockt wie im Prototyp. - Kein Backend/On-Chain-Datenfetching — statische Mock-Daten aus dem Prototyp übernommen.
- Keine Persistenz von Bestellungen (gekaufte Listings erscheinen nicht dynamisch in "My Orders" — der Prototyp macht das ebenfalls nicht).
- Kein manueller Light/Dark-Toggle — die App folgt dem System-Theme (Uniwind unterstützt das nativ).
- Kein Footer (im Prototyp vorhanden, in der App nicht nötig).
- Keine Pixel-genaue 1:1-Übernahme der Inline-Styles des Prototyps — HeroUI-Native-Komponenten und ihre Standard-Abstände/Formen bleiben so weit wie möglich erhalten.
Theming
Anpassung ausschließlich über CSS-Variablen-Overrides in src/global.css (@layer theme { @variant light {...} @variant dark {...} }), wie in der HeroUI-Native-Theming-Doku beschrieben. Kein Erstellen neuer Custom-Colors — bestehende semantische Slots werden mit den Prototyp-Werten belegt:
| Variable | Dark (Prototyp --c-*) |
Light (Prototyp --c-*) |
Verwendung |
|---|---|---|---|
--accent / --accent-foreground |
#b060ff / weiß |
#7a34d4 / weiß |
Primär-CTA, Preis-Hervorhebung, aktive Filter |
--success |
#14f195 |
#059669 |
"In Stock", "Verified", "Complete", "Final Payment" |
--warning |
#f5a623 |
#d97706 |
"Low Stock", "Awaiting Confirm" |
--danger |
#ff4d4f |
#dc2626 |
"Out of Stock", "Disputed", "Cancel Order" |
--background / --surface / --surface-secondary |
leicht lila-stichige Dunkeltöne (#0e0e1c/#171730/#1e1e3c) |
helle lila-stichige Töne (#f7f6fb/#ffffff/#f0eef8) |
Basis-/Karten-Hintergründe |
--radius |
Basiswert so gewählt, dass abgeleitete --radius-lg/--radius-xl in etwa den 8–14px-Radii des Prototyps entsprechen |
gleich | Cards, Buttons, Inputs |
Die im Prototyp verwendete "Solana-Mainnet"-Grün-Punkt/"Verified"-Optik nutzt direkt success, keine eigene Farbe nötig.
Datenmodell & Mock-Daten
Neue Datei src/data/mock.ts mit TS-Typen und den Werten 1:1 aus dem Prototyp (_L, _R, _O Arrays in Volana.dc.html):
type Currency = 'SOL' | 'USDC';
interface Product {
id: number; name: string; desc: string;
price: string; priceNum: number; cur: Currency; usd: string;
qty: number; seller: string; bg: string; emoji: string;
alt: Currency[]; cat: string;
}
interface Resolver {
id: number; name: string; desc: string;
fee: string; type: 'Human' | 'DAO' | 'Automated';
wins: number; total: number;
}
type OrderStatus = 'AwaitingConfirm' | 'Active' | 'Complete' | 'Cancelled' | 'Disputed';
interface Order {
id: number; lid: number; name: string; amt: string;
status: OrderStatus; date: string; seller: string; emoji: string;
}
Emojis dienen weiterhin als Platzhalter-"Produktbild" (wie im Prototyp) statt echter Bilder — kein Asset-Aufwand nötig. Helper-Funktionen analog zu _si (Status → Label/Farbe) und _av (Verfügbarkeit → Label/Farbe) werden als reine Funktionen in src/data/mock.ts oder src/lib/status.ts nachgebaut.
State
WalletProvider(src/state/wallet.tsx, React Context):connected: boolean,address: string | null,connect(wallet: 'phantom' | 'solflare' | 'backpack')(setzt eine fixe Mock-Adresse je Wallet, identisch zum Prototyp),disconnect().ModalProvider(src/state/modals.tsx, React Context): zentraler Zustand für die beiden globalen Overlays:- Wallet-Connect-Sheet:
open,pendingListingId(falls "Buy Now" ohne verbundenes Wallet ausgelöst wurde → nach Connect automatisch Checkout öffnen, wie im Prototyp) - Checkout-Sheet:
open,listingId,step: 'review' | 'pending' | 'success', inkl. simuliertemsetTimeout-Übergangpending → successwie im Prototyp (2.2s)
- Wallet-Connect-Sheet:
- Bestellungen bleiben statische Mock-Daten (siehe Nicht-Ziele) — kein zusätzlicher Order-State nötig.
- Toasts über HeroUI Natives eingebauten
useToast/ToastProvider(Teil vonHeroUINativeProvider), verwendet für: Wallet verbunden/getrennt, Adresse kopiert, Order storniert/bestätigt.
Beide Provider werden in app/_layout.tsx um den bestehenden HeroUINativeProvider ergänzt.
Navigation & Screens
app/_layout.tsx Root Stack + WalletProvider + ModalProvider; rendert zusätzlich
<TopNav /> (nur ab `md:`, s.u.) + globale Sheets (WalletConnectSheet, CheckoutSheet)
app/(tabs)/_layout.tsx Bottom Tabs: Home | Browse | Orders (Tab-Bar ab `md:` ausgeblendet)
app/(tabs)/index.tsx Home
app/(tabs)/browse.tsx Browse (ersetzt bisheriges explore.tsx)
app/(tabs)/orders.tsx My Orders (Liste)
app/listing/[id].tsx Listing-Detail — Stack-Push über den Tabs, eigener Header mit Zurück-Button
app/orders/[id].tsx Order-Detail — Stack-Push über den Tabs, eigener Header mit Zurück-Button
Wallet-Connect- und Checkout-Overlay sind bewusst keine Routen, sondern globale, über ModalProvider gesteuerte BottomSheet-Komponenten im Root-Layout — "Buy Now" ist von Home, Browse und Listing-Detail auslösbar und muss überall denselben zentralen State treffen (entspricht dem zentralen Component-State im Prototyp).
Responsive Shell (Mobile vs. Web/Desktop)
Umschaltung über Uniwind-Responsive-Utilities (Breakpoint md:, ~768px) — funktioniert sowohl nativ (z. B. Tablet-Breite) als auch im Web-Build:
TopNav(src/components/TopNav.tsx): Logo, Suchfeld, "Browse"-/"My Orders"-Links, Wallet-Button/-Pill — analog zur Prototyp-Nav. Klassehidden md:flex, liegt im Root-Layout über allen Screens (auch Listing-/Order-Detail), damit Web-Nutzer durchgehend navigieren können.- Bottom-Tab-Bar: in
(tabs)/_layout.tsxperuseWindowDimensions(React-Navigation-tabBarStyleist keine Tailwind-Klasse, daher JS-Bedingung statt CSS) abmd:-Breite aufdisplay: 'none'gesetzt. - Ergebnis: Mobile = Bottom-Tabs + Stack-Pushes für Details. Web/Desktop = Top-Nav wie Prototyp, keine Tab-Bar, Navigation über
router.push.
Grid-Layouts: React Native kennt kein CSS-Grid (auch nicht im Web-Build, da react-native-web View-Primitives nutzt) — alle "Grid"-Bereiche (Browse-Grid, Featured Listings, Customers-also-bought) werden über flex-row flex-wrap + Breiten-Utilities (w-1/2 md:w-1/3 lg:w-1/4 o. ä.) gebaut, nicht über display: grid.
Listing-Detail: flex-col md:flex-row (mobil gestapelt, ab md: zweispaltig wie im Prototyp). Die rechte Kauf-Box nutzt auf Web position: 'sticky' (von react-native-web unterstützt); nativ scrollt sie regulär mit.
Screens im Detail
Home (app/(tabs)/index.tsx)
Kurzer Hero (Headline + Subline + "Browse Listings"-Button, kein Stats-/"Warum Volana"-/"How it works"-Block), darunter Featured-Listings (4 Karten, ListingCard Grid-Variante).
Browse (app/(tabs)/browse.tsx)
SearchField (Name/Beschreibung), Filter-Reihe (Chip-Toggles für Currency All/SOL/USDC und Sort Newest/Price↑/Price↓), Switch "In stock only", List/Grid-View-Toggle (Icon-Buttons). Darunter Produktliste aus den gefilterten/sortierten Mock-Daten:
- List-View: horizontale Card (Bild-Platzhalter · Preis · Name+Beschreibung · Buy-Button), analog Prototyp-Zeilen-Layout.
- Grid-View: 2-spaltige (mobil) / mehr-spaltige (
md:/lg:) vertikale Cards.
Listing-Detail (app/listing/[id].tsx)
Bild-Platzhalter (Emoji auf Farbfläche), Titel, Beschreibung, "Verified on Solana"-Zeile mit Copy-Button (Toast "Address copied!"), Info-Grid (Kategorie/Verfügbar/Währung/ID), "Customers also bought" (horizontale/Flex-Wrap-Liste verwandter Produkte). Kauf-Sektion (sticky ab md:): Preis, Currency-Umschalter (falls alt.length > 0), Resolver-Auswahl (3 selektierbare Cards aus Mock-Resolvern), "Buy Now"-Button (öffnet Wallet-Sheet falls nicht verbunden, sonst Checkout-Sheet), Trust-Badges (Final Payment / Dispute Protection / On-chain Verified).
Orders (app/(tabs)/orders.tsx)
Liste von OrderRow (Emoji, Name, Seller-Kürzel, Betrag, Datum, Status-Chip), Tap → app/orders/[id].tsx.
Order-Detail (app/orders/[id].tsx)
Header (Datum, Name, Seller, Betrag, Status), 3-Schritt-Fortschrittsanzeige (Payment Held → Seller Confirms → You Confirm Receipt) mit Status-abhängiger Einfärbung wie im Prototyp (_si-Logik), Escrow-Info-Box, Aktions-Buttons je Status: AwaitingConfirm → Cancel Order (mock, zeigt Toast + navigiert zurück), Active → Confirm Receipt (mock, zeigt Toast), immer sichtbar → "View Listing".
Gemeinsame Komponenten (src/components/)
TopNav— s. o.AppHeader— einfacher mobiler Screen-Header für Stack-Screens (Titel + Zurück-Button), aufmd:ggf. ausgeblendet daTopNavübernimmtListingCard— VariantenlistundgridStatusChip— mapptOrderStatus/Verfügbarkeit auf Label + Farbe (nutztChipvon HeroUI)ResolverCard— selektierbare Resolver-Option (Listing-Detail + Checkout-Review)OrderRow— Zeile in der Orders-ListeWalletConnectSheet— globalesBottomSheetmit den drei Mock-Wallets (Phantom/Solflare/Backpack)CheckoutSheet— globalesBottomSheet, rendert intern je nachstepReview-/Pending-(Spinner)-/Success-Inhalt
Verifikation
Da keine echte Funktionalität besteht, erfolgt Verifikation visuell: App per expo start (Web + iOS/Android-Simulator soweit verfügbar) starten, jede Seite und beide Breakpoints (schmal/mobil, breit/md:+) durchklicken, Kernflows prüfen (Home → Browse → Listing → Buy Now ohne Wallet → Connect → Checkout Review → Pending → Success → My Orders; Order-Detail Cancel/Confirm-Aktionen; Such-/Filter-/Sortier-/List-Grid-Umschaltung in Browse).