Files
beenvoice-app/components/Logo.tsx
T
soconnor 6d2711e36e Polish mobile app for App Store review and expand CRUD.
Default to beenvoice.soconnor.dev with server settings hidden behind Advanced; add Entities tab with clients/businesses, invoice creation, UI fixes for dashboard layout, date fields, FAB position, and card-matched button radius.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-17 23:14:58 -04:00

111 lines
2.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Image } from "expo-image";
import { StyleSheet, Text, View, type ViewStyle } from "react-native";
import { useAppTheme } from "@/contexts/ThemeContext";
import { fonts } from "@/constants/theme";
const markSource = require("@/assets/images/icon.png");
type LogoSize = "xs" | "sm" | "md" | "lg";
const widths: Record<LogoSize, number> = {
xs: 104,
sm: 140,
md: 180,
lg: 220,
};
type LogoProps = {
size?: LogoSize;
style?: ViewStyle;
/** Force the light wordmark for dark backgrounds (e.g. status bar chrome). */
onDark?: boolean;
};
/** Full beenvoice wordmark from web `public/beenvoice-logo.png` */
export function Logo({ size = "md", style, onDark }: LogoProps) {
const { isDark } = useAppTheme();
const width = widths[size];
const height = width * (436 / 2970);
const useDarkAsset = onDark ?? isDark;
return (
<View style={[styles.row, styles.noShrink, style]}>
<Image
source={
useDarkAsset
? require("@/assets/images/beenvoice-logo-dark.png")
: require("@/assets/images/beenvoice-logo.png")
}
style={{ width, height }}
contentFit="contain"
/>
</View>
);
}
/** Square dollar mark from Icon Composer export (1024×1024 PNG). */
export function LogoMark({
size = 32,
style,
}: {
size?: number;
style?: ViewStyle;
}) {
const fromStyle =
typeof style?.width === "number"
? style.width
: typeof style?.height === "number"
? style.height
: undefined;
const dimension = fromStyle ?? size;
return (
<View
style={[
styles.markBox,
{ width: dimension, height: dimension, aspectRatio: 1 },
style,
]}
>
<Image
source={markSource}
style={{ width: dimension, height: dimension }}
contentFit="contain"
/>
</View>
);
}
export function HeadingText({
children,
style,
}: {
children: React.ReactNode;
style?: object;
}) {
const { colors } = useAppTheme();
return (
<Text style={[styles.heading, { color: colors.foreground }, style]}>{children}</Text>
);
}
const styles = StyleSheet.create({
row: {
flexDirection: "row",
alignItems: "center",
},
noShrink: {
flexShrink: 0,
},
markBox: {
flexShrink: 0,
alignItems: "center",
justifyContent: "center",
},
heading: {
fontFamily: fonts.heading,
},
});