Files
beenvoice-app/components/GlassSurface.tsx
T
soconnor 14c880123c Add beenvoice mobile companion app with full dark mode support.
Expo app with dashboard, time clock, invoices, and settings — native tabs, glass UI, theme-aware components, and iOS Live Activities.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-17 22:36:37 -04:00

113 lines
2.7 KiB
TypeScript

import { BlurView } from "expo-blur";
import type { ReactNode } from "react";
import { Platform, StyleSheet, View, type StyleProp, type ViewStyle } from "react-native";
import { useAppTheme } from "@/contexts/ThemeContext";
import { blurIntensity, radius, shadowMd, shadowSm } from "@/lib/beenvoice-theme";
type GlassSurfaceProps = {
children: ReactNode;
style?: StyleProp<ViewStyle>;
radius?: number;
variant?: "card" | "stat";
};
export function GlassSurface({
children,
style,
radius: cornerRadius = radius.lg,
variant = "card",
}: GlassSurfaceProps) {
const { colors, isDark } = useAppTheme();
const flat = StyleSheet.flatten(style);
const isStat = variant === "stat";
return (
<View
style={[
styles.shell,
isStat ? styles.statShell : null,
{ borderRadius: cornerRadius, borderColor: colors.borderGlass },
isStat ? shadowMd : shadowSm,
flat,
Platform.OS === "android" ? { backgroundColor: colors.cardGlass } : null,
]}
>
{Platform.OS === "ios" ? (
<BlurView
intensity={blurIntensity.card}
tint={isDark ? "dark" : "light"}
style={[StyleSheet.absoluteFill, { borderRadius: cornerRadius }]}
/>
) : null}
<View
pointerEvents="none"
style={[
styles.fill,
{ backgroundColor: colors.cardGlass, borderRadius: cornerRadius },
]}
/>
<View style={styles.content}>{children}</View>
</View>
);
}
export function GlassChrome({
children,
style,
radius: cornerRadius = 0,
}: {
children?: ReactNode;
style?: StyleProp<ViewStyle>;
radius?: number;
}) {
const { colors, isDark } = useAppTheme();
return (
<View
style={[
styles.chromeShell,
{ borderRadius: cornerRadius, backgroundColor: colors.cardGlass },
StyleSheet.flatten(style),
]}
>
{Platform.OS === "ios" ? (
<BlurView
intensity={blurIntensity.chrome}
tint={isDark ? "dark" : "light"}
style={[StyleSheet.absoluteFill, { borderRadius: cornerRadius }]}
/>
) : null}
<View
pointerEvents="none"
style={[
styles.fill,
{ backgroundColor: colors.cardGlass, borderRadius: cornerRadius },
]}
/>
{children ? <View style={styles.content}>{children}</View> : null}
</View>
);
}
const styles = StyleSheet.create({
shell: {
overflow: "hidden",
borderWidth: StyleSheet.hairlineWidth * 2,
backgroundColor: "transparent",
},
statShell: {
borderWidth: 0,
},
chromeShell: {
overflow: "hidden",
},
fill: {
...StyleSheet.absoluteFill,
},
content: {
position: "relative",
zIndex: 2,
},
});