diff --git a/js/app/babel.config.js b/js/app/babel.config.js index 204e5bed..c1d7dffa 100644 --- a/js/app/babel.config.js +++ b/js/app/babel.config.js @@ -3,16 +3,6 @@ module.exports = (api) => { return { presets: [["babel-preset-expo", { jsxRuntime: "automatic" }]], plugins: [ - [ - "@tamagui/babel-plugin", - { - components: ["tamagui"], - config: "./tamagui.config.ts", - logTimings: true, - disableExtraction: process.env.NODE_ENV === "development", - }, - ], - // NOTE: this is only necessary if you are using reanimated for animations "react-native-reanimated/plugin", ], diff --git a/js/app/components/button-selector.tsx b/js/app/components/button-selector.tsx index f77f3ea1..c84197d4 100644 --- a/js/app/components/button-selector.tsx +++ b/js/app/components/button-selector.tsx @@ -1,52 +1,73 @@ -import { Button, Text, XStack, YStack, YStackProps } from "tamagui"; +import { Text, zero } from "@streamplace/components"; +import { Pressable, View, ViewStyle } from "react-native"; + +interface ButtonSelectorProps { + text?: string; + values: { label: string; value: string }[]; + selectedValue: string; + setSelectedValue: (value: any) => void; + style?: ViewStyle; +} export default function ButtonSelector({ text, values, selectedValue, setSelectedValue, + style, ...props -}: { - text?: string; - values: { label: string; value: string }[]; - selectedValue: string; - setSelectedValue: (value: any) => void; -} & YStackProps) { +}: ButtonSelectorProps) { return ( - + {text && ( - - {text} - + {text} )} - {values.map(({ label, value }) => ( - + ))} - - + + ); } diff --git a/js/app/components/container.tsx b/js/app/components/container.tsx index 5a988876..ea44c6a4 100644 --- a/js/app/components/container.tsx +++ b/js/app/components/container.tsx @@ -1,4 +1,5 @@ -import { View } from "tamagui"; +import { zero } from "@streamplace/components"; +import { View, ViewStyle, useWindowDimensions } from "react-native"; const maxContainerWidths = { xxs: 440, @@ -11,31 +12,44 @@ const maxContainerWidths = { threeXl: 1660, }; -export default function Container({ children, ...props }) { +interface ContainerProps { + children: React.ReactNode; + style?: ViewStyle; +} + +function getMaxWidth(width: number): number { + if (width >= 1660) return maxContainerWidths.threeXl; + if (width >= 1260) return maxContainerWidths.twoXl; + if (width >= 800) return maxContainerWidths.xl; + if (width >= 740) return maxContainerWidths.lg; + if (width >= 660) return maxContainerWidths.md; + return maxContainerWidths.sm; +} + +export default function Container({ + children, + style, + ...props +}: ContainerProps) { + const { width } = useWindowDimensions(); + const maxWidth = getMaxWidth(width); + return ( - + {children} diff --git a/js/app/components/countdown.tsx b/js/app/components/countdown.tsx index be44a6ad..7248b8ac 100644 --- a/js/app/components/countdown.tsx +++ b/js/app/components/countdown.tsx @@ -1,117 +1,48 @@ +import { Text, zero } from "@streamplace/components"; import * as chrono from "chrono-node"; import { useEffect, useState } from "react"; -import { - Text, - View, - YStack, - styled, - useMedia, - useWindowDimensions, -} from "tamagui"; - -const CountdownBox = styled(View, { - alignSelf: "center", - flexDirection: "row", - variants: { - small: { - true: { - alignSelf: "auto", - }, - }, - }, -} as const); -const Line = styled(View, { - // alignItems: "center", - // flexWrap: "wrap", - justifyContent: "flex-end", - flexDirection: "row", - variants: { - small: { - true: { - // flex: 0, - // flexDirection: "column", - }, - }, - }, -} as const); -const Unit = styled(YStack, { - marginLeft: "$4", - marginRight: "$4", - flex: 0, - variants: { - small: { - true: { - marginLeft: "$2", - marginRight: "$2", - }, - }, - }, -} as const); -const BorderBox = styled(View, { - borderColor: "white", - borderWidth: 0, - borderBlockStyle: "solid", - borderTopWidth: 4, - // backgroundColor: "green", - variants: { - small: { - true: { - fontSize: "$5", - lineHeight: "$5", - borderTopWidth: 2, - }, - }, - }, -} as const); -const TimeText = styled(Text, { - fontFamily: "$mono", - fontSize: "$10", - // backgroundColor: "red", - // position: "relative", - // top: 5, - lineHeight: "$10", - variants: { - small: { - true: { - fontSize: "$6", - lineHeight: "$6", - }, - }, - }, -} as const); -const LabelText = styled(Text, { - fontSize: "$7", - variants: { - small: { - true: { - fontSize: "$6", - lineHeight: "$6", - }, - }, - }, -} as const); - -const LabelBox = ({ children, small }) => { - return ( - - {children} - - ); -}; +import { View, useWindowDimensions } from "react-native"; -export function Countdown({ - from, - to, - small, -}: { +interface CountdownProps { from?: string; to?: string; small?: boolean; -}) { - const media = useMedia(); +} + +interface LabelBoxProps { + children: React.ReactNode; + small?: boolean; +} + +const LabelBox = ({ children, small }: LabelBoxProps) => { + return ( + + + {children} + + + ); +}; + +export function Countdown({ from, to, small }: CountdownProps) { const [now, setNow] = useState(Date.now()); const [dest, setDest] = useState(null); const { width, height } = useWindowDimensions(); + useEffect(() => { if (from) { const fromDate = chrono.parseDate(from); @@ -129,6 +60,7 @@ export function Countdown({ throw new Error("must provide either from or to"); } }, [from, to]); + useEffect(() => { const tick = () => { if (!running) { @@ -147,6 +79,7 @@ export function Countdown({ if (dest === null) { return ; } + let diff = Math.abs(dest - now); if (to && now > dest) { diff = 0; @@ -156,37 +89,54 @@ export function Countdown({ small = small ?? width <= 600; const [years, days, hrs, min, sec, ms] = toLabels(diff); + const unitStyle = [ + zero.mx[small ? 2 : 4], + zero.flex.values[0], + { flexDirection: "column" }, + ]; + + const timeTextStyle = [ + { fontFamily: "monospace" }, + small ? { fontSize: 18 } : { fontSize: 128 }, + small ? { lineHeight: 24 } : { lineHeight: 40 }, + ]; + return ( - - - - {years} + + + + {years} YEARS - - - {days} + + + {days} DAYS - - - {hrs} + + + {hrs} HRS - - - - - {min} + + + + + {min} MIN - - - {sec} + + + {sec} SEC - - - {ms} + + + {ms} MS - - - + + + ); } diff --git a/js/app/components/create-livestream.tsx b/js/app/components/create-livestream.tsx index cffd2eff..9849b690 100644 --- a/js/app/components/create-livestream.tsx +++ b/js/app/components/create-livestream.tsx @@ -1,4 +1,4 @@ -import { useToastController } from "@tamagui/toast"; +import { zero } from "@streamplace/components"; import ThumbnailSelector from "components/thumbnail-selector"; import { createLivestreamRecord, @@ -8,13 +8,22 @@ import { import { useCaptureVideoFrame } from "hooks/useCaptureVideoFrame"; import { useLiveUser } from "hooks/useLiveUser"; import { useEffect, useState } from "react"; -import { ScrollView, useWindowDimensions } from "react-native"; +import { + Platform, + Pressable, + ScrollView, + Text, + TextInput, + useWindowDimensions, + View, +} from "react-native"; import { useAppDispatch, useAppSelector } from "store/hooks"; -import { Button, Label, Paragraph, TextArea, View, isWeb } from "tamagui"; + +const isWeb = Platform.OS === "web"; export default function CreateLivestream() { const dispatch = useAppDispatch(); - const toast = useToastController(); + // Note: Toast functionality removed, would need simple alert replacement const userIsLive = useLiveUser(); const [title, setTitle] = useState(""); const [loading, setLoading] = useState(false); @@ -32,20 +41,18 @@ export default function CreateLivestream() { useEffect(() => { if (newLivestream?.record) { - toast.show("Livestream announced", { - message: newLivestream.record.title, - }); + // Would show toast: "Livestream announced" with newLivestream.record.title setTitle(""); setCustomThumbnail(undefined); } }, [newLivestream?.record]); + useEffect(() => { if (newLivestream?.error) { - toast.show("Error creating livestream", { - message: newLivestream.error, - }); + // Would show toast: "Error creating livestream" with error message } }, [newLivestream?.error]); + const disabled = !userIsLive || loading || title === ""; const handleSubmit = async () => { @@ -67,9 +74,7 @@ export default function CreateLivestream() { ); } catch (error) { console.error("Error creating livestream:", error); - toast.show("Error creating livestream", { - message: String(error), - }); + // Would show toast: "Error creating livestream" } finally { setLoading(false); } @@ -92,80 +97,138 @@ export default function CreateLivestream() { showsVerticalScrollIndicator={false} > {/* Left column: labels and fields */} - - -