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:
Alejandro Gutiérrez
2026-04-04 21:19:32 +01:00
commit d3163a5bff
1384 changed files with 314925 additions and 0 deletions

View File

@@ -0,0 +1,122 @@
import { oklch, formatHex } from "culori";
import { memo } from "react";
import { FlatList, View } from "react-native";
import { useTranslation } from "@turbostarter/i18n";
import { cn, ThemeColor, ThemeMode, themes } from "@turbostarter/ui";
import { Button } from "./button";
import { Icons } from "./icons";
import { Label } from "./label";
import { Text } from "./text";
import type { ThemeConfig } from "@turbostarter/ui";
interface ThemeCustomizerProps {
readonly config: ThemeConfig;
readonly onChange: (config: ThemeConfig) => void;
readonly resolvedTheme: Exclude<ThemeMode, "system">;
}
export const MODE_ICONS = {
[ThemeMode.LIGHT]: Icons.Sun,
[ThemeMode.DARK]: Icons.Moon,
[ThemeMode.SYSTEM]: Icons.SunMoon,
} as const;
export const ThemeCustomizer = memo<ThemeCustomizerProps>(
({ config, onChange, resolvedTheme }) => {
const { t } = useTranslation("common");
return (
<View className="mt-2 flex-1 items-center gap-4">
<View className="w-full gap-1.5">
<Label nativeID="color" className="text-xs">
{t("theme.color.label")}
</Label>
<FlatList
bounces={false}
showsVerticalScrollIndicator={false}
numColumns={3}
data={Object.values(ThemeColor)}
columnWrapperClassName="gap-2"
contentContainerClassName="gap-2"
renderItem={({ item }) => {
const [l, c, h, alpha] = themes[item][resolvedTheme].primary;
return (
<Button
variant="outline"
key={item}
onPress={() => onChange({ ...config, color: item })}
hitSlop={2}
className={cn(
"grow basis-24 flex-row justify-start gap-2.5 px-3",
config.color === item &&
"border-primary dark:border-primary border-2",
)}
>
<View
className="flex size-4.5 shrink-0 items-center justify-center rounded-full"
style={{
backgroundColor: formatHex(
oklch({
mode: "oklch",
l,
c,
h,
alpha,
}),
),
}}
/>
<Text className="capitalize">{t(`theme.color.${item}`)}</Text>
</Button>
);
}}
/>
</View>
<View className="w-full gap-1.5">
<Label nativeID="mode" className="text-xs">
{t("theme.mode.label")}
</Label>
<FlatList
bounces={false}
showsVerticalScrollIndicator={false}
numColumns={3}
data={Object.values(ThemeMode)}
columnWrapperClassName="gap-2"
contentContainerClassName="gap-2"
renderItem={({ item }) => {
const isActive = config.mode === item;
const Icon = MODE_ICONS[item];
return (
<Button
variant="outline"
key={item}
onPress={() => onChange({ ...config, mode: item })}
hitSlop={2}
className={cn(
"grow basis-24 flex-row justify-start gap-2 px-3 capitalize",
isActive && "border-primary dark:border-primary border-2",
)}
>
<Icon
className="text-foreground shrink-0"
width={18}
height={18}
/>
<Text className="text-sm capitalize">
{t(`theme.mode.${item}`)}
</Text>
</Button>
);
}}
/>
</View>
</View>
);
},
);
ThemeCustomizer.displayName = "ThemeCustomizer";