Uworkout Ucomplete screen
import * as React from "react";
import { View } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import { Button, Icon, Text } from "@lumioui/ui";
import { useHaptic } from "@lumioui/core";
import { Drift, Float, GlowSpot, Mount, Press, PulseRing, StickyBottomBar } from "../shared";
const STATS: { icon: import("@lumioui/ui").IconName; tint: string; label: string; value: string }[] = [
{ icon: "clock", tint: "#0EA5E9", label: "Duration", value: "45:32" },
{ icon: "dumbbell", tint: "#7C3AED", label: "Volume (lbs)", value: "14.2k" },
{ icon: "footprints", tint: "#14B8A6", label: "Exercises", value: "8" },
{ icon: "flame", tint: "#F97316", label: "Total sets", value: "16" },
];
/** Workout complete — the dark celebration: glowing hex badge hero, a 2×2
* stat grid with colored icon discs, a "New record" card carrying the
* sticker, and the split View Log / Share Summary footer. */
export function WorkoutCompleteScreen({ onBack, onDone }: { onBack?: () => void; onDone?: () => void }) {
const haptics = useHaptic();
return (
<View className="flex-1 bg-[#0B0B0F]">
<GlowSpot color="#F97316" size={520} className="-top-40 self-center opacity-30" />
<Drift emoji="✨" cls="left-10 top-44" size="text-[22px]" index={0} />
<Drift emoji="⭐" cls="right-12 top-56" size="text-[18px]" index={2} />
<SafeAreaView className="flex-1" edges={["top", "bottom"]}>
<View className="px-4 pt-1">
<Press
onPress={onBack}
hitSlop={12}
accessibilityRole="button"
accessibilityLabel="Back"
className="h-10 w-10 items-center justify-center rounded-full bg-white/10"
>
<Icon name="chevron-left" size="sm" color="#FFFFFF" />
</Press>
</View>
<View className="flex-1 items-center px-6 pt-6">
{/* hex badge — pops in, then keeps breathing */}
<Mount className="items-center">
<View className="h-28 w-28 items-center justify-center">
<PulseRing color="#F97316" size={112} />
<Float distance={3} className="absolute inset-0">
<View
className="absolute inset-0 bg-[#F97316]"
style={{
transform: [{ rotate: "30deg" }],
borderRadius: 24,
}}
/>
<View
className="absolute inset-0 bg-[#EA580C]"
style={{
transform: [{ rotate: "60deg" }],
borderRadius: 24,
}}
/>
<View
className="absolute inset-0 items-center justify-center bg-[#F97316]"
style={{ borderRadius: 24 }}
>
<Icon name="trophy" size="xl" color="#FFFFFF" />
</View>
</Float>
</View>
<Text className="mt-6 text-[28px] font-bold tracking-tight text-white">
Workout Complete
</Text>
<Text className="mt-1 text-[14px] text-white/50">Push Day · Aug 7, 2025</Text>
</Mount>
{/* stat grid */}
<Mount delay={90} className="mt-8 w-full flex-row flex-wrap gap-3">
{STATS.map((s) => (
<View
key={s.label}
className="w-[47%] grow rounded-3xl bg-white/[0.07] p-4"
>
<View className="mb-3 flex-row items-center justify-between">
<Text className="text-[12px] text-white/50">{s.label}</Text>
<View
className="h-9 w-9 items-center justify-center rounded-full"
style={{ backgroundColor: `${s.tint}26` }}
>
<Icon name={s.icon} size="md" color={s.tint} />
</View>
</View>
<Text className="text-[24px] font-bold text-white">{s.value}</Text>
</View>
))}
</Mount>
{/* new record */}
<Mount delay={160} className="mt-4 w-full">
<View className="flex-row items-center rounded-3xl bg-white/[0.07] p-4">
<View className="flex-1">
<View className="flex-row items-center gap-1.5">
<Icon name="medal" size="sm" color="#F97316" />
<Text className="text-[14px] font-semibold text-white">New record</Text>
</View>
<Text className="mt-1.5 text-[13px] text-white/50">
Bench press{"\n"}185 lbs x 5
</Text>
</View>
<View
className="rounded-2xl bg-[#F97316] px-3.5 py-2.5"
style={{ transform: [{ rotate: "-8deg" }] }}
>
<View className="items-center">
<Icon name="trophy" size="md" color="#FFFFFF" />
<Text className="mt-0.5 text-center text-[13px] font-black leading-tight text-white">NEW{"\n"}RECORD</Text>
</View>
</View>
</View>
</Mount>
</View>
<StickyBottomBar className="px-5">
<View className="flex-row gap-3">
<Button
size="lg"
className="flex-1 bg-white/10"
textClassName="text-white"
onPress={() => {
haptics.light();
onBack?.();
}}
accessibilityLabel="View Log"
>
View Log
</Button>
<Button
size="lg"
className="flex-1 bg-white"
textClassName="text-[#0B0B0F]"
onPress={() => {
haptics.light();
onDone?.();
}}
accessibilityLabel="Share Summary"
>
Share Summary
</Button>
</View>
</StickyBottomBar>
</SafeAreaView>
</View>
);
}
WorkoutCompleteScreen.displayName = "WorkoutCompleteScreen";
Recreate the "Uworkout Ucomplete Screen" screen in React Native using LumioUI.
Goal: Uworkout Ucomplete screen Match the reference implementation's layout, behavior, and motion exactly — this is a production screen, not a mockup.
## Setup
Fastest path — install the screen plus its component deps:
```bash
npx lumioui add health-workout-complete
```
Or pull just the components: `npx lumioui add button text icon avatar`
Native packages:
- @lumioui/ui@latest
- @lumioui/core@latest
- react-native-safe-area-context@*
- react-native-reanimated@*
- react-native-svg@*
- nativewind@*
Stack assumptions: Expo SDK 54 / RN 0.81, Reanimated 4, NativeWind v4, TypeScript strict, Expo Go compatible.
## Components — how, where, when
### `button` — Tactile pill button with press spring, ink wash and async loading.
- `<Button>` ×2
### `text` — Themed type scale from caption to display.
- `<Text>` ×7
### `icon` — Lucide icon set mapped to theme colors and sizes.
- `<Icon>` ×5
### `avatar` — Circular user image with fallback initials and status dot.
- imported but not rendered directly — likely used through a sibling or as a utility
## Conventions (non-negotiable)
- Styling via NativeWind `className` with semantic tokens only: `bg-background`, `text-foreground`, `bg-card`, `text-card-foreground`, `bg-secondary`, `bg-muted`, `text-muted-foreground`, `bg-accent`, `bg-destructive`, `border-border`. Hard-coded colors only inside media overlays (`text-white`, `bg-black/N`).
- Motion via the token presets from `@lumioui/core` (`spring.press`, `spring.surface`, `spring.glide`, `timing.fast`, `timing.slow`, …) — no bespoke spring configs or durations.
- Gate transform motion behind `useReducedMotion()`; keep opacity/color feedback, drop travel and overshoot.
- Haptics via `useHaptic()`: `light` on press, `selection` on toggle/select, `warning` on invalid input. Never import expo-haptics directly.
- Press feedback via `usePressAnimation()` (~0.97 scale), not `activeOpacity` tricks.
- a11y: `accessibilityRole` + `accessibilityLabel` on every control, touch targets ≥44pt.
- Entrance choreography: staggered `Mount` wrappers (delay 0/60/120…) so regions land in sequence instead of popping in at once.
- Wrap the screen in `SafeAreaView`; keep dark mode working via the semantic tokens.
## Deliverable
One file: `screens/health/workout-complete.tsx` exporting WorkoutCompleteScreen. Preserve the props interface — the host app wires the callbacks (navigation, submit handlers) through them.
## Reference implementation
The LumioUI source for this screen — reproduce it faithfully:
```tsx
import * as React from "react";
import { View } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import { Button, Icon, Text } from "@lumioui/ui";
import { useHaptic } from "@lumioui/core";
import { Drift, Float, GlowSpot, Mount, Press, PulseRing, StickyBottomBar } from "../shared";
const STATS: { icon: import("@lumioui/ui").IconName; tint: string; label: string; value: string }[] = [
{ icon: "clock", tint: "#0EA5E9", label: "Duration", value: "45:32" },
{ icon: "dumbbell", tint: "#7C3AED", label: "Volume (lbs)", value: "14.2k" },
{ icon: "footprints", tint: "#14B8A6", label: "Exercises", value: "8" },
{ icon: "flame", tint: "#F97316", label: "Total sets", value: "16" },
];
/** Workout complete — the dark celebration: glowing hex badge hero, a 2×2
* stat grid with colored icon discs, a "New record" card carrying the
* sticker, and the split View Log / Share Summary footer. */
export function WorkoutCompleteScreen({ onBack, onDone }: { onBack?: () => void; onDone?: () => void }) {
const haptics = useHaptic();
return (
<View className="flex-1 bg-[#0B0B0F]">
<GlowSpot color="#F97316" size={520} className="-top-40 self-center opacity-30" />
<Drift emoji="✨" cls="left-10 top-44" size="text-[22px]" index={0} />
<Drift emoji="⭐" cls="right-12 top-56" size="text-[18px]" index={2} />
<SafeAreaView className="flex-1" edges={["top", "bottom"]}>
<View className="px-4 pt-1">
<Press
onPress={onBack}
hitSlop={12}
accessibilityRole="button"
accessibilityLabel="Back"
className="h-10 w-10 items-center justify-center rounded-full bg-white/10"
>
<Icon name="chevron-left" size="sm" color="#FFFFFF" />
</Press>
</View>
<View className="flex-1 items-center px-6 pt-6">
{/* hex badge — pops in, then keeps breathing */}
<Mount className="items-center">
<View className="h-28 w-28 items-center justify-center">
<PulseRing color="#F97316" size={112} />
<Float distance={3} className="absolute inset-0">
<View
className="absolute inset-0 bg-[#F97316]"
style={{
transform: [{ rotate: "30deg" }],
borderRadius: 24,
}}
/>
<View
className="absolute inset-0 bg-[#EA580C]"
style={{
transform: [{ rotate: "60deg" }],
borderRadius: 24,
}}
/>
<View
className="absolute inset-0 items-center justify-center bg-[#F97316]"
style={{ borderRadius: 24 }}
>
<Icon name="trophy" size="xl" color="#FFFFFF" />
</View>
</Float>
</View>
<Text className="mt-6 text-[28px] font-bold tracking-tight text-white">
Workout Complete
</Text>
<Text className="mt-1 text-[14px] text-white/50">Push Day · Aug 7, 2025</Text>
</Mount>
{/* stat grid */}
<Mount delay={90} className="mt-8 w-full flex-row flex-wrap gap-3">
{STATS.map((s) => (
<View
key={s.label}
className="w-[47%] grow rounded-3xl bg-white/[0.07] p-4"
>
<View className="mb-3 flex-row items-center justify-between">
<Text className="text-[12px] text-white/50">{s.label}</Text>
<View
className="h-9 w-9 items-center justify-center rounded-full"
style={{ backgroundColor: `${s.tint}26` }}
>
<Icon name={s.icon} size="md" color={s.tint} />
</View>
</View>
<Text className="text-[24px] font-bold text-white">{s.value}</Text>
</View>
))}
</Mount>
{/* new record */}
<Mount delay={160} className="mt-4 w-full">
<View className="flex-row items-center rounded-3xl bg-white/[0.07] p-4">
<View className="flex-1">
<View className="flex-row items-center gap-1.5">
<Icon name="medal" size="sm" color="#F97316" />
<Text className="text-[14px] font-semibold text-white">New record</Text>
</View>
<Text className="mt-1.5 text-[13px] text-white/50">
Bench press{"\n"}185 lbs x 5
</Text>
</View>
<View
className="rounded-2xl bg-[#F97316] px-3.5 py-2.5"
style={{ transform: [{ rotate: "-8deg" }] }}
>
<View className="items-center">
<Icon name="trophy" size="md" color="#FFFFFF" />
<Text className="mt-0.5 text-center text-[13px] font-black leading-tight text-white">NEW{"\n"}RECORD</Text>
</View>
</View>
</View>
</Mount>
</View>
<StickyBottomBar className="px-5">
<View className="flex-row gap-3">
<Button
size="lg"
className="flex-1 bg-white/10"
textClassName="text-white"
onPress={() => {
haptics.light();
onBack?.();
}}
accessibilityLabel="View Log"
>
View Log
</Button>
<Button
size="lg"
className="flex-1 bg-white"
textClassName="text-[#0B0B0F]"
onPress={() => {
haptics.light();
onDone?.();
}}
accessibilityLabel="Share Summary"
>
Share Summary
</Button>
</View>
</StickyBottomBar>
</SafeAreaView>
</View>
);
}
WorkoutCompleteScreen.displayName = "WorkoutCompleteScreen";
```
Screen: https://lumioui.dev/screens/health-workout-complete