feat(db): mesh data model — meshes, members, invites, audit log
- pgSchema "mesh" with 4 tables isolating the peer mesh domain - Enums: visibility, transport, tier, role - audit_log is metadata-only (E2E encryption enforced at broker/client) - Cascade on mesh delete, soft-delete via archivedAt/revokedAt Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
94
packages/ui/mobile/src/components/progress.tsx
Normal file
94
packages/ui/mobile/src/components/progress.tsx
Normal file
@@ -0,0 +1,94 @@
|
||||
import * as ProgressPrimitive from "@rn-primitives/progress";
|
||||
import { Platform, View } from "react-native";
|
||||
import Animated, {
|
||||
Extrapolation,
|
||||
interpolate,
|
||||
useAnimatedStyle,
|
||||
useDerivedValue,
|
||||
withSpring,
|
||||
} from "react-native-reanimated";
|
||||
|
||||
import { cn } from "@turbostarter/ui";
|
||||
|
||||
function Progress({
|
||||
className,
|
||||
value,
|
||||
indicatorClassName,
|
||||
...props
|
||||
}: ProgressPrimitive.RootProps &
|
||||
React.RefAttributes<ProgressPrimitive.RootRef> & {
|
||||
indicatorClassName?: string;
|
||||
}) {
|
||||
return (
|
||||
<ProgressPrimitive.Root
|
||||
className={cn(
|
||||
"bg-primary/20 relative h-2 w-full overflow-hidden rounded-full",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<Indicator value={value} className={indicatorClassName} />
|
||||
</ProgressPrimitive.Root>
|
||||
);
|
||||
}
|
||||
|
||||
export { Progress };
|
||||
|
||||
const Indicator = Platform.select({
|
||||
web: WebIndicator,
|
||||
native: NativeIndicator,
|
||||
default: NullIndicator,
|
||||
});
|
||||
|
||||
interface IndicatorProps {
|
||||
value: number | undefined | null;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
function WebIndicator({ value, className }: IndicatorProps) {
|
||||
if (Platform.OS !== "web") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<View
|
||||
className={cn(
|
||||
"bg-primary h-full w-full flex-1 transition-all",
|
||||
className,
|
||||
)}
|
||||
style={{ transform: `translateX(-${100 - (value ?? 0)}%)` }}
|
||||
>
|
||||
<ProgressPrimitive.Indicator className={cn("h-full w-full", className)} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
function NativeIndicator({ value, className }: IndicatorProps) {
|
||||
const progress = useDerivedValue(() => value ?? 0);
|
||||
|
||||
const indicator = useAnimatedStyle(() => {
|
||||
return {
|
||||
width: withSpring(
|
||||
`${interpolate(progress.value, [0, 100], [1, 100], Extrapolation.CLAMP)}%`,
|
||||
{ overshootClamping: true },
|
||||
),
|
||||
};
|
||||
}, [value]);
|
||||
|
||||
if (Platform.OS === "web") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ProgressPrimitive.Indicator asChild>
|
||||
<Animated.View
|
||||
style={indicator}
|
||||
className={cn("bg-primary h-full", className)}
|
||||
/>
|
||||
</ProgressPrimitive.Indicator>
|
||||
);
|
||||
}
|
||||
|
||||
function NullIndicator(_props: IndicatorProps) {
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user