diff --git a/.github/workflows/gpt-review.yml b/.github/workflows/gpt-review.yml index f2f5091..8f924cd 100644 --- a/.github/workflows/gpt-review.yml +++ b/.github/workflows/gpt-review.yml @@ -1,105 +1,28 @@ -name: PR Blog Summarizer - -on: - pull_request: - types: [opened, synchronize] +name: Code Review permissions: - issues: write + contents: read pull-requests: write +on: + pull_request: + types: [opened, reopened, synchronize] + jobs: - process: + test: runs-on: ubuntu-latest + if: ${{ contains(github.event.pull_request.title, '#gpt') || contains(github.event.pull_request.body, '#gpt') }} steps: - # Step 1: Check out the code - - name: Check out code - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - # Step 2: Set up Python - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: '3.8' - - # Step 3: Install dependencies - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install openai requests - - # Step 4: Get Changed Files - - name: Get Changed Files - id: get_files - run: | - CHANGED_FILES=$(git diff --name-only origin/main ${{ github.sha }}) - - if [ -z "$CHANGED_FILES" ]; then - echo "changed_files=" >> $GITHUB_ENV - else - # .md 파일만 필터링 - MD_FILES=$(echo "$CHANGED_FILES" | grep -E '^week[0-9]+/.*\.md$') - echo $MD_FILES - - if [ -z "$MD_FILES" ]; then - echo "changed_files=" >> $GITHUB_ENV - else - # 환경 변수에 저장 - echo "changed_files=$MD_FILES" >> $GITHUB_ENV - fi - fi - - # Step 5: Process Changed Files - - name: Process Changed Files + - uses: anc95/ChatGPT-CodeReview@main env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} OPENAI_API_KEY: ${{ secrets.GPT_KEY }} - changed_files: ${{ env.changed_files }} - run: | - if [ -z "$changed_files" ]; then - echo "No changed files to process." - exit 0 - fi - - SUMMARY_MESSAGE="### Automated Review\n" - IFS=$'\n' - for file_path in $changed_files; do - # Skip link.md files - if [[ "$file_path" == *link.md ]]; then - continue - fi - - # Process non-link.md files - echo "Processing file: $file_path" - FILE_CONTENT=$(cat "$file_path" || echo "") - if [ -z "$FILE_CONTENT" ]; then - SUMMARY_MESSAGE+="Error: Could not read content of $file_path\n" - continue - fi - - # Run feedback.py - FEEDBACK=$(python feedback.py --content "$FILE_CONTENT" || echo "Error: feedback.py failed for $file_path") - SUMMARY_MESSAGE+="Feedback for file: $file_path\n" - SUMMARY_MESSAGE+="$FEEDBACK\n" - done - - echo "summary_message<> $GITHUB_ENV - echo -e "$SUMMARY_MESSAGE" >> $GITHUB_ENV - echo "EOF" >> $GITHUB_ENV - - # Step 6: Post Comment on Pull Request - - name: Post Comment on Pull Request - uses: actions/github-script@v6 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const summary = process.env.summary_message; - if (summary && summary.trim().length > 0) { - await github.rest.issues.createComment({ - ...context.repo, - issue_number: context.payload.pull_request.number, - body: summary - }); - } + # optional + LANGUAGE: Korean + max_tokens: 10000 + MAX_PATCH_LENGTH: 10000 + ACTIONS_STEP_DEBUG: true + + IGNORE_PATTERNS: /dist, /node_modules,*.md # Regex pattern to ignore files, separated by comma + # INCLUDE_PATTERNS: '*.js, *.ts, *.jsx, *.tsx' # glob pattern or regex pattern to include files, separated by comma diff --git a/.prettierrc.json b/.prettierrc.json index 41acafa..d31762a 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,6 +1,5 @@ { "$schema": "https://json.schemastore.org/prettierrc", - "semi": true, "tabWidth": 2, "singleQuote": true, "printWidth": 120, diff --git a/apps/mobile/app/(tabs)/_layout.tsx b/apps/mobile/app/(tabs)/_layout.tsx index cfbc1e2..6ff9b73 100644 --- a/apps/mobile/app/(tabs)/_layout.tsx +++ b/apps/mobile/app/(tabs)/_layout.tsx @@ -25,7 +25,8 @@ export default function TabLayout() { }, default: {}, }), - }}> + }} + > - }> + } + > Explore This app includes example code to help you get started. - This app has two screens:{' '} - app/(tabs)/index.tsx and{' '} + This app has two screens: app/(tabs)/index.tsx and{' '} app/(tabs)/explore.tsx - The layout file in app/(tabs)/_layout.tsx{' '} - sets up the tab navigator. + The layout file in app/(tabs)/_layout.tsx sets up the tab + navigator. Learn more @@ -46,8 +46,7 @@ export default function TabTwoScreen() { For static images, you can use the @2x and{' '} - @3x suffixes to provide files for - different screen densities + @3x suffixes to provide files for different screen densities @@ -57,9 +56,7 @@ export default function TabTwoScreen() { Open app/_layout.tsx to see how to load{' '} - - custom fonts such as this one. - + custom fonts such as this one. Learn more @@ -68,8 +65,8 @@ export default function TabTwoScreen() { This template has light and dark mode support. The{' '} - useColorScheme() hook lets you inspect - what the user's current color scheme is, and so you can adjust UI colors accordingly. + useColorScheme() hook lets you inspect what the user's current + color scheme is, and so you can adjust UI colors accordingly. Learn more @@ -78,15 +75,15 @@ export default function TabTwoScreen() { This template includes an example of an animated component. The{' '} - components/HelloWave.tsx component uses - the powerful react-native-reanimated{' '} - library to create a waving hand animation. + components/HelloWave.tsx component uses the powerful{' '} + react-native-reanimated library to create a waving hand + animation. {Platform.select({ ios: ( - The components/ParallaxScrollView.tsx{' '} - component provides a parallax effect for the header image. + The components/ParallaxScrollView.tsx component provides a + parallax effect for the header image. ), })} diff --git a/apps/mobile/app/(tabs)/index.tsx b/apps/mobile/app/(tabs)/index.tsx index 886b079..51a2187 100644 --- a/apps/mobile/app/(tabs)/index.tsx +++ b/apps/mobile/app/(tabs)/index.tsx @@ -9,12 +9,8 @@ export default function HomeScreen() { return ( - }> + headerImage={} + > Welcome! @@ -22,13 +18,12 @@ export default function HomeScreen() { Step 1: Try it - Edit app/(tabs)/index.tsx to see changes. - Press{' '} + Edit app/(tabs)/index.tsx to see changes. Press{' '} {Platform.select({ ios: 'cmd + d', android: 'cmd + m', - web: 'F12' + web: 'F12', })} {' '} to open developer tools. @@ -36,15 +31,12 @@ export default function HomeScreen() { Step 2: Explore - - Tap the Explore tab to learn more about what's included in this starter app. - + Tap the Explore tab to learn more about what's included in this starter app. Step 3: Get a fresh start - When you're ready, run{' '} - npm run reset-project to get a fresh{' '} + When you're ready, run npm run reset-project to get a fresh{' '} app directory. This will move the current{' '} app to{' '} app-example. diff --git a/apps/mobile/components/Collapsible.tsx b/apps/mobile/components/Collapsible.tsx index 55bff2f..4eb12e2 100644 --- a/apps/mobile/components/Collapsible.tsx +++ b/apps/mobile/components/Collapsible.tsx @@ -13,10 +13,7 @@ export function Collapsible({ children, title }: PropsWithChildren & { title: st return ( - setIsOpen((value) => !value)} - activeOpacity={0.8}> + setIsOpen((value) => !value)} activeOpacity={0.8}> { rotationAnimation.value = withRepeat( withSequence(withTiming(25, { duration: 150 }), withTiming(0, { duration: 150 })), - 4 // Run the animation 4 times + 4, // Run the animation 4 times ); }, []); diff --git a/apps/mobile/components/ParallaxScrollView.tsx b/apps/mobile/components/ParallaxScrollView.tsx index 5df1d75..eeb3891 100644 --- a/apps/mobile/components/ParallaxScrollView.tsx +++ b/apps/mobile/components/ParallaxScrollView.tsx @@ -1,11 +1,6 @@ import type { PropsWithChildren, ReactElement } from 'react'; import { StyleSheet } from 'react-native'; -import Animated, { - interpolate, - useAnimatedRef, - useAnimatedStyle, - useScrollViewOffset, -} from 'react-native-reanimated'; +import Animated, { interpolate, useAnimatedRef, useAnimatedStyle, useScrollViewOffset } from 'react-native-reanimated'; import { ThemedView } from '@/components/ThemedView'; import { useBottomTabOverflow } from '@/components/ui/TabBarBackground'; @@ -18,11 +13,7 @@ type Props = PropsWithChildren<{ headerBackgroundColor: { dark: string; light: string }; }>; -export default function ParallaxScrollView({ - children, - headerImage, - headerBackgroundColor, -}: Props) { +export default function ParallaxScrollView({ children, headerImage, headerBackgroundColor }: Props) { const colorScheme = useColorScheme() ?? 'light'; const scrollRef = useAnimatedRef(); const scrollOffset = useScrollViewOffset(scrollRef); @@ -34,7 +25,7 @@ export default function ParallaxScrollView({ translateY: interpolate( scrollOffset.value, [-HEADER_HEIGHT, 0, HEADER_HEIGHT], - [-HEADER_HEIGHT / 2, 0, HEADER_HEIGHT * 0.75] + [-HEADER_HEIGHT / 2, 0, HEADER_HEIGHT * 0.75], ), }, { @@ -50,13 +41,11 @@ export default function ParallaxScrollView({ ref={scrollRef} scrollEventThrottle={16} scrollIndicatorInsets={{ bottom }} - contentContainerStyle={{ paddingBottom: bottom }}> + contentContainerStyle={{ paddingBottom: bottom }} + > + style={[styles.header, { backgroundColor: headerBackgroundColor[colorScheme] }, headerAnimatedStyle]} + > {headerImage} {children} diff --git a/apps/mobile/components/ThemedText.tsx b/apps/mobile/components/ThemedText.tsx index c0e1a78..c8b4931 100644 --- a/apps/mobile/components/ThemedText.tsx +++ b/apps/mobile/components/ThemedText.tsx @@ -8,13 +8,7 @@ export type ThemedTextProps = TextProps & { type?: 'default' | 'title' | 'defaultSemiBold' | 'subtitle' | 'link'; }; -export function ThemedText({ - style, - lightColor, - darkColor, - type = 'default', - ...rest -}: ThemedTextProps) { +export function ThemedText({ style, lightColor, darkColor, type = 'default', ...rest }: ThemedTextProps) { const color = useThemeColor({ light: lightColor, dark: darkColor }, 'text'); return ( diff --git a/apps/mobile/components/ui/IconSymbol.tsx b/apps/mobile/components/ui/IconSymbol.tsx index f1fabd4..91282bd 100644 --- a/apps/mobile/components/ui/IconSymbol.tsx +++ b/apps/mobile/components/ui/IconSymbol.tsx @@ -14,10 +14,7 @@ const MAPPING = { 'chevron.left.forwardslash.chevron.right': 'code', 'chevron.right': 'chevron-right', } as Partial< - Record< - import('expo-symbols').SymbolViewProps['name'], - React.ComponentProps['name'] - > + Record['name']> >; export type IconSymbolName = keyof typeof MAPPING; diff --git a/apps/mobile/hooks/useThemeColor.ts b/apps/mobile/hooks/useThemeColor.ts index 0608e73..08a3019 100644 --- a/apps/mobile/hooks/useThemeColor.ts +++ b/apps/mobile/hooks/useThemeColor.ts @@ -8,7 +8,7 @@ import { useColorScheme } from '@/hooks/useColorScheme'; export function useThemeColor( props: { light?: string; dark?: string }, - colorName: keyof typeof Colors.light & keyof typeof Colors.dark + colorName: keyof typeof Colors.light & keyof typeof Colors.dark, ) { const theme = useColorScheme() ?? 'light'; const colorFromProps = props[theme]; diff --git a/apps/mobile/scripts/reset-project.js b/apps/mobile/scripts/reset-project.js index 51dff15..59665be 100644 --- a/apps/mobile/scripts/reset-project.js +++ b/apps/mobile/scripts/reset-project.js @@ -6,14 +6,14 @@ * You can remove the `reset-project` script from package.json and safely delete this file after running it. */ -const fs = require("fs"); -const path = require("path"); -const readline = require("readline"); +const fs = require('fs'); +const path = require('path'); +const readline = require('readline'); const root = process.cwd(); -const oldDirs = ["app", "components", "hooks", "constants", "scripts"]; -const exampleDir = "app-example"; -const newAppDir = "app"; +const oldDirs = ['app', 'components', 'hooks', 'constants', 'scripts']; +const exampleDir = 'app-example'; +const newAppDir = 'app'; const exampleDirPath = path.join(root, exampleDir); const indexContent = `import { Text, View } from "react-native"; @@ -47,7 +47,7 @@ const rl = readline.createInterface({ const moveDirectories = async (userInput) => { try { - if (userInput === "y") { + if (userInput === 'y') { // Create the app-example directory await fs.promises.mkdir(exampleDirPath, { recursive: true }); console.log(`📁 /${exampleDir} directory created.`); @@ -57,7 +57,7 @@ const moveDirectories = async (userInput) => { for (const dir of oldDirs) { const oldDirPath = path.join(root, dir); if (fs.existsSync(oldDirPath)) { - if (userInput === "y") { + if (userInput === 'y') { const newDirPath = path.join(root, exampleDir, dir); await fs.promises.rename(oldDirPath, newDirPath); console.log(`➡️ /${dir} moved to /${exampleDir}/${dir}.`); @@ -73,40 +73,35 @@ const moveDirectories = async (userInput) => { // Create new /app directory const newAppDirPath = path.join(root, newAppDir); await fs.promises.mkdir(newAppDirPath, { recursive: true }); - console.log("\n📁 New /app directory created."); + console.log('\n📁 New /app directory created.'); // Create index.tsx - const indexPath = path.join(newAppDirPath, "index.tsx"); + const indexPath = path.join(newAppDirPath, 'index.tsx'); await fs.promises.writeFile(indexPath, indexContent); - console.log("📄 app/index.tsx created."); + console.log('📄 app/index.tsx created.'); // Create _layout.tsx - const layoutPath = path.join(newAppDirPath, "_layout.tsx"); + const layoutPath = path.join(newAppDirPath, '_layout.tsx'); await fs.promises.writeFile(layoutPath, layoutContent); - console.log("📄 app/_layout.tsx created."); + console.log('📄 app/_layout.tsx created.'); - console.log("\n✅ Project reset complete. Next steps:"); + console.log('\n✅ Project reset complete. Next steps:'); console.log( `1. Run \`npx expo start\` to start a development server.\n2. Edit app/index.tsx to edit the main screen.${ - userInput === "y" - ? `\n3. Delete the /${exampleDir} directory when you're done referencing it.` - : "" - }` + userInput === 'y' ? `\n3. Delete the /${exampleDir} directory when you're done referencing it.` : '' + }`, ); } catch (error) { console.error(`❌ Error during script execution: ${error.message}`); } }; -rl.question( - "Do you want to move existing files to /app-example instead of deleting them? (Y/n): ", - (answer) => { - const userInput = answer.trim().toLowerCase() || "y"; - if (userInput === "y" || userInput === "n") { - moveDirectories(userInput).finally(() => rl.close()); - } else { - console.log("❌ Invalid input. Please enter 'Y' or 'N'."); - rl.close(); - } +rl.question('Do you want to move existing files to /app-example instead of deleting them? (Y/n): ', (answer) => { + const userInput = answer.trim().toLowerCase() || 'y'; + if (userInput === 'y' || userInput === 'n') { + moveDirectories(userInput).finally(() => rl.close()); + } else { + console.log("❌ Invalid input. Please enter 'Y' or 'N'."); + rl.close(); } -); +}); diff --git a/apps/web/.prettierrc.cjs b/apps/web/.prettierrc.cjs new file mode 100644 index 0000000..c689c11 --- /dev/null +++ b/apps/web/.prettierrc.cjs @@ -0,0 +1,14 @@ +module.exports = { + printWidth: 100, // 한 줄 최대 길이 + tabWidth: 2, // 탭 크기 (스페이스 2칸) + singleQuote: true, // 작은따옴표 사용 + trailingComma: 'all', // 여러 줄일 때 항상 쉼표 사용 + arrowParens: 'avoid', // 화살표 함수 괄호 생략 (ex: x => x) + bracketSpacing: true, // 중괄호 간격 유지 (ex: { foo: bar }) + jsxSingleQuote: false, // JSX에서 작은따옴표 사용 안 함 + endOfLine: 'lf', // 줄바꿈 형식 (LF 고정) + importOrder: ['', '^@repo/(.*)$', '^@/(.*)$', '^../(.*)$', '^./(.*)$'], + importOrderSeparation: true, + importOrderSortSpecifiers: true, + plugins: ['@trivago/prettier-plugin-sort-imports', 'prettier-plugin-tailwindcss'], +}; diff --git a/apps/web/app/ErrorWrapper.tsx b/apps/web/app/ErrorWrapper.tsx new file mode 100644 index 0000000..ddd1228 --- /dev/null +++ b/apps/web/app/ErrorWrapper.tsx @@ -0,0 +1,19 @@ +'use client'; + +import { Suspense } from 'react'; + +import ErrorContent from '@/components/ErrorContnet'; + +export default function ErrorWrapper({ children }: { children: React.ReactNode }) { + return ( + +

로딩 중...

+ + } + > + {children} +
+ ); +} diff --git a/apps/web/app/Footer.tsx b/apps/web/app/Footer.tsx new file mode 100644 index 0000000..5ac3335 --- /dev/null +++ b/apps/web/app/Footer.tsx @@ -0,0 +1,36 @@ +'use client'; + +import Link from 'next/link'; +import { usePathname } from 'next/navigation'; + +import { Button } from '@/components/ui/button'; +import { cn } from '@/utils/cn'; + +const navigation = [ + { name: '부를 곡', href: '/' }, + { name: '검색', href: '/search' }, + { name: '인기곡', href: '/popular' }, + { name: '라이브러리', href: '/library' }, +]; + +export default function Footer() { + const pathname = usePathname(); + + return ( +
+ {navigation.map(item => { + const isActive = pathname === item.href; + return ( + + ); + })} +
+ ); +} diff --git a/apps/web/app/Header.tsx b/apps/web/app/Header.tsx new file mode 100644 index 0000000..dc22b11 --- /dev/null +++ b/apps/web/app/Header.tsx @@ -0,0 +1,18 @@ +'use client'; + +import Image from 'next/image'; +import { useRouter } from 'next/navigation'; + +import Sidebar from './Sidebar'; + +export default function Header() { + const router = useRouter(); + + return ( +
+ logo router.push('/')} /> + + +
+ ); +} diff --git a/apps/web/app/Sidebar.tsx b/apps/web/app/Sidebar.tsx new file mode 100644 index 0000000..265a079 --- /dev/null +++ b/apps/web/app/Sidebar.tsx @@ -0,0 +1,143 @@ +'use client'; + +import { LogOut, Mail, Menu, Pencil, User } from 'lucide-react'; +import { useRouter } from 'next/navigation'; +import { useState } from 'react'; + +import { Button } from '@/components/ui/button'; +import { Separator } from '@/components/ui/separator'; +import { + Sheet, + SheetContent, + SheetFooter, + SheetHeader, + SheetTitle, + SheetTrigger, +} from '@/components/ui/sheet'; +import useAuthStore from '@/stores/useAuthStore'; + +import { Input } from './components/ui/input'; + +export default function Sidebar() { + // 목업 인증 상태 + const { user, isAuthenticated, logout, changeNickname } = useAuthStore(); + const [isOpen, setIsOpen] = useState(false); + const [isEditing, setIsEditing] = useState(false); + const [newNickname, setNewNickname] = useState(user?.nickname || ''); + + const router = useRouter(); + + const handleEditStart = () => { + setIsEditing(true); + setNewNickname(user?.nickname || ''); + }; + + // 닉네임 수정 취소 + const handleEditCancel = () => { + setIsEditing(false); + setNewNickname(user?.nickname || ''); + }; + + const handleEditSave = async () => { + const result = await changeNickname(newNickname); + if (result) setIsEditing(false); + }; + + const handleLogin = () => { + router.push('/login'); + setIsOpen(false); + }; + + const handleLogout = () => { + logout(); + window.location.reload(); + }; + + const handleClickContact = () => { + const contactUrl = 'https://walla.my/survey/K79c5bC6alDqc1qiaaES'; + window.open(contactUrl, '_blank'); + }; + + return ( + + + + + + + 메뉴 + +
+
+
+ {user?.nickname.slice(0, 3)} +
+
+
+ {isEditing ? ( + // 수정 모드 + <> + setNewNickname(e.target.value)} + className="h-8 w-32 text-center" + maxLength={10} + /> +
+ + +
+ + ) : ( + // 표시 모드 + <> + {user ? user.nickname : '손님'} + {user && ( +
+ +
+ )} + + )} +
+
+
+ + + +
+ +
+
+ + {isAuthenticated ? ( + + ) : ( + + )} + +
+
+ ); +} diff --git a/apps/web/app/api/auth/callback/route.ts b/apps/web/app/api/auth/callback/route.ts new file mode 100644 index 0000000..f7427ea --- /dev/null +++ b/apps/web/app/api/auth/callback/route.ts @@ -0,0 +1,31 @@ +import { NextResponse } from 'next/server'; + +// The client you created from the Server-Side Auth instructions +import createClient from '@/lib/supabase/server'; + +export async function GET(request: Request) { + const { searchParams, origin } = new URL(request.url); + const code = searchParams.get('code'); + // if "next" is in param, use it as the redirect URL + const next = searchParams.get('next') ?? '/'; + + if (code) { + const supabase = await createClient(); + const { error } = await supabase.auth.exchangeCodeForSession(code); + if (!error) { + const forwardedHost = request.headers.get('x-forwarded-host'); // original origin before load balancer + const isLocalEnv = process.env.NODE_ENV === 'development'; + if (isLocalEnv) { + // we can be sure that there is no load balancer in between, so no need to watch for X-Forwarded-Host + return NextResponse.redirect(`${origin}${next}`); + } else if (forwardedHost) { + return NextResponse.redirect(`https://${forwardedHost}${next}`); + } else { + return NextResponse.redirect(`${origin}${next}`); + } + } + } + + // return the user to an error page with instructions + return NextResponse.redirect(`${origin}/auth/auth-code-error`); +} diff --git a/apps/web/app/api/auth/confirm.ts b/apps/web/app/api/auth/confirm.ts new file mode 100644 index 0000000..559a382 --- /dev/null +++ b/apps/web/app/api/auth/confirm.ts @@ -0,0 +1,45 @@ +import { type EmailOtpType } from '@supabase/supabase-js'; +import type { NextApiRequest, NextApiResponse } from 'next'; + +import createClient from '@/lib/supabase/api'; + +function stringOrFirstString(item: string | string[] | undefined) { + return Array.isArray(item) ? item[0] : item; +} + +// API Route에서는 throw 대신 적절한 HTTP 응답 필요. 리다이렉팅의 이유? + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + if (req.method !== 'GET') { + res.status(405).appendHeader('Allow', 'GET').end(); + return; + } + + const queryParams = req.query; + const token_hash = stringOrFirstString(queryParams.token_hash); + const type = stringOrFirstString(queryParams.type); + const nextUrl = stringOrFirstString(queryParams.next) || '/'; + + try { + if (!token_hash || !type) { + return res.redirect('/error?message=missing-parameters'); + } + + const supabase = createClient(req, res); + const { error } = await supabase.auth.verifyOtp({ + type: type as EmailOtpType, + token_hash, + }); + + if (error) { + console.error('인증 에러:', error); + return res.redirect(`/error?message=${encodeURIComponent(error.message)}`); + } + + // 성공 시 nextUrl로 리다이렉트 + return res.redirect(nextUrl); + } catch (error) { + console.error('예상치 못한 에러:', error); + return res.redirect('/error?message=unexpected-error'); + } +} diff --git a/apps/web/app/api/open_songs/[type]/[param]/route.ts b/apps/web/app/api/open_songs/[type]/[param]/route.ts new file mode 100644 index 0000000..e6c92f1 --- /dev/null +++ b/apps/web/app/api/open_songs/[type]/[param]/route.ts @@ -0,0 +1,78 @@ +// app/api/songs/[type]/[param]/route.ts +import { NextRequest, NextResponse } from 'next/server'; + +import { + Brand, + Period, + getComposer, + getLyricist, + getNo, + getPopular, + getRelease, + getSinger, + getSong, +} from '@repo/open-api'; + +export async function GET(request: NextRequest) { + try { + const segments = request.nextUrl.pathname.split('/'); + const type = segments[segments.length - 2]; + const param = segments[segments.length - 1]; + + const searchParams = request.nextUrl.searchParams; + const brand = searchParams.get('brand') as Brand | undefined; + + let result = null; + + switch (type) { + case 'title': + result = await getSong({ title: param, brand }); + break; + + case 'singer': + result = await getSinger({ singer: param, brand }); + break; + + case 'composer': + result = await getComposer({ composer: param, brand }); + break; + + case 'lyricist': + result = await getLyricist({ lyricist: param, brand }); + break; + + case 'no': + result = await getNo({ no: param, brand }); + break; + + case 'release': + result = await getRelease({ release: param, brand }); + break; + + case 'popular': + // popular의 경우는 좀 특별하게 처리 + // param은 brand 값이 되고, period는 쿼리 파라미터로 받음 + const period = searchParams.get('period') as Period; + if (!period) { + return NextResponse.json( + { error: '기간(period)은 필수 파라미터입니다.' }, + { status: 400 }, + ); + } + result = await getPopular({ brand: param as Brand, period }); + break; + + default: + return NextResponse.json({ error: '지원하지 않는 검색 유형입니다' }, { status: 400 }); + } + + if (!result) { + return NextResponse.json({ error: '검색 결과가 없습니다' }, { status: 404 }); + } + + return NextResponse.json({ data: result }); + } catch (error) { + console.error('API 요청 오류:', error); + return NextResponse.json({ error: '서버 오류가 발생했습니다' }, { status: 500 }); + } +} diff --git a/apps/web/app/api/search/route.ts b/apps/web/app/api/search/route.ts new file mode 100644 index 0000000..6453a70 --- /dev/null +++ b/apps/web/app/api/search/route.ts @@ -0,0 +1,105 @@ +import { NextResponse } from 'next/server'; + +import createClient from '@/lib/supabase/server'; +import { SearchSong, Song } from '@/types/song'; +import { getAuthenticatedUser } from '@/utils/getAuthenticatedUser'; + +// interface ApiResponse { +// success: boolean; +// data?: T; +// error?: string; +// } + +interface DBSong extends Song { + like_activities: { + user_id: string; + }[]; + tosings: { + user_id: string; + }[]; +} +// export async function GET(request: Request): Promise>> { +export async function GET(request: Request) { + // API KEY 노출을 막기 위해 미들웨어 역할을 할 API ROUTE 활용 + try { + const { searchParams } = new URL(request.url); + const query = searchParams.get('q'); + const type = searchParams.get('type') || 'title'; + + if (!query) { + return NextResponse.json( + { + success: false, + error: 'No query provided', + }, + { status: 400 }, + ); + } + + const supabase = await createClient(); + const userId = await getAuthenticatedUser(supabase); // userId 가져오기 + + // .select( + // ` + // *, + // like_activities!left ( + // user_id + // ), + // tosings!left ( + // user_id + // ) + // `, + // ) + const { data, error } = await supabase + .from('songs') + .select( + ` + *, + like_activities ( + user_id + ), + tosings ( + user_id + ) + `, + ) + .ilike(type, `%${query}%`); + + if (error) { + return NextResponse.json( + { + success: false, + error: error?.message || 'Unknown error', + }, + { status: 500 }, + ); + } + + // data를 Song 타입으로 파싱해야 함 + const songs: SearchSong[] = data.map((song: DBSong) => ({ + id: song.id, + title: song.title, + artist: song.artist, + num_tj: song.num_tj, + num_ky: song.num_ky, + // like_activities에서 현재 사용자의 데이터가 있는지 확인 + isLiked: song.like_activities?.some(like => like.user_id === userId) ?? false, + // tosings에서 현재 사용자의 데이터가 있는지 확인 + isToSing: song.tosings?.some(tosing => tosing.user_id === userId) ?? false, + })); + + return NextResponse.json({ + success: true, + data: songs, + }); + } catch (error) { + console.error('Error in search API:', error); + return NextResponse.json( + { + success: false, + error: 'Internal server error', + }, + { status: 500 }, + ); + } +} diff --git a/apps/web/app/api/sing_logs/route.ts b/apps/web/app/api/sing_logs/route.ts new file mode 100644 index 0000000..30bda2e --- /dev/null +++ b/apps/web/app/api/sing_logs/route.ts @@ -0,0 +1,26 @@ +import { NextResponse } from 'next/server'; + +import createClient from '@/lib/supabase/server'; +import { getAuthenticatedUser } from '@/utils/getAuthenticatedUser'; + +export async function POST(request: Request) { + try { + const supabase = await createClient(); // Supabase 클라이언트 생성 + const { songId } = await request.json(); + const userId = await getAuthenticatedUser(supabase); // userId 가져오기 + + const { error } = await supabase.from('sing_logs').insert({ + song_id: songId, + user_id: userId, // userId 추가 + }); + if (error) throw error; + + return NextResponse.json({ success: true }); + } catch (error) { + console.error('Error in tosings API:', error); + return NextResponse.json( + { success: false, error: 'Failed to post sing_logs' }, + { status: 500 }, + ); + } +} diff --git a/apps/web/app/api/songs/like/arr/route.ts b/apps/web/app/api/songs/like/arr/route.ts new file mode 100644 index 0000000..a0daf91 --- /dev/null +++ b/apps/web/app/api/songs/like/arr/route.ts @@ -0,0 +1,29 @@ +import { NextResponse } from 'next/server'; + +import createClient from '@/lib/supabase/server'; +import { getAuthenticatedUser } from '@/utils/getAuthenticatedUser'; + +export async function DELETE(request: Request) { + try { + const supabase = await createClient(); // Supabase 클라이언트 생성 + const userId = await getAuthenticatedUser(supabase); // userId 가져오기 + + const { songIds } = await request.json(); + + const { error } = await supabase + .from('like_activities') + .delete() + .eq('user_id', userId) + .in('song_id', songIds); + + if (error) throw error; + + return NextResponse.json({ success: true }); + } catch (error) { + console.error('Error in search API:', error); + return NextResponse.json( + { success: false, error: 'Failed to delete like song' }, + { status: 500 }, + ); + } +} diff --git a/apps/web/app/api/songs/like/route.ts b/apps/web/app/api/songs/like/route.ts new file mode 100644 index 0000000..85fb257 --- /dev/null +++ b/apps/web/app/api/songs/like/route.ts @@ -0,0 +1,116 @@ +import { NextResponse } from 'next/server'; + +import createClient from '@/lib/supabase/server'; +import { LikeLog } from '@/types/likeLog'; +import { Song } from '@/types/song'; +import { getAuthenticatedUser } from '@/utils/getAuthenticatedUser'; + +interface ResponseLikeLog extends LikeLog { + songs: Song; +} +export async function GET() { + try { + const supabase = await createClient(); + const userId = await getAuthenticatedUser(supabase); + + // like_activities에서 song_id 목록을 가져옴 + const { data, error: likedError } = await supabase + .from('like_activities') + .select( + `*, + songs ( + * + ) + `, + ) + .eq('user_id', userId) + .order('created_at', { ascending: false }); + + if (likedError) throw likedError; + + const likedSongs = data?.map((item: ResponseLikeLog) => ({ + id: item.user_id + item.song_id, + user_id: item.user_id, + song_id: item.songs.id, + created_at: item.created_at, + title: item.songs.title, + artist: item.songs.artist, + num_tj: item.songs.num_tj, + num_ky: item.songs.num_ky, + })); + + // 가져온 song_id 목록을 사용하여 songs 테이블에서 정보를 가져옴 + const songIds = likedSongs.map(item => item.song_id); + + // tosings 테이블에서 해당 user_id와 song_id가 일치하는 레코드를 가져옴 + const { data: tosingSongs, error: tosingError } = await supabase + .from('tosings') + .select('song_id') + .eq('user_id', userId) + .in('song_id', songIds); + + if (tosingError) throw tosingError; + + const tosingSongIds = new Set(tosingSongs.map(item => item.song_id)); + + // tosingSongIds에 포함된 song_id를 가진 노래에 isInToSingList: true 추가 + const processedData = likedSongs.map(song => ({ + ...song, + isInToSingList: tosingSongIds.has(song.song_id), + })); + + return NextResponse.json({ success: true, data: processedData }); + } catch (error) { + console.error('Error in like API:', error); + return NextResponse.json( + { success: false, error: 'Failed to get like songs' }, + { status: 500 }, + ); + } +} + +export async function POST(request: Request) { + try { + const supabase = await createClient(); // Supabase 클라이언트 생성 + const userId = await getAuthenticatedUser(supabase); // userId 가져오기 + + const { songId } = await request.json(); + + const { error } = await supabase + .from('like_activities') + .insert({ user_id: userId, song_id: songId }); + + if (error) throw error; + + return NextResponse.json({ success: true }); + } catch (error) { + console.error('Error in like API:', error); + return NextResponse.json( + { success: false, error: 'Failed to post like song' }, + { status: 500 }, + ); + } +} +export async function DELETE(request: Request) { + try { + const supabase = await createClient(); // Supabase 클라이언트 생성 + const userId = await getAuthenticatedUser(supabase); // userId 가져오기 + + const { songId } = await request.json(); + + const { error } = await supabase + .from('like_activities') + .delete() + .match({ user_id: userId, song_id: songId }); + + if (error) throw error; + + return NextResponse.json({ success: true }); + } catch (error) { + console.error('Error in search API:', error); + return NextResponse.json( + { success: false, error: 'Failed to delete like song' }, + { status: 500 }, + ); + } +} diff --git a/apps/web/app/api/songs/recent/route.tsx b/apps/web/app/api/songs/recent/route.tsx new file mode 100644 index 0000000..03c5345 --- /dev/null +++ b/apps/web/app/api/songs/recent/route.tsx @@ -0,0 +1,71 @@ +import { NextResponse } from 'next/server'; + +import createClient from '@/lib/supabase/server'; +import { SingLog } from '@/types/singLog'; +import { Song } from '@/types/song'; +import { getAuthenticatedUser } from '@/utils/getAuthenticatedUser'; + +interface ResponseSingLog extends SingLog { + songs: Song; +} +export async function GET() { + try { + const supabase = await createClient(); + const userId = await getAuthenticatedUser(supabase); + + // sing_logs에서 song_id 목록을 가져옴 (최신순) + const { data, error: recentError } = await supabase + .from('sing_logs') // sing_logs 테이블에서 시작 + .select( + `*, + songs ( + * + ) + `, + ) + .eq('user_id', userId) + .order('created_at', { ascending: false }) // 단순히 sing_logs의 created_at으로 정렬 + .limit(10); + + if (recentError) throw recentError; + + const recentSongs = data?.map((item: ResponseSingLog) => ({ + id: item.id, + user_id: item.user_id, + song_id: item.songs.id, + created_at: item.created_at, + title: item.songs.title, + artist: item.songs.artist, + num_tj: item.songs.num_tj, + num_ky: item.songs.num_ky, + })); + + // 가져온 song_id 목록을 사용하여 songs 테이블에서 정보를 가져옴 + const songIds = recentSongs.map(item => item.song_id); + + // tosings 테이블에서 해당 user_id와 song_id가 일치하는 레코드를 가져옴 + const { data: tosingSongs, error: tosingError } = await supabase + .from('tosings') + .select('song_id') + .eq('user_id', userId) + .in('song_id', songIds); + + if (tosingError) throw tosingError; + + const tosingSongIds = new Set(tosingSongs.map(item => item.song_id)); + + // tosingSongIds에 포함된 song_id를 가진 노래에 isInToSingList: true 추가 + const processedData = recentSongs.map(song => ({ + ...song, + isInToSingList: tosingSongIds.has(song.song_id), + })); + + return NextResponse.json({ success: true, data: processedData }); + } catch (error) { + console.error('Error in recent API:', error); + return NextResponse.json( + { success: false, error: 'Failed to get recent songs' }, + { status: 500 }, + ); + } +} diff --git a/apps/web/app/api/songs/tosing/arr/route.ts b/apps/web/app/api/songs/tosing/arr/route.ts new file mode 100644 index 0000000..69b5b6f --- /dev/null +++ b/apps/web/app/api/songs/tosing/arr/route.ts @@ -0,0 +1,42 @@ +import { NextResponse } from 'next/server'; + +import createClient from '@/lib/supabase/server'; +import { getAuthenticatedUser } from '@/utils/getAuthenticatedUser'; + +export async function POST(request: Request) { + try { + const supabase = await createClient(); // Supabase 클라이언트 생성 + const userId = await getAuthenticatedUser(supabase); // userId 가져오기 + const { songIds } = await request.json(); + + const { data: maxRow, error: maxError } = await supabase + .from('tosings') + .select('order_weight') + .eq('user_id', userId) + .order('order_weight', { ascending: false }) + .limit(1); + + if (maxError) throw maxError; + + const lastWeight = maxRow?.[0]?.order_weight ?? 0; + const newWeight = lastWeight + 1; + + const { error } = await supabase.from('tosings').insert( + songIds.map((songId: string) => ({ + user_id: userId, + song_id: songId, + order_weight: newWeight, + })), + ); + + if (error) throw error; + + return NextResponse.json({ success: true }); + } catch (error) { + console.error('Error in tosings API:', error); + return NextResponse.json( + { success: false, error: 'Failed to post tosings song' }, + { status: 500 }, + ); + } +} diff --git a/apps/web/app/api/songs/tosing/route.ts b/apps/web/app/api/songs/tosing/route.ts new file mode 100644 index 0000000..8bacbb5 --- /dev/null +++ b/apps/web/app/api/songs/tosing/route.ts @@ -0,0 +1,133 @@ +import { NextResponse } from 'next/server'; + +import createClient from '@/lib/supabase/server'; +import { getAuthenticatedUser } from '@/utils/getAuthenticatedUser'; + +export async function GET() { + try { + const supabase = await createClient(); // Supabase 클라이언트 생성 + const userId = await getAuthenticatedUser(supabase); // userId 가져오기 + + const { data, error } = await supabase + .from('tosings') + .select( + ` + order_weight, + songs ( + id, + title, + artist, + num_tj, + num_ky + ) +`, + ) + .eq('user_id', userId) + .order('order_weight'); + + if (error) { + return NextResponse.json( + { + success: false, + error: error?.message || 'Unknown error', + }, + { status: 500 }, + ); + } + + return NextResponse.json({ success: true, data }); + } catch (error) { + console.error('Error in tosings API:', error); + return NextResponse.json( + { success: false, error: 'Failed to get tosings song' }, + { status: 500 }, + ); + } +} + +export async function POST(request: Request) { + try { + const supabase = await createClient(); // Supabase 클라이언트 생성 + const userId = await getAuthenticatedUser(supabase); // userId 가져오기 + const { songId } = await request.json(); + + const { data: maxRow, error: maxError } = await supabase + .from('tosings') + .select('order_weight') + .eq('user_id', userId) + .order('order_weight', { ascending: false }) + .limit(1); + + if (maxError) throw maxError; + + const lastWeight = maxRow?.[0]?.order_weight ?? 0; + const newWeight = lastWeight + 1; + + const { error } = await supabase + .from('tosings') + .insert({ user_id: userId, song_id: songId, order_weight: newWeight }); + + if (error) throw error; + + return NextResponse.json({ success: true }); + } catch (error) { + console.error('Error in tosings API:', error); + return NextResponse.json( + { success: false, error: 'Failed to post tosings song' }, + { status: 500 }, + ); + } +} + +export async function PATCH(request: Request) { + try { + const supabase = await createClient(); // Supabase 클라이언트 생성 + const userId = await getAuthenticatedUser(supabase); // userId 가져오기 + const { songId, newWeight } = await request.json(); + + if (!songId || newWeight === undefined) { + return NextResponse.json( + { success: false, error: 'Missing songId or newSequence' }, + { status: 400 }, + ); + } + + const { error } = await supabase + .from('tosings') + .update({ order_weight: newWeight }) + .match({ user_id: userId, song_id: songId }); + if (error) throw error; + + return NextResponse.json({ success: true }); + } catch (error) { + console.error('Error in tosings API:', error); + return NextResponse.json( + { success: false, error: 'Failed to patch tosings song' }, + { status: 500 }, + ); + } +} + +export async function DELETE(request: Request) { + try { + const supabase = await createClient(); // Supabase 클라이언트 생성 + const userId = await getAuthenticatedUser(supabase); // userId 가져오기 + const { songId } = await request.json(); + + const { error } = await supabase + .from('tosings') + .delete() + .match({ user_id: userId, song_id: songId }) + .select('*'); // 삭제된 row의 sequence 값을 가져오기 위해 select('*') 추가 + + if (error) throw error; + + return NextResponse.json({ success: true }); + } catch (error) { + console.error('Error in tosings API:', error); + return NextResponse.json( + { success: false, error: 'Failed to delete tosings song' }, + { status: 500 }, + ); + } +} diff --git a/apps/web/app/api/total_stats/route.ts b/apps/web/app/api/total_stats/route.ts new file mode 100644 index 0000000..852b223 --- /dev/null +++ b/apps/web/app/api/total_stats/route.ts @@ -0,0 +1,51 @@ +import { NextResponse } from 'next/server'; + +import createClient from '@/lib/supabase/server'; + +// 유효한 카운트 타입 정의 +type CountType = 'sing_count' | 'like_count' | 'saved_count'; + +export async function POST(request: Request) { + try { + const supabase = await createClient(); + const { songId, countType, isMinus } = await request.json(); + + // countType 유효성 검사 + if (!['sing_count', 'like_count', 'saved_count'].includes(countType)) { + return NextResponse.json({ success: false, error: 'Invalid count type' }, { status: 400 }); + } + + const { data } = await supabase.from('total_stats').select('*').eq('song_id', songId).single(); + + if (data) { + // 기존 레코드 업데이트 + const { error: updateError } = await supabase + .from('total_stats') + .update({ + [countType]: data[countType as CountType] + (isMinus ? -1 : 1), + }) + .eq('song_id', songId); + + if (updateError) throw updateError; + } else { + // 새 레코드 생성 + const { error: insertError } = await supabase.from('total_stats').insert({ + song_id: songId, + [countType]: 1, + sing_count: countType === 'sing_count' ? 1 : 0, + like_count: countType === 'like_count' ? 1 : 0, + saved_count: countType === 'saved_count' ? 1 : 0, + }); + + if (insertError) throw insertError; + } + + return NextResponse.json({ success: true }); + } catch (error) { + console.error('Error in total_stats API:', error); + return NextResponse.json( + { success: false, error: 'Failed to update total_stats' }, + { status: 500 }, + ); + } +} diff --git a/apps/web/app/api/user_stats/route.ts b/apps/web/app/api/user_stats/route.ts new file mode 100644 index 0000000..6014711 --- /dev/null +++ b/apps/web/app/api/user_stats/route.ts @@ -0,0 +1,75 @@ +import { NextResponse } from 'next/server'; + +import createClient from '@/lib/supabase/server'; +import { getAuthenticatedUser } from '@/utils/getAuthenticatedUser'; + +export async function GET() { + const supabase = await createClient(); + const userId = await getAuthenticatedUser(supabase); + + const { data, error } = await supabase + .from('user_stats') + .select(`*, songs(*)`) + .eq('user_id', userId) + .order('sing_count', { ascending: false }); + + if (error) throw error; + + const parsedData = data?.map(item => ({ + userId: item.user_id, + songId: item.song_id, + singCount: item.sing_count, + lastSingAt: item.last_sing_at, + title: item.songs.title, + artist: item.songs.artist, + })); + + return NextResponse.json({ success: true, data: parsedData }); +} + +export async function POST(request: Request) { + try { + const supabase = await createClient(); // Supabase 클라이언트 생성 + const { songId } = await request.json(); + const userId = await getAuthenticatedUser(supabase); // userId 가져오기 + + const { data } = await supabase + .from('user_stats') + .select('*') + .eq('user_id', userId) + .eq('song_id', songId) + .single(); + + if (data) { + // 있다면 count 증가 + const { error: updateError } = await supabase + .from('user_stats') + .update({ + sing_count: data.sing_count + 1, + last_sing_at: new Date().toISOString(), // 현재 시각으로 갱신 + }) + .eq('song_id', songId) + .eq('user_id', userId); // userId 조건 추가 + + if (updateError) throw updateError; + } else { + // 없다면 새로운 레코드 생성 + const { error: insertError } = await supabase.from('user_stats').insert({ + song_id: songId, + user_id: userId, // userId 추가 + sing_count: 1, + last_sing_at: new Date().toISOString(), // 현재 시각 설정 + }); + + if (insertError) throw insertError; + } + + return NextResponse.json({ success: true }); + } catch (error) { + console.error('Error in tosings API:', error); + return NextResponse.json( + { success: false, error: 'Failed to post user_stats' }, + { status: 500 }, + ); + } +} diff --git a/apps/web/app/auth.tsx b/apps/web/app/auth.tsx new file mode 100644 index 0000000..6964120 --- /dev/null +++ b/apps/web/app/auth.tsx @@ -0,0 +1,31 @@ +'use client'; + +import { usePathname, useRouter } from 'next/navigation'; +import { useEffect } from 'react'; +import { toast } from 'sonner'; + +import useAuthStore from '@/stores/useAuthStore'; + +export default function AuthProvider({ children }: { children: React.ReactNode }) { + const router = useRouter(); + const pathname = usePathname(); + const { checkAuth } = useAuthStore(); + + useEffect(() => { + const handleAuth = async () => { + const allowPaths = ['/login', '/signup', 'update-password']; + + const isAuthenticated = await checkAuth(); + if (!isAuthenticated && !allowPaths.includes(pathname)) { + toast.error('로그인이 필요해요.', { + description: '로그인 후 이용해주세요.', + }); + router.push('/login'); + } + }; + + handleAuth(); + }, [pathname, router, checkAuth]); + + return <>{children}; +} diff --git a/apps/web/app/components/ErrorContnet.tsx b/apps/web/app/components/ErrorContnet.tsx new file mode 100644 index 0000000..0cd1b86 --- /dev/null +++ b/apps/web/app/components/ErrorContnet.tsx @@ -0,0 +1,26 @@ +'use client'; + +import { useSearchParams } from 'next/navigation'; +import { useEffect } from 'react'; + +export default function ErrorContent({ children }: { children: React.ReactNode }) { + const searchParams = useSearchParams(); + + useEffect(() => { + const error = searchParams.get('error'); + const errorCode = searchParams.get('error_code'); + const errorDescription = searchParams.get('error_description'); + + if (error) { + const errorMessage = { + code: errorCode || 'unknown', + message: errorDescription?.replace(/\+/g, ' ') || '인증 오류가 발생했습니다.', + type: error, + }; + + throw new Error(JSON.stringify(errorMessage)); + } + }, [searchParams]); + + return children; +} diff --git a/apps/web/app/components/LoadingOverlay.tsx b/apps/web/app/components/LoadingOverlay.tsx new file mode 100644 index 0000000..4aa4639 --- /dev/null +++ b/apps/web/app/components/LoadingOverlay.tsx @@ -0,0 +1,24 @@ +'use client'; + +import { useEffect, useState } from 'react'; + +import useLoadingStore from '@/stores/useLoadingStore'; + +export default function LoadingOverlay() { + const { isLoading } = useLoadingStore(); + const [isMounted, setIsMounted] = useState(false); + + useEffect(() => { + setIsMounted(true); + }, []); + + if (!isMounted) return null; + + if (!isLoading) return null; + + return ( +
+
+
+ ); +} diff --git a/apps/web/app/components/RankingList.tsx b/apps/web/app/components/RankingList.tsx new file mode 100644 index 0000000..6b22c30 --- /dev/null +++ b/apps/web/app/components/RankingList.tsx @@ -0,0 +1,69 @@ +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { UserSongStat } from '@/types/userStat'; +import { cn } from '@/utils/cn'; + +interface RankingItemProps extends UserSongStat { + rank: number; + className?: string; +} + +export function RankingItem({ rank, title, artist, singCount, className }: RankingItemProps) { + // 등수에 따른 색상 및 스타일 결정 + const getRankStyle = (rank: number) => { + switch (rank) { + case 1: + return 'bg-amber-500 text-white font-bold'; // 금메달 색상 + case 2: + return 'bg-gray-300 text-white font-bold'; // 은메달 색상 + case 3: + return 'bg-amber-700 text-white font-bold'; // 동메달 색상 + default: + return 'bg-muted text-muted-foreground'; + } + }; + + return ( +
+
+ {rank} +
+
+
+

{title}

+

{artist}

+
+
+

{singCount}회

+
+
+
+ ); +} + +interface RankingListProps { + title: string; + items: UserSongStat[]; + className?: string; +} + +export default function RankingList({ title, items, className }: RankingListProps) { + return ( + + + {title} + + +
+ {items.map((item, index) => ( + + ))} +
+
+
+ ); +} diff --git a/apps/web/app/components/messageDialog.tsx b/apps/web/app/components/messageDialog.tsx new file mode 100644 index 0000000..76edb10 --- /dev/null +++ b/apps/web/app/components/messageDialog.tsx @@ -0,0 +1,94 @@ +'use client'; + +import { AlertCircle, CheckCircle2, Info, XCircle } from 'lucide-react'; +import { useEffect } from 'react'; + +import { Button } from '@/components/ui/button'; +import { + Dialog, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog'; +import useModalStore from '@/stores/useModalStore'; +import { cn } from '@/utils/cn'; + +export default function MessageDialog() { + const { isOpen, title, message, variant, buttonText, onButtonClick, closeMessage } = + useModalStore(); + + // 버튼 클릭 핸들러 + const handleButtonClick = () => { + if (onButtonClick) { + onButtonClick(); + } + closeMessage(); + }; + + // ESC 키로 닫기 방지 (필요한 경우) + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === 'Escape' && isOpen) { + e.preventDefault(); + } + }; + + window.addEventListener('keydown', handleKeyDown); + return () => window.removeEventListener('keydown', handleKeyDown); + }, [isOpen]); + + // 아이콘 선택 + const IconComponent = (() => { + switch (variant) { + case 'success': + return CheckCircle2; + case 'error': + return XCircle; + case 'warning': + case 'info': + return AlertCircle; + default: + return Info; + } + })(); + + return ( + !open && closeMessage()}> + + +
+ + {title && {title}} +
+
+ +
+

{message}

+
+ + + + +
+
+ ); +} diff --git a/apps/web/app/components/ui/alert.tsx b/apps/web/app/components/ui/alert.tsx new file mode 100644 index 0000000..4ef8379 --- /dev/null +++ b/apps/web/app/components/ui/alert.tsx @@ -0,0 +1,60 @@ +import { type VariantProps, cva } from 'class-variance-authority'; +import * as React from 'react'; + +import { cn } from '@/utils/cn'; + +const alertVariants = cva( + 'relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current', + { + variants: { + variant: { + default: 'bg-card text-card-foreground', + destructive: + 'text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90', + }, + }, + defaultVariants: { + variant: 'default', + }, + }, +); + +function Alert({ + className, + variant, + ...props +}: React.ComponentProps<'div'> & VariantProps) { + return ( +
+ ); +} + +function AlertTitle({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function AlertDescription({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +export { Alert, AlertTitle, AlertDescription }; diff --git a/apps/web/app/components/ui/button.tsx b/apps/web/app/components/ui/button.tsx new file mode 100644 index 0000000..0065ddd --- /dev/null +++ b/apps/web/app/components/ui/button.tsx @@ -0,0 +1,56 @@ +import { Slot } from '@radix-ui/react-slot'; +import { type VariantProps, cva } from 'class-variance-authority'; +import * as React from 'react'; + +import { cn } from '@/utils/cn'; + +const buttonVariants = cva( + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", + { + variants: { + variant: { + default: 'bg-primary text-primary-foreground shadow-xs hover:bg-primary/90', + destructive: + 'bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60', + outline: + 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50', + secondary: 'bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80', + ghost: 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50', + link: 'text-primary underline-offset-4 hover:underline', + }, + size: { + default: 'h-9 px-4 py-2 has-[>svg]:px-3', + sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5', + lg: 'h-10 rounded-md px-6 has-[>svg]:px-4', + icon: 'size-9', + }, + }, + defaultVariants: { + variant: 'default', + size: 'default', + }, + }, +); + +function Button({ + className, + variant, + size, + asChild = false, + ...props +}: React.ComponentProps<'button'> & + VariantProps & { + asChild?: boolean; + }) { + const Comp = asChild ? Slot : 'button'; + + return ( + + ); +} + +export { Button, buttonVariants }; diff --git a/apps/web/app/components/ui/card.tsx b/apps/web/app/components/ui/card.tsx new file mode 100644 index 0000000..f8f021b --- /dev/null +++ b/apps/web/app/components/ui/card.tsx @@ -0,0 +1,75 @@ +import * as React from 'react'; + +import { cn } from '@/utils/cn'; + +function Card({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function CardHeader({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function CardTitle({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function CardDescription({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function CardAction({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function CardContent({ className, ...props }: React.ComponentProps<'div'>) { + return
; +} + +function CardFooter({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +export { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent }; diff --git a/apps/web/app/components/ui/checkbox.tsx b/apps/web/app/components/ui/checkbox.tsx new file mode 100644 index 0000000..ab2d9f3 --- /dev/null +++ b/apps/web/app/components/ui/checkbox.tsx @@ -0,0 +1,29 @@ +'use client'; + +import * as CheckboxPrimitive from '@radix-ui/react-checkbox'; +import { CheckIcon } from 'lucide-react'; +import * as React from 'react'; + +import { cn } from '@/utils/cn'; + +function Checkbox({ className, ...props }: React.ComponentProps) { + return ( + + + + + + ); +} + +export { Checkbox }; diff --git a/apps/web/app/components/ui/dialog.tsx b/apps/web/app/components/ui/dialog.tsx new file mode 100644 index 0000000..3333a55 --- /dev/null +++ b/apps/web/app/components/ui/dialog.tsx @@ -0,0 +1,121 @@ +'use client'; + +import * as DialogPrimitive from '@radix-ui/react-dialog'; +import { XIcon } from 'lucide-react'; +import * as React from 'react'; + +import { cn } from '@/utils/cn'; + +function Dialog({ ...props }: React.ComponentProps) { + return ; +} + +function DialogTrigger({ ...props }: React.ComponentProps) { + return ; +} + +function DialogPortal({ ...props }: React.ComponentProps) { + return ; +} + +function DialogClose({ ...props }: React.ComponentProps) { + return ; +} + +function DialogOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DialogContent({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + {children} + + + Close + + + + ); +} + +function DialogHeader({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function DialogFooter({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function DialogTitle({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function DialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogOverlay, + DialogPortal, + DialogTitle, + DialogTrigger, +}; diff --git a/apps/web/app/components/ui/dropdown-menu.tsx b/apps/web/app/components/ui/dropdown-menu.tsx new file mode 100644 index 0000000..8ebf7aa --- /dev/null +++ b/apps/web/app/components/ui/dropdown-menu.tsx @@ -0,0 +1,228 @@ +'use client'; + +import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'; +import { CheckIcon, ChevronRightIcon, CircleIcon } from 'lucide-react'; +import * as React from 'react'; + +import { cn } from '@/utils/cn'; + +function DropdownMenu({ ...props }: React.ComponentProps) { + return ; +} + +function DropdownMenuPortal({ + ...props +}: React.ComponentProps) { + return ; +} + +function DropdownMenuTrigger({ + ...props +}: React.ComponentProps) { + return ; +} + +function DropdownMenuContent({ + className, + sideOffset = 4, + ...props +}: React.ComponentProps) { + return ( + + + + ); +} + +function DropdownMenuGroup({ ...props }: React.ComponentProps) { + return ; +} + +function DropdownMenuItem({ + className, + inset, + variant = 'default', + ...props +}: React.ComponentProps & { + inset?: boolean; + variant?: 'default' | 'destructive'; +}) { + return ( + + ); +} + +function DropdownMenuCheckboxItem({ + className, + children, + checked, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ); +} + +function DropdownMenuRadioGroup({ + ...props +}: React.ComponentProps) { + return ; +} + +function DropdownMenuRadioItem({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ); +} + +function DropdownMenuLabel({ + className, + inset, + ...props +}: React.ComponentProps & { + inset?: boolean; +}) { + return ( + + ); +} + +function DropdownMenuSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<'span'>) { + return ( + + ); +} + +function DropdownMenuSub({ ...props }: React.ComponentProps) { + return ; +} + +function DropdownMenuSubTrigger({ + className, + inset, + children, + ...props +}: React.ComponentProps & { + inset?: boolean; +}) { + return ( + + {children} + + + ); +} + +function DropdownMenuSubContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export { + DropdownMenu, + DropdownMenuPortal, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuLabel, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuSub, + DropdownMenuSubTrigger, + DropdownMenuSubContent, +}; diff --git a/apps/web/app/components/ui/input.tsx b/apps/web/app/components/ui/input.tsx new file mode 100644 index 0000000..3245b33 --- /dev/null +++ b/apps/web/app/components/ui/input.tsx @@ -0,0 +1,21 @@ +import * as React from 'react'; + +import { cn } from '@/utils/cn'; + +function Input({ className, type, ...props }: React.ComponentProps<'input'>) { + return ( + + ); +} + +export { Input }; diff --git a/apps/web/app/components/ui/label.tsx b/apps/web/app/components/ui/label.tsx new file mode 100644 index 0000000..aedcfcd --- /dev/null +++ b/apps/web/app/components/ui/label.tsx @@ -0,0 +1,21 @@ +'use client'; + +import * as LabelPrimitive from '@radix-ui/react-label'; +import * as React from 'react'; + +import { cn } from '@/utils/cn'; + +function Label({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +export { Label }; diff --git a/apps/web/app/components/ui/scroll-area.tsx b/apps/web/app/components/ui/scroll-area.tsx new file mode 100644 index 0000000..b1731ae --- /dev/null +++ b/apps/web/app/components/ui/scroll-area.tsx @@ -0,0 +1,56 @@ +'use client'; + +import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area'; +import * as React from 'react'; + +import { cn } from '@/utils/cn'; + +function ScrollArea({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + {children} + + + + + ); +} + +function ScrollBar({ + className, + orientation = 'vertical', + ...props +}: React.ComponentProps) { + return ( + + + + ); +} + +export { ScrollArea, ScrollBar }; diff --git a/apps/web/app/components/ui/separator.tsx b/apps/web/app/components/ui/separator.tsx new file mode 100644 index 0000000..649abe0 --- /dev/null +++ b/apps/web/app/components/ui/separator.tsx @@ -0,0 +1,28 @@ +'use client'; + +import * as SeparatorPrimitive from '@radix-ui/react-separator'; +import * as React from 'react'; + +import { cn } from '@/utils/cn'; + +function Separator({ + className, + orientation = 'horizontal', + decorative = true, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export { Separator }; diff --git a/apps/web/app/components/ui/sheet.tsx b/apps/web/app/components/ui/sheet.tsx new file mode 100644 index 0000000..c2c1abf --- /dev/null +++ b/apps/web/app/components/ui/sheet.tsx @@ -0,0 +1,130 @@ +'use client'; + +import * as SheetPrimitive from '@radix-ui/react-dialog'; +import { XIcon } from 'lucide-react'; +import * as React from 'react'; + +import { cn } from '@/utils/cn'; + +function Sheet({ ...props }: React.ComponentProps) { + return ; +} + +function SheetTrigger({ ...props }: React.ComponentProps) { + return ; +} + +function SheetClose({ ...props }: React.ComponentProps) { + return ; +} + +function SheetPortal({ ...props }: React.ComponentProps) { + return ; +} + +function SheetOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function SheetContent({ + className, + children, + side = 'right', + ...props +}: React.ComponentProps & { + side?: 'top' | 'right' | 'bottom' | 'left'; +}) { + return ( + + + + {children} + + + Close + + + + ); +} + +function SheetHeader({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function SheetFooter({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function SheetTitle({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function SheetDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export { + Sheet, + SheetTrigger, + SheetClose, + SheetContent, + SheetHeader, + SheetFooter, + SheetTitle, + SheetDescription, +}; diff --git a/apps/web/app/components/ui/sonner.tsx b/apps/web/app/components/ui/sonner.tsx new file mode 100644 index 0000000..90197d1 --- /dev/null +++ b/apps/web/app/components/ui/sonner.tsx @@ -0,0 +1,25 @@ +'use client'; + +import { useTheme } from 'next-themes'; +import { Toaster as Sonner, ToasterProps } from 'sonner'; + +function Toaster({ ...props }: ToasterProps) { + const { theme = 'system' } = useTheme(); + + return ( + + ); +} + +export { Toaster }; diff --git a/apps/web/app/components/ui/tabs.tsx b/apps/web/app/components/ui/tabs.tsx new file mode 100644 index 0000000..784b792 --- /dev/null +++ b/apps/web/app/components/ui/tabs.tsx @@ -0,0 +1,54 @@ +'use client'; + +import * as TabsPrimitive from '@radix-ui/react-tabs'; +import * as React from 'react'; + +import { cn } from '@/utils/cn'; + +function Tabs({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function TabsList({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function TabsTrigger({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function TabsContent({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +export { Tabs, TabsList, TabsTrigger, TabsContent }; diff --git a/apps/web/app/error.tsx b/apps/web/app/error.tsx new file mode 100644 index 0000000..e1403e6 --- /dev/null +++ b/apps/web/app/error.tsx @@ -0,0 +1,100 @@ +'use client'; + +import { AlertCircle, Home } from 'lucide-react'; +import { useEffect } from 'react'; + +import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; +import { Button } from '@/components/ui/button'; +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from '@/components/ui/card'; + +type ErrorPageProps = { + error: Error; + reset: () => void; +}; + +interface AuthError { + code: string; + message: string; + type: string; +} + +export default function Error({ error }: ErrorPageProps) { + const errorMessage = error.message; + let errorDetails: AuthError | null = null; + let isAuthError = false; + + // 에러 메시지 파싱 시도 + try { + errorDetails = JSON.parse(error.message) as AuthError; + isAuthError = Boolean(errorDetails?.code); + } catch { + // 파싱 실패 시 기본 메시지 사용 + } + + // 에러 로깅 + useEffect(() => { + console.error('페이지 에러:', error); + }, [error]); + + return ( +
+ + + + {isAuthError ? '인증 오류' : '오류가 발생했습니다'} + + + {isAuthError + ? '인증 과정에서 문제가 발생했습니다' + : '페이지를 로드하는 중 문제가 발생했습니다'} + + + + + + + + {errorDetails?.code ? `에러 코드: ${errorDetails.code}` : '오류 발생'} + + + {errorDetails + ? decodeURIComponent(errorDetails.message) + : errorMessage || '서버에서 오류가 발생했습니다.'} + + + + {errorDetails?.type === 'access_denied' && ( +
+

+ 인증 링크가 만료되었거나 유효하지 않습니다. 새로운 인증 링크를 요청하시거나 다시 + 시도해주세요. +

+
+ )} + + {!isAuthError && ( +
+

+ 일시적인 문제일 수 있습니다. 다시 시도하거나 홈으로 돌아가 다른 기능을 이용해보세요. +

+
+ )} +
+ + + + +
+
+ ); +} diff --git a/apps/web/app/error/page.tsx b/apps/web/app/error/page.tsx new file mode 100644 index 0000000..33dc9c7 --- /dev/null +++ b/apps/web/app/error/page.tsx @@ -0,0 +1,27 @@ +'use client'; + +import { useSearchParams } from 'next/navigation'; + +export default function ErrorPage() { + const searchParams = useSearchParams(); + const errorMessage = searchParams.get('message'); + + return ( +
+

인증 오류

+
+

+ {errorMessage ? errorMessage : '알 수 없는 오류가 발생했습니다.'} +

+
+ + +
+
+
+ ); +} diff --git a/apps/web/app/globals.css b/apps/web/app/globals.css index e3734be..8d74ca2 100644 --- a/apps/web/app/globals.css +++ b/apps/web/app/globals.css @@ -1,42 +1,144 @@ -:root { - --background: #ffffff; - --foreground: #171717; -} +@import 'tailwindcss'; +@import 'tw-animate-css'; -@media (prefers-color-scheme: dark) { - :root { - --background: #0a0a0a; - --foreground: #ededed; - } -} +@custom-variant dark (&:is(.dark *)); + +/* @theme { + --color-background: #121212; + --color-primary: #1db954; + --color-secondary: #191414; + --color-text-primary: #ffffff; + --color-text-secondary: #b3b3b3; + --color-text-accent: #1ed760; +} */ -html, -body { - max-width: 100vw; - overflow-x: hidden; +@theme inline { + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); + --color-brand-tj: var(--brand-tj); + --color-brand-ky: var(--brand-ky); } -body { - color: var(--foreground); - background: var(--background); - font-family: Arial, Helvetica, sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } } -* { - box-sizing: border-box; - padding: 0; - margin: 0; +:root { + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + /* --primary: oklch(0.726 0.202 145.92); + --primary-foreground: oklch(0.985 0 0); */ + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.65 0.15 250); /* 부드러운 파란색 */ + --accent-foreground: oklch(0.985 0 0); /* 흰색 */ + /* --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); */ + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); + /* oklch로는 표현 ff4a00 */ + --brand-tj: oklch(66.48% 0.226 36.37); + --brand-ky: oklch(61.23% 0.159 288.46); } -a { - color: inherit; - text-decoration: none; +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + /* --primary: oklch(0.726 0.202 145.92); + --primary-foreground: oklch(0.985 0 0); */ + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); } -@media (prefers-color-scheme: dark) { - html { - color-scheme: dark; - } +button { + @apply cursor-pointer; } diff --git a/apps/web/app/home/AddListModal.tsx b/apps/web/app/home/AddListModal.tsx new file mode 100644 index 0000000..52e7d6c --- /dev/null +++ b/apps/web/app/home/AddListModal.tsx @@ -0,0 +1,102 @@ +'use client'; + +import { Button } from '@/components/ui/button'; +import { + Dialog, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog'; +import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; +import useAddListModal from '@/hooks/useAddSongList'; +import useSongStore from '@/stores/useSongStore'; + +import ModalSongItem from './ModalSongItem'; + +interface AddListModalProps { + isOpen: boolean; + onClose: () => void; +} + +export default function AddListModal({ isOpen, onClose }: AddListModalProps) { + const { + activeTab, + setActiveTab, + songSelected, + handleToggleSelect, + handleConfirmAdd, + totalSelectedCount, + } = useAddListModal(); + + const { likedSongs, recentSongs } = useSongStore(); + + const handleClickConfirm = () => { + handleConfirmAdd(); + onClose(); + }; + + return ( + !open && onClose()}> + + + 플레이리스트에 추가할 노래 선택 + + +
+ +
+ + 좋아요한 노래 + 최근 부른 노래 + +
+ +
+ +
+ {likedSongs && + likedSongs.map(song => ( + + ))} +
+
+ + +
+ {recentSongs && + recentSongs.map(song => ( + + ))} +
+
+
+
+
+ + + + + +
+
+ ); +} diff --git a/apps/web/app/home/ModalSongItem.tsx b/apps/web/app/home/ModalSongItem.tsx new file mode 100644 index 0000000..aa394ea --- /dev/null +++ b/apps/web/app/home/ModalSongItem.tsx @@ -0,0 +1,34 @@ +import { Checkbox } from '@/components/ui/checkbox'; +import { AddListModalSong } from '@/types/song'; +import { cn } from '@/utils/cn'; + +// 노래 항목 컴포넌트 +export default function ModalSongItem({ + song, + isSelected, + onToggleSelect, +}: { + song: AddListModalSong; + isSelected: boolean; + onToggleSelect: (id: string) => void; +}) { + return ( +
+ onToggleSelect(song.id)} + disabled={song.isInToSingList} + /> +
+

{song.title}

+

{song.artist}

+
+
+ ); +} diff --git a/apps/web/app/home/SongCard.tsx b/apps/web/app/home/SongCard.tsx new file mode 100644 index 0000000..51c8609 --- /dev/null +++ b/apps/web/app/home/SongCard.tsx @@ -0,0 +1,108 @@ +'use client'; + +import { useSortable } from '@dnd-kit/sortable'; +import { CSS } from '@dnd-kit/utilities'; +import { ChevronsDown, ChevronsUp, GripVertical, Mic, Trash } from 'lucide-react'; + +import { Card } from '@/components/ui/card'; +import { Song } from '@/types/song'; + +interface SongCardProps { + song: Song; + onSung: () => void; + onDelete: () => void; + onMoveToTop: () => void; + onMoveToBottom: () => void; +} + +export default function SongCard({ + song, + onSung, + onDelete, + onMoveToTop, + onMoveToBottom, +}: SongCardProps) { + const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id: song.id }); + + const { title, artist, num_tj, num_ky } = song; + const style = { + transform: CSS.Transform.toString(transform), + transition, + }; + + return ( + + {/* 메인 콘텐츠 영역 */} +
+ {/* 노래 정보 */} +
+ {/* 제목 및 가수 */} +
+

{title}

+

{artist}

+
+ + {/* 노래방 번호 */} +
+
+ TJ + {num_tj} +
+
+ 금영 + {num_ky} +
+
+
+ + {/* 버튼 영역 - 우측 하단에 고정 */} +
+ + + + + + + +
+
+ {/* 드래그 핸들 */} +
+ +
+
+ ); +} diff --git a/apps/web/app/home/SongList.tsx b/apps/web/app/home/SongList.tsx new file mode 100644 index 0000000..2fcfef2 --- /dev/null +++ b/apps/web/app/home/SongList.tsx @@ -0,0 +1,75 @@ +'use client'; + +import { + DndContext, + KeyboardSensor, + PointerSensor, + closestCenter, + useSensor, + useSensors, +} from '@dnd-kit/core'; +import { restrictToVerticalAxis } from '@dnd-kit/modifiers'; +import { + SortableContext, + sortableKeyboardCoordinates, + verticalListSortingStrategy, +} from '@dnd-kit/sortable'; +import { Loader2 } from 'lucide-react'; + +import useSong from '@/hooks/useSong'; +import useLoadingStore from '@/stores/useLoadingStore'; +import useSongStore from '@/stores/useSongStore'; +import { ToSing } from '@/types/song'; + +import SongCard from './SongCard'; + +export default function SongList() { + const { handleDragEnd, handleDelete, handleMoveToTop, handleMoveToBottom, handleSung } = + useSong(); + const { toSings } = useSongStore(); + const { isInitialLoading } = useLoadingStore(); + + const sensors = useSensors( + useSensor(PointerSensor), + useSensor(KeyboardSensor, { + coordinateGetter: sortableKeyboardCoordinates, + }), + ); + + return ( + + item.songs.id)} + strategy={verticalListSortingStrategy} + > +
+ {isInitialLoading && ( +
+ +
+ )} + {!isInitialLoading && toSings.length === 0 && ( +
+

노래방 플레이리스트가 없습니다.

+
+ )} + {toSings.map((item: ToSing, index: number) => ( + handleSung(item.songs.id)} + onDelete={() => handleDelete(item.songs.id)} + onMoveToTop={() => handleMoveToTop(item.songs.id, index)} + onMoveToBottom={() => handleMoveToBottom(item.songs.id, index)} + /> + ))} +
+
+
+ ); +} diff --git a/apps/web/app/home/page.tsx b/apps/web/app/home/page.tsx new file mode 100644 index 0000000..03a55b7 --- /dev/null +++ b/apps/web/app/home/page.tsx @@ -0,0 +1,36 @@ +'use client'; + +import { AirplayIcon } from 'lucide-react'; +import { useState } from 'react'; + +import { Button } from '@/components/ui/button'; +import { ScrollArea } from '@/components/ui/scroll-area'; + +import AddListModal from './AddListModal'; +import SongList from './SongList'; + +export default function HomePage() { + const [isModalOpen, setIsModalOpen] = useState(false); + + return ( +
+
+

노래방 플레이리스트

+ +
+ + + + + setIsModalOpen(false)} /> +
+ ); +} diff --git a/apps/web/app/hooks/useAddSongList.ts b/apps/web/app/hooks/useAddSongList.ts new file mode 100644 index 0000000..34383b3 --- /dev/null +++ b/apps/web/app/hooks/useAddSongList.ts @@ -0,0 +1,71 @@ +'use client'; + +import { useEffect, useState } from 'react'; + +import useLoadingStore from '@/stores/useLoadingStore'; +import useSongStore from '@/stores/useSongStore'; + +export default function useAddSongList() { + const [activeTab, setActiveTab] = useState('liked'); + + const [songSelected, setSongSelected] = useState([]); + const { startLoading, stopLoading, initialLoading } = useLoadingStore(); + + const { refreshLikedSongs, refreshRecentSongs, postToSingSongs } = useSongStore(); + + const handleApiCall = async (apiCall: () => Promise, onError?: () => void) => { + startLoading(); + try { + const result = await apiCall(); + return result; + } catch (error) { + console.error('API 호출 실패:', error); + if (onError) onError(); + return null; + } finally { + stopLoading(); + } + }; + + const getLikedSongs = async () => { + await handleApiCall(async () => { + refreshLikedSongs(); + }); + }; + + const getRecentSongs = async () => { + await handleApiCall(async () => { + refreshRecentSongs(); + }); + }; + + const handleToggleSelect = (songId: string) => { + setSongSelected(prev => + prev.includes(songId) ? prev.filter(id => id !== songId) : [...prev, songId], + ); + }; + + const handleConfirmAdd = async () => { + await handleApiCall(async () => { + await postToSingSongs(songSelected); + setSongSelected([]); + }); + }; + + const totalSelectedCount = songSelected.length; + + useEffect(() => { + getLikedSongs(); + getRecentSongs(); + initialLoading(); + }, []); + + return { + activeTab, + setActiveTab, + songSelected, + handleToggleSelect, + handleConfirmAdd, + totalSelectedCount, + }; +} diff --git a/apps/web/app/hooks/useSearch.ts b/apps/web/app/hooks/useSearch.ts new file mode 100644 index 0000000..609c871 --- /dev/null +++ b/apps/web/app/hooks/useSearch.ts @@ -0,0 +1,136 @@ +import { useEffect, useState } from 'react'; + +import { deleteLikedSongs, postLikedSongs } from '@/lib/api/like_activites'; +import { getSearch } from '@/lib/api/search'; +import { deleteToSingSongs, postToSingSongs } from '@/lib/api/tosings'; +import { postTotalStats } from '@/lib/api/total_stats'; +import useLoadingStore from '@/stores/useLoadingStore'; +import { Method } from '@/types/common'; +import { SearchSong } from '@/types/song'; + +type SearchType = 'title' | 'artist'; + +export default function useSearch() { + const [search, setSearch] = useState(''); + const [searchResults, setSearchResults] = useState([]); + const [searchType, setSearchType] = useState('title'); + const { startLoading, stopLoading, initialLoading } = useLoadingStore(); + const [isModal, setIsModal] = useState(false); + const [selectedSong, setSelectedSong] = useState(null); + + const handleApiCall = async (apiCall: () => Promise, onError?: () => void) => { + startLoading(); + try { + const result = await apiCall(); + return result; + } catch (error) { + console.error('API 호출 실패:', error); + if (onError) onError(); + return null; + } finally { + stopLoading(); + } + }; + + const handleSearchTypeChange = (value: string) => { + setSearchType(value as SearchType); + }; + + const handleSearch = async () => { + if (!search) return; + + await handleApiCall( + async () => { + const { success, data } = await getSearch(search, searchType); + if (success) { + setSearchResults(data); + } else { + setSearchResults([]); + } + return success; + }, + () => { + setSearchResults([]); + }, + ); + }; + + const handleToggleToSing = async (songId: string, method: Method) => { + await handleApiCall(async () => { + let response; + if (method === 'POST') { + response = await postToSingSongs({ songId }); + } else { + response = await deleteToSingSongs({ songId }); + } + + const { success } = response; + if (success) { + const newResults = searchResults.map(song => { + if (song.id === songId) { + return { ...song, isToSing: !song.isToSing }; + } + return song; + }); + setSearchResults(newResults); + } else { + handleSearch(); + } + return success; + }, handleSearch); + }; + + const handleToggleLike = async (songId: string, method: Method) => { + await handleApiCall(async () => { + await postTotalStats({ + songId, + countType: 'like_count', + isMinus: method === 'DELETE', + }); + + let response; + if (method === 'POST') { + response = await postLikedSongs({ songId }); + } else { + response = await deleteLikedSongs({ songId }); + } + + const { success } = response; + const newResults = searchResults.map(song => { + if (song.id === songId) { + return { ...song, isLiked: !song.isLiked }; + } + return song; + }); + setSearchResults(newResults); + + return success; + }, handleSearch); + }; + + const handleOpenPlaylistModal = (song: SearchSong) => { + setSelectedSong(song); + setIsModal(true); + }; + + const handleSavePlaylist = async () => {}; + + useEffect(() => { + initialLoading(); + }, []); + + return { + search, + setSearch, + searchResults, + searchType, + handleSearchTypeChange, + handleSearch, + handleToggleToSing, + handleToggleLike, + handleOpenPlaylistModal, + isModal, + selectedSong, + handleSavePlaylist, + }; +} diff --git a/apps/web/app/hooks/useSong.ts b/apps/web/app/hooks/useSong.ts new file mode 100644 index 0000000..004c92e --- /dev/null +++ b/apps/web/app/hooks/useSong.ts @@ -0,0 +1,160 @@ +// hooks/useToSingList.ts +import { DragEndEvent } from '@dnd-kit/core'; +import { arrayMove } from '@dnd-kit/sortable'; +import { useEffect } from 'react'; + +import { postSingLog } from '@/lib/api/sing_logs'; +import { patchToSingSongs } from '@/lib/api/tosings'; +import { postTotalStats } from '@/lib/api/total_stats'; +import { postUserStats } from '@/lib/api/user_stats'; +import useAuthStore from '@/stores/useAuthStore'; +import useLoadingStore from '@/stores/useLoadingStore'; +import useSongStore from '@/stores/useSongStore'; + +export default function useSong() { + const { startLoading, stopLoading, initialLoading } = useLoadingStore(); + const { isAuthenticated } = useAuthStore(); + const { toSings, swapToSings, refreshToSings, deleteToSingSong } = useSongStore(); + + const handleApiCall = async (apiCall: () => Promise, onError?: () => void) => { + startLoading(); + try { + const result = await apiCall(); + return result; + } catch (error) { + console.error('API 호출 실패:', error); + if (onError) onError(); + return null; + } finally { + stopLoading(); + } + }; + + const handleSearch = async () => { + await handleApiCall(async () => { + refreshToSings(); + }); + }; + + const handleDragEnd = async (event: DragEndEvent) => { + await handleApiCall(async () => { + const { active, over } = event; + + if (!over || active.id === over.id) return; + + const oldIndex = toSings.findIndex(item => item.songs.id === active.id); + const newIndex = toSings.findIndex(item => item.songs.id === over.id); + + if (oldIndex === newIndex) return; + + const newItems = arrayMove(toSings, oldIndex, newIndex); + const prevItem = newItems[newIndex - 1]; + const nextItem = newItems[newIndex + 1]; + + let newWeight; + + if (!prevItem && nextItem) { + // 제일 앞으로 이동한 경우 + newWeight = toSings[0].order_weight - 1; + } else if (prevItem && !nextItem) { + // 제일 뒤로 이동한 경우 + newWeight = toSings[toSings.length - 1].order_weight + 1; + } else { + // 중간에 삽입 + newWeight = (prevItem.order_weight + nextItem.order_weight) / 2; + } + + const response = await patchToSingSongs({ + songId: active.id as string, + newWeight, + }); + const { success } = await response.json(); + + swapToSings(newItems); + return success; + }, handleSearch); + }; + + const handleDelete = async (songId: string) => { + await handleApiCall(async () => { + await deleteToSingSong(songId); + swapToSings(toSings.filter(item => item.songs.id !== songId)); + // await fetch('/api/songs/tosing/arr', { + // method: 'DELETE', + // body: JSON.stringify({ songIds }), + // headers: { 'Content-Type': 'application/json' }, + // }); + // swapToSings(toSings.filter(item => !songIds.includes(item.songs.id))); + // refreshLikedSongs(); + // refreshRecentSongs(); + }); + }; + + const handleMoveToTop = async (songId: string, oldIndex: number) => { + if (oldIndex === 0) return; + + await handleApiCall(async () => { + const newItems = arrayMove(toSings, oldIndex, 0); + const newWeight = toSings[0].order_weight - 1; + + const response = await patchToSingSongs({ + songId: songId, + newWeight, + }); + const { success } = await response.json(); + swapToSings(newItems); + return success; + }, handleSearch); + }; + + const handleMoveToBottom = async (songId: string, oldIndex: number) => { + const lastIndex = toSings.length - 1; + if (oldIndex === lastIndex) return; + + await handleApiCall(async () => { + const newItems = arrayMove(toSings, oldIndex, lastIndex); + const newWeight = toSings[lastIndex].order_weight + 1; + + const response = await patchToSingSongs({ + songId: songId, + newWeight, + }); + const { success } = await response.json(); + swapToSings(newItems); + return success; + }, handleSearch); + }; + + const handleSung = async (songId: string) => { + await handleApiCall(async () => { + // 순서 이동 + const oldIndex = toSings.findIndex(item => item.songs.id === songId); + await handleMoveToBottom(songId, oldIndex); + + // 통계 업데이트 + await Promise.all([ + postTotalStats({ songId, countType: 'sing', isMinus: false }), + postUserStats(songId), + postSingLog(songId), + handleDelete(songId), + ]); + }, handleSearch); + }; + + // 초기 데이터 로드 + useEffect(() => { + if (isAuthenticated) { + handleSearch(); + initialLoading(); + } + }, [isAuthenticated]); + + return { + handleDragEnd, + handleSearch, + handleDelete, + handleMoveToTop, + handleMoveToBottom, + handleSung, + }; +} diff --git a/apps/web/app/hooks/useSongInfo.ts b/apps/web/app/hooks/useSongInfo.ts new file mode 100644 index 0000000..23f2acb --- /dev/null +++ b/apps/web/app/hooks/useSongInfo.ts @@ -0,0 +1,67 @@ +'use client'; + +import { useEffect, useState } from 'react'; + +import useLoadingStore from '@/stores/useLoadingStore'; +import useSongStore from '@/stores/useSongStore'; + +export default function useAddSongList() { + const [deleteLikeSelected, setDeleteLikeSelected] = useState([]); + const { startLoading, stopLoading, initialLoading } = useLoadingStore(); + + const { refreshLikedSongs, refreshRecentSongs, deleteLikedSongs } = useSongStore(); + + const handleApiCall = async (apiCall: () => Promise, onError?: () => void) => { + startLoading(); + try { + const result = await apiCall(); + return result; + } catch (error) { + console.error('API 호출 실패:', error); + if (onError) onError(); + return null; + } finally { + stopLoading(); + } + }; + + const getLikedSongs = async () => { + await handleApiCall(async () => { + refreshLikedSongs(); + }); + }; + + const getRecentSongs = async () => { + await handleApiCall(async () => { + refreshRecentSongs(); + }); + }; + + const handleToggleSelect = (songId: string) => { + setDeleteLikeSelected(prev => + prev.includes(songId) ? prev.filter(id => id !== songId) : [...prev, songId], + ); + }; + + const handleDelete = async () => { + await handleApiCall(async () => { + await deleteLikedSongs(deleteLikeSelected); + setDeleteLikeSelected([]); + }); + }; + + const totalSelectedCount = deleteLikeSelected.length; + + useEffect(() => { + getLikedSongs(); + getRecentSongs(); + initialLoading(); + }, []); + + return { + deleteLikeSelected, + totalSelectedCount, + handleToggleSelect, + handleDelete, + }; +} diff --git a/apps/web/app/hooks/useUserStat.ts b/apps/web/app/hooks/useUserStat.ts new file mode 100644 index 0000000..56d334a --- /dev/null +++ b/apps/web/app/hooks/useUserStat.ts @@ -0,0 +1,23 @@ +'use client'; + +import { useEffect, useState } from 'react'; + +import { getUserStats } from '@/lib/api/user_stats'; +import { UserSongStat } from '@/types/userStat'; + +export default function useUserStat() { + const [userStat, setUserStat] = useState([]); + + const getUserStat = async () => { + const { success, data } = await getUserStats(); + if (success) { + setUserStat(data); + } + }; + + useEffect(() => { + getUserStat(); + }, []); + + return { userStat, getUserStat }; +} diff --git a/apps/web/app/layout.tsx b/apps/web/app/layout.tsx index 42fc323..06d2b3c 100644 --- a/apps/web/app/layout.tsx +++ b/apps/web/app/layout.tsx @@ -1,20 +1,21 @@ -import type { Metadata } from "next"; -import { Geist, Geist_Mono } from "next/font/google"; -import "./globals.css"; +import { Analytics } from '@vercel/analytics/react'; +import { SpeedInsights } from '@vercel/speed-insights/next'; +import type { Metadata } from 'next'; +import { Toaster } from 'sonner'; -const geistSans = Geist({ - variable: "--font-geist-sans", - subsets: ["latin"], -}); +import LoadingOverlay from '@/components/LoadingOverlay'; +import MessageDialog from '@/components/messageDialog'; -const geistMono = Geist_Mono({ - variable: "--font-geist-mono", - subsets: ["latin"], -}); +import ErrorWrapper from './ErrorWrapper'; +import Footer from './Footer'; +import Header from './Header'; +import AuthProvider from './auth'; +import './globals.css'; +import QueryProvider from './query'; export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: 'Singcode', + description: 'Singcode', }; export default function RootLayout({ @@ -23,9 +24,34 @@ export default function RootLayout({ children: React.ReactNode; }>) { return ( - - - {children} + + + + + +
+
+
{children}
+
+
+ + + + + + + +
+
+
); diff --git a/apps/web/app/lib/api/like_activites.ts b/apps/web/app/lib/api/like_activites.ts new file mode 100644 index 0000000..ab99f72 --- /dev/null +++ b/apps/web/app/lib/api/like_activites.ts @@ -0,0 +1,42 @@ +export async function getLikedSongs() { + const response = await fetch('/api/songs/like'); + if (!response.ok) { + throw new Error('Failed to fetch liked songs'); + } + return response.json(); +} +export async function postLikedSongs(body: { songId: string }) { + const response = await fetch('/api/songs/like', { + method: 'POST', + body: JSON.stringify(body), + headers: { 'Content-Type': 'application/json' }, + }); + if (!response.ok) { + throw new Error('Failed to post liked songs'); + } + return response.json(); +} + +export async function deleteLikedSongs(body: { songId: string }) { + const response = await fetch('/api/songs/like', { + method: 'DELETE', + body: JSON.stringify(body), + headers: { 'Content-Type': 'application/json' }, + }); + if (!response.ok) { + throw new Error('Failed to delete liked songs'); + } + return response.json(); +} + +export async function deleteLikedSongsArray(body: { songIds: string[] }) { + const response = await fetch('/api/songs/like/arr', { + method: 'DELETE', + body: JSON.stringify(body), + headers: { 'Content-Type': 'application/json' }, + }); + if (!response.ok) { + throw new Error('Failed to delete liked songs array'); + } + return response.json(); +} diff --git a/apps/web/app/lib/api/search.ts b/apps/web/app/lib/api/search.ts new file mode 100644 index 0000000..936a7c9 --- /dev/null +++ b/apps/web/app/lib/api/search.ts @@ -0,0 +1,7 @@ +export async function getSearch(search: string, searchType: string) { + const response = await fetch(`/api/search?q=${search}&type=${searchType}`); + if (!response.ok) { + throw new Error('Failed to search songs'); + } + return response.json(); +} diff --git a/apps/web/app/lib/api/sing_logs.ts b/apps/web/app/lib/api/sing_logs.ts new file mode 100644 index 0000000..39fd03d --- /dev/null +++ b/apps/web/app/lib/api/sing_logs.ts @@ -0,0 +1,11 @@ +export async function postSingLog(songId: string) { + const response = await fetch(`/api/songs/sing_logs`, { + method: 'POST', + body: JSON.stringify({ songId }), + headers: { 'Content-Type': 'application/json' }, + }); + if (!response.ok) { + throw new Error('Failed to post sing log'); + } + return response.json(); +} diff --git a/apps/web/app/lib/api/songs.ts b/apps/web/app/lib/api/songs.ts new file mode 100644 index 0000000..52ae7ba --- /dev/null +++ b/apps/web/app/lib/api/songs.ts @@ -0,0 +1,7 @@ +export async function getRecentSongs() { + const response = await fetch('/api/songs/recent'); + if (!response.ok) { + throw new Error('Failed to fetch recent songs'); + } + return response.json(); +} diff --git a/apps/web/app/lib/api/tosings.ts b/apps/web/app/lib/api/tosings.ts new file mode 100644 index 0000000..d96ce18 --- /dev/null +++ b/apps/web/app/lib/api/tosings.ts @@ -0,0 +1,67 @@ +export async function getToSingSongs() { + const response = await fetch(`/api/songs/tosing`); + if (!response.ok) { + throw new Error('Failed to fetch tosing songs'); + } + return response.json(); +} + +export async function patchToSingSongs(body: { songId: string; newWeight: number }) { + const response = await fetch(`/api/songs/tosing`, { + method: 'PATCH', + body: JSON.stringify(body), + headers: { 'Content-Type': 'application/json' }, + }); + if (!response.ok) { + throw new Error('Failed to patch tosing songs'); + } + return response.json(); +} + +export async function postToSingSongs(body: { songId: string }) { + const response = await fetch(`/api/songs/tosing`, { + method: 'POST', + body: JSON.stringify(body), + headers: { 'Content-Type': 'application/json' }, + }); + if (!response.ok) { + throw new Error('Failed to post tosing songs'); + } + return response.json(); +} + +export async function postToSingSongsArray(body: { songIds: string[] }) { + const response = await fetch(`/api/songs/tosing/array`, { + method: 'POST', + body: JSON.stringify(body), + headers: { 'Content-Type': 'application/json' }, + }); + if (!response.ok) { + throw new Error('Failed to post tosing songs array'); + } + return response.json(); +} + +export async function deleteToSingSongs(body: { songId: string }) { + const response = await fetch(`/api/songs/tosing`, { + method: 'DELETE', + body: JSON.stringify(body), + headers: { 'Content-Type': 'application/json' }, + }); + if (!response.ok) { + throw new Error('Failed to delete tosing songs'); + } + return response.json(); +} + +export async function deleteToSingSongsArray(body: { songIds: string[] }) { + const response = await fetch(`/api/songs/tosing/arr`, { + method: 'DELETE', + body: JSON.stringify(body), + headers: { 'Content-Type': 'application/json' }, + }); + if (!response.ok) { + throw new Error('Failed to delete tosing songs array'); + } + return response.json(); +} diff --git a/apps/web/app/lib/api/total_stats.ts b/apps/web/app/lib/api/total_stats.ts new file mode 100644 index 0000000..5db68e7 --- /dev/null +++ b/apps/web/app/lib/api/total_stats.ts @@ -0,0 +1,15 @@ +export async function postTotalStats(body: { + songId: string; + countType: string; + isMinus: boolean; +}) { + const response = await fetch(`/api/total_stats`, { + method: 'POST', + body: JSON.stringify(body), + headers: { 'Content-Type': 'application/json' }, + }); + if (!response.ok) { + throw new Error('Failed to post total stats'); + } + return response.json(); +} diff --git a/apps/web/app/lib/api/user_stats.ts b/apps/web/app/lib/api/user_stats.ts new file mode 100644 index 0000000..acd0032 --- /dev/null +++ b/apps/web/app/lib/api/user_stats.ts @@ -0,0 +1,19 @@ +export async function getUserStats() { + const response = await fetch(`/api/user_stats`); + if (!response.ok) { + throw new Error('Failed to get user stats'); + } + return response.json(); +} + +export async function postUserStats(songId: string) { + const response = await fetch(`/api/user_stats`, { + method: 'POST', + body: JSON.stringify({ songId }), + headers: { 'Content-Type': 'application/json' }, + }); + if (!response.ok) { + throw new Error('Failed to post user stats'); + } + return response.json(); +} diff --git a/apps/web/app/lib/supabase/api.ts b/apps/web/app/lib/supabase/api.ts new file mode 100644 index 0000000..0d7dd71 --- /dev/null +++ b/apps/web/app/lib/supabase/api.ts @@ -0,0 +1,27 @@ +import { createServerClient, serializeCookieHeader } from '@supabase/ssr'; +import { type NextApiRequest, type NextApiResponse } from 'next'; + +// API client + +export default function createClient(req: NextApiRequest, res: NextApiResponse) { + const supabase = createServerClient(process.env.SUPABASE_URL!, process.env.SUPABASE_ANON_KEY!, { + cookies: { + getAll() { + return Object.keys(req.cookies).map(name => ({ + name, + value: req.cookies[name] || '', + })); + }, + setAll(cookiesToSet) { + res.setHeader( + 'Set-Cookie', + cookiesToSet.map(({ name, value, options }) => + serializeCookieHeader(name, value, options), + ), + ); + }, + }, + }); + + return supabase; +} diff --git a/apps/web/app/lib/supabase/client.ts b/apps/web/app/lib/supabase/client.ts new file mode 100644 index 0000000..62af38f --- /dev/null +++ b/apps/web/app/lib/supabase/client.ts @@ -0,0 +1,12 @@ +import { createBrowserClient } from '@supabase/ssr'; + +// Component client + +export default function createClient() { + // CSR에서는 Next_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY 사용 + + return createBrowserClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, + ); +} diff --git a/apps/web/app/lib/supabase/middleware.ts b/apps/web/app/lib/supabase/middleware.ts new file mode 100644 index 0000000..d298cdd --- /dev/null +++ b/apps/web/app/lib/supabase/middleware.ts @@ -0,0 +1,61 @@ +import { createServerClient } from '@supabase/ssr'; +import { type NextRequest, NextResponse } from 'next/server'; + +export async function updateSession(request: NextRequest) { + let supabaseResponse = NextResponse.next({ + request, + }); + + const supabase = createServerClient(process.env.SUPABASE_URL!, process.env.SUPABASE_ANON_KEY!, { + cookies: { + getAll() { + return request.cookies.getAll(); + }, + setAll(cookiesToSet) { + cookiesToSet.forEach(({ name, value }) => request.cookies.set(name, value)); + supabaseResponse = NextResponse.next({ + request, + }); + cookiesToSet.forEach(({ name, value, options }) => + supabaseResponse.cookies.set(name, value, options), + ); + }, + }, + }); + + // Do not run code between createServerClient and + // supabase.auth.getUser(). A simple mistake could make it very hard to debug + // issues with users being randomly logged out. + + // IMPORTANT: DO NOT REMOVE auth.getUser() + + const { + data: { user }, + } = await supabase.auth.getUser(); + + if ( + !user && + !request.nextUrl.pathname.startsWith('/login') && + !request.nextUrl.pathname.startsWith('/auth') + ) { + // no user, potentially respond by redirecting the user to the login page + const url = request.nextUrl.clone(); + url.pathname = '/login'; + return NextResponse.redirect(url); + } + + // IMPORTANT: You *must* return the supabaseResponse object as it is. + // If you're creating a new response object with NextResponse.next() make sure to: + // 1. Pass the request in it, like so: + // const myNewResponse = NextResponse.next({ request }) + // 2. Copy over the cookies, like so: + // myNewResponse.cookies.setAll(supabaseResponse.cookies.getAll()) + // 3. Change the myNewResponse object to fit your needs, but avoid changing + // the cookies! + // 4. Finally: + // return myNewResponse + // If this is not done, you may be causing the browser and server to go out + // of sync and terminate the user's session prematurely! + + return supabaseResponse; +} diff --git a/apps/web/app/lib/supabase/server.ts b/apps/web/app/lib/supabase/server.ts new file mode 100644 index 0000000..928ccf7 --- /dev/null +++ b/apps/web/app/lib/supabase/server.ts @@ -0,0 +1,24 @@ +import { createServerClient } from '@supabase/ssr'; +import { cookies } from 'next/headers'; + +// Server client +export default async function createClient() { + const cookieStore = await cookies(); + + return createServerClient(process.env.SUPABASE_URL!, process.env.SUPABASE_ANON_KEY!, { + cookies: { + getAll() { + return cookieStore.getAll(); + }, + setAll(cookiesToSet) { + try { + cookiesToSet.forEach(({ name, value, options }) => cookieStore.set(name, value, options)); + } catch { + // The `setAll` method was called from a Server Component. + // This can be ignored if you have middleware refreshing + // user sessions. + } + }, + }, + }); +} diff --git a/apps/web/app/library/liked/SongItem.tsx b/apps/web/app/library/liked/SongItem.tsx new file mode 100644 index 0000000..010380d --- /dev/null +++ b/apps/web/app/library/liked/SongItem.tsx @@ -0,0 +1,28 @@ +import { Checkbox } from '@/components/ui/checkbox'; +import { AddListModalSong } from '@/types/song'; +import { cn } from '@/utils/cn'; + +// 노래 항목 컴포넌트 +export default function SongItem({ + song, + isSelected, + onToggleSelect, +}: { + song: AddListModalSong; + isSelected: boolean; + onToggleSelect: (id: string) => void; +}) { + return ( +
+ onToggleSelect(song.id)} + /> +
+

{song.title}

+

{song.artist}

+
+
+ ); +} diff --git a/apps/web/app/library/liked/page.tsx b/apps/web/app/library/liked/page.tsx new file mode 100644 index 0000000..0019929 --- /dev/null +++ b/apps/web/app/library/liked/page.tsx @@ -0,0 +1,55 @@ +'use client'; + +import { ArrowLeft } from 'lucide-react'; +import { useRouter } from 'next/navigation'; + +import { Button } from '@/components/ui/button'; +import { ScrollArea } from '@/components/ui/scroll-area'; +import { Separator } from '@/components/ui/separator'; +import useSongInfo from '@/hooks/useSongInfo'; +import useSongStore from '@/stores/useSongStore'; + +import SongItem from './SongItem'; + +export default function LikedPage() { + const router = useRouter(); + const { likedSongs } = useSongStore(); + const { deleteLikeSelected, handleToggleSelect, handleDelete } = useSongInfo(); + + return ( +
+
+ +

좋아요 곡 관리

+
+ +
+

+ {deleteLikeSelected.length > 0 + ? `${deleteLikeSelected.length}곡 선택됨` + : `총 ${likedSongs.length}곡`} +

+ {deleteLikeSelected.length > 0 && ( + + )} +
+ + + + + {likedSongs.map(song => ( + + ))} + +
+ ); +} diff --git a/apps/web/app/library/page.tsx b/apps/web/app/library/page.tsx new file mode 100644 index 0000000..79d850c --- /dev/null +++ b/apps/web/app/library/page.tsx @@ -0,0 +1,49 @@ +'use client'; + +import { BarChart2, Heart } from 'lucide-react'; +import { useRouter } from 'next/navigation'; + +import { Card, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; +import useAuthStore from '@/stores/useAuthStore'; + +const menuItems = [ + { + id: 'liked', + title: '좋아요 곡 관리', + description: '좋아요를 누른 노래를 관리합니다', + icon: , + }, + { + id: 'stats', + title: '노래방 통계', + description: '나의 노래 통계를 확인합니다', + icon: , + }, +]; + +export default function LibraryPage() { + const router = useRouter(); + const { user } = useAuthStore(); + + return ( +
+

반갑습니다, {user?.nickname}님

+ + {menuItems.map(item => ( + router.push(`/library/${item.id}`)} + > + +
{item.icon}
+
+ {item.title} + {item.description} +
+
+
+ ))} +
+ ); +} diff --git a/apps/web/app/library/stats/page.tsx b/apps/web/app/library/stats/page.tsx new file mode 100644 index 0000000..6a1ff55 --- /dev/null +++ b/apps/web/app/library/stats/page.tsx @@ -0,0 +1,32 @@ +'use client'; + +import { ArrowLeft } from 'lucide-react'; +import { useRouter } from 'next/navigation'; + +import RankingList from '@/components/RankingList'; +import { Button } from '@/components/ui/button'; +import { ScrollArea } from '@/components/ui/scroll-area'; +import useUserStat from '@/hooks/useUserStat'; + +export default function StatsPage() { + const router = useRouter(); + + const { userStat } = useUserStat(); + + console.log('userStat', userStat); + + return ( +
+
+ +

노래방 통계

+
+ + + + +
+ ); +} diff --git a/apps/web/app/login/KakaoLogin.tsx b/apps/web/app/login/KakaoLogin.tsx new file mode 100644 index 0000000..645250e --- /dev/null +++ b/apps/web/app/login/KakaoLogin.tsx @@ -0,0 +1,21 @@ +'use client'; + +import Image from 'next/image'; + +import useAuthStore from '@/stores/useAuthStore'; + +// 클라이언트용 Supabase 클라이언트 + +export default function KakaoLogin() { + const { authKaKaoLogin } = useAuthStore(); + + const handleKakaoLogin = async () => { + await authKaKaoLogin(); + }; + + return ( +
+ kakao +
+ ); +} diff --git a/apps/web/app/login/actions.ts b/apps/web/app/login/actions.ts new file mode 100644 index 0000000..54dc943 --- /dev/null +++ b/apps/web/app/login/actions.ts @@ -0,0 +1,27 @@ +'use server'; + +import { revalidatePath } from 'next/cache'; + +import createClient from '@/lib/supabase/server'; + +export async function login(email: string, password: string) { + const supabase = await createClient(); + + const data = { + email, + password, + }; + + const response = await supabase.auth.signInWithPassword(data); + if (response.error) { + throw new Error( + JSON.stringify({ + code: response.error.status || 500, + message: response.error.message, + }), + ); + } + + revalidatePath('/', 'layout'); + return response; +} diff --git a/apps/web/app/login/page.tsx b/apps/web/app/login/page.tsx new file mode 100644 index 0000000..ca0907a --- /dev/null +++ b/apps/web/app/login/page.tsx @@ -0,0 +1,126 @@ +'use client'; + +import { Eye, EyeOff } from 'lucide-react'; +import Link from 'next/link'; +import { useRouter } from 'next/navigation'; +import { useEffect, useState } from 'react'; +import { toast } from 'sonner'; + +import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; +import { Label } from '@/components/ui/label'; +import { Separator } from '@/components/ui/separator'; +import useAuthStore from '@/stores/useAuthStore'; +import useModalStore from '@/stores/useModalStore'; + +import KakaoLogin from './KakaoLogin'; + +export default function LoginPage() { + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [showPassword, setShowPassword] = useState(false); + + const { isLoading, isAuthenticated, login, checkAuth } = useAuthStore(); + const { openMessage } = useModalStore(); + const router = useRouter(); + + const handleLogin = async (e: React.FormEvent) => { + e.preventDefault(); + const { isSuccess, errorTitle, errorMessage } = await login(email, password); + if (isSuccess) { + checkAuth(); + router.push('/'); + } else { + openMessage({ + title: errorTitle, + message: errorMessage || '로그인 실패', + variant: 'error', + }); + } + }; + + useEffect(() => { + if (isAuthenticated) { + toast.success('로그인 확인', { + description: '이미 로그인 하셨어요!', + }); + router.push('/'); + } + }, [isAuthenticated, router]); + + return ( +
+
+
+

로그인

+

계정에 로그인하여 서비스를 이용하세요

+
+ +
+
+ + setEmail(e.target.value)} + required + /> +
+ +
+ +
+ setPassword(e.target.value)} + required + /> + +
+
+ + + +
+ + 계정이 없으신가요? 회원가입 + +
+ +
+ + 비밀번호를 잊으셨나요? 비밀번호 재설정 + +
+
+ +
+
+ +
+
+ 또는 +
+
+ + +
+
+ ); +} diff --git a/apps/web/app/not-found.tsx b/apps/web/app/not-found.tsx new file mode 100644 index 0000000..f40f4fe --- /dev/null +++ b/apps/web/app/not-found.tsx @@ -0,0 +1,44 @@ +import { Home } from 'lucide-react'; +import Link from 'next/link'; + +import { Button } from '@/components/ui/button'; +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from '@/components/ui/card'; + +export default function NotFound() { + return ( +
+ + + 페이지를 찾을 수 없어요 + + 요청하신 페이지가 존재하지 않아요 + + + + +
404
+

+ 주소가 올바른지 확인하거나
+ 다른 페이지로 이동해보세요 +

+
+ + + + +
+
+ ); +} diff --git a/apps/web/app/page.module.css b/apps/web/app/page.module.css deleted file mode 100644 index a11c8f3..0000000 --- a/apps/web/app/page.module.css +++ /dev/null @@ -1,168 +0,0 @@ -.page { - --gray-rgb: 0, 0, 0; - --gray-alpha-200: rgba(var(--gray-rgb), 0.08); - --gray-alpha-100: rgba(var(--gray-rgb), 0.05); - - --button-primary-hover: #383838; - --button-secondary-hover: #f2f2f2; - - display: grid; - grid-template-rows: 20px 1fr 20px; - align-items: center; - justify-items: center; - min-height: 100svh; - padding: 80px; - gap: 64px; - font-family: var(--font-geist-sans); -} - -@media (prefers-color-scheme: dark) { - .page { - --gray-rgb: 255, 255, 255; - --gray-alpha-200: rgba(var(--gray-rgb), 0.145); - --gray-alpha-100: rgba(var(--gray-rgb), 0.06); - - --button-primary-hover: #ccc; - --button-secondary-hover: #1a1a1a; - } -} - -.main { - display: flex; - flex-direction: column; - gap: 32px; - grid-row-start: 2; -} - -.main ol { - font-family: var(--font-geist-mono); - padding-left: 0; - margin: 0; - font-size: 14px; - line-height: 24px; - letter-spacing: -0.01em; - list-style-position: inside; -} - -.main li:not(:last-of-type) { - margin-bottom: 8px; -} - -.main code { - font-family: inherit; - background: var(--gray-alpha-100); - padding: 2px 4px; - border-radius: 4px; - font-weight: 600; -} - -.ctas { - display: flex; - gap: 16px; -} - -.ctas a { - appearance: none; - border-radius: 128px; - height: 48px; - padding: 0 20px; - border: none; - border: 1px solid transparent; - transition: - background 0.2s, - color 0.2s, - border-color 0.2s; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - font-size: 16px; - line-height: 20px; - font-weight: 500; -} - -a.primary { - background: var(--foreground); - color: var(--background); - gap: 8px; -} - -a.secondary { - border-color: var(--gray-alpha-200); - min-width: 158px; -} - -.footer { - grid-row-start: 3; - display: flex; - gap: 24px; -} - -.footer a { - display: flex; - align-items: center; - gap: 8px; -} - -.footer img { - flex-shrink: 0; -} - -/* Enable hover only on non-touch devices */ -@media (hover: hover) and (pointer: fine) { - a.primary:hover { - background: var(--button-primary-hover); - border-color: transparent; - } - - a.secondary:hover { - background: var(--button-secondary-hover); - border-color: transparent; - } - - .footer a:hover { - text-decoration: underline; - text-underline-offset: 4px; - } -} - -@media (max-width: 600px) { - .page { - padding: 32px; - padding-bottom: 80px; - } - - .main { - align-items: center; - } - - .main ol { - text-align: center; - } - - .ctas { - flex-direction: column; - } - - .ctas a { - font-size: 14px; - height: 40px; - padding: 0 16px; - } - - a.secondary { - min-width: auto; - } - - .footer { - flex-wrap: wrap; - align-items: center; - justify-content: center; - } -} - -@media (prefers-color-scheme: dark) { - .logo { - filter: invert(); - } -} diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx index 3948e16..8fff115 100644 --- a/apps/web/app/page.tsx +++ b/apps/web/app/page.tsx @@ -1,25 +1,7 @@ 'use client'; -import styles from './page.module.css'; -import { getComposer } from '@repo/api'; -import { useEffect } from 'react'; +import HomePage from '@/home/page'; export default function Home() { - const testAPI = async () => { - const response = await getComposer({ composer: '아이유' }); - console.log(response); - }; - useEffect(() => { - testAPI(); - }, []); - return ( -
-
-

Hello World

-
-
-

fotter

-
-
- ); + return ; } diff --git a/apps/web/app/popular/page.tsx b/apps/web/app/popular/page.tsx new file mode 100644 index 0000000..6b5e755 --- /dev/null +++ b/apps/web/app/popular/page.tsx @@ -0,0 +1,27 @@ +import { Construction } from 'lucide-react'; + +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; + +export default function PopularPage() { + return ( +
+ + + 서비스 준비 중 + + 더 나은 서비스를 위해 준비 중입니다 + + + + + +

+ 곧 새로운 기능으로 찾아뵙겠습니다 +
+ 조금만 기다려주세요 +

+
+
+
+ ); +} diff --git a/apps/web/app/query.tsx b/apps/web/app/query.tsx new file mode 100644 index 0000000..67799b3 --- /dev/null +++ b/apps/web/app/query.tsx @@ -0,0 +1,10 @@ +'use client'; + +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { useState } from 'react'; + +export default function QueryProvider({ children }: { children: React.ReactNode }) { + const [queryClient] = useState(() => new QueryClient()); + + return {children}; +} diff --git a/apps/web/app/search/SearchResultCard.tsx b/apps/web/app/search/SearchResultCard.tsx new file mode 100644 index 0000000..80051d8 --- /dev/null +++ b/apps/web/app/search/SearchResultCard.tsx @@ -0,0 +1,91 @@ +import { Heart, MinusCircle, PlusCircle } from 'lucide-react'; + +import { Button } from '@/components/ui/button'; +import { Card } from '@/components/ui/card'; +import { SearchSong } from '@/types/song'; + +interface IProps { + song: SearchSong; + onToggleToSing: () => void; + onToggleLike: () => void; + onClickOpenPlaylistModal: () => void; +} + +export default function SearchResultCard({ + song, + onToggleToSing, + onToggleLike, + // onClickOpenPlaylistModal, +}: IProps) { + const { title, artist, num_tj, num_ky, isToSing, isLiked } = song; + + return ( + + {/* 메인 콘텐츠 영역 */} +
+ {/* 노래 정보 */} +
+ {/* 제목 및 가수 */} +
+

{title}

+

{artist}

+
+ + {/* 노래방 번호 */} + +
+
+ TJ + {num_tj} +
+
+ 금영 + {num_ky} +
+
+
+ + {/* 버튼 영역 - 우측 하단에 고정 */} +
+ + + + {/* + */} +
+
+
+ ); +} diff --git a/apps/web/app/search/page.tsx b/apps/web/app/search/page.tsx new file mode 100644 index 0000000..269b79d --- /dev/null +++ b/apps/web/app/search/page.tsx @@ -0,0 +1,93 @@ +'use client'; + +import { Mic, Search } from 'lucide-react'; + +import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; +import { ScrollArea } from '@/components/ui/scroll-area'; +import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs'; +import useSearch from '@/hooks/useSearch'; + +import SearchResultCard from './SearchResultCard'; + +export default function SearchPage() { + const { + search, + setSearch, + searchResults, + searchType, + handleSearchTypeChange, + handleSearch, + handleToggleToSing, + handleToggleLike, + handleOpenPlaylistModal, + // isModal, + // selectedSong, + // handleSavePlaylist, + } = useSearch(); + + // 엔터 키 처리 + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'Enter') { + handleSearch(); + } + }; + + return ( +
+
+

노래 검색

+ + + + 제목 + 가수 + + + +
+
+ + setSearch(e.target.value)} + onKeyDown={handleKeyDown} + /> +
+ +
+
+ + {searchResults.length > 0 ? ( +
+ {searchResults.map((song, index) => ( + + handleToggleToSing(song.id, song.isToSing ? 'DELETE' : 'POST') + } + onToggleLike={() => handleToggleLike(song.id, song.isLiked ? 'DELETE' : 'POST')} + onClickOpenPlaylistModal={() => handleOpenPlaylistModal(song)} + /> + ))} +
+ ) : ( +
+

노래 제목이나 가수를 검색해보세요

+ +
+ )} +
+ {/* {isModal && } */} +
+ ); +} diff --git a/apps/web/app/signup/actions.ts b/apps/web/app/signup/actions.ts new file mode 100644 index 0000000..de4d1ae --- /dev/null +++ b/apps/web/app/signup/actions.ts @@ -0,0 +1,31 @@ +'use server'; + +import { revalidatePath } from 'next/cache'; +import { redirect } from 'next/navigation'; + +import createClient from '@/lib/supabase/server'; + +export async function register(email: string, password: string) { + const supabase = await createClient(); + + const data = { + email, + password, + }; + + const response = await supabase.auth.signUp(data); + console.log('response : ', response); + if (response.error) { + // 에러를 클라이언트에 전달 + + throw new Error( + JSON.stringify({ + code: response.error.status || 500, + message: response.error.message, + }), + ); + } + + revalidatePath('/', 'layout'); + redirect('/'); +} diff --git a/apps/web/app/signup/page.tsx b/apps/web/app/signup/page.tsx new file mode 100644 index 0000000..84cb112 --- /dev/null +++ b/apps/web/app/signup/page.tsx @@ -0,0 +1,112 @@ +'use client'; + +import Link from 'next/link'; +import { useRouter } from 'next/navigation'; +import type React from 'react'; +import { useState } from 'react'; + +import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; +import { Label } from '@/components/ui/label'; +import useAuthStore from '@/stores/useAuthStore'; +import useModalStore from '@/stores/useModalStore'; + +export default function SignupPage() { + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [confirmPassword, setConfirmPassword] = useState(''); + + const { register, isLoading } = useAuthStore(); + const { openMessage } = useModalStore(); + const router = useRouter(); + + const handleSignup = async (e: React.FormEvent) => { + e.preventDefault(); + + if (password !== confirmPassword) { + openMessage({ + title: '일치하지 않는 비밀번호', + message: '비밀번호가 일치하지 않습니다.', + variant: 'error', + }); + return; + } + + const { isSuccess, errorTitle, errorMessage } = await register(email, password); + + if (isSuccess) { + openMessage({ + title: '회원가입 성공', + message: '입력한 이메일로 인증 메일을 보냈어요.', + variant: 'success', + onButtonClick: () => router.push('/login'), + }); + } else { + openMessage({ + title: errorTitle, + message: errorMessage || '회원가입 실패', + variant: 'error', + }); + } + }; + + return ( +
+
+
+

회원가입

+

계정을 만들어 서비스를 이용하세요

+
+ +
+
+ + setEmail(e.target.value)} + required + /> +
+ +
+ + setPassword(e.target.value)} + required + /> +
+ +
+ + setConfirmPassword(e.target.value)} + required + /> +
+ + + +
+ + 이미 계정이 있으신가요? 로그인 + +
+
+
+
+ ); +} diff --git a/apps/web/app/stores/middleware.ts b/apps/web/app/stores/middleware.ts new file mode 100644 index 0000000..4228ef9 --- /dev/null +++ b/apps/web/app/stores/middleware.ts @@ -0,0 +1,27 @@ +// const withLoading = async (set: any, fn: () => Promise): Promise => { +import { toast } from 'sonner'; + +export const withLoading = async ( + set: (fn: (state: S) => void) => void, + get: () => S, + fn: () => Promise, +): Promise => { + const state = get(); + + if (state.isLoading) { + toast.warning('기다려주세요', { description: '요청을 처리 중입니다.' }); + return Promise.resolve(false as T); + } + + set(state => { + state.isLoading = true; + }); + + try { + return await fn(); + } finally { + set(state => { + state.isLoading = false; + }); + } +}; diff --git a/apps/web/app/stores/useAuthStore.ts b/apps/web/app/stores/useAuthStore.ts new file mode 100644 index 0000000..2629fd3 --- /dev/null +++ b/apps/web/app/stores/useAuthStore.ts @@ -0,0 +1,238 @@ +import { AuthError } from '@supabase/supabase-js'; +import { toast } from 'sonner'; +import { create } from 'zustand'; +import { immer } from 'zustand/middleware/immer'; + +import createClient from '@/lib/supabase/client'; +import { User } from '@/types/user'; +import { getErrorMessage } from '@/utils/getErrorMessage'; + +import { withLoading } from './middleware'; + +const supabase = createClient(); + +// 사용자 타입 정의 + +interface AuthState { + user: User | null; + isLoading: boolean; + isAuthenticated: boolean; + + // 액션 + register: (email: string, password: string) => Promise; // 반환 타입 변경 + login: (email: string, password: string) => Promise; // 반환 타입 변경 + authKaKaoLogin: () => Promise; + logout: () => Promise; + checkAuth: () => Promise; + insertUser: (id: string) => Promise; + + changeNickname: (nickname: string) => Promise; + sendPasswordResetLink: (email: string) => Promise; + changePassword: (password: string) => Promise; +} + +// useModalStore에서 사용할 데이터를 전달해줘야 할 때의 타입 +// 기본적인 toast 제어는 store 단에서 처리할 계획 +interface ModalResponseState { + isSuccess: boolean; + errorTitle?: string; + errorMessage?: string; +} + +const useAuthStore = create( + immer((set, get) => ({ + user: null, + isLoading: false, + isAuthenticated: false, + + register: async (email, password) => { + return await withLoading(set, get, async () => { + try { + const { data, error } = await supabase.auth.signUp({ email, password }); + if (error) throw error; + + if (data.user?.identities?.length === 0) { + return { + isSuccess: false, + errorTitle: '이메일 중복', + errorMessage: '이미 가입된 이메일입니다.', + }; + } + + toast.success('회원가입 성공', { description: '만나서 반가워요!' }); + return { isSuccess: true }; + } catch (error) { + if (error instanceof AuthError) { + return getErrorMessage(error.code as string); + } + return { + isSuccess: false, + errorTitle: '회원가입 실패', + errorMessage: '회원 가입이 실패했어요.', + }; + } + }); + }, + // 로그인 액션 + login: async (email, password) => { + return await withLoading(set, get, async () => { + try { + const { error } = await supabase.auth.signInWithPassword({ email, password }); + if (error) throw error; + toast.success('로그인 성공', { description: '다시 만나서 반가워요!' }); + return { isSuccess: true }; + } catch (error) { + const { code } = error as AuthError; + return getErrorMessage(code as string); + } + }); + }, + authKaKaoLogin: async () => { + try { + const { error } = await supabase.auth.signInWithOAuth({ + provider: 'kakao', + }); + if (error) throw error; + + return true; + } catch (error) { + console.error('카카오 로그인 오류:', error); + toast.error('카카오 로그인 실패', { + description: '카카오 로그인에 문제가 있어요...', + }); + + return false; + } + }, + // 로그아웃 액션 + logout: async () => { + await supabase.auth.signOut(); + set({ user: null, isAuthenticated: false }); + }, + + // 인증 상태 확인 + checkAuth: async () => { + try { + const { data, error } = await supabase.auth.getUser(); + + if (error) throw error; + if (!get().user) { + const id = data.user.id; + const { data: existingUser } = await supabase + .from('users') + .select('*') + .eq('id', id) + .single(); + + if (!existingUser) get().insertUser(id); + else { + set(state => { + state.user = existingUser; + state.isAuthenticated = true; + }); + } + } + return true; + } catch (error) { + console.error('checkAuth 오류:', error); + return false; + } + }, + insertUser: async (id: string) => { + try { + const { data: user, error } = await supabase.from('users').insert({ id }).select().single(); + if (error) throw error; + set(state => { + state.user = user; + state.isAuthenticated = true; + }); + } catch (error) { + console.error('insertUser 오류:', error); + } + }, + changeNickname: async (nickname: string) => { + return await withLoading(set, get, async () => { + try { + const { user } = get(); + if (!user) throw new Error('No user found in store'); + + if (nickname.length < 2) { + toast.error('닉네임 수정 실패', { + description: '닉네임은 2자 이상이어야 해요.', + }); + return false; + } + + if (nickname === user.nickname) { + toast.error('닉네임 수정 실패', { + description: '이전과 동일한 닉네임이에요.', + }); + return false; + } + + const result = await supabase + .from('users') + .update({ nickname: nickname }) + .eq('id', user.id) + .select() + .single(); + set({ user: result.data, isAuthenticated: true }); + + toast.success('닉네임 수정 성공', { + description: '닉네임이 성공적으로 수정되었어요!', + }); + return true; + } catch (error) { + toast.error('닉네임 수정 실패', { + description: '닉네임 수정에 실패했어요.', + }); + + console.error('changeNickname 오류:', error); + return false; + } + }); + }, + sendPasswordResetLink: async (email: string) => { + return await withLoading(set, get, async () => { + try { + const { error } = await supabase.auth.resetPasswordForEmail(email, { + redirectTo: `http://localhost:3000/update-password`, + }); + if (error) { + throw error; + } + toast.success('재설정 링크 발송 완료', { + description: `${email}로 비밀번호 재설정 링크를 발송했어요. 이메일을 확인해주세요.`, + }); + } catch (error) { + console.error('비밀번호 재설정 링크 발송 실패:', error); + toast.error('링크 발송 실패', { + description: '비밀번호 재설정 링크 발송 중 오류가 발생했어요.', + }); + } + }); + }, + + changePassword: async (password: string) => { + return await withLoading(set, get, async () => { + try { + const { error } = await supabase.auth.updateUser({ password }); + if (error) throw error; + + toast.success('비밀번호 변경 완료', { + description: '비밀번호가 성공적으로 변경되었어요.', + }); + return true; + } catch (error) { + console.error('비밀번호 변경 실패:', error); + toast.error('비밀번호 변경 실패', { + description: '비밀번호 변경 중 오류가 발생했어요.', + }); + return false; + } + }); + }, + })), +); + +export default useAuthStore; diff --git a/apps/web/app/stores/useLoadingStore.ts b/apps/web/app/stores/useLoadingStore.ts new file mode 100644 index 0000000..b7254dc --- /dev/null +++ b/apps/web/app/stores/useLoadingStore.ts @@ -0,0 +1,32 @@ +import { create } from 'zustand'; + +interface LoadingState { + count: number; + isLoading: boolean; + isInitialLoading: boolean; + startLoading: () => void; + stopLoading: () => void; + initialLoading: () => void; +} + +const useLoadingStore = create((set, get) => ({ + count: 0, + isLoading: false, + isInitialLoading: true, + startLoading: () => { + const newCount = get().count + 1; + set({ count: newCount, isLoading: true }); + }, + stopLoading: () => { + const newCount = Math.max(0, get().count - 1); + set({ + count: newCount, + isLoading: newCount > 0, + }); + }, + initialLoading: () => { + set({ isInitialLoading: false }); + }, +})); + +export default useLoadingStore; diff --git a/apps/web/app/stores/useModalStore.ts b/apps/web/app/stores/useModalStore.ts new file mode 100644 index 0000000..ce1fb3c --- /dev/null +++ b/apps/web/app/stores/useModalStore.ts @@ -0,0 +1,49 @@ +import { create } from 'zustand'; + +type MessageVariant = 'default' | 'success' | 'error' | 'warning' | 'info'; + +interface ModalState { + isOpen: boolean; + title?: string; + message: string; + variant: MessageVariant; + buttonText?: string; + onButtonClick?: () => void; + + // 액션 + openMessage: (props: { + title?: string; + message: string; + variant?: MessageVariant; + buttonText?: string; + onButtonClick?: () => void; + }) => void; + closeMessage: () => void; +} + +const useModalStore = create(set => ({ + isOpen: false, + title: undefined, + message: '', + variant: 'default', + buttonText: undefined, + onButtonClick: undefined, + // onButtonClick 없어도 closeMessage는 기본적으로 호출 된다 + + openMessage: ({ title, message, variant = 'default', buttonText, onButtonClick }) => { + set({ + isOpen: true, + title, + message, + variant, + buttonText, + onButtonClick, + }); + }, + + closeMessage: () => { + set({ isOpen: false }); + }, +})); + +export default useModalStore; diff --git a/apps/web/app/stores/useSongStore.ts b/apps/web/app/stores/useSongStore.ts new file mode 100644 index 0000000..8ac6b47 --- /dev/null +++ b/apps/web/app/stores/useSongStore.ts @@ -0,0 +1,76 @@ +import { create } from 'zustand'; + +import { deleteLikedSongsArray, getLikedSongs } from '@/lib/api/like_activites'; +import { getRecentSongs } from '@/lib/api/songs'; +import { deleteToSingSongs, getToSingSongs, postToSingSongsArray } from '@/lib/api/tosings'; +import { AddListModalSong, ToSing } from '@/types/song'; + +interface SongStore { + toSings: ToSing[]; + likedSongs: AddListModalSong[]; + recentSongs: AddListModalSong[]; + swapToSings: (toSings: ToSing[]) => void; + refreshToSings: () => Promise; + refreshLikedSongs: () => Promise; + refreshRecentSongs: () => Promise; + postToSingSongs: (songIds: string[]) => Promise; + deleteToSingSong: (songId: string) => Promise; + deleteLikedSongs: (songIds: string[]) => Promise; +} + +const useSongStore = create((set, get) => ({ + toSings: [], + likedSongs: [], + recentSongs: [], + + swapToSings: (toSings: ToSing[]) => { + set({ toSings }); + }, + + refreshToSings: async () => { + const { success, data } = await getToSingSongs(); + if (success) { + set({ toSings: data }); + } + }, + + refreshLikedSongs: async () => { + const { success, data } = await getLikedSongs(); + if (success) { + set({ likedSongs: data }); + } + }, + refreshRecentSongs: async () => { + const { success, data } = await getRecentSongs(); + if (success) { + set({ recentSongs: data }); + } + }, + + postToSingSongs: async (songIds: string[]) => { + const { success } = await postToSingSongsArray({ songIds }); + if (success) { + get().refreshToSings(); + get().refreshLikedSongs(); + get().refreshRecentSongs(); + } + }, + + deleteToSingSong: async (songId: string) => { + const { success } = await deleteToSingSongs({ songId }); + if (success) { + get().refreshToSings(); + get().refreshLikedSongs(); + get().refreshRecentSongs(); + } + }, + + deleteLikedSongs: async (songIds: string[]) => { + const { success } = await deleteLikedSongsArray({ songIds }); + if (success) { + get().refreshLikedSongs(); + } + }, +})); + +export default useSongStore; diff --git a/apps/web/app/types/common.ts b/apps/web/app/types/common.ts new file mode 100644 index 0000000..619625c --- /dev/null +++ b/apps/web/app/types/common.ts @@ -0,0 +1 @@ +export type Method = 'GET' | 'POST' | 'DELETE' | 'UPDATE'; diff --git a/apps/web/app/types/likeLog.ts b/apps/web/app/types/likeLog.ts new file mode 100644 index 0000000..1e2ae30 --- /dev/null +++ b/apps/web/app/types/likeLog.ts @@ -0,0 +1,5 @@ +export interface LikeLog { + song_id: string; + user_id: string; + created_at: string; +} diff --git a/apps/web/app/types/singLog.ts b/apps/web/app/types/singLog.ts new file mode 100644 index 0000000..8e2a0b6 --- /dev/null +++ b/apps/web/app/types/singLog.ts @@ -0,0 +1,6 @@ +export interface SingLog { + id: string; + song_id: string; + user_id: string; + created_at: string; +} diff --git a/apps/web/app/types/song.ts b/apps/web/app/types/song.ts new file mode 100644 index 0000000..d3aa1f8 --- /dev/null +++ b/apps/web/app/types/song.ts @@ -0,0 +1,21 @@ +export interface Song { + id: string; + title: string; + artist: string; + num_tj: string; + num_ky: string; +} + +export interface SearchSong extends Song { + isLiked: boolean; + isToSing: boolean; +} + +export interface ToSing { + order_weight: number; + songs: Song; +} + +export interface AddListModalSong extends Song { + isInToSingList: boolean; +} diff --git a/apps/web/app/types/user.ts b/apps/web/app/types/user.ts new file mode 100644 index 0000000..f53345a --- /dev/null +++ b/apps/web/app/types/user.ts @@ -0,0 +1,5 @@ +export interface User { + id: string; + nickname: string; + profile_image: string | null; +} diff --git a/apps/web/app/types/userStat.ts b/apps/web/app/types/userStat.ts new file mode 100644 index 0000000..22647cf --- /dev/null +++ b/apps/web/app/types/userStat.ts @@ -0,0 +1,8 @@ +export interface UserSongStat { + userId: string; + songId: string; + singCount: number; + lastSingAt: string; + title: string; + artist: string; +} diff --git a/apps/web/app/update-password/page.tsx b/apps/web/app/update-password/page.tsx new file mode 100644 index 0000000..89b0d7f --- /dev/null +++ b/apps/web/app/update-password/page.tsx @@ -0,0 +1,202 @@ +'use client'; + +import { AlertCircle, ArrowLeft, CheckCircle2, Eye, EyeOff } from 'lucide-react'; +import Link from 'next/link'; +import { useRouter } from 'next/navigation'; +import type React from 'react'; +import { useEffect, useState } from 'react'; +import { toast } from 'sonner'; + +import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; +import { Label } from '@/components/ui/label'; +import createClient from '@/lib/supabase/client'; +import useAuthStore from '@/stores/useAuthStore'; +import useModalStore from '@/stores/useModalStore'; + +export default function UpdatePasswordPage() { + // 상태 관리 + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [confirmPassword, setConfirmPassword] = useState(''); + const [showPassword, setShowPassword] = useState(false); + const [showConfirmPassword, setShowConfirmPassword] = useState(false); + const [step, setStep] = useState<'email' | 'reset'>('email'); + + const { isLoading, sendPasswordResetLink, changePassword } = useAuthStore(); + const { openMessage } = useModalStore(); + + const router = useRouter(); + + // 이메일 제출 처리 (비밀번호 재설정 링크 요청) + const handleSendResetLink = async (e: React.FormEvent) => { + e.preventDefault(); + await sendPasswordResetLink(email); + }; + + // 비밀번호 재설정 처리 + const handleUpdatePassword = async (e: React.FormEvent) => { + e.preventDefault(); + + // 비밀번호 일치 여부 확인 + if (password !== confirmPassword) { + toast.error('비밀번호 불일치', { + description: '비밀번호를 다시 확인해주세요.', + }); + return; + } + + const result = await changePassword(password); + + if (result) { + openMessage({ + title: '비밀번호 변경 성공', + message: '비밀번호가 성공적으로 변경되었어요.', + variant: 'success', + onButtonClick: () => router.push('/login'), + }); + } + }; + + useEffect(() => { + const supabase = createClient(); + supabase.auth.onAuthStateChange(async event => { + if (event == 'PASSWORD_RECOVERY') { + setStep('reset'); // 비밀번호 재설정 단계로 이동 + } + }); + }, []); + + return ( +
+
+ {step === 'email' ? ( + // 이메일 입력 단계 + <> +
+

비밀번호 찾기

+

+ 가입한 이메일 주소를 입력하시면 비밀번호 재설정 링크를 보내드립니다. +

+
+ +
+
+ + setEmail(e.target.value)} + required + /> +
+ + + +
+ + + 로그인 페이지로 돌아가기 + +
+
+ + ) : ( + // 비밀번호 재설정 단계 + <> +
+

비밀번호 재설정

+

새로운 비밀번호를 입력해주세요

+
+ +
+
+ +
+ setPassword(e.target.value)} + required + /> + +
+
+ +
+ +
+ setConfirmPassword(e.target.value)} + required + className={ + confirmPassword && + (password === confirmPassword ? 'border-green-500' : 'border-red-500') + } + /> + +
+ + {/* 비밀번호 일치 여부 */} + {confirmPassword && ( +
+ {password === confirmPassword ? ( + <> + + 비밀번호가 일치합니다 + + ) : ( + <> + + 비밀번호가 일치하지 않습니다 + + )} +
+ )} +
+ + + +
+ + + 로그인 페이지로 돌아가기 + +
+
+ + )} +
+
+ ); +} diff --git a/apps/web/app/utils/cn.ts b/apps/web/app/utils/cn.ts new file mode 100644 index 0000000..bff778e --- /dev/null +++ b/apps/web/app/utils/cn.ts @@ -0,0 +1,6 @@ +import { type ClassValue, clsx } from 'clsx'; +import { twMerge } from 'tailwind-merge'; + +export const cn = (...inputs: ClassValue[]) => { + return twMerge(clsx(inputs)); +}; diff --git a/apps/web/app/utils/getAuthenticatedUser.ts b/apps/web/app/utils/getAuthenticatedUser.ts new file mode 100644 index 0000000..dc4a786 --- /dev/null +++ b/apps/web/app/utils/getAuthenticatedUser.ts @@ -0,0 +1,14 @@ +import { SupabaseClient } from '@supabase/supabase-js'; + +export async function getAuthenticatedUser(supabase: SupabaseClient): Promise { + const { + data: { user }, + error: authError, + } = await supabase.auth.getUser(); + + if (authError || !user) { + throw new Error('User not authenticated'); + } + + return user.id; // userId만 반환 +} diff --git a/apps/web/app/utils/getErrorMessage.ts b/apps/web/app/utils/getErrorMessage.ts new file mode 100644 index 0000000..d1841c0 --- /dev/null +++ b/apps/web/app/utils/getErrorMessage.ts @@ -0,0 +1,41 @@ +export const getErrorMessage = (errorCode: string | null) => { + if (!errorCode) { + return { + isSuccess: false, + errorTitle: '알 수 없는 오류', + errorMessage: '회원가입이 실패했어요.', + }; + } + switch (errorCode) { + case 'email_address_invalid': + return { + isSuccess: false, + errorTitle: '유효하지 않은 이메일', + errorMessage: '이메일 주소가 올바르지 않아요.', + }; + case 'weak_password': + return { + isSuccess: false, + errorTitle: '약한 비밀번호', + errorMessage: '비밀번호가 최소 6자 이상이어야 해요.', + }; + case 'email_not_confirmed': + return { + isSuccess: false, + errorTitle: '인증되지 않은 계정', + errorMessage: '이메일 인증이 필요해요.', + }; + case 'invalid_credentials': + return { + isSuccess: false, + errorTitle: '잘못된 정보', + errorMessage: '이메일 또는 비밀번호가 일치하지 않아요.', + }; + default: + return { + isSuccess: false, + errorTitle: '알 수 없는 오류', + errorMessage: '회원가입이 실패했어요.', + }; + } +}; diff --git a/apps/web/components.json b/apps/web/components.json new file mode 100644 index 0000000..335484f --- /dev/null +++ b/apps/web/components.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "", + "css": "app/globals.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "iconLibrary": "lucide" +} \ No newline at end of file diff --git a/apps/web/eslint.config.mjs b/apps/web/eslint.config.mjs index c85fb67..46f02ae 100644 --- a/apps/web/eslint.config.mjs +++ b/apps/web/eslint.config.mjs @@ -1,16 +1,14 @@ -import { dirname } from "path"; -import { fileURLToPath } from "url"; -import { FlatCompat } from "@eslint/eslintrc"; +import { dirname } from 'path' +import { fileURLToPath } from 'url' +import { FlatCompat } from '@eslint/eslintrc' -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); +const __filename = fileURLToPath(import.meta.url) +const __dirname = dirname(__filename) const compat = new FlatCompat({ baseDirectory: __dirname, -}); +}) -const eslintConfig = [ - ...compat.extends("next/core-web-vitals", "next/typescript"), -]; +const eslintConfig = [...compat.extends('next/core-web-vitals', 'next/typescript')] -export default eslintConfig; +export default eslintConfig diff --git a/apps/web/next.config.ts b/apps/web/next.config.ts index e9ffa30..5e891cf 100644 --- a/apps/web/next.config.ts +++ b/apps/web/next.config.ts @@ -1,4 +1,4 @@ -import type { NextConfig } from "next"; +import type { NextConfig } from 'next'; const nextConfig: NextConfig = { /* config options here */ diff --git a/apps/web/package.json b/apps/web/package.json index ef9f91c..cc83b5f 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -7,22 +7,61 @@ "dev": "next dev --turbopack", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "next lint", + "format": "prettier --write \"**/*.{ts,tsx,md}\"" }, "dependencies": { - "@repo/api": "workspace:*", + "@dnd-kit/core": "^6.3.1", + "@dnd-kit/modifiers": "^9.0.0", + "@dnd-kit/sortable": "^10.0.0", + "@dnd-kit/utilities": "^3.2.2", + "@radix-ui/react-checkbox": "^1.1.5", + "@radix-ui/react-dialog": "^1.1.6", + "@radix-ui/react-dropdown-menu": "^2.1.6", + "@radix-ui/react-label": "^2.1.2", + "@radix-ui/react-scroll-area": "^1.2.4", + "@radix-ui/react-separator": "^1.1.2", + "@radix-ui/react-slot": "^1.1.2", + "@radix-ui/react-tabs": "^1.1.3", + "@repo/open-api": "workspace:*", + "@repo/query": "workspace:*", + "@supabase/ssr": "^0.6.1", + "@supabase/supabase-js": "^2.49.1", + "@tanstack/react-query": "^5.68.0", + "@tanstack/react-query-devtools": "^5.68.0", + "@vercel/analytics": "^1.5.0", + "@vercel/speed-insights": "^1.2.0", "axios": "^1.5.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "immer": "^10.1.1", + "lucide-react": "^0.483.0", "next": "15.2.2", + "next-themes": "^0.4.6", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "sonner": "^2.0.3", + "tailwind-merge": "^3.0.2", + "tw-animate-css": "^1.2.4", + "zustand": "^5.0.3" }, "devDependencies": { "@eslint/eslintrc": "^3", + "@tailwindcss/postcss": "^4.0.15", + "@trivago/prettier-plugin-sort-imports": "^5.2.2", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", + "autoprefixer": "^10.4.21", "eslint": "^9", "eslint-config-next": "15.2.2", + "postcss": "^8.5.3", + "prettier": "^3.5.3", + "prettier-plugin-tailwindcss": "^0.6.11", + "tailwindcss": "^4.0.15", "typescript": "^5" + }, + "peerDependencies": { + "react": "^19.0.0" } } diff --git a/apps/web/postcss.config.mjs b/apps/web/postcss.config.mjs new file mode 100644 index 0000000..317d71c --- /dev/null +++ b/apps/web/postcss.config.mjs @@ -0,0 +1,6 @@ +const config = { + plugins: { + '@tailwindcss/postcss': {}, + }, +} +export default config diff --git a/apps/web/public/kakao_login.png b/apps/web/public/kakao_login.png new file mode 100644 index 0000000..c882acc Binary files /dev/null and b/apps/web/public/kakao_login.png differ diff --git a/apps/web/public/logo.png b/apps/web/public/logo.png new file mode 100644 index 0000000..57fe257 Binary files /dev/null and b/apps/web/public/logo.png differ diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json index c133409..45c5f4a 100644 --- a/apps/web/tsconfig.json +++ b/apps/web/tsconfig.json @@ -13,13 +13,15 @@ "isolatedModules": true, "jsx": "preserve", "incremental": true, + "forceConsistentCasingInFileNames": true, "plugins": [ { "name": "next" } ], "paths": { - "@/*": ["./src/*"] + "@/*": ["./app/*"], + "react": ["./node_modules/@types/react"] // lucide-react : cannot be used as a JSX component. 이슈 해결 } }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], diff --git a/package.json b/package.json index f6e3cca..110d520 100644 --- a/package.json +++ b/package.json @@ -5,19 +5,20 @@ "build": "turbo run build", "dev": "turbo run dev", "lint": "turbo run lint", - "format": "prettier --write \"**/*.{ts,tsx,md}\"", + "format": "turbo run format", "check-types": "turbo run check-types" }, - "devDependencies": { - "prettier": "^3.5.3", - "turbo": "^2.4.4", - "typescript": "5.8.2" - }, "packageManager": "pnpm@9.0.0", "engines": { "node": ">=18" }, "dependencies": { - "tamagui": "^1.125.23" + "react": "^19.0.0" + }, + "devDependencies": { + "prettier": "^3.5.3", + "prettier-plugin-tailwindcss": "^0.6.11", + "turbo": "^2.4.4", + "typescript": "5.8.2" } } diff --git a/packages/api/src/getSong.ts b/packages/api/src/getSong.ts deleted file mode 100644 index 2b7c152..0000000 --- a/packages/api/src/getSong.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { apiRequest } from './instance'; - -import type { Brand, ResponseType } from './types'; - -interface GetSongProps { - title: string; - brand?: Brand; -} - -const getSong = async ({ title, brand }: GetSongProps): Promise => { - const response = await apiRequest('/song', title, brand); - - if (!response.success) { - return null; - } - - return response.data; -}; - -export default getSong; diff --git a/packages/api/src/test.ts b/packages/api/src/test.ts deleted file mode 100644 index 14436cd..0000000 --- a/packages/api/src/test.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { getSong, getSinger, getComposer, getLyricist } from './index'; - -console.log('get song test'); - -const response = await getSong({ title: '아이유', brand: 'kumyoung' }); -console.log('response', response); - -const response2 = await getSong({ title: '아이유' }); -console.log('response2', response2); - -console.log('get singer test'); - -const response3 = await getSinger({ singer: '아이유', brand: 'kumyoung' }); -console.log('response3', response3); - -const response4 = await getSinger({ singer: '아이유' }); -console.log('response4', response4); - -console.log('get composer test'); - -const response5 = await getComposer({ composer: '아이유', brand: 'kumyoung' }); -console.log('response5', response5); - -const response6 = await getComposer({ composer: '아이유' }); -console.log('response6', response6); - -console.log('get lyricist test'); - -const response7 = await getLyricist({ lyricist: '아이유', brand: 'kumyoung' }); -console.log('response7', response7); - -const response8 = await getLyricist({ lyricist: '아이유' }); -console.log('response8', response8); diff --git a/packages/crawling/package.json b/packages/crawling/package.json new file mode 100644 index 0000000..5ca1794 --- /dev/null +++ b/packages/crawling/package.json @@ -0,0 +1,16 @@ +{ + "name": "@repo/crawling", + "version": "0.0.0", + "type": "module", + "main": "./src/index.js", + "exports": { + ".": "./src/index.js" + }, + "dependencies": { + "@supabase/supabase-js": "^2.49.1", + "@repo/open-api": "workspace:*", + "axios": "^1.5.0", + "cheerio": "^1.0.0", + "dotenv": "^16.4.7" + } +} diff --git a/packages/crawling/src/argList.js b/packages/crawling/src/argList.js new file mode 100644 index 0000000..5f550af --- /dev/null +++ b/packages/crawling/src/argList.js @@ -0,0 +1,38 @@ +const getObject = (url, artist, titleIndex, tjIndex, kyIndex) => { + return { url, artist, titleIndex, tjIndex, kyIndex }; +}; + +// 테이블 구조 상 불가능했던 문서 +// aiko, AKB48, 노기자카46, 니시노 카나, 모닝구 무스메, Sound Horizon, 오오츠카 아이, 케야키자카46 +// 너무 적은 데이터 +// &TEAM, NiziU + +export const argList = [ + // url, artist, titleIndex, tjIndex, kyIndex + getObject('AAA(혼성그룹)', 'AAA', 0, 3, 2), + getObject('Aimer', '에이머(Aimer)', 2, 0, 1), + getObject('amazarashi', '아마자라시(amazarashi)', 0, 1, 2), + getObject('BUMP OF CHICKEN', 'BUMP OF CHICKEN', 0, 1, 2), + getObject('DREAMS COME TRUE(밴드)', 'DREAMS COME TRUE', 0, 1, 2), + getObject('ELLEGARDEN', '엘르가든(ELLEGARDEN)', 0, 1, 2), + getObject('King Gnu', '킹누(King Gnu)', 0, 1, 2), + getObject('LiSA', '리사(LiSA)', 2, 0, 1), + getObject('Mrs. GREEN APPLE', '미세스그린애플(Mrs. GREEN APPLE)', 0, 1, 2), + getObject('Official髭男dism', '오피셜히게단디즘(Official髭男dism)', 2, 0, 1), + getObject('Perfume', '퍼퓸(Perfume)', 0, 1, 2), + getObject('RADWIMPS', '래드윔프스(RADWIMPS)', 2, 0, 1), + getObject('SEKAI NO OWARI', '세카이노오와리(SEKAI NO OWARI)', 0, 1, 2), + getObject('SPYAIR', '스파이에어(SPYAIR)', 2, 0, 1), + getObject('Vaundy', '바운디(Vaundy)', 2, 0, 1), + getObject('w-inds.', 'w-inds.', 0, 1, 2), + getObject('YOASOBI', '요아소비(YOASOBI)', 0, 1, 2), + getObject('계속 한밤중이면 좋을 텐데.', '계속 한밤중이면 좋을 텐데.(즛토마요나카데이이노니)', 2, 0, 1), + getObject('베리즈코보', '베리즈코보', 0, 1, 2), + getObject('아라시(아이돌)', '아라시', 0, 1, 2), + getObject('아이묭', '아이묭(あいみょん)', 0, 1, 2), + getObject('요네즈 켄시', '요네즈 켄시', 2, 0, 1), + getObject('요루시카', '요루시카(ヨルシカ)', 0, 1, 2), + getObject('유이카', '유이카', 0, 1, 2), + getObject('호시노 겐', '호시노 겐', 0, 1, 2), + getObject('Creepy Nuts', '크리피 넛츠(Creepy Nuts)', 2, 0, 1), +]; diff --git a/packages/crawling/src/crawlWiki.js b/packages/crawling/src/crawlWiki.js new file mode 100644 index 0000000..56142db --- /dev/null +++ b/packages/crawling/src/crawlWiki.js @@ -0,0 +1,112 @@ +import axios from 'axios'; +import * as cheerio from 'cheerio'; +import dotenv from 'dotenv'; + +import { parseNumber, parseJapaneseText, parseText } from './utils.js'; +dotenv.config(); + +// ✅ 나무위키에서 데이터 크롤링 +export async function scrapeSongs(dst) { + try { + const { url, artist, titleIndex, tjIndex, kyIndex } = dst; + if (!url || !artist) { + throw new Error('url 또는 artist가 없습니다.'); + } + + const baseUrl = process.env.NAMU_KARAOKE_URL; + const endURL = process.env.NAMU_KARAOKE_END_URL; + const fullURL = baseUrl + url + endURL; + console.log(fullURL); + const { data } = await axios.get(fullURL); + // const { data } = await axios.get(url, { headers: { 'User-Agent': 'Mozilla/5.0' } }); + const $ = cheerio.load(data); + + let songs = []; + + $('table tbody tr').each((index, element) => { + const cols = $(element).find('td'); + + const title = parseJapaneseText($(cols[titleIndex]).text()); + const num_tj = parseNumber($(cols[tjIndex]).text().trim().slice(0, 5)); + const num_ky = parseNumber($(cols[kyIndex]).text().trim().slice(0, 5)); + if (num_tj || num_ky) { + songs.push({ title, artist, num_tj, num_ky }); + } + }); + + return songs; + } catch (error) { + console.error('크롤링 실패:', error); + return []; + } +} + +export async function scrapeAllSongs(dst) { + try { + const titleIndex = 2; + const artistIndex = 3; + const tjIndex = 0; + const kyIndex = 1; + + const baseUrl = process.env.NAMU_KARAOKE_URL; + const url = '애니메이션%20음악/노래방%20수록%20목록/전체곡%20일람'; + const fullURL = baseUrl + url; + console.log(fullURL); + const { data } = await axios.get(fullURL, { headers: { 'User-Agent': 'Mozilla/5.0' } }); + const $ = cheerio.load(data); + + let songs = []; + + $('table tbody tr').each((index, element) => { + const cols = $(element).find('td'); + + const title = parseText($(cols[titleIndex]).text()); + const artist = parseText($(cols[artistIndex]).text()); + const num_tj = parseNumber($(cols[tjIndex]).text().trim().slice(0, 5)); + const num_ky = parseNumber($(cols[kyIndex]).text().trim().slice(0, 5)); + if (num_tj || num_ky) { + songs.push({ title, artist, num_tj, num_ky }); + } + }); + + return songs; + } catch (error) { + console.error('크롤링 실패:', error); + return []; + } +} + +export async function scrapeUtaiteSongs() { + try { + const titleIndex = 2; + const artistIndex = 3; + const tjIndex = 0; + const kyIndex = 1; + + const baseUrl = process.env.NAMU_KARAOKE_URL; + const url = '우타이테 오리지널 곡/노래방 수록 목록'; + const fullURL = baseUrl + url; + console.log(fullURL); + const { data } = await axios.get(fullURL, { headers: { 'User-Agent': 'Mozilla/5.0' } }); + const $ = cheerio.load(data); + + let songs = []; + + $('table tbody tr').each((index, element) => { + const cols = $(element).find('td'); + + const title = parseText($(cols[titleIndex]).text()); + const artist = parseText($(cols[artistIndex]).text()); + const num_tj = parseNumber($(cols[tjIndex]).text().trim().slice(0, 5)); + const num_ky = parseNumber($(cols[kyIndex]).text().trim().slice(0, 5)); + if (num_tj || num_ky) { + songs.push({ title, artist, num_tj, num_ky }); + } + }); + + return songs; + } catch (error) { + console.error('크롤링 실패:', error); + return []; + } +} diff --git a/packages/crawling/src/index.js b/packages/crawling/src/index.js new file mode 100644 index 0000000..0bda7d9 --- /dev/null +++ b/packages/crawling/src/index.js @@ -0,0 +1,39 @@ +import { scrapeAllSongs, scrapeSongs, scrapeUtaiteSongs } from './CrawlWiki.js'; +import { postDB } from './postDB.js'; +import { argList } from './argList.js'; + +const postSongs = async () => { + const postPromises = argList.map(async (arg) => { + const songs = await scrapeSongs(arg); + + // console.log(songs); // 크롤링한 데이터 확인 + // console.log(songs.length); // 크롤링한 데이터 확인 + + await postDB(songs); + }); + await Promise.all(postPromises); +}; + +const postAllSongs = async () => { + const allSongs = await scrapeAllSongs(); + const postPromises = allSongs.map(async (song) => { + await postDB(song); + }); + await Promise.all(postPromises); +}; + +const postUtaiteSongs = async () => { + const utaiteSongs = await scrapeUtaiteSongs(); + const postPromises = utaiteSongs.map(async (song) => { + await postDB(song); + }); + await Promise.all(postPromises); +}; + +// 그대로 활용 불가 (잘못된 데이터 존재) + +// postSongs(); +// postAllSongs(); +// postUtaiteSongs(); + +// 크롤링 후 데이터 확인 diff --git a/packages/crawling/src/postByRelease.js b/packages/crawling/src/postByRelease.js new file mode 100644 index 0000000..05c343e --- /dev/null +++ b/packages/crawling/src/postByRelease.js @@ -0,0 +1,11 @@ +import { + Brand, + Period, + getComposer, + getLyricist, + getNo, + getPopular, + getRelease, + getSinger, + getSong, +} from '@repo/open-api'; diff --git a/packages/crawling/src/postDB.js b/packages/crawling/src/postDB.js new file mode 100644 index 0000000..cc947f2 --- /dev/null +++ b/packages/crawling/src/postDB.js @@ -0,0 +1,26 @@ +import dotenv from 'dotenv'; +dotenv.config(); + +import { createClient } from '@supabase/supabase-js'; + +export async function postDB(songs) { + const supabaseUrl = process.env.SUPABASE_URL; + const supabaseKey = process.env.SUPABASE_KEY; + + const supabase = createClient(supabaseUrl, supabaseKey); + + let { data, error } = await supabase + .from('songs') + .upsert(songs, { + onConflict: ['title', 'artist'], + }) + .select(); + + console.log('res : ', data); + + if (!error) { + console.log('✅ Supabase에 데이터 저장 완료!'); + } else { + console.error('❌ Supabase 저장 실패:', error); + } +} diff --git a/packages/crawling/src/utils.js b/packages/crawling/src/utils.js new file mode 100644 index 0000000..17d8df6 --- /dev/null +++ b/packages/crawling/src/utils.js @@ -0,0 +1,42 @@ +export const parseNumber = (str) => { + if (str.length < 5 || !isNumber(str)) { + return null; + } + return str; +}; + +// 정규식으로 숫자 확인 +export const isNumber = (str) => { + return /^\d+$/.test(str); +}; + +export const parseJapaneseText = (text) => { + const koreanParts = text.match(/[가-힣\s,]+/g); + const koreanText = koreanParts ? koreanParts.join('').trim() : ''; + let result = text + // 일본어 독음 제거 + .replace(/\([^)]*\)/g, ''); + + // 한글 제거 + result = result.replace(/[가-힣,]+/g, '').trim(); + + // 특수 기호 제거 + result = result.replace(/[ⓢⓗⓕⓛ]/g, ''); + + if (result.length === 0 && koreanText.length > 0) { + return koreanText; + } + + if (koreanText.length > 0) { + result += `(${koreanText})`; + } + + return result; +}; + +export const parseText = (text) => { + return text + .replace(/\[[^\]]*\]/g, '') + .replace(/[※★☆○●◎◇◆□■△▲▽▼→←↑↓↔]/g, '') + .trim(); +}; diff --git a/packages/eslint-config/base.js b/packages/eslint-config/base.js index 09d316e..9bcbf88 100644 --- a/packages/eslint-config/base.js +++ b/packages/eslint-config/base.js @@ -1,8 +1,8 @@ -import js from "@eslint/js"; -import eslintConfigPrettier from "eslint-config-prettier"; -import turboPlugin from "eslint-plugin-turbo"; -import tseslint from "typescript-eslint"; -import onlyWarn from "eslint-plugin-only-warn"; +import js from '@eslint/js'; +import eslintConfigPrettier from 'eslint-config-prettier'; +import turboPlugin from 'eslint-plugin-turbo'; +import tseslint from 'typescript-eslint'; +import onlyWarn from 'eslint-plugin-only-warn'; /** * A shared ESLint configuration for the repository. @@ -18,7 +18,7 @@ export const config = [ turbo: turboPlugin, }, rules: { - "turbo/no-undeclared-env-vars": "warn", + 'turbo/no-undeclared-env-vars': 'warn', }, }, { @@ -27,6 +27,6 @@ export const config = [ }, }, { - ignores: ["dist/**"], + ignores: ['dist/**'], }, ]; diff --git a/packages/eslint-config/next.js b/packages/eslint-config/next.js index 6bf01a7..364681d 100644 --- a/packages/eslint-config/next.js +++ b/packages/eslint-config/next.js @@ -1,11 +1,11 @@ -import js from "@eslint/js"; -import eslintConfigPrettier from "eslint-config-prettier"; -import tseslint from "typescript-eslint"; -import pluginReactHooks from "eslint-plugin-react-hooks"; -import pluginReact from "eslint-plugin-react"; -import globals from "globals"; -import pluginNext from "@next/eslint-plugin-next"; -import { config as baseConfig } from "./base.js"; +import js from '@eslint/js'; +import eslintConfigPrettier from 'eslint-config-prettier'; +import tseslint from 'typescript-eslint'; +import pluginReactHooks from 'eslint-plugin-react-hooks'; +import pluginReact from 'eslint-plugin-react'; +import globals from 'globals'; +import pluginNext from '@next/eslint-plugin-next'; +import { config as baseConfig } from './base.js'; /** * A custom ESLint configuration for libraries that use Next.js. @@ -28,22 +28,22 @@ export const nextJsConfig = [ }, { plugins: { - "@next/next": pluginNext, + '@next/next': pluginNext, }, rules: { ...pluginNext.configs.recommended.rules, - ...pluginNext.configs["core-web-vitals"].rules, + ...pluginNext.configs['core-web-vitals'].rules, }, }, { plugins: { - "react-hooks": pluginReactHooks, + 'react-hooks': pluginReactHooks, }, - settings: { react: { version: "detect" } }, + settings: { react: { version: 'detect' } }, rules: { ...pluginReactHooks.configs.recommended.rules, // React scope no longer necessary with new JSX transform. - "react/react-in-jsx-scope": "off", + 'react/react-in-jsx-scope': 'off', }, }, ]; diff --git a/packages/eslint-config/react-internal.js b/packages/eslint-config/react-internal.js index daeccba..b8b50e7 100644 --- a/packages/eslint-config/react-internal.js +++ b/packages/eslint-config/react-internal.js @@ -1,10 +1,10 @@ -import js from "@eslint/js"; -import eslintConfigPrettier from "eslint-config-prettier"; -import tseslint from "typescript-eslint"; -import pluginReactHooks from "eslint-plugin-react-hooks"; -import pluginReact from "eslint-plugin-react"; -import globals from "globals"; -import { config as baseConfig } from "./base.js"; +import js from '@eslint/js'; +import eslintConfigPrettier from 'eslint-config-prettier'; +import tseslint from 'typescript-eslint'; +import pluginReactHooks from 'eslint-plugin-react-hooks'; +import pluginReact from 'eslint-plugin-react'; +import globals from 'globals'; +import { config as baseConfig } from './base.js'; /** * A custom ESLint configuration for libraries that use React. @@ -27,13 +27,13 @@ export const config = [ }, { plugins: { - "react-hooks": pluginReactHooks, + 'react-hooks': pluginReactHooks, }, - settings: { react: { version: "detect" } }, + settings: { react: { version: 'detect' } }, rules: { ...pluginReactHooks.configs.recommended.rules, // React scope no longer necessary with new JSX transform. - "react/react-in-jsx-scope": "off", + 'react/react-in-jsx-scope': 'off', }, }, ]; diff --git a/packages/api/package.json b/packages/open-api/package.json similarity index 65% rename from packages/api/package.json rename to packages/open-api/package.json index aa14073..6a49954 100644 --- a/packages/api/package.json +++ b/packages/open-api/package.json @@ -1,5 +1,5 @@ { - "name": "@repo/api", + "name": "@repo/open-api", "version": "1.0.0", "description": "", "main": "./src/index.ts", @@ -8,12 +8,14 @@ }, "type": "module", "scripts": { - "test": "node --loader ts-node/esm" + "test": "node --experimental-specifier-resolution=node --loader ts-node/esm src/test.ts", + "build": "tsup src/index.ts --format esm,cjs --dts" }, "dependencies": { "axios": "^1.5.0" }, "devDependencies": { + "tsup": "^8.4.0", "@types/node": "^22.13.10", "ts-node": "^10.9.2", "typescript": "^5.8.2" diff --git a/packages/api/src/getComposer.ts b/packages/open-api/src/getComposer.ts similarity index 91% rename from packages/api/src/getComposer.ts rename to packages/open-api/src/getComposer.ts index 68b2800..2fbdb50 100644 --- a/packages/api/src/getComposer.ts +++ b/packages/open-api/src/getComposer.ts @@ -7,7 +7,7 @@ interface GetComposerProps { brand?: Brand; } -const getComposer = async ({ composer, brand }: GetComposerProps): Promise => { +const getComposer = async ({ composer, brand }: GetComposerProps): Promise => { const response = await apiRequest('/composer', composer, brand); if (!response.success) { diff --git a/packages/api/src/getLyricist.ts b/packages/open-api/src/getLyricist.ts similarity index 91% rename from packages/api/src/getLyricist.ts rename to packages/open-api/src/getLyricist.ts index 0bf6676..c68d4b1 100644 --- a/packages/api/src/getLyricist.ts +++ b/packages/open-api/src/getLyricist.ts @@ -7,7 +7,7 @@ interface GetLyricistProps { brand?: Brand; } -const getLyricist = async ({ lyricist, brand }: GetLyricistProps): Promise => { +const getLyricist = async ({ lyricist, brand }: GetLyricistProps): Promise => { const response = await apiRequest('/lyricist', lyricist, brand); if (!response.success) { diff --git a/packages/api/src/getNo.ts b/packages/open-api/src/getNo.ts similarity index 94% rename from packages/api/src/getNo.ts rename to packages/open-api/src/getNo.ts index 6df7f5b..e1f4554 100644 --- a/packages/api/src/getNo.ts +++ b/packages/open-api/src/getNo.ts @@ -7,7 +7,7 @@ interface GetNoProps { brand?: Brand; } -const GetNo = async ({ no, brand }: GetNoProps): Promise => { +const GetNo = async ({ no, brand }: GetNoProps): Promise => { const response = await apiRequest('/no', no, brand); if (!response.success) { diff --git a/packages/api/src/getPopular.ts b/packages/open-api/src/getPopular.ts similarity index 94% rename from packages/api/src/getPopular.ts rename to packages/open-api/src/getPopular.ts index aedc843..7953c9c 100644 --- a/packages/api/src/getPopular.ts +++ b/packages/open-api/src/getPopular.ts @@ -7,7 +7,7 @@ interface GetPopularProps { period: Period; } -const getPopular = async ({ brand, period }: GetPopularProps): Promise => { +const getPopular = async ({ brand, period }: GetPopularProps): Promise => { if (!isVaildBrand(brand)) { throw new Error('Invalid brand type'); } diff --git a/packages/api/src/getRelease.ts b/packages/open-api/src/getRelease.ts similarity index 91% rename from packages/api/src/getRelease.ts rename to packages/open-api/src/getRelease.ts index bd8e120..4e54ebe 100644 --- a/packages/api/src/getRelease.ts +++ b/packages/open-api/src/getRelease.ts @@ -7,7 +7,7 @@ interface GetReleaseProps { brand?: Brand; } -const getRelease = async ({ release, brand }: GetReleaseProps): Promise => { +const getRelease = async ({ release, brand }: GetReleaseProps): Promise => { const response = await apiRequest('/release', release, brand); if (!response.success) { diff --git a/packages/api/src/getSinger.ts b/packages/open-api/src/getSinger.ts similarity index 92% rename from packages/api/src/getSinger.ts rename to packages/open-api/src/getSinger.ts index ca5b991..c40797b 100644 --- a/packages/api/src/getSinger.ts +++ b/packages/open-api/src/getSinger.ts @@ -7,7 +7,7 @@ interface GetSingerProps { brand?: Brand; } -const getSinger = async ({ singer, brand }: GetSingerProps): Promise => { +const getSinger = async ({ singer, brand }: GetSingerProps): Promise => { const response = await apiRequest('/singer', singer, brand); if (!response.success) { diff --git a/packages/open-api/src/getSong.ts b/packages/open-api/src/getSong.ts new file mode 100644 index 0000000..d1760ef --- /dev/null +++ b/packages/open-api/src/getSong.ts @@ -0,0 +1,33 @@ +import { apiRequest } from './instance'; + +import type { Brand, ResponseType } from './types'; + +interface GetSongProps { + title: string; + brand?: Brand; +} + +const getSong = async ({ title, brand }: GetSongProps): Promise => { + const response = await apiRequest('/song', title, brand); + + if (!response.success) { + return null; + } + + return response.data; +}; + +// const getSong = async ({ title, brand = ['tj', 'kumyoung'] }: GetSongProps): Promise => { +// const responseArray = await Promise.all(brand.map((brand) => apiRequest('/song', title, brand))); + +// if (!responseArray.every((response) => response.success)) { +// return null; +// } +// const response = responseArray.map((response) => response.data); +// console.log('response', response); + +// return null; +// // return response; +// }; + +export default getSong; diff --git a/packages/api/src/index.ts b/packages/open-api/src/index.ts similarity index 82% rename from packages/api/src/index.ts rename to packages/open-api/src/index.ts index 27b0056..281824a 100644 --- a/packages/api/src/index.ts +++ b/packages/open-api/src/index.ts @@ -5,3 +5,4 @@ export { default as getLyricist } from './getLyricist'; export { default as getNo } from './getNo'; export { default as getRelease } from './getRelease'; export { default as getPopular } from './getPopular'; +export type { Brand, Period, ResponseType, InstanceResponse } from './types'; diff --git a/packages/api/src/instance.ts b/packages/open-api/src/instance.ts similarity index 94% rename from packages/api/src/instance.ts rename to packages/open-api/src/instance.ts index 4b78dca..db0bf11 100644 --- a/packages/api/src/instance.ts +++ b/packages/open-api/src/instance.ts @@ -27,7 +27,7 @@ const createApiRequest = (instance: AxiosInstance) => { // brand가 있는 경우 path 수정 const finalPath = brand ? `${path}/${param}/${brand}.json` : `${path}/${param}.json`; - const response: AxiosResponse = await instance.get(finalPath); + const response: AxiosResponse = await instance.get(finalPath); return { data: response.data, diff --git a/packages/open-api/src/test.ts b/packages/open-api/src/test.ts new file mode 100644 index 0000000..1eba272 --- /dev/null +++ b/packages/open-api/src/test.ts @@ -0,0 +1,63 @@ +import { getSong, getSinger, getComposer, getLyricist, getRelease } from './index.js'; + +console.log('get song test'); + +// 요청 시 공백 제거해서 보내져야 함 + +// const response = await getSong({ title: 'theworldsmallest' }); +// console.log('response', response); + +// const response2 = await getSong({ title: '반딧불' }); +// console.log('response2', response2); + +// console.log('get singer test'); + +// const response3 = await getSinger({ singer: '아이유', brand: 'kumyoung' }); +// console.log('response3', response3); + +// const response4 = await getSinger({ singer: 'PLAVE' }); +// console.log('response4', response4); + +// console.log('get composer test'); + +// const response5 = await getComposer({ composer: '아이유', brand: 'kumyoung' }); +// console.log('response5', response5); + +// const response6 = await getComposer({ composer: '아이유' }); +// console.log('response6', response6); + +// console.log('get lyricist test'); + +// const response7 = await getLyricist({ lyricist: '아이유', brand: 'kumyoung' }); +// console.log('response7', response7); + +// const response8 = await getLyricist({ lyricist: '아이유' }); +// console.log('response8', response8); + +// console.log('get release test'); + +let year = 2025; +let month = 1; + +const parseMonth = (month: number) => { + return month < 10 ? `0${month}` : month; +}; + +// TJ는 업데이트 충실한데 금영은 안되있음 +// 그냥 TJ 것만 파싱해서 넣을까? +// 기존 DB와 중복되지 않게 tj_num, ky_num 고유값으로 +while (year <= 2025) { + month = 1; + while (month <= 12) { + const response9 = await getRelease({ release: `${year}${parseMonth(month)}`, brand: 'tj' }); + // console.log('response9', response9); + // console.log('response9', `${year}${parseMonth(month)}`, response9?.length); + response9?.forEach((item: any) => { + const { title, singer, composer, lyricist } = item; + console.log('item', item); + }); + + month++; + } + year++; +} diff --git a/packages/api/src/types.ts b/packages/open-api/src/types.ts similarity index 92% rename from packages/api/src/types.ts rename to packages/open-api/src/types.ts index 66dd88a..b07c26e 100644 --- a/packages/api/src/types.ts +++ b/packages/open-api/src/types.ts @@ -13,7 +13,7 @@ export interface ResponseType { } export interface InstanceResponse { - data: ResponseType | null; + data: ResponseType[] | null; success: boolean; error?: string; } diff --git a/packages/open-api/tsconfig.json b/packages/open-api/tsconfig.json new file mode 100644 index 0000000..6984ac0 --- /dev/null +++ b/packages/open-api/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "lib": ["ESNext", "esnext.asynciterable"], + "moduleResolution": "node", + "esModuleInterop": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "outDir": "dist", + "rootDir": "src", + "declaration": true, + "declarationDir": "./dist/types", // 디버깅 편의를 위해 추가 + "declarationMap": true // 디버깅 편의를 위해 추가 + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", "dist"], + + "ts-node": { + "esm": true, + "experimentalSpecifierResolution": "node" + } +} diff --git a/packages/query/package.json b/packages/query/package.json new file mode 100644 index 0000000..92f5e60 --- /dev/null +++ b/packages/query/package.json @@ -0,0 +1,27 @@ +{ + "name": "@repo/query", + "version": "1.0.0", + "description": "", + "main": "./src/index.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, + "type": "module", + "scripts": { + "build": "tsup src/index.ts --format esm,cjs --dts" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@repo/open-api": "workspace:*", + "@tanstack/react-query": "^5.68.0" + }, + "devDependencies": { + "tsup": "^8.4.0", + "typescript": "^5.8.2" + } +} diff --git a/packages/query/src/index.ts b/packages/query/src/index.ts new file mode 100644 index 0000000..228f28c --- /dev/null +++ b/packages/query/src/index.ts @@ -0,0 +1,8 @@ +export { default as useSong } from './useSong'; +export { default as useSinger } from './useSinger'; +export { default as useComposer } from './useComposer'; +export { default as useLyricist } from './useLyricist'; +export { default as useNo } from './useNo'; +export { default as useRelease } from './useRelease'; +export { default as usePopular } from './usePopular'; +export type { UseQueryReturn } from './types'; diff --git a/packages/query/src/types.ts b/packages/query/src/types.ts new file mode 100644 index 0000000..a71b4a6 --- /dev/null +++ b/packages/query/src/types.ts @@ -0,0 +1,8 @@ +import { ResponseType } from '@repo/open-api'; + +export interface UseQueryReturn { + data: ResponseType[] | null | undefined; + isLoading: boolean; + isError: boolean; + error: Error | null; +} diff --git a/packages/query/src/useComposer.ts b/packages/query/src/useComposer.ts new file mode 100644 index 0000000..81327c8 --- /dev/null +++ b/packages/query/src/useComposer.ts @@ -0,0 +1,29 @@ +import { useQuery } from '@tanstack/react-query'; +import { getComposer, Brand } from '@repo/open-api'; +import { UseQueryReturn } from './types'; + +interface GetComposerProps { + composer: string; + brand?: Brand; +} + +const useComposer = (props: GetComposerProps): UseQueryReturn => { + const { composer, brand } = props; + + // queryKey를 위한 brandKey 생성 (없으면 'all' 사용) + const brandKey = brand || 'all'; + + const { data, isLoading, isError, error } = useQuery({ + queryKey: ['composer', composer, brandKey], + queryFn: () => getComposer({ composer, brand }), + }); + + return { + data, + isLoading, + isError, + error, + }; +}; + +export default useComposer; diff --git a/packages/query/src/useLyricist.ts b/packages/query/src/useLyricist.ts new file mode 100644 index 0000000..1ed52d7 --- /dev/null +++ b/packages/query/src/useLyricist.ts @@ -0,0 +1,29 @@ +import { useQuery } from '@tanstack/react-query'; +import { getLyricist, Brand } from '@repo/open-api'; +import { UseQueryReturn } from './types'; + +interface GetLyricistProps { + lyricist: string; + brand?: Brand; +} + +const useLyricist = (props: GetLyricistProps): UseQueryReturn => { + const { lyricist, brand } = props; + + // queryKey를 위한 brandKey 생성 (없으면 'all' 사용) + const brandKey = brand || 'all'; + + const { data, isLoading, isError, error } = useQuery({ + queryKey: ['lyricist', lyricist, brandKey], + queryFn: () => getLyricist({ lyricist, brand }), + }); + + return { + data, + isLoading, + isError, + error, + }; +}; + +export default useLyricist; diff --git a/packages/query/src/useNo.ts b/packages/query/src/useNo.ts new file mode 100644 index 0000000..3d36862 --- /dev/null +++ b/packages/query/src/useNo.ts @@ -0,0 +1,29 @@ +import { useQuery } from '@tanstack/react-query'; +import { getNo, Brand } from '@repo/open-api'; +import { UseQueryReturn } from './types'; + +interface GetNoProps { + no: string; + brand?: Brand; +} + +const useNo = (props: GetNoProps): UseQueryReturn => { + const { no, brand } = props; + + // queryKey를 위한 brandKey 생성 (없으면 'all' 사용) + const brandKey = brand || 'all'; + + const { data, isLoading, isError, error } = useQuery({ + queryKey: ['no', no, brandKey], + queryFn: () => getNo({ no, brand }), + }); + + return { + data, + isLoading, + isError, + error, + }; +}; + +export default useNo; diff --git a/packages/query/src/usePopular.ts b/packages/query/src/usePopular.ts new file mode 100644 index 0000000..2d13679 --- /dev/null +++ b/packages/query/src/usePopular.ts @@ -0,0 +1,27 @@ +import { useQuery } from '@tanstack/react-query'; +import { getPopular, Brand, Period } from '@repo/open-api'; +import { UseQueryReturn } from './types'; + +interface GetPopularProps { + brand: Brand; + period: Period; +} + +const usePopular = (props: GetPopularProps): UseQueryReturn => { + const { brand, period } = props; + + const { data, isLoading, isError, error } = useQuery({ + queryKey: ['popular', brand, period], + queryFn: () => getPopular({ brand, period }), + enabled: Boolean(brand) && Boolean(period), + }); + + return { + data, + isLoading, + isError, + error, + }; +}; + +export default usePopular; diff --git a/packages/query/src/useRelease.ts b/packages/query/src/useRelease.ts new file mode 100644 index 0000000..047a5a3 --- /dev/null +++ b/packages/query/src/useRelease.ts @@ -0,0 +1,29 @@ +import { useQuery } from '@tanstack/react-query'; +import { getRelease, Brand } from '@repo/open-api'; +import { UseQueryReturn } from './types'; + +interface GetReleaseProps { + release: string; + brand?: Brand; +} + +const useRelease = (props: GetReleaseProps): UseQueryReturn => { + const { release, brand } = props; + + // queryKey를 위한 brandKey 생성 (없으면 'all' 사용) + const brandKey = brand || 'all'; + + const { data, isLoading, isError, error } = useQuery({ + queryKey: ['release', release, brandKey], + queryFn: () => getRelease({ release, brand }), + }); + + return { + data, + isLoading, + isError, + error, + }; +}; + +export default useRelease; diff --git a/packages/query/src/useSinger.ts b/packages/query/src/useSinger.ts new file mode 100644 index 0000000..807af07 --- /dev/null +++ b/packages/query/src/useSinger.ts @@ -0,0 +1,29 @@ +import { useQuery } from '@tanstack/react-query'; +import { getSinger, Brand } from '@repo/open-api'; +import { UseQueryReturn } from './types'; + +interface GetSingerProps { + singer: string; + brand?: Brand; +} + +const useSinger = (props: GetSingerProps): UseQueryReturn => { + const { singer, brand } = props; + + // queryKey를 위한 brandKey 생성 (없으면 'all' 사용) + const brandKey = brand || 'all'; + + const { data, isLoading, isError, error } = useQuery({ + queryKey: ['singer', singer, brandKey], + queryFn: () => getSinger({ singer, brand }), + }); + + return { + data, + isLoading, + isError, + error, + }; +}; + +export default useSinger; diff --git a/packages/query/src/useSong.ts b/packages/query/src/useSong.ts new file mode 100644 index 0000000..d5251c3 --- /dev/null +++ b/packages/query/src/useSong.ts @@ -0,0 +1,29 @@ +import { useQuery } from '@tanstack/react-query'; +import { getSong, Brand, ResponseType } from '@repo/open-api'; +import { UseQueryReturn } from './types'; + +interface GetSongProps { + title: string; + brand?: Brand; +} + +const useSong = (props: GetSongProps): UseQueryReturn => { + const { title, brand } = props; + + // queryKey를 위한 brandKey 생성 (없으면 'all' 사용) + const brandKey = brand || 'all'; + + const { data, isLoading, isError, error } = useQuery({ + queryKey: ['song', title, brandKey], + queryFn: () => getSong({ title, brand }), + }); + + return { + data, + isLoading, + isError, + error, + }; +}; + +export default useSong; diff --git a/packages/api/tsconfig.json b/packages/query/tsconfig.json similarity index 55% rename from packages/api/tsconfig.json rename to packages/query/tsconfig.json index 26456b7..8b9089c 100644 --- a/packages/api/tsconfig.json +++ b/packages/query/tsconfig.json @@ -9,8 +9,11 @@ "strict": true, "forceConsistentCasingInFileNames": true, "outDir": "dist", - "rootDir": "src" + "rootDir": "src", + "declaration": true, + "declarationDir": "./dist/types", // 디버깅 편의를 위해 추가 + "declarationMap": true // 디버깅 편의를 위해 추가 }, - "include": ["**/*.ts"], - "exclude": ["node_modules"] + "include": ["src"], + "exclude": ["node_modules", "dist"] } diff --git a/packages/ui/eslint.config.mjs b/packages/ui/eslint.config.mjs index 19170f8..fe059de 100644 --- a/packages/ui/eslint.config.mjs +++ b/packages/ui/eslint.config.mjs @@ -1,4 +1,4 @@ -import { config } from "@repo/eslint-config/react-internal"; +import { config } from '@repo/eslint-config/react-internal'; /** @type {import("eslint").Linter.Config} */ export default config; diff --git a/packages/ui/src/button.tsx b/packages/ui/src/button.tsx index 78e5420..7b117d2 100644 --- a/packages/ui/src/button.tsx +++ b/packages/ui/src/button.tsx @@ -1,6 +1,6 @@ -"use client"; +'use client'; -import { ReactNode } from "react"; +import { ReactNode } from 'react'; interface ButtonProps { children: ReactNode; @@ -10,10 +10,7 @@ interface ButtonProps { export const Button = ({ children, className, appName }: ButtonProps) => { return ( - ); diff --git a/packages/ui/src/card.tsx b/packages/ui/src/card.tsx index 7b98893..002db20 100644 --- a/packages/ui/src/card.tsx +++ b/packages/ui/src/card.tsx @@ -1,4 +1,4 @@ -import { type JSX } from "react"; +import { type JSX } from 'react'; export function Card({ className, diff --git a/packages/ui/src/code.tsx b/packages/ui/src/code.tsx index f7cbd22..cee06ef 100644 --- a/packages/ui/src/code.tsx +++ b/packages/ui/src/code.tsx @@ -1,11 +1,5 @@ -import { type JSX } from "react"; +import { type JSX } from 'react'; -export function Code({ - children, - className, -}: { - children: React.ReactNode; - className?: string; -}): JSX.Element { +export function Code({ children, className }: { children: React.ReactNode; className?: string }): JSX.Element { return {children}; } diff --git a/packages/ui/turbo/generators/config.ts b/packages/ui/turbo/generators/config.ts index 40100ba..58c565f 100644 --- a/packages/ui/turbo/generators/config.ts +++ b/packages/ui/turbo/generators/config.ts @@ -1,27 +1,27 @@ -import type { PlopTypes } from "@turbo/gen"; +import type { PlopTypes } from '@turbo/gen'; // Learn more about Turborepo Generators at https://turbo.build/repo/docs/core-concepts/monorepos/code-generation export default function generator(plop: PlopTypes.NodePlopAPI): void { // A simple generator to add a new React component to the internal UI library - plop.setGenerator("react-component", { - description: "Adds a new react component", + plop.setGenerator('react-component', { + description: 'Adds a new react component', prompts: [ { - type: "input", - name: "name", - message: "What is the name of the component?", + type: 'input', + name: 'name', + message: 'What is the name of the component?', }, ], actions: [ { - type: "add", - path: "src/{{kebabCase name}}.tsx", - templateFile: "templates/component.hbs", + type: 'add', + path: 'src/{{kebabCase name}}.tsx', + templateFile: 'templates/component.hbs', }, { - type: "append", - path: "package.json", + type: 'append', + path: 'package.json', pattern: /"exports": {(?)/g, template: ' "./{{kebabCase name}}": "./src/{{kebabCase name}}.tsx",', }, diff --git a/packages/ui/turbo/generators/templates/component.hbs b/packages/ui/turbo/generators/templates/component.hbs index d968b9e..5a3ace4 100644 --- a/packages/ui/turbo/generators/templates/component.hbs +++ b/packages/ui/turbo/generators/templates/component.hbs @@ -1,8 +1,8 @@ -export const {{ pascalCase name }} = ({ children }: { children: React.ReactNode }) => { - return ( -
-

{{ pascalCase name }} Component

- {children} -
- ); -}; +export const +{{pascalCase name}} += ({ children }: { children: React.ReactNode }) => { return ( +
+

{{pascalCase name}} Component

+ {children} +
+); }; \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fe74611..aa91e17 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,13 +8,16 @@ importers: .: dependencies: - tamagui: - specifier: ^1.125.23 - version: 1.125.23(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) + react: + specifier: ^19.0.0 + version: 19.0.0 devDependencies: prettier: specifier: ^3.5.3 version: 3.5.3 + prettier-plugin-tailwindcss: + specifier: ^0.6.11 + version: 0.6.11(@trivago/prettier-plugin-sort-imports@5.2.2(prettier@3.5.3))(prettier@3.5.3) turbo: specifier: ^2.4.4 version: 2.4.4 @@ -111,10 +114,10 @@ importers: version: 18.3.1 jest: specifier: ^29.2.1 - version: 29.7.0(@types/node@22.13.9)(ts-node@10.9.2(@types/node@22.13.9)(typescript@5.8.2)) + version: 29.7.0(@types/node@22.13.10)(ts-node@10.9.2(@types/node@22.13.10)(typescript@5.8.2)) jest-expo: specifier: ~52.0.6 - version: 52.0.6(@babel/core@7.26.10)(expo@52.0.38(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1)))(react-native-webview@13.12.5(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(jest@29.7.0(@types/node@22.13.9)(ts-node@10.9.2(@types/node@22.13.9)(typescript@5.8.2)))(react-dom@18.3.1(react@18.3.1))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1)(webpack@5.98.0) + version: 52.0.6(@babel/core@7.26.10)(expo@52.0.38(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1)))(react-native-webview@13.12.5(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(jest@29.7.0(@types/node@22.13.10)(ts-node@10.9.2(@types/node@22.13.10)(typescript@5.8.2)))(react-dom@18.3.1(react@18.3.1))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1)(webpack@5.98.0) react-test-renderer: specifier: 18.3.1 version: 18.3.1(react@18.3.1) @@ -124,25 +127,115 @@ importers: apps/web: dependencies: - '@repo/api': + '@dnd-kit/core': + specifier: ^6.3.1 + version: 6.3.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@dnd-kit/modifiers': + specifier: ^9.0.0 + version: 9.0.0(@dnd-kit/core@6.3.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0) + '@dnd-kit/sortable': + specifier: ^10.0.0 + version: 10.0.0(@dnd-kit/core@6.3.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0) + '@dnd-kit/utilities': + specifier: ^3.2.2 + version: 3.2.2(react@19.0.0) + '@radix-ui/react-checkbox': + specifier: ^1.1.5 + version: 1.1.5(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-dialog': + specifier: ^1.1.6 + version: 1.1.6(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-dropdown-menu': + specifier: ^2.1.6 + version: 2.1.6(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-label': + specifier: ^2.1.2 + version: 2.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-scroll-area': + specifier: ^1.2.4 + version: 1.2.4(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-separator': + specifier: ^1.1.2 + version: 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-slot': + specifier: ^1.1.2 + version: 1.1.2(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-tabs': + specifier: ^1.1.3 + version: 1.1.3(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@repo/open-api': + specifier: workspace:* + version: link:../../packages/open-api + '@repo/query': specifier: workspace:* - version: link:../../packages/api + version: link:../../packages/query + '@supabase/ssr': + specifier: ^0.6.1 + version: 0.6.1(@supabase/supabase-js@2.49.1) + '@supabase/supabase-js': + specifier: ^2.49.1 + version: 2.49.1 + '@tanstack/react-query': + specifier: ^5.68.0 + version: 5.68.0(react@19.0.0) + '@tanstack/react-query-devtools': + specifier: ^5.68.0 + version: 5.68.0(@tanstack/react-query@5.68.0(react@19.0.0))(react@19.0.0) + '@vercel/analytics': + specifier: ^1.5.0 + version: 1.5.0(next@15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0) + '@vercel/speed-insights': + specifier: ^1.2.0 + version: 1.2.0(next@15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0) axios: specifier: ^1.5.0 version: 1.8.3 + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + immer: + specifier: ^10.1.1 + version: 10.1.1 + lucide-react: + specifier: ^0.483.0 + version: 0.483.0(react@19.0.0) next: specifier: 15.2.2 - version: 15.2.2(@babel/core@7.26.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + version: 15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + next-themes: + specifier: ^0.4.6 + version: 0.4.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react: specifier: ^19.0.0 version: 19.0.0 react-dom: specifier: ^19.0.0 version: 19.0.0(react@19.0.0) + sonner: + specifier: ^2.0.3 + version: 2.0.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + tailwind-merge: + specifier: ^3.0.2 + version: 3.0.2 + tw-animate-css: + specifier: ^1.2.4 + version: 1.2.4 + zustand: + specifier: ^5.0.3 + version: 5.0.3(@types/react@19.0.10)(immer@10.1.1)(react@19.0.0)(use-sync-external-store@1.4.0(react@19.0.0)) devDependencies: '@eslint/eslintrc': specifier: ^3 version: 3.3.0 + '@tailwindcss/postcss': + specifier: ^4.0.15 + version: 4.0.15 + '@trivago/prettier-plugin-sort-imports': + specifier: ^5.2.2 + version: 5.2.2(prettier@3.5.3) '@types/node': specifier: ^20 version: 20.17.24 @@ -152,31 +245,48 @@ importers: '@types/react-dom': specifier: ^19 version: 19.0.4(@types/react@19.0.10) + autoprefixer: + specifier: ^10.4.21 + version: 10.4.21(postcss@8.5.3) eslint: specifier: ^9 - version: 9.22.0 + version: 9.22.0(jiti@2.4.2) eslint-config-next: specifier: 15.2.2 - version: 15.2.2(eslint@9.22.0)(typescript@5.8.2) + version: 15.2.2(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) + postcss: + specifier: ^8.5.3 + version: 8.5.3 + prettier: + specifier: ^3.5.3 + version: 3.5.3 + prettier-plugin-tailwindcss: + specifier: ^0.6.11 + version: 0.6.11(@trivago/prettier-plugin-sort-imports@5.2.2(prettier@3.5.3))(prettier@3.5.3) + tailwindcss: + specifier: ^4.0.15 + version: 4.0.15 typescript: specifier: ^5 version: 5.8.2 - packages/api: + packages/crawling: dependencies: + '@repo/open-api': + specifier: workspace:* + version: link:../open-api + '@supabase/supabase-js': + specifier: ^2.49.1 + version: 2.49.1 axios: specifier: ^1.5.0 version: 1.8.3 - devDependencies: - '@types/node': - specifier: ^22.13.10 - version: 22.13.10 - ts-node: - specifier: ^10.9.2 - version: 10.9.2(@types/node@22.13.10)(typescript@5.8.2) - typescript: - specifier: ^5.8.2 - version: 5.8.2 + cheerio: + specifier: ^1.0.0 + version: 1.0.0 + dotenv: + specifier: ^16.4.7 + version: 16.4.7 packages/eslint-config: devDependencies: @@ -188,22 +298,22 @@ importers: version: 15.2.1 eslint: specifier: ^9.22.0 - version: 9.22.0 + version: 9.22.0(jiti@2.4.2) eslint-config-prettier: specifier: ^10.1.1 - version: 10.1.1(eslint@9.22.0) + version: 10.1.1(eslint@9.22.0(jiti@2.4.2)) eslint-plugin-only-warn: specifier: ^1.1.0 version: 1.1.0 eslint-plugin-react: specifier: ^7.37.4 - version: 7.37.4(eslint@9.22.0) + version: 7.37.4(eslint@9.22.0(jiti@2.4.2)) eslint-plugin-react-hooks: specifier: ^5.2.0 - version: 5.2.0(eslint@9.22.0) + version: 5.2.0(eslint@9.22.0(jiti@2.4.2)) eslint-plugin-turbo: specifier: ^2.4.4 - version: 2.4.4(eslint@9.22.0)(turbo@2.4.4) + version: 2.4.4(eslint@9.22.0(jiti@2.4.2))(turbo@2.4.4) globals: specifier: ^16.0.0 version: 16.0.0 @@ -212,7 +322,42 @@ importers: version: 5.8.2 typescript-eslint: specifier: ^8.26.0 - version: 8.26.0(eslint@9.22.0)(typescript@5.8.2) + version: 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) + + packages/open-api: + dependencies: + axios: + specifier: ^1.5.0 + version: 1.8.3 + devDependencies: + '@types/node': + specifier: ^22.13.10 + version: 22.13.10 + ts-node: + specifier: ^10.9.2 + version: 10.9.2(@types/node@22.13.10)(typescript@5.8.2) + tsup: + specifier: ^8.4.0 + version: 8.4.0(jiti@2.4.2)(postcss@8.5.3)(typescript@5.8.2) + typescript: + specifier: ^5.8.2 + version: 5.8.2 + + packages/query: + dependencies: + '@repo/open-api': + specifier: workspace:* + version: link:../open-api + '@tanstack/react-query': + specifier: ^5.68.0 + version: 5.68.0(react@19.0.0) + devDependencies: + tsup: + specifier: ^8.4.0 + version: 8.4.0(jiti@2.4.2)(postcss@8.5.3)(typescript@5.8.2) + typescript: + specifier: ^5.8.2 + version: 5.8.2 packages/typescript-config: {} @@ -245,7 +390,7 @@ importers: version: 19.0.4(@types/react@19.0.10) eslint: specifier: ^9.22.0 - version: 9.22.0 + version: 9.22.0(jiti@2.4.2) typescript: specifier: 5.8.2 version: 5.8.2 @@ -260,6 +405,10 @@ packages: graphql: optional: true + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + '@ampproject/remapping@2.3.0': resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} @@ -986,6 +1135,34 @@ packages: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} + '@dnd-kit/accessibility@3.1.1': + resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==} + peerDependencies: + react: '>=16.8.0' + + '@dnd-kit/core@6.3.1': + resolution: {integrity: sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@dnd-kit/modifiers@9.0.0': + resolution: {integrity: sha512-ybiLc66qRGuZoC20wdSSG6pDXFikui/dCNGthxv4Ndy8ylErY0N3KVxY2bgo7AWwIbxDmXDg3ylAFmnrjcbVvw==} + peerDependencies: + '@dnd-kit/core': ^6.3.0 + react: '>=16.8.0' + + '@dnd-kit/sortable@10.0.0': + resolution: {integrity: sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==} + peerDependencies: + '@dnd-kit/core': ^6.3.0 + react: '>=16.8.0' + + '@dnd-kit/utilities@3.2.2': + resolution: {integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==} + peerDependencies: + react: '>=16.8.0' + '@egjs/hammerjs@2.0.17': resolution: {integrity: sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==} engines: {node: '>=0.8.0'} @@ -993,6 +1170,156 @@ packages: '@emnapi/runtime@1.3.1': resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==} + '@esbuild/aix-ppc64@0.25.1': + resolution: {integrity: sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.1': + resolution: {integrity: sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.1': + resolution: {integrity: sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.1': + resolution: {integrity: sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.1': + resolution: {integrity: sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.1': + resolution: {integrity: sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.1': + resolution: {integrity: sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.1': + resolution: {integrity: sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.1': + resolution: {integrity: sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.1': + resolution: {integrity: sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.1': + resolution: {integrity: sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.1': + resolution: {integrity: sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.1': + resolution: {integrity: sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.1': + resolution: {integrity: sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.1': + resolution: {integrity: sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.1': + resolution: {integrity: sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.1': + resolution: {integrity: sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.1': + resolution: {integrity: sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.1': + resolution: {integrity: sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.1': + resolution: {integrity: sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.1': + resolution: {integrity: sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.25.1': + resolution: {integrity: sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.1': + resolution: {integrity: sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.1': + resolution: {integrity: sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.1': + resolution: {integrity: sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.4.1': resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1124,18 +1451,6 @@ packages: react: '>=16.8.0' react-dom: '>=16.8.0' - '@floating-ui/react-native@0.10.7': - resolution: {integrity: sha512-deSecLPrdfl8RL1yyNJlbgqDDZFPuhBtJhY2aTnOZOoJWaal2vVOad9EBVIa0QV/YordgTyFPgDI8oLfyLZuZA==} - peerDependencies: - react: '>=16.8.0' - react-native: '>=0.64.0' - - '@floating-ui/react@0.27.5': - resolution: {integrity: sha512-BX3jKxo39Ba05pflcQmqPPwc0qdNsdNi/eweAFtoIdrJWNen2sVEWMEac3i6jU55Qfx+lOcdMNKYn2CtWmlnOQ==} - peerDependencies: - react: '>=17.0.0' - react-dom: '>=17.0.0' - '@floating-ui/utils@0.2.9': resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==} @@ -1455,542 +1770,814 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@radix-ui/react-compose-refs@1.0.0': - resolution: {integrity: sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 - - '@radix-ui/react-slot@1.0.1': - resolution: {integrity: sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 + '@radix-ui/number@1.1.1': + resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} - '@react-native/assets-registry@0.76.7': - resolution: {integrity: sha512-o79whsqL5fbPTUQO9w1FptRd4cw1TaeOrXtQSLQeDrMVAenw/wmsjyPK10VKtvqxa1KNMtWEyfgxcM8CVZVFmg==} - engines: {node: '>=18'} + '@radix-ui/primitive@1.1.1': + resolution: {integrity: sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==} - '@react-native/babel-plugin-codegen@0.76.7': - resolution: {integrity: sha512-+8H4DXJREM4l/pwLF/wSVMRzVhzhGDix5jLezNrMD9J1U1AMfV2aSkWA1XuqR7pjPs/Vqf6TaPL7vJMZ4LU05Q==} - engines: {node: '>=18'} + '@radix-ui/primitive@1.1.2': + resolution: {integrity: sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==} - '@react-native/babel-preset@0.76.7': - resolution: {integrity: sha512-/c5DYZ6y8tyg+g8tgXKndDT7mWnGmkZ9F+T3qNDfoE3Qh7ucrNeC2XWvU9h5pk8eRtj9l4SzF4aO1phzwoibyg==} - engines: {node: '>=18'} + '@radix-ui/react-arrow@1.1.2': + resolution: {integrity: sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg==} peerDependencies: - '@babel/core': '*' + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@react-native/codegen@0.76.7': - resolution: {integrity: sha512-FAn585Ll65YvkSrKDyAcsdjHhhAGiMlSTUpHh0x7J5ntudUns+voYms0xMP+pEPt0XuLdjhD7zLIIlAWP407+g==} - engines: {node: '>=18'} + '@radix-ui/react-checkbox@1.1.5': + resolution: {integrity: sha512-B0gYIVxl77KYDR25AY9EGe/G//ef85RVBIxQvK+m5pxAC7XihAc/8leMHhDvjvhDu02SBSb6BuytlWr/G7F3+g==} peerDependencies: - '@babel/preset-env': ^7.1.6 + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@react-native/community-cli-plugin@0.76.7': - resolution: {integrity: sha512-lrcsY2WPLCEWU1pjdNV9+Ccj8vCEwCCURZiPa5aqi7lKB4C++1hPrxA8/CWWnTNcQp76DsBKGYqTFj7Ud4aupw==} - engines: {node: '>=18'} + '@radix-ui/react-collection@1.1.2': + resolution: {integrity: sha512-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw==} peerDependencies: - '@react-native-community/cli-server-api': '*' + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: - '@react-native-community/cli-server-api': + '@types/react': + optional: true + '@types/react-dom': optional: true - '@react-native/debugger-frontend@0.76.7': - resolution: {integrity: sha512-89ZtZXt7ZxE94i7T94qzZMhp4Gfcpr/QVpGqEaejAxZD+gvDCH21cYSF+/Rz2ttBazm0rk5MZ0mFqb0Iqp1jmw==} - engines: {node: '>=18'} - - '@react-native/dev-middleware@0.76.7': - resolution: {integrity: sha512-Jsw8g9DyLPnR9yHEGuT09yHZ7M88/GL9CtU9WmyChlBwdXSeE3AmRqLegsV3XcgULQ1fqdemokaOZ/MwLYkjdA==} - engines: {node: '>=18'} - - '@react-native/gradle-plugin@0.76.7': - resolution: {integrity: sha512-gQI6RcrJbigU8xk7F960C5xQIgvbBj20TUvGecD+N2PHfbLpqR+92cj7hz3UcbrCONmTP40WHnbMMJ8P+kLsrA==} - engines: {node: '>=18'} - - '@react-native/js-polyfills@0.76.7': - resolution: {integrity: sha512-+iEikj6c6Zvrg1c3cYMeiPB+5nS8EaIC3jCtP6Muk3qc7c386IymEPM2xycIlfg04DPZvO3D4P2/vaO9/TCnUg==} - engines: {node: '>=18'} - - '@react-native/metro-babel-transformer@0.76.7': - resolution: {integrity: sha512-jDS1wR7q46xY5ah+jF714Mvss9l7+lmwW/tplahZgLKozkYDC8Td5o9TOCgKlv18acw9H1V7zv8ivuRSj8ICPg==} - engines: {node: '>=18'} + '@radix-ui/react-compose-refs@1.0.0': + resolution: {integrity: sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==} peerDependencies: - '@babel/core': '*' - - '@react-native/normalize-color@2.1.0': - resolution: {integrity: sha512-Z1jQI2NpdFJCVgpY+8Dq/Bt3d+YUi1928Q+/CZm/oh66fzM0RUl54vvuXlPJKybH4pdCZey1eDTPaLHkMPNgWA==} - - '@react-native/normalize-colors@0.74.89': - resolution: {integrity: sha512-qoMMXddVKVhZ8PA1AbUCk83trpd6N+1nF2A6k1i6LsQObyS92fELuk8kU/lQs6M7BsMHwqyLCpQJ1uFgNvIQXg==} - - '@react-native/normalize-colors@0.76.7': - resolution: {integrity: sha512-ST1xxBuYVIXPdD81dR6+tzIgso7m3pa9+6rOBXTh5Xm7KEEFik7tnQX+GydXYMp3wr1gagJjragdXkPnxK6WNg==} + react: ^16.8 || ^17.0 || ^18.0 - '@react-native/virtualized-lists@0.76.7': - resolution: {integrity: sha512-pRUf1jUO8H9Ft04CaWv76t34QI9wY0sydoYlIwEtqXjjMJgmgDoOCAWBjArgn2mk8/rK+u/uicI67ZCYCp1pJw==} - engines: {node: '>=18'} + '@radix-ui/react-compose-refs@1.1.1': + resolution: {integrity: sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==} peerDependencies: - '@types/react': ^18.2.6 - react: '*' - react-native: '*' + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true - '@react-navigation/bottom-tabs@7.2.1': - resolution: {integrity: sha512-UGC7csRD/1+SJKLbaEg8K44KvkdBaEBIro0PpIRawRmHS93emf4LNfDafd8y6pReJN93OVVnqLWqcYozx4lZ4A==} + '@radix-ui/react-compose-refs@1.1.2': + resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} peerDependencies: - '@react-navigation/native': ^7.0.15 - react: '>= 18.2.0' - react-native: '*' - react-native-safe-area-context: '>= 4.0.0' - react-native-screens: '>= 4.0.0' + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@react-navigation/core@7.4.0': - resolution: {integrity: sha512-URiDluFl7cLA7GtOAsEvRqPmEMlSSXadqQ3wi9+Dl43dNRMqnoF76WQ9BCXeUPLydJq4yVte9XeMPyD6a0lY1g==} + '@radix-ui/react-context@1.1.1': + resolution: {integrity: sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==} peerDependencies: - react: '>= 18.2.0' + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@react-navigation/elements@2.2.6': - resolution: {integrity: sha512-UPeaCcEDSDRaxjG+qEHbur6jmNW/f9QNCyPsUt6NMgPEdbB5Z8K8oSx2swIaiCnvUbs/K5G3MuWkqQxGj8QXXA==} + '@radix-ui/react-context@1.1.2': + resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} peerDependencies: - '@react-native-masked-view/masked-view': '>= 0.2.0' - '@react-navigation/native': ^7.0.15 - react: '>= 18.2.0' - react-native: '*' - react-native-safe-area-context: '>= 4.0.0' + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: - '@react-native-masked-view/masked-view': + '@types/react': optional: true - '@react-navigation/native-stack@7.2.1': - resolution: {integrity: sha512-zqC6DVpO4pFZrl+8JuIgV8qk+AGdTuv+hJ5EHePmzs9gYSUrDpw6LahFCiXshwBvi9LinIw9Do7mtnQK2Q8AGA==} + '@radix-ui/react-dialog@1.1.6': + resolution: {integrity: sha512-/IVhJV5AceX620DUJ4uYVMymzsipdKBzo3edo+omeskCKGm9FRHM0ebIdbPnlQVJqyuHbuBltQUOG2mOTq2IYw==} peerDependencies: - '@react-navigation/native': ^7.0.15 - react: '>= 18.2.0' - react-native: '*' - react-native-safe-area-context: '>= 4.0.0' - react-native-screens: '>= 4.0.0' + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@react-navigation/native@7.0.15': - resolution: {integrity: sha512-72PabJJ8VY3GM8i/DCutFW+ATED96ZV6NH+bW+ry1EL0ZFGHoie96H+KzTqktsrUbBw1rd9KXbEQhBQgo0N7iQ==} + '@radix-ui/react-direction@1.1.0': + resolution: {integrity: sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==} peerDependencies: - react: '>= 18.2.0' - react-native: '*' - - '@react-navigation/routers@7.2.0': - resolution: {integrity: sha512-lMyib39H4a//u+eiyt162U6TwCfI8zJbjl9ovjKtDddQ4/Vf7b8/OhyimnJH09N2CBfm4pv0gCV6Q0WnZcfaJg==} - - '@rtsao/scc@1.1.0': - resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - - '@rushstack/eslint-patch@1.11.0': - resolution: {integrity: sha512-zxnHvoMQVqewTJr/W4pKjF0bMGiKJv1WX7bSrkl46Hg0QjESbzBROWK0Wg4RphzSOS5Jiy7eFimmM3UgMrMZbQ==} - - '@segment/loosely-validate-event@2.0.0': - resolution: {integrity: sha512-ZMCSfztDBqwotkl848ODgVcAmN4OItEWDCkshcKz0/W6gGSQayuuCtWV/MlodFivAZD793d6UgANd6wCXUfrIw==} - - '@sinclair/typebox@0.27.8': - resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} - - '@sinonjs/commons@3.0.1': - resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} - - '@sinonjs/fake-timers@10.3.0': - resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} - - '@swc/counter@0.1.3': - resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} - - '@swc/helpers@0.5.15': - resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@tamagui/accordion@1.125.23': - resolution: {integrity: sha512-jJWjiFmseqL/O72KBu51suzO2+Fk45fvXHY7JQyJW4l+lNukak+Y6H0c53ynqL2n3rImP8mGQHNyrOOTi7jpaA==} + '@radix-ui/react-direction@1.1.1': + resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} peerDependencies: - react: '*' - - '@tamagui/adapt@1.125.23': - resolution: {integrity: sha512-zTHwyh0bWzX1rFTcJsdI0gTzPIAYpqzE/HikHk+lT+cYqRFIK9gtj6Aw3tk//ZWd8iHSsPJUbf63mgBxvcR7sA==} + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@tamagui/alert-dialog@1.125.23': - resolution: {integrity: sha512-tNk9KW9k5zgX/xl0rSpCZj9px3t5kd/d0vM3jPBObDd4s4y9A7s340t8SPXLag4vaChuZVEds6Wii6kGhYtwVQ==} + '@radix-ui/react-dismissable-layer@1.1.5': + resolution: {integrity: sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==} peerDependencies: - react: '*' - - '@tamagui/animate-presence@1.125.23': - resolution: {integrity: sha512-N4P9wOeJd0+bO9TYIaTE3MCEq2dbujku+FovM1J4cGmx3WySHvvFIjPMGshLccfgWtCIPkIHDHgZn4MhBFTrJQ==} - - '@tamagui/animate@1.125.23': - resolution: {integrity: sha512-1jfmH3a9fp3tNovIg1lr6LeNoyx816C0sZIA9SCtROQ9RVmZnDahi4y5TVimhSqzwWvHxgRyETc1kE9SFRk4sA==} + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@tamagui/animations-react-native@1.125.23': - resolution: {integrity: sha512-NdoqAZr5g+RXqlnxkTBQ1oxKzM0e/+b9/01gT+38D0bSqawB1tt7xz6PLYG5Sua9swT31HfevX6U3k09wJWabQ==} + '@radix-ui/react-dropdown-menu@2.1.6': + resolution: {integrity: sha512-no3X7V5fD487wab/ZYSHXq3H37u4NVeLDKI/Ks724X/eEFSSEFYZxWgsIlr1UBeEyDaM29HM5x9p1Nv8DuTYPA==} peerDependencies: - react: '*' + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@tamagui/aria-hidden@1.125.23': - resolution: {integrity: sha512-WUOROYNpZhRE6x1XYV0sw9oPYh7kFdv8BYvOKGLOgvc4SsMhmmhKKn1qP7MEH0/DKrvEzcfIRRx0ovFy8vlq4w==} + '@radix-ui/react-focus-guards@1.1.1': + resolution: {integrity: sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==} peerDependencies: - react: '*' + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@tamagui/avatar@1.125.23': - resolution: {integrity: sha512-ccpzRWIgNzfxt2eRSJ7UY6bo+L3p4tD96R6FkZM433O9w9AaocxxkT+RUCWL0dp2zefnfphZQNOsr3c9kZTJPQ==} + '@radix-ui/react-focus-scope@1.1.2': + resolution: {integrity: sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA==} peerDependencies: - react: '*' + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@tamagui/button@1.125.23': - resolution: {integrity: sha512-10YqFz+R84D+0zH2hY9296z1A8+QPvoUXMm7Hme0cSjK3kLlBOzEjY3jqZ+4vKlKzu2tCtvg3X4H/aSzJNdKVQ==} + '@radix-ui/react-id@1.1.0': + resolution: {integrity: sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==} peerDependencies: - react: '*' + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@tamagui/card@1.125.23': - resolution: {integrity: sha512-gU4cSphPAaSSVs4YEZcUtVQP/eQ8Gfos8GpMvOVeiVy78ioEbe56PwrpxrtjiZ22z5Rn9CKF/UN8ed+hflj7jg==} + '@radix-ui/react-label@2.1.2': + resolution: {integrity: sha512-zo1uGMTaNlHehDyFQcDZXRJhUPDuukcnHz0/jnrup0JA6qL+AFpAnty+7VKa9esuU5xTblAZzTGYJKSKaBxBhw==} peerDependencies: - react: '*' + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@tamagui/checkbox-headless@1.125.23': - resolution: {integrity: sha512-kH5b3+Nes1Fbh+lg+SUGVh0tQ1m3CycBUTxlVjCDlKil+Xk6gb3eqtFnthgXCrl590S/KaQekTZZf0SiOi1zsA==} + '@radix-ui/react-menu@2.1.6': + resolution: {integrity: sha512-tBBb5CXDJW3t2mo9WlO7r6GTmWV0F0uzHZVFmlRmYpiSK1CDU5IKojP1pm7oknpBOrFZx/YgBRW9oorPO2S/Lg==} peerDependencies: - react: '*' + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@tamagui/checkbox@1.125.23': - resolution: {integrity: sha512-egbNuVsmiVHnVRbqv5UVLRafaRcox94J9CVxXCmZR6k7/UzUvD6qUWUZdDC0DmQefudEeseWnCugJWHpZTuwPw==} + '@radix-ui/react-popper@1.2.2': + resolution: {integrity: sha512-Rvqc3nOpwseCyj/rgjlJDYAgyfw7OC1tTkKn2ivhaMGcYt8FSBlahHOZak2i3QwkRXUXgGgzeEe2RuqeEHuHgA==} peerDependencies: - react: '*' + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@tamagui/collapsible@1.125.23': - resolution: {integrity: sha512-j5CZHEAl+TuyQOAQi3BmWpEtvWkSHsJrizEhPcc5LfXntprq10gjBdydj8n/TSDlOLkBB/A1jh6JnJQAgMLdow==} + '@radix-ui/react-portal@1.1.4': + resolution: {integrity: sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==} peerDependencies: - react: '*' + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@tamagui/collection@1.125.23': - resolution: {integrity: sha512-zLHtxroqS/zDh3QreahqYqMPJpjRbQXd03CYyYmZigw/QZ/sk0nIP724sEIE3BjKgKVpA0EfdCGtxv9xjkfD+Q==} + '@radix-ui/react-presence@1.1.2': + resolution: {integrity: sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==} peerDependencies: - react: '*' + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@tamagui/compose-refs@1.125.23': - resolution: {integrity: sha512-H4r0lQYmF7aIyWiPoxW7tDvLpk43NGj/rttZ93e4iCBfeSHLhSNFULlrXPMCQE1oDwFqdG7b0Yx9O93rviLtRg==} + '@radix-ui/react-presence@1.1.3': + resolution: {integrity: sha512-IrVLIhskYhH3nLvtcBLQFZr61tBG7wx7O3kEmdzcYwRGAEBmBicGGL7ATzNgruYJ3xBTbuzEEq9OXJM3PAX3tA==} peerDependencies: - react: '*' + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@tamagui/constants@1.125.23': - resolution: {integrity: sha512-r37NVwYwGjLaKnlxOVeecSALWq4o15Sc0MMFgvtRvM65Jg2T7wjo3r1BjzymWKhnMSDUiwmkQRPM76ly4Lfz5g==} + '@radix-ui/react-primitive@2.0.2': + resolution: {integrity: sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==} peerDependencies: - react: '*' - - '@tamagui/core@1.125.23': - resolution: {integrity: sha512-lHI55xtxkfnMBiCJSxT8510fF0sulIuGmeXOm9ZhppNtCcrhnSXLAEFsVN2B+Ai+tjheIgLyhKCxWTrgOBCdhQ==} + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@tamagui/create-context@1.125.23': - resolution: {integrity: sha512-7LxRXPE3FSaiD4/q4PntfXxlVcNx8DL6nOPB7uwwTBoshsM8h9/AlhI0J1XE3lbZATCxsakZlZHbfwLIr/oV7g==} + '@radix-ui/react-primitive@2.0.3': + resolution: {integrity: sha512-Pf/t/GkndH7CQ8wE2hbkXA+WyZ83fhQQn5DDmwDiDo6AwN/fhaH8oqZ0jRjMrO2iaMhDi6P1HRx6AZwyMinY1g==} peerDependencies: - react: '*' + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@tamagui/dialog@1.125.23': - resolution: {integrity: sha512-xVGNMgh6Cxnp3FZBdomgBiCOEzXXnTiXV8GSQHrPWsEwYHxk0jtKkUsa0cTeJfk17JTpIaddqpNw50Cc+hYYkw==} + '@radix-ui/react-roving-focus@1.1.2': + resolution: {integrity: sha512-zgMQWkNO169GtGqRvYrzb0Zf8NhMHS2DuEB/TiEmVnpr5OqPU3i8lfbxaAmC2J/KYuIQxyoQQ6DxepyXp61/xw==} peerDependencies: - react: '*' + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@tamagui/dismissable@1.125.23': - resolution: {integrity: sha512-DWWLHtrN0xOpU1MdHrtC/NGAOH7aq2AKG/+1CAOFNdoT06qaJgJkgA3Hw2Rmwyz5GjCNhaQ6zsNd0uOuzBsRfw==} + '@radix-ui/react-scroll-area@1.2.4': + resolution: {integrity: sha512-G9rdWTQjOR4sk76HwSdROhPU0jZWpfozn9skU1v4N0/g9k7TmswrJn8W8WMU+aYktnLLpk5LX6fofj2bGe5NFQ==} peerDependencies: - react: '*' + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@tamagui/elements@1.125.23': - resolution: {integrity: sha512-5cst7q1gnLshA1U+EbZ4PDLo8z0lHT1cwj93WSu/wUABGZDUlfdDeoXlRtQo3Dap8z36s2+rR/uXwU1GDmNJ3Q==} + '@radix-ui/react-separator@1.1.2': + resolution: {integrity: sha512-oZfHcaAp2Y6KFBX6I5P1u7CQoy4lheCGiYj+pGFrHy8E/VNRb5E39TkTr3JrV520csPBTZjkuKFdEsjS5EUNKQ==} peerDependencies: - react: '*' - - '@tamagui/fake-react-native@1.125.23': - resolution: {integrity: sha512-3I391LBLo0Rw6rdhxKbh+p3B6hhZ6rkvWgKC/cjDESTy5+feIgJh+l4GxRm9riK7qL0FevAPUy5BZSPiJpqiAA==} + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@tamagui/floating@1.125.23': - resolution: {integrity: sha512-4Z5KOGmceH/0ukHhyUyaX8WUHtMpq1pDTmuxUAcXXblvQIJ83UJyoCELRgkVAphHN4LsxHN1KWlES7iX3nCPJA==} + '@radix-ui/react-slot@1.0.1': + resolution: {integrity: sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw==} peerDependencies: - react: '*' + react: ^16.8 || ^17.0 || ^18.0 - '@tamagui/focus-scope@1.125.23': - resolution: {integrity: sha512-GjGqaBSRxZB4+E1B/vkIg4hBy8XJtyv51AFOifYJulH8tptReDNauA483EcZSd2WFWPeik6DC2zk66nTPb3r+g==} + '@radix-ui/react-slot@1.1.2': + resolution: {integrity: sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==} peerDependencies: - react: '*' + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@tamagui/focusable@1.125.23': - resolution: {integrity: sha512-rd62D+a+FtGl3l+fUZymHbu0YXTE18RUtfz8i/O4fQSpo/haS8DHcCO6C9zKD4OtoyfmjBQWcK3dOQujYsc26w==} + '@radix-ui/react-slot@1.2.0': + resolution: {integrity: sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w==} peerDependencies: - react: '*' + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@tamagui/font-size@1.125.23': - resolution: {integrity: sha512-XlZ6jH7JRyUYbyeNvdNAsazFIWKZS1kB0DtaDRnfabMfTze04ZyYwQaXIgQOMAUCzif/wvhFYSkzBtnltE9f+g==} + '@radix-ui/react-tabs@1.1.3': + resolution: {integrity: sha512-9mFyI30cuRDImbmFF6O2KUJdgEOsGh9Vmx9x/Dh9tOhL7BngmQPQfwW4aejKm5OHpfWIdmeV6ySyuxoOGjtNng==} peerDependencies: - react: '*' + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@tamagui/form@1.125.23': - resolution: {integrity: sha512-dPZvcRsHw97wrlenmuNKCj5hJhMSeIKL8o8z3dTMPEHbfsPOsbGhDGXEUfTRRFK4DlC/0eR7uJTMQL6UQ1FM+Q==} + '@radix-ui/react-use-callback-ref@1.1.0': + resolution: {integrity: sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==} peerDependencies: - react: '*' + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@tamagui/get-button-sized@1.125.23': - resolution: {integrity: sha512-fAj0LCOjEMr78+SI6U86+aJ9GYbyBBqRHklEZb2VSHbcHxN0kcHgu26dO8tLpTz+lT9HCUyVWcPI8SKgSurTgQ==} + '@radix-ui/react-use-callback-ref@1.1.1': + resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} peerDependencies: - react: '*' + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@tamagui/get-font-sized@1.125.23': - resolution: {integrity: sha512-SBgg6Wc9bIntyt/Ou3DnipOclNx9R1IpDhbgMqCouu4AGdIr2o0P2RL/bNXXHQfoNuWf9yocrtyKbc6RxcuwZQ==} + '@radix-ui/react-use-controllable-state@1.1.0': + resolution: {integrity: sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==} peerDependencies: - react: '*' + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@tamagui/get-token@1.125.23': - resolution: {integrity: sha512-Aov4I7ZFPmJEdqIscZV3JJ49tidO0hVcuWgkIuSUKntcrbAweSIMuju0HBoXKoPnZ3UG4nokHs6yqkeZX0HLRg==} + '@radix-ui/react-use-controllable-state@1.1.1': + resolution: {integrity: sha512-YnEXIy8/ga01Y1PN0VfaNH//MhA91JlEGVBDxDzROqwrAtG5Yr2QGEPz8A/rJA3C7ZAHryOYGaUv8fLSW2H/mg==} peerDependencies: - react: '*' + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@tamagui/group@1.125.23': - resolution: {integrity: sha512-TqpBP27yKYAq9X17Upwbw/P4gAISW95agu4Tt3WiFXw291gm/P4mWTV8MaNDwi9oajUjnQmHv+AqOydZkDoucg==} + '@radix-ui/react-use-escape-keydown@1.1.0': + resolution: {integrity: sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==} peerDependencies: - react: '*' + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@tamagui/helpers-tamagui@1.125.23': - resolution: {integrity: sha512-0u9ophyFv+7bVFr8FqnPlfW+zR1M8Q/Xu0YCR6pAIRbCn4yy9Qb6uGcPHtN3qLFnWIO5N+wSUHk1LVeytawcDg==} + '@radix-ui/react-use-layout-effect@1.1.0': + resolution: {integrity: sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==} peerDependencies: - react: '*' - - '@tamagui/helpers@1.125.23': - resolution: {integrity: sha512-Lw8IKpRfZC1/QZhx0Ck9E7rvR96kfNBUV2GYckqsRLOe8dei3cZYcYVWDTBjNx5GK0towmwJszfdjp+9yT/Qcw==} + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@tamagui/image@1.125.23': - resolution: {integrity: sha512-aG72DH8GxImhiauBlB1eG+RldN91+8VFCrCRZzSiAPaEKEgrXa3VTvmNlkV3Lc1zvagvtBz1oNVNwCnCm9d6ig==} + '@radix-ui/react-use-layout-effect@1.1.1': + resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} peerDependencies: - react: '*' + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@tamagui/label@1.125.23': - resolution: {integrity: sha512-B8HYoIaS/OZoU+5qQVb6mSVEPWqL/KsKMA0OhgtvrbabEy+LyZO6LVFW2ACMzNHDXgQRqpWcEu9bdXNPsjnoWg==} + '@radix-ui/react-use-previous@1.1.1': + resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} peerDependencies: - react: '*' - react-native: '*' + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@tamagui/linear-gradient@1.125.23': - resolution: {integrity: sha512-FYoSX7WERJvEy3bvHh81dFEDiEYfaA27vukaMPbQc8L+GGT9vohQxjrGkGRsdwSGhs8jRFqAIe7H4EXsE++ehg==} + '@radix-ui/react-use-rect@1.1.0': + resolution: {integrity: sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==} peerDependencies: - react: '*' + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@tamagui/list-item@1.125.23': - resolution: {integrity: sha512-1xY76RCqC553Ykcf1iOxGvvpGyybwPccsRw1Am3h57QRbapCdz8mQqRhe/jaQaK4Tzo2BHjYmWtARMKlI1FwZQ==} + '@radix-ui/react-use-size@1.1.0': + resolution: {integrity: sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==} peerDependencies: - react: '*' - - '@tamagui/normalize-css-color@1.125.23': - resolution: {integrity: sha512-bDn7+3uNNrPiljMlK1m4QcwNZ+q/5sI49XuqKB4brn1X30XIqn3J/I9lbOt1B+skAapos3Es2PEkI4RQc0AnaA==} - - '@tamagui/polyfill-dev@1.125.23': - resolution: {integrity: sha512-xm8VmbVXPpnxVM4kPMaqH9MEaTrSP3XiJFrWu1eYOqgxnlOSDBMyn/ZPDmQueisZfUqhG6IhBTIpE4G4j3v+RQ==} + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@tamagui/popover@1.125.23': - resolution: {integrity: sha512-5n8PAzHfpoQO+UommLjD9yXemNY/Qt5SgI5ecr5zHvszIN9HHkINV5zQzs2ZYVfrbrag8gIotO3jAC0fjpKa6A==} + '@radix-ui/react-use-size@1.1.1': + resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} peerDependencies: - react: '*' + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@tamagui/popper@1.125.23': - resolution: {integrity: sha512-9tzwXIzY0kmdSasLAsOtznCfVYkXMAuzI5MUezJlEFi0YmXV62Xi9l5c+VRHxKlESmJKrM2IJBb3gh2MNoaHzA==} - peerDependencies: - react: '*' + '@radix-ui/rect@1.1.0': + resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==} - '@tamagui/portal@1.125.23': - resolution: {integrity: sha512-ZFSEM7/k82vka29/1Ak6vc4TdZpptcfios0iO94ScrQoiUtqecXBzXZnkF6u1R9dTze/aoqtV024dmFLa/VZSg==} + '@react-native/assets-registry@0.76.7': + resolution: {integrity: sha512-o79whsqL5fbPTUQO9w1FptRd4cw1TaeOrXtQSLQeDrMVAenw/wmsjyPK10VKtvqxa1KNMtWEyfgxcM8CVZVFmg==} + engines: {node: '>=18'} - '@tamagui/progress@1.125.23': - resolution: {integrity: sha512-eSk9INMBp1tJDHV+e5o6xtezztqTT7kT28L0er2NZVNWdkSo6k+Uy6USR58qUWWeVkpfWO5xVGk8GigmTvW2mQ==} - peerDependencies: - react: '*' + '@react-native/babel-plugin-codegen@0.76.7': + resolution: {integrity: sha512-+8H4DXJREM4l/pwLF/wSVMRzVhzhGDix5jLezNrMD9J1U1AMfV2aSkWA1XuqR7pjPs/Vqf6TaPL7vJMZ4LU05Q==} + engines: {node: '>=18'} - '@tamagui/radio-group@1.125.23': - resolution: {integrity: sha512-hSScfFxeUX+xandKdqg+ZxaYLg87sdquSIZBpHRDyPBNOwcBDMGM+xh4ttEH70/8hlQ4g5ksgNSNz+XitV2rxA==} + '@react-native/babel-preset@0.76.7': + resolution: {integrity: sha512-/c5DYZ6y8tyg+g8tgXKndDT7mWnGmkZ9F+T3qNDfoE3Qh7ucrNeC2XWvU9h5pk8eRtj9l4SzF4aO1phzwoibyg==} + engines: {node: '>=18'} peerDependencies: - react: '*' + '@babel/core': '*' - '@tamagui/radio-headless@1.125.23': - resolution: {integrity: sha512-ftsA9mSB8Psbrm4OEZ4lgl1XDg/i7aeeftH15ngjocqyIuijyoiAkWmdUjpc/2qiON3GJYOTYMXkadxwwXEF9Q==} + '@react-native/codegen@0.76.7': + resolution: {integrity: sha512-FAn585Ll65YvkSrKDyAcsdjHhhAGiMlSTUpHh0x7J5ntudUns+voYms0xMP+pEPt0XuLdjhD7zLIIlAWP407+g==} + engines: {node: '>=18'} peerDependencies: - react: '*' + '@babel/preset-env': ^7.1.6 - '@tamagui/react-native-media-driver@1.125.23': - resolution: {integrity: sha512-uzV3xBXwD64brbrZEJmSKOz+E5S77NPBdY9bYpcQzENe/GSO0euPyNIANwOy2zVQTT8i8A3yrHBae2s112Rirg==} + '@react-native/community-cli-plugin@0.76.7': + resolution: {integrity: sha512-lrcsY2WPLCEWU1pjdNV9+Ccj8vCEwCCURZiPa5aqi7lKB4C++1hPrxA8/CWWnTNcQp76DsBKGYqTFj7Ud4aupw==} + engines: {node: '>=18'} peerDependencies: - react-native: '*' + '@react-native-community/cli-server-api': '*' + peerDependenciesMeta: + '@react-native-community/cli-server-api': + optional: true - '@tamagui/react-native-use-pressable@1.125.23': - resolution: {integrity: sha512-PmpsEcuhpf+2Xy9+6obLvtWsXudV7uBjhsqXM7jiaS7ELQIaWqtud+Izn+6Av7QLFPUqdFtoA0S0ZLU6mrUo5A==} - peerDependencies: - react: '*' + '@react-native/debugger-frontend@0.76.7': + resolution: {integrity: sha512-89ZtZXt7ZxE94i7T94qzZMhp4Gfcpr/QVpGqEaejAxZD+gvDCH21cYSF+/Rz2ttBazm0rk5MZ0mFqb0Iqp1jmw==} + engines: {node: '>=18'} - '@tamagui/react-native-use-responder-events@1.125.23': - resolution: {integrity: sha512-R4ijteeeahDp7Gu9RH/nvTXvRimV73C+C4/EDK5h+NHb2oKIwlf9EKiqG6kUDYvGHNmKEL5ESVb1zutOQRf6pQ==} - peerDependencies: - react: '*' + '@react-native/dev-middleware@0.76.7': + resolution: {integrity: sha512-Jsw8g9DyLPnR9yHEGuT09yHZ7M88/GL9CtU9WmyChlBwdXSeE3AmRqLegsV3XcgULQ1fqdemokaOZ/MwLYkjdA==} + engines: {node: '>=18'} + + '@react-native/gradle-plugin@0.76.7': + resolution: {integrity: sha512-gQI6RcrJbigU8xk7F960C5xQIgvbBj20TUvGecD+N2PHfbLpqR+92cj7hz3UcbrCONmTP40WHnbMMJ8P+kLsrA==} + engines: {node: '>=18'} - '@tamagui/remove-scroll@1.125.23': - resolution: {integrity: sha512-FGoCFQjexEBhvzfiYD4DdEL44S1Yg0wmciObsdX/YSx60USszjQQyKu8VyRhFZiydko1CBSETPHaP7NyKuRcXg==} + '@react-native/js-polyfills@0.76.7': + resolution: {integrity: sha512-+iEikj6c6Zvrg1c3cYMeiPB+5nS8EaIC3jCtP6Muk3qc7c386IymEPM2xycIlfg04DPZvO3D4P2/vaO9/TCnUg==} + engines: {node: '>=18'} + + '@react-native/metro-babel-transformer@0.76.7': + resolution: {integrity: sha512-jDS1wR7q46xY5ah+jF714Mvss9l7+lmwW/tplahZgLKozkYDC8Td5o9TOCgKlv18acw9H1V7zv8ivuRSj8ICPg==} + engines: {node: '>=18'} peerDependencies: - react: '*' + '@babel/core': '*' + + '@react-native/normalize-colors@0.74.89': + resolution: {integrity: sha512-qoMMXddVKVhZ8PA1AbUCk83trpd6N+1nF2A6k1i6LsQObyS92fELuk8kU/lQs6M7BsMHwqyLCpQJ1uFgNvIQXg==} - '@tamagui/roving-focus@1.125.23': - resolution: {integrity: sha512-hGj+Ki0cVu1JaQfloryCZ7yoG3cnrsAb5p0md/I0WjrdTeVLO+7qqiaXF/3iWPvRzxW719/cMIjDKNhgED1UwA==} + '@react-native/normalize-colors@0.76.7': + resolution: {integrity: sha512-ST1xxBuYVIXPdD81dR6+tzIgso7m3pa9+6rOBXTh5Xm7KEEFik7tnQX+GydXYMp3wr1gagJjragdXkPnxK6WNg==} + + '@react-native/virtualized-lists@0.76.7': + resolution: {integrity: sha512-pRUf1jUO8H9Ft04CaWv76t34QI9wY0sydoYlIwEtqXjjMJgmgDoOCAWBjArgn2mk8/rK+u/uicI67ZCYCp1pJw==} + engines: {node: '>=18'} peerDependencies: + '@types/react': ^18.2.6 react: '*' + react-native: '*' + peerDependenciesMeta: + '@types/react': + optional: true - '@tamagui/scroll-view@1.125.23': - resolution: {integrity: sha512-9OWosnhPAhS0aPJNfxoUcM0XA/jjRtTbbFeOXW9ZZPsnYohmZrVtA/xkghtH/hzUEj3dfAQqxim39BRT+fBRXw==} + '@react-navigation/bottom-tabs@7.2.1': + resolution: {integrity: sha512-UGC7csRD/1+SJKLbaEg8K44KvkdBaEBIro0PpIRawRmHS93emf4LNfDafd8y6pReJN93OVVnqLWqcYozx4lZ4A==} peerDependencies: - react: '*' + '@react-navigation/native': ^7.0.15 + react: '>= 18.2.0' + react-native: '*' + react-native-safe-area-context: '>= 4.0.0' + react-native-screens: '>= 4.0.0' - '@tamagui/select@1.125.23': - resolution: {integrity: sha512-GMp7q9lfV75GgHuPsl/NVSrjxbQ+MT2bk8ODtXJRt0KMiWFyD9flKMNeeRB0ZoXIpE/C9tmbJLP6KjU+v+Msqg==} + '@react-navigation/core@7.4.0': + resolution: {integrity: sha512-URiDluFl7cLA7GtOAsEvRqPmEMlSSXadqQ3wi9+Dl43dNRMqnoF76WQ9BCXeUPLydJq4yVte9XeMPyD6a0lY1g==} peerDependencies: - react: '*' + react: '>= 18.2.0' - '@tamagui/separator@1.125.23': - resolution: {integrity: sha512-KRvo0t+mcyY2QkNFhOxqDUyPmexFgjr00q32UkrUMoqJJY9lWCTva4iNZT/plIpNmL4xUgz4VShtvYmUR8Ec2Q==} + '@react-navigation/elements@2.2.6': + resolution: {integrity: sha512-UPeaCcEDSDRaxjG+qEHbur6jmNW/f9QNCyPsUt6NMgPEdbB5Z8K8oSx2swIaiCnvUbs/K5G3MuWkqQxGj8QXXA==} peerDependencies: - react: '*' + '@react-native-masked-view/masked-view': '>= 0.2.0' + '@react-navigation/native': ^7.0.15 + react: '>= 18.2.0' + react-native: '*' + react-native-safe-area-context: '>= 4.0.0' + peerDependenciesMeta: + '@react-native-masked-view/masked-view': + optional: true - '@tamagui/shapes@1.125.23': - resolution: {integrity: sha512-KvCgKlpbj0/Fz2PXNoodKyONOpjlLHvy8NcWUhUu/G1pjKIvzbWpztJhWJgRlR4XBIZCALQhwjxCT4/i/4XC7A==} + '@react-navigation/native-stack@7.2.1': + resolution: {integrity: sha512-zqC6DVpO4pFZrl+8JuIgV8qk+AGdTuv+hJ5EHePmzs9gYSUrDpw6LahFCiXshwBvi9LinIw9Do7mtnQK2Q8AGA==} peerDependencies: - react: '*' + '@react-navigation/native': ^7.0.15 + react: '>= 18.2.0' + react-native: '*' + react-native-safe-area-context: '>= 4.0.0' + react-native-screens: '>= 4.0.0' - '@tamagui/sheet@1.125.23': - resolution: {integrity: sha512-UaJL9XmZ4sturqvGO71AWqoDKFDSdnNRnXs2K43QpvSgd2JD4FrVxpNjHTYlB44hcFj1vffM+kF7ElT8kvPsUw==} + '@react-navigation/native@7.0.15': + resolution: {integrity: sha512-72PabJJ8VY3GM8i/DCutFW+ATED96ZV6NH+bW+ry1EL0ZFGHoie96H+KzTqktsrUbBw1rd9KXbEQhBQgo0N7iQ==} peerDependencies: - react: '*' + react: '>= 18.2.0' + react-native: '*' - '@tamagui/simple-hash@1.125.23': - resolution: {integrity: sha512-128MZTO0CcPDY+RC9Uleu22CRGAFcIyA4dMiMhpQDzE+pxcBXeqy3aVfMoiK7awo0BsQ5BahXci4ZgCRaGwuog==} + '@react-navigation/routers@7.2.0': + resolution: {integrity: sha512-lMyib39H4a//u+eiyt162U6TwCfI8zJbjl9ovjKtDddQ4/Vf7b8/OhyimnJH09N2CBfm4pv0gCV6Q0WnZcfaJg==} - '@tamagui/slider@1.125.23': - resolution: {integrity: sha512-bCGO6krlrMeFwwgyofSsJHoE2cSwIuR2mfUFB0Gm+yakC25v6Mj6MFMkyTFGASulBerDOutqFwoELbvCHrU9UA==} - peerDependencies: - react: '*' + '@rollup/rollup-android-arm-eabi@4.35.0': + resolution: {integrity: sha512-uYQ2WfPaqz5QtVgMxfN6NpLD+no0MYHDBywl7itPYd3K5TjjSghNKmX8ic9S8NU8w81NVhJv/XojcHptRly7qQ==} + cpu: [arm] + os: [android] - '@tamagui/stacks@1.125.23': - resolution: {integrity: sha512-aQiwfgucjpi0k1W3Mjdg91XmSqSGNjdWMY1a7bcmH3dvb8tRWF6mUlLuFmiJt0u90cqzfrwCMr/eUDHOvyQNnQ==} - peerDependencies: - react: '*' + '@rollup/rollup-android-arm64@4.35.0': + resolution: {integrity: sha512-FtKddj9XZudurLhdJnBl9fl6BwCJ3ky8riCXjEw3/UIbjmIY58ppWwPEvU3fNu+W7FUsAsB1CdH+7EQE6CXAPA==} + cpu: [arm64] + os: [android] - '@tamagui/start-transition@1.125.23': - resolution: {integrity: sha512-h3hAX9QthgIo4qPgzfwb+S9mu9MZLnCLWh1r4q1xReG9gEluiOwd9AZqIDXqcj31+Kd4z97QY3EY2+jHia50SQ==} + '@rollup/rollup-darwin-arm64@4.35.0': + resolution: {integrity: sha512-Uk+GjOJR6CY844/q6r5DR/6lkPFOw0hjfOIzVx22THJXMxktXG6CbejseJFznU8vHcEBLpiXKY3/6xc+cBm65Q==} + cpu: [arm64] + os: [darwin] - '@tamagui/switch-headless@1.125.23': - resolution: {integrity: sha512-YvJqqYpKjdd9+4EdxAa0yALz9FEXx04LO8178+NLnzd87K94xrzWlujWo5JgOWQ0DeGsSMk8ue3y90LcS2aEeQ==} - peerDependencies: - react: '*' + '@rollup/rollup-darwin-x64@4.35.0': + resolution: {integrity: sha512-3IrHjfAS6Vkp+5bISNQnPogRAW5GAV1n+bNCrDwXmfMHbPl5EhTmWtfmwlJxFRUCBZ+tZ/OxDyU08aF6NI/N5Q==} + cpu: [x64] + os: [darwin] - '@tamagui/switch@1.125.23': - resolution: {integrity: sha512-FpfduhmUBkNUq0P9Ova6wlVEyt5YzeoIynyfNHWa8nF6rYH3Yb1l191mKhrBVWbEiBIHBA4IhGeVnWd88MHX1w==} - peerDependencies: - react: '*' + '@rollup/rollup-freebsd-arm64@4.35.0': + resolution: {integrity: sha512-sxjoD/6F9cDLSELuLNnY0fOrM9WA0KrM0vWm57XhrIMf5FGiN8D0l7fn+bpUeBSU7dCgPV2oX4zHAsAXyHFGcQ==} + cpu: [arm64] + os: [freebsd] - '@tamagui/tabs@1.125.23': - resolution: {integrity: sha512-jj0l+I2kNtwd5EiM32VYYOeOAFuTX4VjYE8k3WK8mLN72uaw8M3+LvVuLVINDhEiD6ORBI3HSpxSYPaVZvnH6Q==} - peerDependencies: - react: '*' + '@rollup/rollup-freebsd-x64@4.35.0': + resolution: {integrity: sha512-2mpHCeRuD1u/2kruUiHSsnjWtHjqVbzhBkNVQ1aVD63CcexKVcQGwJ2g5VphOd84GvxfSvnnlEyBtQCE5hxVVw==} + cpu: [x64] + os: [freebsd] - '@tamagui/text@1.125.23': - resolution: {integrity: sha512-Arwzqd7HG7IfM6sqG9CBgZsds8rQ5aZDzvyE+1OEDV5cZGH0QP1UVt8L9uwiWcCd62SMdTcsDLycwiXxUl2sQQ==} - peerDependencies: - react: '*' + '@rollup/rollup-linux-arm-gnueabihf@4.35.0': + resolution: {integrity: sha512-mrA0v3QMy6ZSvEuLs0dMxcO2LnaCONs1Z73GUDBHWbY8tFFocM6yl7YyMu7rz4zS81NDSqhrUuolyZXGi8TEqg==} + cpu: [arm] + os: [linux] - '@tamagui/theme@1.125.23': - resolution: {integrity: sha512-EZWu6CmxFem4Npj7Xjc+8AeRKD+Su3S9PGiQJw1egxrS0VBraV/k4t/53kpkykEtBV58sr6oGdIx8J3+8yZcng==} - peerDependencies: - react: '*' + '@rollup/rollup-linux-arm-musleabihf@4.35.0': + resolution: {integrity: sha512-DnYhhzcvTAKNexIql8pFajr0PiDGrIsBYPRvCKlA5ixSS3uwo/CWNZxB09jhIapEIg945KOzcYEAGGSmTSpk7A==} + cpu: [arm] + os: [linux] - '@tamagui/timer@1.125.23': - resolution: {integrity: sha512-qNxMLA7RyCsKsC8Uwcl03iQtNhvJ0Zedjxbyr3RsX8ylIC0dHcV5lybt/kcK4aAYIfrQ9MQe5gvOMCh5owW6ug==} + '@rollup/rollup-linux-arm64-gnu@4.35.0': + resolution: {integrity: sha512-uagpnH2M2g2b5iLsCTZ35CL1FgyuzzJQ8L9VtlJ+FckBXroTwNOaD0z0/UF+k5K3aNQjbm8LIVpxykUOQt1m/A==} + cpu: [arm64] + os: [linux] - '@tamagui/toggle-group@1.125.23': - resolution: {integrity: sha512-j08jAZhMi4QAs5vKKVUYZYEePsxB+Aj85yWXs8/4TkKCdp7o5mU26NLlXIO3U2cJKHT3RvC61VnyMXvjkgEljg==} - peerDependencies: - react: '*' + '@rollup/rollup-linux-arm64-musl@4.35.0': + resolution: {integrity: sha512-XQxVOCd6VJeHQA/7YcqyV0/88N6ysSVzRjJ9I9UA/xXpEsjvAgDTgH3wQYz5bmr7SPtVK2TsP2fQ2N9L4ukoUg==} + cpu: [arm64] + os: [linux] - '@tamagui/tooltip@1.125.23': - resolution: {integrity: sha512-fZENmXDNE0kHhs0jOA/Xk4D4CQeAhpg6xxUCOQsHQjBSjdiW40f5Pvc3ZzM4WuQZ7npiNdkb3YD40GjcE0yK5g==} - peerDependencies: - react: '*' + '@rollup/rollup-linux-loongarch64-gnu@4.35.0': + resolution: {integrity: sha512-5pMT5PzfgwcXEwOaSrqVsz/LvjDZt+vQ8RT/70yhPU06PTuq8WaHhfT1LW+cdD7mW6i/J5/XIkX/1tCAkh1W6g==} + cpu: [loong64] + os: [linux] - '@tamagui/types@1.125.23': - resolution: {integrity: sha512-YyBCFm0D82LshHIpVG1Zt8QRFsQMeg96TJLx+O6tTpWgfrXJy7agIRCAD6ePnKoMGZnFSllMCzxzx+hFTOoTrw==} + '@rollup/rollup-linux-powerpc64le-gnu@4.35.0': + resolution: {integrity: sha512-c+zkcvbhbXF98f4CtEIP1EBA/lCic5xB0lToneZYvMeKu5Kamq3O8gqrxiYYLzlZH6E3Aq+TSW86E4ay8iD8EA==} + cpu: [ppc64] + os: [linux] - '@tamagui/use-callback-ref@1.125.23': - resolution: {integrity: sha512-3DR724QaNCyec8vs0VSdNNnJw0VHURBcReOyS+oeV6piu9E7w5q2qgdBga5fLf2qD0xr7uU5OEWksO/+B1xAzQ==} + '@rollup/rollup-linux-riscv64-gnu@4.35.0': + resolution: {integrity: sha512-s91fuAHdOwH/Tad2tzTtPX7UZyytHIRR6V4+2IGlV0Cej5rkG0R61SX4l4y9sh0JBibMiploZx3oHKPnQBKe4g==} + cpu: [riscv64] + os: [linux] - '@tamagui/use-constant@1.125.23': - resolution: {integrity: sha512-/OOC+YtL18r4slTqx5Xh4Vw8HrDcDVhcIZp06CeroFKUCl1lxMbUEfkNYFM3qom66sm6ueEO6F7oKPgRu71jPw==} - peerDependencies: - react: '*' + '@rollup/rollup-linux-s390x-gnu@4.35.0': + resolution: {integrity: sha512-hQRkPQPLYJZYGP+Hj4fR9dDBMIM7zrzJDWFEMPdTnTy95Ljnv0/4w/ixFw3pTBMEuuEuoqtBINYND4M7ujcuQw==} + cpu: [s390x] + os: [linux] - '@tamagui/use-controllable-state@1.125.23': - resolution: {integrity: sha512-n4WPAQpDCVZ/JSNjMoPRaHZ8xJtjHKLuCvbNbHPQD9AaOQ1fVvEQwtj8BFLdBSJ4IUT+jAFEjNnvGhrDEXdXew==} - peerDependencies: - react: '*' + '@rollup/rollup-linux-x64-gnu@4.35.0': + resolution: {integrity: sha512-Pim1T8rXOri+0HmV4CdKSGrqcBWX0d1HoPnQ0uw0bdp1aP5SdQVNBy8LjYncvnLgu3fnnCt17xjWGd4cqh8/hA==} + cpu: [x64] + os: [linux] - '@tamagui/use-debounce@1.125.23': - resolution: {integrity: sha512-rbqcpMsfUif7NPqMcpBBr156DH0jyUfZa8/npjYMw/v7ePUMET0dpozJ+vqylL68ClG6qEiTAVHW8Beli9bGbg==} - peerDependencies: - react: '*' + '@rollup/rollup-linux-x64-musl@4.35.0': + resolution: {integrity: sha512-QysqXzYiDvQWfUiTm8XmJNO2zm9yC9P/2Gkrwg2dH9cxotQzunBHYr6jk4SujCTqnfGxduOmQcI7c2ryuW8XVg==} + cpu: [x64] + os: [linux] - '@tamagui/use-did-finish-ssr@1.125.23': - resolution: {integrity: sha512-D3/PpzU7n7toxsZfLHEFbKwYsDrsnfgU4TBJXV0ryP61Ffj6o/wcDeWNo7+7wAYy+3+H2N6zBMRW1rkWp3TTwg==} - peerDependencies: - react: '*' + '@rollup/rollup-win32-arm64-msvc@4.35.0': + resolution: {integrity: sha512-OUOlGqPkVJCdJETKOCEf1mw848ZyJ5w50/rZ/3IBQVdLfR5jk/6Sr5m3iO2tdPgwo0x7VcncYuOvMhBWZq8ayg==} + cpu: [arm64] + os: [win32] - '@tamagui/use-direction@1.125.23': - resolution: {integrity: sha512-vW0qnYJwnYsfSKOzfE5dz763+6H+++h7jxDBTvc9LIqIIs+RePn/Br48qt7rJdBQvrfD1+XXRzlD4064KDtTKg==} - peerDependencies: - react: '*' + '@rollup/rollup-win32-ia32-msvc@4.35.0': + resolution: {integrity: sha512-2/lsgejMrtwQe44glq7AFFHLfJBPafpsTa6JvP2NGef/ifOa4KBoglVf7AKN7EV9o32evBPRqfg96fEHzWo5kw==} + cpu: [ia32] + os: [win32] - '@tamagui/use-escape-keydown@1.125.23': - resolution: {integrity: sha512-TjqRNvsqtCI8eR+CfJPFCGZhrl8T734vlQS6sn2Ta62jWsDcoBmbxPCKraA6CN6zyEJqzDbdlO3SC871gOO+qg==} + '@rollup/rollup-win32-x64-msvc@4.35.0': + resolution: {integrity: sha512-PIQeY5XDkrOysbQblSW7v3l1MDZzkTEzAfTPkj5VAu3FW8fS4ynyLg2sINp0fp3SjZ8xkRYpLqoKcYqAkhU1dw==} + cpu: [x64] + os: [win32] - '@tamagui/use-event@1.125.23': - resolution: {integrity: sha512-uyZMepvoXngmYxJ6j+HNUN9g6XC76Zz2WGOZZRkxlincqIVXo46y66IExV0VPidevd9BxBC66374wqueZm3hGw==} - peerDependencies: - react: '*' + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - '@tamagui/use-force-update@1.125.23': - resolution: {integrity: sha512-o+v2vUAhTo9d1uS46Jf1WWhwLfV26KA9oxAlplbCsDXDgkayqgfB2sIG9ZxkNCed5t7cYjF33HstrFC6oscBvQ==} - peerDependencies: - react: '*' + '@rushstack/eslint-patch@1.11.0': + resolution: {integrity: sha512-zxnHvoMQVqewTJr/W4pKjF0bMGiKJv1WX7bSrkl46Hg0QjESbzBROWK0Wg4RphzSOS5Jiy7eFimmM3UgMrMZbQ==} - '@tamagui/use-keyboard-visible@1.125.23': - resolution: {integrity: sha512-MAnp5/uRsqorYpWo8oBGs1y14snrmC3nSQ2uaF63HcZomgPuV4nFMLN0J/TBMcWOcnqtKeFX9WR0GFTE17ZEvA==} - peerDependencies: - react: '*' + '@segment/loosely-validate-event@2.0.0': + resolution: {integrity: sha512-ZMCSfztDBqwotkl848ODgVcAmN4OItEWDCkshcKz0/W6gGSQayuuCtWV/MlodFivAZD793d6UgANd6wCXUfrIw==} - '@tamagui/use-presence@1.125.23': - resolution: {integrity: sha512-WaDwU3n60fdWG5rJTkjbYPrfpO1/nhgTT5QWbq1eWVx443TbJPttfwx+yGiQq5hqbaDKBeRylipqnhcgriA7lQ==} - peerDependencies: - react: '*' + '@sinclair/typebox@0.27.8': + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} - '@tamagui/use-previous@1.125.23': - resolution: {integrity: sha512-Av4XXrbTHFbP3B6E/GjtWqlnCMEDD8uJvZBz7V9yOZBNfG4EpSL5fjnSoK8aH7mlPOCAbuGcGi6FuA1Sws7qUQ==} + '@sinonjs/commons@3.0.1': + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} - '@tamagui/use-window-dimensions@1.125.23': - resolution: {integrity: sha512-RXpU/vbBQ8iW/XKCdDIvdNfw+bdrpAIEG7V9wD03sMqh9cDfc2ffUUVmmkx+bhUBVzmpbpg9AEvm0R6ov8Q+ZQ==} - peerDependencies: - react: '*' + '@sinonjs/fake-timers@10.3.0': + resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} - '@tamagui/visually-hidden@1.125.23': - resolution: {integrity: sha512-WgzBl/o1eKo93OPkliFI3aHoQMHbeM/KuIJz/rRdha83PlJN6tJzkz+9TWuqyLGbcdbrAUa0YtMW+bt72gx59g==} + '@supabase/auth-js@2.68.0': + resolution: {integrity: sha512-odG7nb7aOmZPUXk6SwL2JchSsn36Ppx11i2yWMIc/meUO2B2HK9YwZHPK06utD9Ql9ke7JKDbwGin/8prHKxxQ==} + + '@supabase/functions-js@2.4.4': + resolution: {integrity: sha512-WL2p6r4AXNGwop7iwvul2BvOtuJ1YQy8EbOd0dhG1oN1q8el/BIRSFCFnWAMM/vJJlHWLi4ad22sKbKr9mvjoA==} + + '@supabase/node-fetch@2.6.15': + resolution: {integrity: sha512-1ibVeYUacxWYi9i0cf5efil6adJ9WRyZBLivgjs+AUpewx1F3xPi7gLgaASI2SmIQxPoCEjAsLAzKPgMJVgOUQ==} + engines: {node: 4.x || >=6.0.0} + + '@supabase/postgrest-js@1.19.2': + resolution: {integrity: sha512-MXRbk4wpwhWl9IN6rIY1mR8uZCCG4MZAEji942ve6nMwIqnBgBnZhZlON6zTTs6fgveMnoCILpZv1+K91jN+ow==} + + '@supabase/realtime-js@2.11.2': + resolution: {integrity: sha512-u/XeuL2Y0QEhXSoIPZZwR6wMXgB+RQbJzG9VErA3VghVt7uRfSVsjeqd7m5GhX3JR6dM/WRmLbVR8URpDWG4+w==} + + '@supabase/ssr@0.6.1': + resolution: {integrity: sha512-QtQgEMvaDzr77Mk3vZ3jWg2/y+D8tExYF7vcJT+wQ8ysuvOeGGjYbZlvj5bHYsj/SpC0bihcisnwPrM4Gp5G4g==} peerDependencies: - react: '*' + '@supabase/supabase-js': ^2.43.4 + + '@supabase/storage-js@2.7.1': + resolution: {integrity: sha512-asYHcyDR1fKqrMpytAS1zjyEfvxuOIp1CIXX7ji4lHHcJKqyk+sLl/Vxgm4sN6u8zvuUtae9e4kDxQP2qrwWBA==} - '@tamagui/web@1.125.23': - resolution: {integrity: sha512-IWYyssSMjVafcFBqGqi+yzdo9e0XgYTCNRDrd2q5s1Io164q3a+BXU+pycboodhWq3c2SOTeZCEECgBP8KUEgQ==} + '@supabase/supabase-js@2.49.1': + resolution: {integrity: sha512-lKaptKQB5/juEF5+jzmBeZlz69MdHZuxf+0f50NwhL+IE//m4ZnOeWlsKRjjsM0fVayZiQKqLvYdBn0RLkhGiQ==} + + '@swc/counter@0.1.3': + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + + '@tailwindcss/node@4.0.15': + resolution: {integrity: sha512-IODaJjNmiasfZX3IoS+4Em3iu0fD2HS0/tgrnkYfW4hyUor01Smnr5eY3jc4rRgaTDrJlDmBTHbFO0ETTDaxWA==} + + '@tailwindcss/oxide-android-arm64@4.0.15': + resolution: {integrity: sha512-EBuyfSKkom7N+CB3A+7c0m4+qzKuiN0WCvzPvj5ZoRu4NlQadg/mthc1tl5k9b5ffRGsbDvP4k21azU4VwVk3Q==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.0.15': + resolution: {integrity: sha512-ObVAnEpLepMhV9VoO0JSit66jiN5C4YCqW3TflsE9boo2Z7FIjV80RFbgeL2opBhtxbaNEDa6D0/hq/EP03kgQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.0.15': + resolution: {integrity: sha512-IElwoFhUinOr9MyKmGTPNi1Rwdh68JReFgYWibPWTGuevkHkLWKEflZc2jtI5lWZ5U9JjUnUfnY43I4fEXrc4g==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.0.15': + resolution: {integrity: sha512-6BLLqyx7SIYRBOnTZ8wgfXANLJV5TQd3PevRJZp0vn42eO58A2LykRKdvL1qyPfdpmEVtF+uVOEZ4QTMqDRAWA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.0.15': + resolution: {integrity: sha512-Zy63EVqO9241Pfg6G0IlRIWyY5vNcWrL5dd2WAKVJZRQVeolXEf1KfjkyeAAlErDj72cnyXObEZjMoPEKHpdNw==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.0.15': + resolution: {integrity: sha512-2NemGQeaTbtIp1Z2wyerbVEJZTkAWhMDOhhR5z/zJ75yMNf8yLnE+sAlyf6yGDNr+1RqvWrRhhCFt7i0CIxe4Q==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.0.15': + resolution: {integrity: sha512-342GVnhH/6PkVgKtEzvNVuQ4D+Q7B7qplvuH20Cfz9qEtydG6IQczTZ5IT4JPlh931MG1NUCVxg+CIorr1WJyw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.0.15': + resolution: {integrity: sha512-g76GxlKH124RuGqacCEFc2nbzRl7bBrlC8qDQMiUABkiifDRHOIUjgKbLNG4RuR9hQAD/MKsqZ7A8L08zsoBrw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.0.15': + resolution: {integrity: sha512-Gg/Y1XrKEvKpq6WeNt2h8rMIKOBj/W3mNa5NMvkQgMC7iO0+UNLrYmt6zgZufht66HozNpn+tJMbbkZ5a3LczA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-win32-arm64-msvc@4.0.15': + resolution: {integrity: sha512-7QtSSJwYZ7ZK1phVgcNZpuf7c7gaCj8Wb0xjliligT5qCGCp79OV2n3SJummVZdw4fbTNKUOYMO7m1GinppZyA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.0.15': + resolution: {integrity: sha512-JQ5H+5MLhOjpgNp6KomouE0ZuKmk3hO5h7/ClMNAQ8gZI2zkli3IH8ZqLbd2DVfXDbdxN2xvooIEeIlkIoSCqw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.0.15': + resolution: {integrity: sha512-e0uHrKfPu7JJGMfjwVNyt5M0u+OP8kUmhACwIRlM+JNBuReDVQ63yAD1NWe5DwJtdaHjugNBil76j+ks3zlk6g==} + engines: {node: '>= 10'} + + '@tailwindcss/postcss@4.0.15': + resolution: {integrity: sha512-qyrpoDKIO7wzkRbKCvGLo7gXRjT9/Njf7ZJiJhG4njrfZkvOhjwnaHpYbpxYeDysEg+9pB1R4jcd+vQ7ZUDsmQ==} + + '@tanstack/query-core@5.68.0': + resolution: {integrity: sha512-r8rFYYo8/sY/LNaOqX84h12w7EQev4abFXDWy4UoDVUJzJ5d9Fbmb8ayTi7ScG+V0ap44SF3vNs/45mkzDGyGw==} + + '@tanstack/query-devtools@5.67.2': + resolution: {integrity: sha512-O4QXFFd7xqp6EX7sdvc9tsVO8nm4lpWBqwpgjpVLW5g7IeOY6VnS/xvs/YzbRhBVkKTMaJMOUGU7NhSX+YGoNg==} + + '@tanstack/react-query-devtools@5.68.0': + resolution: {integrity: sha512-h9ArHkfa7SD5eGnJ9h+9M5uYWBdeVeY+WalrtGLCAtJJvHx6/RrtbbzxeoEQbPyx3f0kPcwJ58DGQ+7CBXelpg==} peerDependencies: - react: '*' - react-dom: '*' + '@tanstack/react-query': ^5.68.0 + react: ^18 || ^19 - '@tamagui/z-index-stack@1.125.23': - resolution: {integrity: sha512-u+krshexbayeQyG3vX58RMwyexDOVofyLuh48E6RePEG4s9eaDz/v+uKwHcOz0ChT1+c7HHZ1X6saSGKYzcPhQ==} + '@tanstack/react-query@5.68.0': + resolution: {integrity: sha512-mMOdGDKlwTP/WV72QqSNf4PAMeoBp/DqBHQ222wBfb51Looi8QUqnCnb9O98ZgvNISmy6fzxRGBJdZ+9IBvX2Q==} + peerDependencies: + react: ^18 || ^19 '@tootallnate/once@2.0.0': resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} @@ -1999,6 +2586,22 @@ packages: '@tootallnate/quickjs-emscripten@0.23.0': resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + '@trivago/prettier-plugin-sort-imports@5.2.2': + resolution: {integrity: sha512-fYDQA9e6yTNmA13TLVSA+WMQRc5Bn/c0EUBditUHNfMMxN7M82c38b1kEggVE3pLpZ0FwkwJkUEKMiOi52JXFA==} + engines: {node: '>18.12'} + peerDependencies: + '@vue/compiler-sfc': 3.x + prettier: 2.x - 3.x + prettier-plugin-svelte: 3.x + svelte: 4.x || 5.x + peerDependenciesMeta: + '@vue/compiler-sfc': + optional: true + prettier-plugin-svelte: + optional: true + svelte: + optional: true + '@tsconfig/node10@1.0.11': resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} @@ -2086,6 +2689,9 @@ packages: '@types/node@22.13.9': resolution: {integrity: sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw==} + '@types/phoenix@1.6.6': + resolution: {integrity: sha512-PIzZZlEppgrpoT2QgbnDU+MMzuR6BbCjllj0bM70lWoejMeNJAxCchxnv7J3XFkI8MpygtRpzXrIlmWUBclP5A==} + '@types/prop-types@15.7.14': resolution: {integrity: sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==} @@ -2115,6 +2721,9 @@ packages: '@types/tough-cookie@4.0.5': resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} + '@types/ws@8.18.0': + resolution: {integrity: sha512-8svvI3hMyvN0kKCJMvTJP/x6Y/EoQbepff882wL+Sn5QsXb3etnamgrJq4isrBxSJj5L2AuXcI0+bgkoAXGUJw==} + '@types/yargs-parser@21.0.3': resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} @@ -2176,6 +2785,55 @@ packages: peerDependencies: '@urql/core': ^5.0.0 + '@vercel/analytics@1.5.0': + resolution: {integrity: sha512-MYsBzfPki4gthY5HnYN7jgInhAZ7Ac1cYDoRWFomwGHWEX7odTEzbtg9kf/QSo7XEsEAqlQugA6gJ2WS2DEa3g==} + peerDependencies: + '@remix-run/react': ^2 + '@sveltejs/kit': ^1 || ^2 + next: '>= 13' + react: ^18 || ^19 || ^19.0.0-rc + svelte: '>= 4' + vue: ^3 + vue-router: ^4 + peerDependenciesMeta: + '@remix-run/react': + optional: true + '@sveltejs/kit': + optional: true + next: + optional: true + react: + optional: true + svelte: + optional: true + vue: + optional: true + vue-router: + optional: true + + '@vercel/speed-insights@1.2.0': + resolution: {integrity: sha512-y9GVzrUJ2xmgtQlzFP2KhVRoCglwfRQgjyfY607aU0hh0Un6d0OUyrJkjuAlsV18qR4zfoFPs/BiIj9YDS6Wzw==} + peerDependencies: + '@sveltejs/kit': ^1 || ^2 + next: '>= 13' + react: ^18 || ^19 || ^19.0.0-rc + svelte: '>= 4' + vue: ^3 + vue-router: ^4 + peerDependenciesMeta: + '@sveltejs/kit': + optional: true + next: + optional: true + react: + optional: true + svelte: + optional: true + vue: + optional: true + vue-router: + optional: true + '@webassemblyjs/ast@1.14.1': resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} @@ -2432,6 +3090,13 @@ packages: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} + autoprefixer@10.4.21: + resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} @@ -2536,6 +3201,9 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + bplist-creator@0.0.7: resolution: {integrity: sha512-xp/tcaV3T5PCiaY04mXga7o/TE+t95gqeLmADeBI1CvZtdWTbgBt3uLpvh4UWtenKeBhCV6oVxGk38yZr2uYEA==} @@ -2583,6 +3251,12 @@ packages: buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + bundle-require@5.1.0: + resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + esbuild: '>=0.18' + busboy@1.6.0: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} @@ -2591,6 +3265,10 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + cacache@18.0.4: resolution: {integrity: sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==} engines: {node: ^16.14.0 || >=18.0.0} @@ -2637,6 +3315,9 @@ packages: caniuse-lite@1.0.30001701: resolution: {integrity: sha512-faRs/AW3jA9nTwmJBSO1PQ6L/EOgsB5HMQQq4iCu5zhPgVVgO/pZRHlmatwijZKetFw8/Pr4q6dEN8sJuq8qTw==} + caniuse-lite@1.0.30001707: + resolution: {integrity: sha512-3qtRjw/HQSMlDWf+X79N206fepf4SOOU6SQLMaq/0KkZLmSjPxAkBOQQ+FxbHKfHmYLZFfdWsO3KA90ceHPSnw==} + chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -2666,6 +3347,17 @@ packages: charenc@0.0.2: resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} + cheerio-select@2.1.0: + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} + + cheerio@1.0.0: + resolution: {integrity: sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==} + engines: {node: '>=18.17'} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + chownr@2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} @@ -2692,6 +3384,9 @@ packages: cjs-module-lexer@1.4.3: resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + clean-stack@2.2.0: resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} engines: {node: '>=6'} @@ -2727,6 +3422,10 @@ packages: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + co@4.6.0: resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} @@ -2801,12 +3500,20 @@ packages: resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} engines: {node: '>= 0.10.0'} + consola@3.4.0: + resolution: {integrity: sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==} + engines: {node: ^14.18.0 || >=16.10.0} + constant-case@2.0.0: resolution: {integrity: sha512-eS0N9WwmjTqrOmR3o83F5vW8Z+9R1HnVz3xmzT2PMFug9ly+Au/fxRWlEBSb6LcZwspSsEn9Xs1uw9YgzAg1EQ==} convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie@1.0.2: + resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} + engines: {node: '>=18'} + core-js-compat@3.41.0: resolution: {integrity: sha512-RFsU9LySVue9RTwdDVX/T0e2Y6jRYWXERKElIjpuEOEnxaXffI0X7RUwVzfYLfzuLXSNJDYoRYUAmRUcyln20A==} @@ -2846,6 +3553,13 @@ packages: css-in-js-utils@3.1.0: resolution: {integrity: sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==} + css-select@5.1.0: + resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} + + css-what@6.1.0: + resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} + engines: {node: '>= 6'} + cssom@0.3.8: resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==} @@ -3008,11 +3722,24 @@ packages: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + domexception@4.0.0: resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==} engines: {node: '>=12'} deprecated: Use your platform's native DOMException instead + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + dot-case@2.1.1: resolution: {integrity: sha512-HnM6ZlFqcajLsyudHq7LeeLDr2rFAVYtDv/hV5qchQEidSck8j9OPUsXY9KwJv/lHMtYlX4DjRQqwFYa+0r8Ug==} @@ -3059,6 +3786,9 @@ packages: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} + encoding-sniffer@0.2.0: + resolution: {integrity: sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==} + end-of-stream@1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} @@ -3118,6 +3848,11 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} + esbuild@0.25.1: + resolution: {integrity: sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -3574,6 +4309,9 @@ packages: resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==} engines: {node: '>= 6'} + fraction.js@4.3.7: + resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + freeport-async@2.0.0: resolution: {integrity: sha512-K7od3Uw45AJg00XUmy15+Hae2hOcgKcmN3/EF6Y7i01O0gaqiRx8sUSpsb9+BRNL8RPBrhzPsVfy8q9ADlJuWQ==} engines: {node: '>=8'} @@ -3795,6 +4533,9 @@ packages: html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + htmlparser2@9.1.0: + resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==} + http-errors@2.0.0: resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} engines: {node: '>= 0.8'} @@ -3842,6 +4583,9 @@ packages: engines: {node: '>=16.x'} hasBin: true + immer@10.1.1: + resolution: {integrity: sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==} + import-fresh@2.0.0: resolution: {integrity: sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==} engines: {node: '>=4'} @@ -4117,6 +4861,9 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + javascript-natural-sort@0.7.1: + resolution: {integrity: sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==} + jest-changed-files@29.7.0: resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -4278,9 +5025,17 @@ packages: jimp-compact@0.16.1: resolution: {integrity: sha512-dZ6Ra7u1G8c4Letq/B5EzAxj4tLFHL+cGtdpR+PVm4yzPDj+lCk+AbivWt1eOM+ikzkowtyV7qSqX6qr3t71Ww==} + jiti@2.4.2: + resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} + hasBin: true + join-component@1.1.0: resolution: {integrity: sha512-bF7vcQxbODoGK1imE2P9GS9aw4zD0Sd+Hni68IMZLj7zRnquH7dXUmMw9hDI5S/Jzt7q+IyTXN0rSg2GI0IKhQ==} + joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -4397,67 +5152,139 @@ packages: cpu: [arm64] os: [darwin] + lightningcss-darwin-arm64@1.29.2: + resolution: {integrity: sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + lightningcss-darwin-x64@1.27.0: resolution: {integrity: sha512-0+mZa54IlcNAoQS9E0+niovhyjjQWEMrwW0p2sSdLRhLDc8LMQ/b67z7+B5q4VmjYCMSfnFi3djAAQFIDuj/Tg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] + lightningcss-darwin-x64@1.29.2: + resolution: {integrity: sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + lightningcss-freebsd-x64@1.27.0: resolution: {integrity: sha512-n1sEf85fePoU2aDN2PzYjoI8gbBqnmLGEhKq7q0DKLj0UTVmOTwDC7PtLcy/zFxzASTSBlVQYJUhwIStQMIpRA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] + lightningcss-freebsd-x64@1.29.2: + resolution: {integrity: sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + lightningcss-linux-arm-gnueabihf@1.27.0: resolution: {integrity: sha512-MUMRmtdRkOkd5z3h986HOuNBD1c2lq2BSQA1Jg88d9I7bmPGx08bwGcnB75dvr17CwxjxD6XPi3Qh8ArmKFqCA==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] + lightningcss-linux-arm-gnueabihf@1.29.2: + resolution: {integrity: sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + lightningcss-linux-arm64-gnu@1.27.0: resolution: {integrity: sha512-cPsxo1QEWq2sfKkSq2Bq5feQDHdUEwgtA9KaB27J5AX22+l4l0ptgjMZZtYtUnteBofjee+0oW1wQ1guv04a7A==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + lightningcss-linux-arm64-gnu@1.29.2: + resolution: {integrity: sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + lightningcss-linux-arm64-musl@1.27.0: resolution: {integrity: sha512-rCGBm2ax7kQ9pBSeITfCW9XSVF69VX+fm5DIpvDZQl4NnQoMQyRwhZQm9pd59m8leZ1IesRqWk2v/DntMo26lg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + lightningcss-linux-arm64-musl@1.29.2: + resolution: {integrity: sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + lightningcss-linux-x64-gnu@1.27.0: resolution: {integrity: sha512-Dk/jovSI7qqhJDiUibvaikNKI2x6kWPN79AQiD/E/KeQWMjdGe9kw51RAgoWFDi0coP4jinaH14Nrt/J8z3U4A==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + lightningcss-linux-x64-gnu@1.29.2: + resolution: {integrity: sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + lightningcss-linux-x64-musl@1.27.0: resolution: {integrity: sha512-QKjTxXm8A9s6v9Tg3Fk0gscCQA1t/HMoF7Woy1u68wCk5kS4fR+q3vXa1p3++REW784cRAtkYKrPy6JKibrEZA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + lightningcss-linux-x64-musl@1.29.2: + resolution: {integrity: sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + lightningcss-win32-arm64-msvc@1.27.0: resolution: {integrity: sha512-/wXegPS1hnhkeG4OXQKEMQeJd48RDC3qdh+OA8pCuOPCyvnm/yEayrJdJVqzBsqpy1aJklRCVxscpFur80o6iQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] + lightningcss-win32-arm64-msvc@1.29.2: + resolution: {integrity: sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + lightningcss-win32-x64-msvc@1.27.0: resolution: {integrity: sha512-/OJLj94Zm/waZShL8nB5jsNj3CfNATLCTyFxZyouilfTmSoLDX7VlVAmhPHoZWVFp4vdmoiEbPEYC8HID3m6yw==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] + lightningcss-win32-x64-msvc@1.29.2: + resolution: {integrity: sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + lightningcss@1.27.0: resolution: {integrity: sha512-8f7aNmS1+etYSLHht0fQApPc2kNO8qGRutifN5rVIc6Xo6ABsEbqOr758UwI7ALVbTt4x1fllKt0PYgzD9S3yQ==} engines: {node: '>= 12.0.0'} + lightningcss@1.29.2: + resolution: {integrity: sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA==} + engines: {node: '>= 12.0.0'} + + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + load-tsconfig@0.2.5: + resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + loader-runner@4.3.0: resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} engines: {node: '>=6.11.5'} @@ -4483,6 +5310,9 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash.sortby@4.7.0: + resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} + lodash.throttle@4.1.1: resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==} @@ -4520,6 +5350,11 @@ packages: resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} engines: {node: '>=12'} + lucide-react@0.483.0: + resolution: {integrity: sha512-WldsY17Qb/T3VZdMnVQ9C3DDIP7h1ViDTHVdVGnLZcvHNg30zH/MTQ04RTORjexoGmpsXroiQXZ4QyR0kBy0FA==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + make-dir@2.1.0: resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} engines: {node: '>=6'} @@ -4733,6 +5568,12 @@ packages: resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} engines: {node: '>= 0.4.0'} + next-themes@0.4.6: + resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==} + peerDependencies: + react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + next@15.2.2: resolution: {integrity: sha512-dgp8Kcx5XZRjMw2KNwBtUzhngRaURPioxoNIVl5BOyJbhi9CUgEtKDO7fx5wh8Z8vOVX1nYZ9meawJoRrlASYA==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} @@ -4791,6 +5632,10 @@ packages: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} + normalize-range@0.1.2: + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + engines: {node: '>=0.10.0'} + npm-package-arg@11.0.3: resolution: {integrity: sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw==} engines: {node: ^16.14.0 || >=18.0.0} @@ -4803,6 +5648,9 @@ packages: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + nullthrows@1.1.1: resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} @@ -4966,6 +5814,12 @@ packages: resolution: {integrity: sha512-Nt/a5SfCLiTnQAjx3fHlqp8hRgTL3z7kTQZzvIMS9uCAepnCyjpdEc6M/sz69WqMBdaDBw9sF1F1UaHROYzGkQ==} engines: {node: '>=10'} + parse5-htmlparser2-tree-adapter@7.1.0: + resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} + + parse5-parser-stream@7.1.2: + resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} + parse5@7.2.1: resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==} @@ -5059,6 +5913,24 @@ packages: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} + peerDependencies: + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} @@ -5070,13 +5942,73 @@ packages: resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} engines: {node: ^10 || ^12 || >=14} + postcss@8.5.3: + resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} + engines: {node: ^10 || ^12 || >=14} + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + prettier-plugin-tailwindcss@0.6.11: + resolution: {integrity: sha512-YxaYSIvZPAqhrrEpRtonnrXdghZg1irNg4qrjboCXrpybLWVs55cW2N3juhspVJiO0JBvYJT8SYsJpc8OQSnsA==} + engines: {node: '>=14.21.3'} + peerDependencies: + '@ianvs/prettier-plugin-sort-imports': '*' + '@prettier/plugin-pug': '*' + '@shopify/prettier-plugin-liquid': '*' + '@trivago/prettier-plugin-sort-imports': '*' + '@zackad/prettier-plugin-twig': '*' + prettier: ^3.0 + prettier-plugin-astro: '*' + prettier-plugin-css-order: '*' + prettier-plugin-import-sort: '*' + prettier-plugin-jsdoc: '*' + prettier-plugin-marko: '*' + prettier-plugin-multiline-arrays: '*' + prettier-plugin-organize-attributes: '*' + prettier-plugin-organize-imports: '*' + prettier-plugin-sort-imports: '*' + prettier-plugin-style-order: '*' + prettier-plugin-svelte: '*' + peerDependenciesMeta: + '@ianvs/prettier-plugin-sort-imports': + optional: true + '@prettier/plugin-pug': + optional: true + '@shopify/prettier-plugin-liquid': + optional: true + '@trivago/prettier-plugin-sort-imports': + optional: true + '@zackad/prettier-plugin-twig': + optional: true + prettier-plugin-astro: + optional: true + prettier-plugin-css-order: + optional: true + prettier-plugin-import-sort: + optional: true + prettier-plugin-jsdoc: + optional: true + prettier-plugin-marko: + optional: true + prettier-plugin-multiline-arrays: + optional: true + prettier-plugin-organize-attributes: + optional: true + prettier-plugin-organize-imports: + optional: true + prettier-plugin-sort-imports: + optional: true + prettier-plugin-style-order: + optional: true + prettier-plugin-svelte: + optional: true + prettier@3.5.3: resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==} engines: {node: '>=14'} + hasBin: true pretty-bytes@5.6.0: resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==} @@ -5311,6 +6243,10 @@ packages: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + readline@1.3.0: resolution: {integrity: sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg==} @@ -5434,6 +6370,11 @@ packages: rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + rollup@4.35.0: + resolution: {integrity: sha512-kg6oI4g+vc41vePJyO6dHt/yl0Rz3Thv0kJeVQ3D1kS3E5XSuKbPc29G4IpT/Kv1KQwgHVcN+HtyS+HYLNSvQg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + run-async@2.4.1: resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} engines: {node: '>=0.12.0'} @@ -5647,6 +6588,12 @@ packages: resolution: {integrity: sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==} engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + sonner@2.0.3: + resolution: {integrity: sha512-njQ4Hht92m0sMqqHVDL32V2Oun9W1+PHO9NDv9FHfJjT3JT22IG4Jpo3FPQy+mouRKCXFWO+r67v6MrHX2zeIA==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -5669,6 +6616,10 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + source-map@0.8.0-beta.0: + resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} + engines: {node: '>= 8'} + split-on-first@1.1.0: resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==} engines: {node: '>=6'} @@ -5865,13 +6816,11 @@ packages: symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - tabbable@6.2.0: - resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} + tailwind-merge@3.0.2: + resolution: {integrity: sha512-l7z+OYZ7mu3DTqrL88RiKrKIqO3NcpEO8V/Od04bNpvk0kiIFndGEoqfuzvj4yuhRkHKjRkII2z+KS2HfPcSxw==} - tamagui@1.125.23: - resolution: {integrity: sha512-FED+bH5zKf1C3EoLL1cLgZL0N3YpADDcIh2jICIvKEIcSPjPJzBc7721REg0Nehf+2pcWYxvvNKgztOykHK5cQ==} - peerDependencies: - react: '*' + tailwindcss@4.0.15: + resolution: {integrity: sha512-6ZMg+hHdMJpjpeCCFasX7K+U615U9D+7k5/cDK/iRwl6GptF24+I/AbKgOnXhVKePzrEyIXutLv36n4cRsq3Sg==} tapable@2.2.1: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} @@ -5938,6 +6887,9 @@ packages: tinycolor2@1.6.0: resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyglobby@0.2.12: resolution: {integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==} engines: {node: '>=12.0.0'} @@ -5970,10 +6922,17 @@ packages: tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + tr46@1.0.1: + resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} + tr46@3.0.0: resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==} engines: {node: '>=12'} + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + ts-api-utils@2.0.1: resolution: {integrity: sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==} engines: {node: '>=18.12'} @@ -6006,6 +6965,25 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsup@8.4.0: + resolution: {integrity: sha512-b+eZbPCjz10fRryaAA7C8xlIHnf8VnsaRqydheLIqwG/Mcpfk8Z5zp3HayX7GaTygkigHl5cBUs+IhcySiIexQ==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + '@microsoft/api-extractor': ^7.36.0 + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: '>=4.5.0' + peerDependenciesMeta: + '@microsoft/api-extractor': + optional: true + '@swc/core': + optional: true + postcss: + optional: true + typescript: + optional: true + turbo-darwin-64@2.4.4: resolution: {integrity: sha512-5kPvRkLAfmWI0MH96D+/THnDMGXlFNmjeqNRj5grLKiry+M9pKj3pRuScddAXPdlxjO5Ptz06UNaOQrrYGTx1g==} cpu: [x64] @@ -6039,6 +7017,9 @@ packages: turbo@2.4.4: resolution: {integrity: sha512-N9FDOVaY3yz0YCOhYIgOGYad7+m2ptvinXygw27WPLQvcZDl3+0Sa77KGVlLSiuPDChOUEnTKE9VJwLSi9BPGQ==} + tw-animate-css@1.2.4: + resolution: {integrity: sha512-yt+HkJB41NAvOffe4NweJU6fLqAlVx/mBX6XmHRp15kq0JxTtOKaIw8pVSWM1Z+n2nXtyi7cW6C9f0WG/F/QAQ==} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -6268,6 +7249,9 @@ packages: webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + webidl-conversions@4.0.2: + resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} + webidl-conversions@5.0.0: resolution: {integrity: sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==} engines: {node: '>=8'} @@ -6294,6 +7278,10 @@ packages: resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} engines: {node: '>=12'} + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + whatwg-fetch@3.6.20: resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} @@ -6301,6 +7289,10 @@ packages: resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} engines: {node: '>=12'} + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + whatwg-url-without-unicode@8.0.0-3: resolution: {integrity: sha512-HoKuzZrUlgpz35YO27XgD28uh/WJH4B0+3ttFqRo//lmq+9T/mIOJ6kqmINI9HpUpz1imRC/nR/lxKpJiv0uig==} engines: {node: '>=10'} @@ -6312,6 +7304,9 @@ packages: whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + whatwg-url@7.1.0: + resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} + which-boxed-primitive@1.1.1: resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} engines: {node: '>= 0.4'} @@ -6456,10 +7451,30 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + zustand@5.0.3: + resolution: {integrity: sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + snapshots: '@0no-co/graphql.web@1.1.2': {} + '@alloc/quick-lru@5.2.0': {} + '@ampproject/remapping@2.3.0': dependencies: '@jridgewell/gen-mapping': 0.3.8 @@ -7370,72 +8385,179 @@ snapshots: dependencies: '@jridgewell/trace-mapping': 0.3.9 - '@egjs/hammerjs@2.0.17': + '@dnd-kit/accessibility@3.1.1(react@19.0.0)': dependencies: - '@types/hammerjs': 2.0.46 + react: 19.0.0 + tslib: 2.8.1 - '@emnapi/runtime@1.3.1': + '@dnd-kit/core@6.3.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: + '@dnd-kit/accessibility': 3.1.1(react@19.0.0) + '@dnd-kit/utilities': 3.2.2(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) tslib: 2.8.1 - optional: true - '@eslint-community/eslint-utils@4.4.1(eslint@9.22.0)': + '@dnd-kit/modifiers@9.0.0(@dnd-kit/core@6.3.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)': dependencies: - eslint: 9.22.0 - eslint-visitor-keys: 3.4.3 - - '@eslint-community/regexpp@4.12.1': {} + '@dnd-kit/core': 6.3.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@dnd-kit/utilities': 3.2.2(react@19.0.0) + react: 19.0.0 + tslib: 2.8.1 - '@eslint/config-array@0.19.2': + '@dnd-kit/sortable@10.0.0(@dnd-kit/core@6.3.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)': dependencies: - '@eslint/object-schema': 2.1.6 - debug: 4.4.0 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color + '@dnd-kit/core': 6.3.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@dnd-kit/utilities': 3.2.2(react@19.0.0) + react: 19.0.0 + tslib: 2.8.1 - '@eslint/config-helpers@0.1.0': {} + '@dnd-kit/utilities@3.2.2(react@19.0.0)': + dependencies: + react: 19.0.0 + tslib: 2.8.1 - '@eslint/core@0.12.0': + '@egjs/hammerjs@2.0.17': dependencies: - '@types/json-schema': 7.0.15 + '@types/hammerjs': 2.0.46 - '@eslint/eslintrc@3.3.0': + '@emnapi/runtime@1.3.1': dependencies: - ajv: 6.12.6 - debug: 4.4.0 - espree: 10.3.0 - globals: 14.0.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color + tslib: 2.8.1 + optional: true - '@eslint/js@9.22.0': {} + '@esbuild/aix-ppc64@0.25.1': + optional: true - '@eslint/object-schema@2.1.6': {} + '@esbuild/android-arm64@0.25.1': + optional: true - '@eslint/plugin-kit@0.2.7': - dependencies: - '@eslint/core': 0.12.0 - levn: 0.4.1 + '@esbuild/android-arm@0.25.1': + optional: true - '@expo/bunyan@4.0.1': - dependencies: - uuid: 8.3.2 + '@esbuild/android-x64@0.25.1': + optional: true - '@expo/cli@0.22.19': - dependencies: - '@0no-co/graphql.web': 1.1.2 - '@babel/runtime': 7.26.10 - '@expo/code-signing-certificates': 0.0.5 - '@expo/config': 10.0.11 - '@expo/config-plugins': 9.0.17 - '@expo/devcert': 1.1.4 - '@expo/env': 0.4.2 + '@esbuild/darwin-arm64@0.25.1': + optional: true + + '@esbuild/darwin-x64@0.25.1': + optional: true + + '@esbuild/freebsd-arm64@0.25.1': + optional: true + + '@esbuild/freebsd-x64@0.25.1': + optional: true + + '@esbuild/linux-arm64@0.25.1': + optional: true + + '@esbuild/linux-arm@0.25.1': + optional: true + + '@esbuild/linux-ia32@0.25.1': + optional: true + + '@esbuild/linux-loong64@0.25.1': + optional: true + + '@esbuild/linux-mips64el@0.25.1': + optional: true + + '@esbuild/linux-ppc64@0.25.1': + optional: true + + '@esbuild/linux-riscv64@0.25.1': + optional: true + + '@esbuild/linux-s390x@0.25.1': + optional: true + + '@esbuild/linux-x64@0.25.1': + optional: true + + '@esbuild/netbsd-arm64@0.25.1': + optional: true + + '@esbuild/netbsd-x64@0.25.1': + optional: true + + '@esbuild/openbsd-arm64@0.25.1': + optional: true + + '@esbuild/openbsd-x64@0.25.1': + optional: true + + '@esbuild/sunos-x64@0.25.1': + optional: true + + '@esbuild/win32-arm64@0.25.1': + optional: true + + '@esbuild/win32-ia32@0.25.1': + optional: true + + '@esbuild/win32-x64@0.25.1': + optional: true + + '@eslint-community/eslint-utils@4.4.1(eslint@9.22.0(jiti@2.4.2))': + dependencies: + eslint: 9.22.0(jiti@2.4.2) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.1': {} + + '@eslint/config-array@0.19.2': + dependencies: + '@eslint/object-schema': 2.1.6 + debug: 4.4.0 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.1.0': {} + + '@eslint/core@0.12.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.0': + dependencies: + ajv: 6.12.6 + debug: 4.4.0 + espree: 10.3.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.22.0': {} + + '@eslint/object-schema@2.1.6': {} + + '@eslint/plugin-kit@0.2.7': + dependencies: + '@eslint/core': 0.12.0 + levn: 0.4.1 + + '@expo/bunyan@4.0.1': + dependencies: + uuid: 8.3.2 + + '@expo/cli@0.22.19': + dependencies: + '@0no-co/graphql.web': 1.1.2 + '@babel/runtime': 7.26.10 + '@expo/code-signing-certificates': 0.0.5 + '@expo/config': 10.0.11 + '@expo/config-plugins': 9.0.17 + '@expo/devcert': 1.1.4 + '@expo/env': 0.4.2 '@expo/image-utils': 0.6.5 '@expo/json-file': 9.0.2 '@expo/metro-config': 0.19.12 @@ -7737,20 +8859,6 @@ snapshots: react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - '@floating-ui/react-native@0.10.7(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': - dependencies: - '@floating-ui/core': 1.6.9 - react: 19.0.0 - react-native: 0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0) - - '@floating-ui/react@0.27.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': - dependencies: - '@floating-ui/react-dom': 2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@floating-ui/utils': 0.2.9 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - tabbable: 6.2.0 - '@floating-ui/utils@0.2.9': {} '@humanfs/core@0.19.1': {} @@ -7865,27 +8973,27 @@ snapshots: '@jest/console@29.7.0': dependencies: '@jest/types': 29.6.3 - '@types/node': 22.13.9 + '@types/node': 22.13.10 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 slash: 3.0.0 - '@jest/core@29.7.0(ts-node@10.9.2(@types/node@22.13.9)(typescript@5.8.2))': + '@jest/core@29.7.0(ts-node@10.9.2(@types/node@22.13.10)(typescript@5.8.2))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 22.13.9 + '@types/node': 22.13.10 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.9.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@22.13.9)(ts-node@10.9.2(@types/node@22.13.9)(typescript@5.8.2)) + jest-config: 29.7.0(@types/node@22.13.10)(ts-node@10.9.2(@types/node@22.13.10)(typescript@5.8.2)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -7914,7 +9022,7 @@ snapshots: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 22.13.9 + '@types/node': 22.13.10 jest-mock: 29.7.0 '@jest/expect-utils@29.7.0': @@ -7932,7 +9040,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 22.13.9 + '@types/node': 22.13.10 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -7954,7 +9062,7 @@ snapshots: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.25 - '@types/node': 22.13.9 + '@types/node': 22.13.10 chalk: 4.1.2 collect-v8-coverage: 1.0.2 exit: 0.1.2 @@ -8024,7 +9132,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 22.13.9 + '@types/node': 22.13.10 '@types/yargs': 17.0.33 chalk: 4.1.2 @@ -8110,1116 +9218,840 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@radix-ui/react-compose-refs@1.0.0(react@18.3.1)': - dependencies: - '@babel/runtime': 7.26.10 - react: 18.3.1 - - '@radix-ui/react-slot@1.0.1(react@18.3.1)': - dependencies: - '@babel/runtime': 7.26.10 - '@radix-ui/react-compose-refs': 1.0.0(react@18.3.1) - react: 18.3.1 + '@radix-ui/number@1.1.1': {} - '@react-native/assets-registry@0.76.7': {} + '@radix-ui/primitive@1.1.1': {} - '@react-native/babel-plugin-codegen@0.76.7(@babel/preset-env@7.26.9(@babel/core@7.26.10))': - dependencies: - '@react-native/codegen': 0.76.7(@babel/preset-env@7.26.9(@babel/core@7.26.10)) - transitivePeerDependencies: - - '@babel/preset-env' - - supports-color + '@radix-ui/primitive@1.1.2': {} - '@react-native/babel-preset@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))': + '@radix-ui/react-arrow@1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@babel/core': 7.26.10 - '@babel/plugin-proposal-export-default-from': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.26.10) - '@babel/plugin-syntax-export-default-from': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.10) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.10) - '@babel/plugin-transform-arrow-functions': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-async-generator-functions': 7.26.8(@babel/core@7.26.10) - '@babel/plugin-transform-async-to-generator': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-block-scoping': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-class-properties': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-classes': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-computed-properties': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-destructuring': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-flow-strip-types': 7.26.5(@babel/core@7.26.10) - '@babel/plugin-transform-for-of': 7.26.9(@babel/core@7.26.10) - '@babel/plugin-transform-function-name': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-literals': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-logical-assignment-operators': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-modules-commonjs': 7.26.3(@babel/core@7.26.10) - '@babel/plugin-transform-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-nullish-coalescing-operator': 7.26.6(@babel/core@7.26.10) - '@babel/plugin-transform-numeric-separator': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-object-rest-spread': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-optional-catch-binding': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-private-property-in-object': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-react-display-name': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-regenerator': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-runtime': 7.26.10(@babel/core@7.26.10) - '@babel/plugin-transform-shorthand-properties': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-spread': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-sticky-regex': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-typescript': 7.26.8(@babel/core@7.26.10) - '@babel/plugin-transform-unicode-regex': 7.25.9(@babel/core@7.26.10) - '@babel/template': 7.26.9 - '@react-native/babel-plugin-codegen': 0.76.7(@babel/preset-env@7.26.9(@babel/core@7.26.10)) - babel-plugin-syntax-hermes-parser: 0.25.1 - babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.26.10) - react-refresh: 0.14.2 - transitivePeerDependencies: - - '@babel/preset-env' - - supports-color - - '@react-native/codegen@0.76.7(@babel/preset-env@7.26.9(@babel/core@7.26.10))': - dependencies: - '@babel/parser': 7.26.10 - '@babel/preset-env': 7.26.9(@babel/core@7.26.10) - glob: 7.2.3 - hermes-parser: 0.23.1 - invariant: 2.2.4 - jscodeshift: 0.14.0(@babel/preset-env@7.26.9(@babel/core@7.26.10)) - mkdirp: 0.5.6 - nullthrows: 1.1.1 - yargs: 17.7.2 - transitivePeerDependencies: - - supports-color - - '@react-native/community-cli-plugin@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))': - dependencies: - '@react-native/dev-middleware': 0.76.7 - '@react-native/metro-babel-transformer': 0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10)) - chalk: 4.1.2 - execa: 5.1.1 - invariant: 2.2.4 - metro: 0.81.3 - metro-config: 0.81.3 - metro-core: 0.81.3 - node-fetch: 2.7.0 - readline: 1.3.0 - semver: 7.7.1 - transitivePeerDependencies: - - '@babel/core' - - '@babel/preset-env' - - bufferutil - - encoding - - supports-color - - utf-8-validate - - '@react-native/debugger-frontend@0.76.7': {} - - '@react-native/dev-middleware@0.76.7': - dependencies: - '@isaacs/ttlcache': 1.4.1 - '@react-native/debugger-frontend': 0.76.7 - chrome-launcher: 0.15.2 - chromium-edge-launcher: 0.2.0 - connect: 3.7.0 - debug: 2.6.9 - invariant: 2.2.4 - nullthrows: 1.1.1 - open: 7.4.2 - selfsigned: 2.4.1 - serve-static: 1.16.2 - ws: 6.2.3 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - '@react-native/gradle-plugin@0.76.7': {} - - '@react-native/js-polyfills@0.76.7': {} - - '@react-native/metro-babel-transformer@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))': - dependencies: - '@babel/core': 7.26.10 - '@react-native/babel-preset': 0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10)) - hermes-parser: 0.23.1 - nullthrows: 1.1.1 - transitivePeerDependencies: - - '@babel/preset-env' - - supports-color - - '@react-native/normalize-color@2.1.0': {} - - '@react-native/normalize-colors@0.74.89': {} - - '@react-native/normalize-colors@0.76.7': {} - - '@react-native/virtualized-lists@0.76.7(@types/react@18.3.18)(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1)': - dependencies: - invariant: 2.2.4 - nullthrows: 1.1.1 - react: 18.3.1 - react-native: 0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) optionalDependencies: - '@types/react': 18.3.18 - - '@react-native/virtualized-lists@0.76.7(@types/react@19.0.10)(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': - dependencies: - invariant: 2.2.4 - nullthrows: 1.1.1 + '@types/react': 19.0.10 + '@types/react-dom': 19.0.4(@types/react@19.0.10) + + '@radix-ui/react-checkbox@1.1.5(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-presence': 1.1.3(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-primitive': 2.0.3(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-controllable-state': 1.1.1(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.0.10)(react@19.0.0) react: 19.0.0 - react-native: 0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0) + react-dom: 19.0.0(react@19.0.0) optionalDependencies: '@types/react': 19.0.10 + '@types/react-dom': 19.0.4(@types/react@19.0.10) - '@react-navigation/bottom-tabs@7.2.1(@react-navigation/native@7.0.15(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native-screens@4.4.0(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1)': - dependencies: - '@react-navigation/elements': 2.2.6(@react-navigation/native@7.0.15(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1) - '@react-navigation/native': 7.0.15(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1) - color: 4.2.3 - react: 18.3.1 - react-native: 0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1) - react-native-safe-area-context: 4.12.0(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1) - react-native-screens: 4.4.0(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1) - transitivePeerDependencies: - - '@react-native-masked-view/masked-view' - - '@react-navigation/core@7.4.0(react@18.3.1)': + '@radix-ui/react-collection@1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@react-navigation/routers': 7.2.0 - escape-string-regexp: 4.0.0 - nanoid: 3.3.8 - query-string: 7.1.3 - react: 18.3.1 - react-is: 18.3.1 - use-latest-callback: 0.2.3(react@18.3.1) - use-sync-external-store: 1.4.0(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-context': 1.1.1(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-slot': 1.1.2(@types/react@19.0.10)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.10 + '@types/react-dom': 19.0.4(@types/react@19.0.10) - '@react-navigation/elements@2.2.6(@react-navigation/native@7.0.15(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-compose-refs@1.0.0(react@18.3.1)': dependencies: - '@react-navigation/native': 7.0.15(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1) - color: 4.2.3 + '@babel/runtime': 7.26.10 react: 18.3.1 - react-native: 0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1) - react-native-safe-area-context: 4.12.0(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1) - '@react-navigation/native-stack@7.2.1(@react-navigation/native@7.0.15(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native-screens@4.4.0(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-compose-refs@1.1.1(@types/react@19.0.10)(react@19.0.0)': dependencies: - '@react-navigation/elements': 2.2.6(@react-navigation/native@7.0.15(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1) - '@react-navigation/native': 7.0.15(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-native: 0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1) - react-native-safe-area-context: 4.12.0(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1) - react-native-screens: 4.4.0(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1) - warn-once: 0.1.1 - transitivePeerDependencies: - - '@react-native-masked-view/masked-view' + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.10 - '@react-navigation/native@7.0.15(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.0.10)(react@19.0.0)': dependencies: - '@react-navigation/core': 7.4.0(react@18.3.1) - escape-string-regexp: 4.0.0 - fast-deep-equal: 3.1.3 - nanoid: 3.3.8 - react: 18.3.1 - react-native: 0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1) - use-latest-callback: 0.2.3(react@18.3.1) + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.10 - '@react-navigation/routers@7.2.0': + '@radix-ui/react-context@1.1.1(@types/react@19.0.10)(react@19.0.0)': dependencies: - nanoid: 3.3.8 - - '@rtsao/scc@1.1.0': {} - - '@rushstack/eslint-patch@1.11.0': {} + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.10 - '@segment/loosely-validate-event@2.0.0': + '@radix-ui/react-context@1.1.2(@types/react@19.0.10)(react@19.0.0)': dependencies: - component-type: 1.2.2 - join-component: 1.1.0 - - '@sinclair/typebox@0.27.8': {} + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.10 - '@sinonjs/commons@3.0.1': - dependencies: - type-detect: 4.0.8 + '@radix-ui/react-dialog@1.1.6(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-context': 1.1.1(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-dismissable-layer': 1.1.5(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-focus-guards': 1.1.1(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-focus-scope': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-id': 1.1.0(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-portal': 1.1.4(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-slot': 1.1.2(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.10)(react@19.0.0) + aria-hidden: 1.2.4 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + react-remove-scroll: 2.6.3(@types/react@19.0.10)(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.10 + '@types/react-dom': 19.0.4(@types/react@19.0.10) - '@sinonjs/fake-timers@10.3.0': + '@radix-ui/react-direction@1.1.0(@types/react@19.0.10)(react@19.0.0)': dependencies: - '@sinonjs/commons': 3.0.1 - - '@swc/counter@0.1.3': {} + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.10 - '@swc/helpers@0.5.15': + '@radix-ui/react-direction@1.1.1(@types/react@19.0.10)(react@19.0.0)': dependencies: - tslib: 2.8.1 - - '@tamagui/accordion@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': - dependencies: - '@tamagui/collapsible': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/collection': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/create-context': 1.125.23(react@19.0.0) - '@tamagui/polyfill-dev': 1.125.23 - '@tamagui/stacks': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/text': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/use-controllable-state': 1.125.23(react@19.0.0) react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + optionalDependencies: + '@types/react': 19.0.10 - '@tamagui/adapt@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-dismissable-layer@1.1.5(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/portal': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/z-index-stack': 1.125.23 - transitivePeerDependencies: - - react - - react-dom - - react-native - - '@tamagui/alert-dialog@1.125.23(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': - dependencies: - '@tamagui/animate-presence': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/aria-hidden': 1.125.23(react@19.0.0) - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/create-context': 1.125.23(react@19.0.0) - '@tamagui/dialog': 1.125.23(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/dismissable': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/focus-scope': 1.125.23(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/polyfill-dev': 1.125.23 - '@tamagui/popper': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/portal': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/remove-scroll': 1.125.23(@types/react@19.0.10)(react@19.0.0) - '@tamagui/stacks': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/text': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/use-controllable-state': 1.125.23(react@19.0.0) + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@19.0.10)(react@19.0.0) react: 19.0.0 - transitivePeerDependencies: - - '@types/react' - - react-dom - - react-native + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.10 + '@types/react-dom': 19.0.4(@types/react@19.0.10) - '@tamagui/animate-presence@1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-dropdown-menu@2.1.6(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/use-constant': 1.125.23(react@19.0.0) - '@tamagui/use-force-update': 1.125.23(react@19.0.0) - '@tamagui/use-presence': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/web': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - transitivePeerDependencies: - - react - - react-dom + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-context': 1.1.1(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-id': 1.1.0(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-menu': 2.1.6(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.10)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.10 + '@types/react-dom': 19.0.4(@types/react@19.0.10) - '@tamagui/animate@1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-focus-guards@1.1.1(@types/react@19.0.10)(react@19.0.0)': dependencies: - '@tamagui/animate-presence': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - transitivePeerDependencies: - - react - - react-dom + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.10 - '@tamagui/animations-react-native@1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-focus-scope@1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/use-presence': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/web': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.10)(react@19.0.0) react: 19.0.0 - transitivePeerDependencies: - - react-dom + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.10 + '@types/react-dom': 19.0.4(@types/react@19.0.10) - '@tamagui/aria-hidden@1.125.23(react@19.0.0)': + '@radix-ui/react-id@1.1.0(@types/react@19.0.10)(react@19.0.0)': dependencies: - aria-hidden: 1.2.4 + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.10)(react@19.0.0) react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.10 - '@tamagui/avatar@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-label@2.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/image': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/shapes': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/text': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native - - '@tamagui/button@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': - dependencies: - '@tamagui/font-size': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/get-button-sized': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/helpers-tamagui': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/stacks': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/text': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/web': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.10 + '@types/react-dom': 19.0.4(@types/react@19.0.10) + + '@radix-ui/react-menu@2.1.6(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-collection': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-context': 1.1.1(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-direction': 1.1.0(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-dismissable-layer': 1.1.5(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-focus-guards': 1.1.1(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-focus-scope': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-id': 1.1.0(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-popper': 1.2.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-portal': 1.1.4(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-roving-focus': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-slot': 1.1.2(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.10)(react@19.0.0) + aria-hidden: 1.2.4 react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + react-dom: 19.0.0(react@19.0.0) + react-remove-scroll: 2.6.3(@types/react@19.0.10)(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.10 + '@types/react-dom': 19.0.4(@types/react@19.0.10) - '@tamagui/card@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-popper@1.2.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@tamagui/create-context': 1.125.23(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/stacks': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/web': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@floating-ui/react-dom': 2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-arrow': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-context': 1.1.1(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-use-rect': 1.1.0(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-use-size': 1.1.0(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/rect': 1.1.0 react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.10 + '@types/react-dom': 19.0.4(@types/react@19.0.10) - '@tamagui/checkbox-headless@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-portal@1.1.4(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/create-context': 1.125.23(react@19.0.0) - '@tamagui/focusable': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/label': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/use-controllable-state': 1.125.23(react@19.0.0) - '@tamagui/use-previous': 1.125.23 + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.10)(react@19.0.0) react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.10 + '@types/react-dom': 19.0.4(@types/react@19.0.10) - '@tamagui/checkbox@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': - dependencies: - '@tamagui/checkbox-headless': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/create-context': 1.125.23(react@19.0.0) - '@tamagui/focusable': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/font-size': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/get-token': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/helpers-tamagui': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/label': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/stacks': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/use-controllable-state': 1.125.23(react@19.0.0) - '@tamagui/use-previous': 1.125.23 + '@radix-ui/react-presence@1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.10)(react@19.0.0) react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.10 + '@types/react-dom': 19.0.4(@types/react@19.0.10) - '@tamagui/collapsible@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-presence@1.1.3(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@tamagui/animate-presence': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/create-context': 1.125.23(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/polyfill-dev': 1.125.23 - '@tamagui/stacks': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/use-controllable-state': 1.125.23(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.10)(react@19.0.0) react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.10 + '@types/react-dom': 19.0.4(@types/react@19.0.10) - '@tamagui/collection@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-primitive@2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/create-context': 1.125.23(react@19.0.0) - '@tamagui/polyfill-dev': 1.125.23 - '@tamagui/stacks': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/use-controllable-state': 1.125.23(react@19.0.0) + '@radix-ui/react-slot': 1.1.2(@types/react@19.0.10)(react@19.0.0) react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.10 + '@types/react-dom': 19.0.4(@types/react@19.0.10) - '@tamagui/compose-refs@1.125.23(react@19.0.0)': + '@radix-ui/react-primitive@2.0.3(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: + '@radix-ui/react-slot': 1.2.0(@types/react@19.0.10)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.10 + '@types/react-dom': 19.0.4(@types/react@19.0.10) + + '@radix-ui/react-roving-focus@1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-collection': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-context': 1.1.1(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-direction': 1.1.0(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-id': 1.1.0(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.10)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.10 + '@types/react-dom': 19.0.4(@types/react@19.0.10) + + '@radix-ui/react-scroll-area@1.2.4(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-presence': 1.1.3(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-primitive': 2.0.3(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.10)(react@19.0.0) react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.10 + '@types/react-dom': 19.0.4(@types/react@19.0.10) - '@tamagui/constants@1.125.23(react@19.0.0)': + '@radix-ui/react-separator@1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.10 + '@types/react-dom': 19.0.4(@types/react@19.0.10) - '@tamagui/core@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-slot@1.0.1(react@18.3.1)': dependencies: - '@tamagui/react-native-media-driver': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/react-native-use-pressable': 1.125.23(react@19.0.0) - '@tamagui/react-native-use-responder-events': 1.125.23(react@19.0.0) - '@tamagui/use-event': 1.125.23(react@19.0.0) - '@tamagui/web': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - transitivePeerDependencies: - - react - - react-dom - - react-native + '@babel/runtime': 7.26.10 + '@radix-ui/react-compose-refs': 1.0.0(react@18.3.1) + react: 18.3.1 - '@tamagui/create-context@1.125.23(react@19.0.0)': + '@radix-ui/react-slot@1.1.2(@types/react@19.0.10)(react@19.0.0)': dependencies: + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0) react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.10 - '@tamagui/dialog@1.125.23(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': - dependencies: - '@tamagui/adapt': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/animate-presence': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/aria-hidden': 1.125.23(react@19.0.0) - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/create-context': 1.125.23(react@19.0.0) - '@tamagui/dismissable': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/focus-scope': 1.125.23(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/polyfill-dev': 1.125.23 - '@tamagui/popper': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/portal': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/remove-scroll': 1.125.23(@types/react@19.0.10)(react@19.0.0) - '@tamagui/sheet': 1.125.23(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/stacks': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/text': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/use-controllable-state': 1.125.23(react@19.0.0) - '@tamagui/z-index-stack': 1.125.23 + '@radix-ui/react-slot@1.2.0(@types/react@19.0.10)(react@19.0.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.10)(react@19.0.0) react: 19.0.0 - transitivePeerDependencies: - - '@types/react' - - react-dom - - react-native + optionalDependencies: + '@types/react': 19.0.10 - '@tamagui/dismissable@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-tabs@1.1.3(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/use-escape-keydown': 1.125.23 - '@tamagui/use-event': 1.125.23(react@19.0.0) + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-context': 1.1.1(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-direction': 1.1.0(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-id': 1.1.0(@types/react@19.0.10)(react@19.0.0) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-roving-focus': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.10)(react@19.0.0) react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.10 + '@types/react-dom': 19.0.4(@types/react@19.0.10) - '@tamagui/elements@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-use-callback-ref@1.1.0(@types/react@19.0.10)(react@19.0.0)': dependencies: - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native - - '@tamagui/fake-react-native@1.125.23': {} + optionalDependencies: + '@types/react': 19.0.10 - '@tamagui/floating@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.0.10)(react@19.0.0)': dependencies: - '@floating-ui/react-dom': 2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@floating-ui/react-native': 0.10.7(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + optionalDependencies: + '@types/react': 19.0.10 - '@tamagui/focus-scope@1.125.23(react@19.0.0)': + '@radix-ui/react-use-controllable-state@1.1.0(@types/react@19.0.10)(react@19.0.0)': dependencies: - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/start-transition': 1.125.23 - '@tamagui/use-event': 1.125.23(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.10)(react@19.0.0) react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.10 - '@tamagui/focusable@1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-use-controllable-state@1.1.1(@types/react@19.0.10)(react@19.0.0)': dependencies: - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/web': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.0.10)(react@19.0.0) react: 19.0.0 - transitivePeerDependencies: - - react-dom + optionalDependencies: + '@types/react': 19.0.10 - '@tamagui/font-size@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-use-escape-keydown@1.1.0(@types/react@19.0.10)(react@19.0.0)': dependencies: - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.10)(react@19.0.0) react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + optionalDependencies: + '@types/react': 19.0.10 - '@tamagui/form@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-use-layout-effect@1.1.0(@types/react@19.0.10)(react@19.0.0)': dependencies: - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/create-context': 1.125.23(react@19.0.0) - '@tamagui/focusable': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/get-button-sized': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/get-font-sized': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/text': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + optionalDependencies: + '@types/react': 19.0.10 - '@tamagui/get-button-sized@1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.0.10)(react@19.0.0)': dependencies: - '@tamagui/get-token': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/web': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react: 19.0.0 - transitivePeerDependencies: - - react-dom + optionalDependencies: + '@types/react': 19.0.10 - '@tamagui/get-font-sized@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-use-previous@1.1.1(@types/react@19.0.10)(react@19.0.0)': dependencies: - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + optionalDependencies: + '@types/react': 19.0.10 - '@tamagui/get-token@1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-use-rect@1.1.0(@types/react@19.0.10)(react@19.0.0)': dependencies: - '@tamagui/web': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/rect': 1.1.0 react: 19.0.0 - transitivePeerDependencies: - - react-dom + optionalDependencies: + '@types/react': 19.0.10 - '@tamagui/group@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-use-size@1.1.0(@types/react@19.0.10)(react@19.0.0)': dependencies: - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/create-context': 1.125.23(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/stacks': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/use-controllable-state': 1.125.23(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.10)(react@19.0.0) react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + optionalDependencies: + '@types/react': 19.0.10 - '@tamagui/helpers-tamagui@1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-use-size@1.1.1(@types/react@19.0.10)(react@19.0.0)': dependencies: - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/web': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.10)(react@19.0.0) react: 19.0.0 - transitivePeerDependencies: - - react-dom + optionalDependencies: + '@types/react': 19.0.10 + + '@radix-ui/rect@1.1.0': {} + + '@react-native/assets-registry@0.76.7': {} - '@tamagui/helpers@1.125.23(react@19.0.0)': + '@react-native/babel-plugin-codegen@0.76.7(@babel/preset-env@7.26.9(@babel/core@7.26.10))': dependencies: - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/simple-hash': 1.125.23 + '@react-native/codegen': 0.76.7(@babel/preset-env@7.26.9(@babel/core@7.26.10)) transitivePeerDependencies: - - react + - '@babel/preset-env' + - supports-color - '@tamagui/image@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': + '@react-native/babel-preset@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))': dependencies: - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - react: 19.0.0 + '@babel/core': 7.26.10 + '@babel/plugin-proposal-export-default-from': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.26.10) + '@babel/plugin-syntax-export-default-from': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.10) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.10) + '@babel/plugin-transform-arrow-functions': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-async-generator-functions': 7.26.8(@babel/core@7.26.10) + '@babel/plugin-transform-async-to-generator': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-block-scoping': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-class-properties': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-classes': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-computed-properties': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-destructuring': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-flow-strip-types': 7.26.5(@babel/core@7.26.10) + '@babel/plugin-transform-for-of': 7.26.9(@babel/core@7.26.10) + '@babel/plugin-transform-function-name': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-literals': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-logical-assignment-operators': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-modules-commonjs': 7.26.3(@babel/core@7.26.10) + '@babel/plugin-transform-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-nullish-coalescing-operator': 7.26.6(@babel/core@7.26.10) + '@babel/plugin-transform-numeric-separator': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-object-rest-spread': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-optional-catch-binding': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-private-property-in-object': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-react-display-name': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-regenerator': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-runtime': 7.26.10(@babel/core@7.26.10) + '@babel/plugin-transform-shorthand-properties': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-spread': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-sticky-regex': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-typescript': 7.26.8(@babel/core@7.26.10) + '@babel/plugin-transform-unicode-regex': 7.25.9(@babel/core@7.26.10) + '@babel/template': 7.26.9 + '@react-native/babel-plugin-codegen': 0.76.7(@babel/preset-env@7.26.9(@babel/core@7.26.10)) + babel-plugin-syntax-hermes-parser: 0.25.1 + babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.26.10) + react-refresh: 0.14.2 transitivePeerDependencies: - - react-dom - - react-native + - '@babel/preset-env' + - supports-color - '@tamagui/label@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': + '@react-native/codegen@0.76.7(@babel/preset-env@7.26.9(@babel/core@7.26.10))': dependencies: - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/create-context': 1.125.23(react@19.0.0) - '@tamagui/focusable': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/get-button-sized': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/get-font-sized': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/text': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/web': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react: 19.0.0 - react-native: 0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0) + '@babel/parser': 7.26.10 + '@babel/preset-env': 7.26.9(@babel/core@7.26.10) + glob: 7.2.3 + hermes-parser: 0.23.1 + invariant: 2.2.4 + jscodeshift: 0.14.0(@babel/preset-env@7.26.9(@babel/core@7.26.10)) + mkdirp: 0.5.6 + nullthrows: 1.1.1 + yargs: 17.7.2 transitivePeerDependencies: - - react-dom + - supports-color - '@tamagui/linear-gradient@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': + '@react-native/community-cli-plugin@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))': dependencies: - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/stacks': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - react: 19.0.0 + '@react-native/dev-middleware': 0.76.7 + '@react-native/metro-babel-transformer': 0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10)) + chalk: 4.1.2 + execa: 5.1.1 + invariant: 2.2.4 + metro: 0.81.3 + metro-config: 0.81.3 + metro-core: 0.81.3 + node-fetch: 2.7.0 + readline: 1.3.0 + semver: 7.7.1 transitivePeerDependencies: - - react-dom - - react-native + - '@babel/core' + - '@babel/preset-env' + - bufferutil + - encoding + - supports-color + - utf-8-validate + + '@react-native/debugger-frontend@0.76.7': {} - '@tamagui/list-item@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': + '@react-native/dev-middleware@0.76.7': dependencies: - '@tamagui/font-size': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/get-font-sized': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/get-token': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/helpers-tamagui': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/stacks': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/text': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/web': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react: 19.0.0 + '@isaacs/ttlcache': 1.4.1 + '@react-native/debugger-frontend': 0.76.7 + chrome-launcher: 0.15.2 + chromium-edge-launcher: 0.2.0 + connect: 3.7.0 + debug: 2.6.9 + invariant: 2.2.4 + nullthrows: 1.1.1 + open: 7.4.2 + selfsigned: 2.4.1 + serve-static: 1.16.2 + ws: 6.2.3 transitivePeerDependencies: - - react-dom - - react-native + - bufferutil + - supports-color + - utf-8-validate - '@tamagui/normalize-css-color@1.125.23': - dependencies: - '@react-native/normalize-color': 2.1.0 - - '@tamagui/polyfill-dev@1.125.23': {} - - '@tamagui/popover@1.125.23(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': - dependencies: - '@floating-ui/react': 0.27.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/adapt': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/animate': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/aria-hidden': 1.125.23(react@19.0.0) - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/dismissable': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/floating': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/focus-scope': 1.125.23(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/polyfill-dev': 1.125.23 - '@tamagui/popper': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/portal': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/remove-scroll': 1.125.23(@types/react@19.0.10)(react@19.0.0) - '@tamagui/scroll-view': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/sheet': 1.125.23(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/stacks': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/use-controllable-state': 1.125.23(react@19.0.0) - react: 19.0.0 - react-freeze: 1.0.4(react@19.0.0) - transitivePeerDependencies: - - '@types/react' - - react-dom - - react-native + '@react-native/gradle-plugin@0.76.7': {} - '@tamagui/popper@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': - dependencies: - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/floating': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/get-token': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/stacks': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/start-transition': 1.125.23 - '@tamagui/use-controllable-state': 1.125.23(react@19.0.0) - react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + '@react-native/js-polyfills@0.76.7': {} - '@tamagui/portal@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': + '@react-native/metro-babel-transformer@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))': dependencies: - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/stacks': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/start-transition': 1.125.23 - '@tamagui/use-did-finish-ssr': 1.125.23(react@19.0.0) - '@tamagui/use-event': 1.125.23(react@19.0.0) - '@tamagui/z-index-stack': 1.125.23 + '@babel/core': 7.26.10 + '@react-native/babel-preset': 0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10)) + hermes-parser: 0.23.1 + nullthrows: 1.1.1 transitivePeerDependencies: - - react - - react-dom - - react-native + - '@babel/preset-env' + - supports-color - '@tamagui/progress@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': - dependencies: - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/create-context': 1.125.23(react@19.0.0) - '@tamagui/get-token': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/stacks': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + '@react-native/normalize-colors@0.74.89': {} - '@tamagui/radio-group@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': - dependencies: - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/create-context': 1.125.23(react@19.0.0) - '@tamagui/focusable': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/get-token': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/label': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/radio-headless': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/roving-focus': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/stacks': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/use-controllable-state': 1.125.23(react@19.0.0) - '@tamagui/use-previous': 1.125.23 - react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + '@react-native/normalize-colors@0.76.7': {} - '@tamagui/radio-headless@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': + '@react-native/virtualized-lists@0.76.7(@types/react@18.3.18)(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1)': dependencies: - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/create-context': 1.125.23(react@19.0.0) - '@tamagui/focusable': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/label': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/use-controllable-state': 1.125.23(react@19.0.0) - '@tamagui/use-previous': 1.125.23 - react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + invariant: 2.2.4 + nullthrows: 1.1.1 + react: 18.3.1 + react-native: 0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.18 - '@tamagui/react-native-media-driver@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': + '@react-navigation/bottom-tabs@7.2.1(@react-navigation/native@7.0.15(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native-screens@4.4.0(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1)': dependencies: - '@tamagui/web': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react-native: 0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0) + '@react-navigation/elements': 2.2.6(@react-navigation/native@7.0.15(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1) + '@react-navigation/native': 7.0.15(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1) + color: 4.2.3 + react: 18.3.1 + react-native: 0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1) + react-native-safe-area-context: 4.12.0(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1) + react-native-screens: 4.4.0(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1) transitivePeerDependencies: - - react - - react-dom + - '@react-native-masked-view/masked-view' - '@tamagui/react-native-use-pressable@1.125.23(react@19.0.0)': + '@react-navigation/core@7.4.0(react@18.3.1)': dependencies: - react: 19.0.0 + '@react-navigation/routers': 7.2.0 + escape-string-regexp: 4.0.0 + nanoid: 3.3.8 + query-string: 7.1.3 + react: 18.3.1 + react-is: 18.3.1 + use-latest-callback: 0.2.3(react@18.3.1) + use-sync-external-store: 1.4.0(react@18.3.1) - '@tamagui/react-native-use-responder-events@1.125.23(react@19.0.0)': + '@react-navigation/elements@2.2.6(@react-navigation/native@7.0.15(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1)': dependencies: - react: 19.0.0 + '@react-navigation/native': 7.0.15(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1) + color: 4.2.3 + react: 18.3.1 + react-native: 0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1) + react-native-safe-area-context: 4.12.0(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1) - '@tamagui/remove-scroll@1.125.23(@types/react@19.0.10)(react@19.0.0)': + '@react-navigation/native-stack@7.2.1(@react-navigation/native@7.0.15(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native-screens@4.4.0(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1)': dependencies: - react: 19.0.0 - react-remove-scroll: 2.6.3(@types/react@19.0.10)(react@19.0.0) + '@react-navigation/elements': 2.2.6(@react-navigation/native@7.0.15(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1) + '@react-navigation/native': 7.0.15(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-native: 0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1) + react-native-safe-area-context: 4.12.0(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1) + react-native-screens: 4.4.0(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1) + warn-once: 0.1.1 transitivePeerDependencies: - - '@types/react' + - '@react-native-masked-view/masked-view' - '@tamagui/roving-focus@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': + '@react-navigation/native@7.0.15(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1)': dependencies: - '@tamagui/collection': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/create-context': 1.125.23(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/use-controllable-state': 1.125.23(react@19.0.0) - '@tamagui/use-direction': 1.125.23(react@19.0.0) - '@tamagui/use-event': 1.125.23(react@19.0.0) - react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + '@react-navigation/core': 7.4.0(react@18.3.1) + escape-string-regexp: 4.0.0 + fast-deep-equal: 3.1.3 + nanoid: 3.3.8 + react: 18.3.1 + react-native: 0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1) + use-latest-callback: 0.2.3(react@18.3.1) - '@tamagui/scroll-view@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': + '@react-navigation/routers@7.2.0': dependencies: - '@tamagui/stacks': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/web': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + nanoid: 3.3.8 - '@tamagui/select@1.125.23(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': - dependencies: - '@floating-ui/react': 0.27.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@floating-ui/react-dom': 2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@floating-ui/react-native': 0.10.7(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/adapt': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/animate-presence': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/create-context': 1.125.23(react@19.0.0) - '@tamagui/dismissable': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/focus-scope': 1.125.23(react@19.0.0) - '@tamagui/get-token': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/list-item': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/portal': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/remove-scroll': 1.125.23(@types/react@19.0.10)(react@19.0.0) - '@tamagui/separator': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/sheet': 1.125.23(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/stacks': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/text': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/use-controllable-state': 1.125.23(react@19.0.0) - '@tamagui/use-debounce': 1.125.23(react@19.0.0) - '@tamagui/use-event': 1.125.23(react@19.0.0) - '@tamagui/use-previous': 1.125.23 - react: 19.0.0 - transitivePeerDependencies: - - '@types/react' - - react-dom - - react-native + '@rollup/rollup-android-arm-eabi@4.35.0': + optional: true - '@tamagui/separator@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': - dependencies: - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + '@rollup/rollup-android-arm64@4.35.0': + optional: true - '@tamagui/shapes@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': - dependencies: - '@tamagui/stacks': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/web': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + '@rollup/rollup-darwin-arm64@4.35.0': + optional: true - '@tamagui/sheet@1.125.23(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': - dependencies: - '@tamagui/adapt': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/animate-presence': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/animations-react-native': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/create-context': 1.125.23(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/portal': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/remove-scroll': 1.125.23(@types/react@19.0.10)(react@19.0.0) - '@tamagui/scroll-view': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/stacks': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/use-constant': 1.125.23(react@19.0.0) - '@tamagui/use-controllable-state': 1.125.23(react@19.0.0) - '@tamagui/use-did-finish-ssr': 1.125.23(react@19.0.0) - '@tamagui/use-keyboard-visible': 1.125.23(react@19.0.0) - '@tamagui/z-index-stack': 1.125.23 - react: 19.0.0 - transitivePeerDependencies: - - '@types/react' - - react-dom - - react-native + '@rollup/rollup-darwin-x64@4.35.0': + optional: true - '@tamagui/simple-hash@1.125.23': {} + '@rollup/rollup-freebsd-arm64@4.35.0': + optional: true - '@tamagui/slider@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': - dependencies: - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/create-context': 1.125.23(react@19.0.0) - '@tamagui/get-token': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/stacks': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/use-controllable-state': 1.125.23(react@19.0.0) - '@tamagui/use-debounce': 1.125.23(react@19.0.0) - '@tamagui/use-direction': 1.125.23(react@19.0.0) - react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + '@rollup/rollup-freebsd-x64@4.35.0': + optional: true - '@tamagui/stacks@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': - dependencies: - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + '@rollup/rollup-linux-arm-gnueabihf@4.35.0': + optional: true - '@tamagui/start-transition@1.125.23': {} + '@rollup/rollup-linux-arm-musleabihf@4.35.0': + optional: true - '@tamagui/switch-headless@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': - dependencies: - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/label': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/use-previous': 1.125.23 - react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + '@rollup/rollup-linux-arm64-gnu@4.35.0': + optional: true - '@tamagui/switch@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': - dependencies: - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/focusable': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/get-token': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/label': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/stacks': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/switch-headless': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/use-controllable-state': 1.125.23(react@19.0.0) - '@tamagui/use-previous': 1.125.23 - react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + '@rollup/rollup-linux-arm64-musl@4.35.0': + optional: true - '@tamagui/tabs@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': - dependencies: - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/create-context': 1.125.23(react@19.0.0) - '@tamagui/get-button-sized': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/group': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/roving-focus': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/stacks': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/use-controllable-state': 1.125.23(react@19.0.0) - '@tamagui/use-direction': 1.125.23(react@19.0.0) - '@tamagui/web': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + '@rollup/rollup-linux-loongarch64-gnu@4.35.0': + optional: true - '@tamagui/text@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': - dependencies: - '@tamagui/get-font-sized': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/helpers-tamagui': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/web': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + '@rollup/rollup-linux-powerpc64le-gnu@4.35.0': + optional: true - '@tamagui/theme@1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': - dependencies: - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/web': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react: 19.0.0 - transitivePeerDependencies: - - react-dom + '@rollup/rollup-linux-riscv64-gnu@4.35.0': + optional: true - '@tamagui/timer@1.125.23': {} - - '@tamagui/toggle-group@1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': - dependencies: - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/create-context': 1.125.23(react@19.0.0) - '@tamagui/focusable': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/font-size': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/get-token': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/group': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/helpers-tamagui': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/roving-focus': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/stacks': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/use-controllable-state': 1.125.23(react@19.0.0) - '@tamagui/use-direction': 1.125.23(react@19.0.0) - '@tamagui/web': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react: 19.0.0 - transitivePeerDependencies: - - react-dom - - react-native + '@rollup/rollup-linux-s390x-gnu@4.35.0': + optional: true - '@tamagui/tooltip@1.125.23(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': - dependencies: - '@floating-ui/react': 0.27.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/create-context': 1.125.23(react@19.0.0) - '@tamagui/floating': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/get-token': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/polyfill-dev': 1.125.23 - '@tamagui/popover': 1.125.23(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/popper': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/stacks': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/text': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/use-controllable-state': 1.125.23(react@19.0.0) - react: 19.0.0 - transitivePeerDependencies: - - '@types/react' - - react-dom - - react-native + '@rollup/rollup-linux-x64-gnu@4.35.0': + optional: true + + '@rollup/rollup-linux-x64-musl@4.35.0': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.35.0': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.35.0': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.35.0': + optional: true - '@tamagui/types@1.125.23': {} + '@rtsao/scc@1.1.0': {} - '@tamagui/use-callback-ref@1.125.23': {} + '@rushstack/eslint-patch@1.11.0': {} - '@tamagui/use-constant@1.125.23(react@19.0.0)': + '@segment/loosely-validate-event@2.0.0': dependencies: - react: 19.0.0 + component-type: 1.2.2 + join-component: 1.1.0 + + '@sinclair/typebox@0.27.8': {} + + '@sinonjs/commons@3.0.1': + dependencies: + type-detect: 4.0.8 - '@tamagui/use-controllable-state@1.125.23(react@19.0.0)': + '@sinonjs/fake-timers@10.3.0': dependencies: - '@tamagui/start-transition': 1.125.23 - '@tamagui/use-event': 1.125.23(react@19.0.0) - react: 19.0.0 + '@sinonjs/commons': 3.0.1 - '@tamagui/use-debounce@1.125.23(react@19.0.0)': + '@supabase/auth-js@2.68.0': dependencies: - react: 19.0.0 + '@supabase/node-fetch': 2.6.15 - '@tamagui/use-did-finish-ssr@1.125.23(react@19.0.0)': + '@supabase/functions-js@2.4.4': dependencies: - react: 19.0.0 + '@supabase/node-fetch': 2.6.15 - '@tamagui/use-direction@1.125.23(react@19.0.0)': + '@supabase/node-fetch@2.6.15': dependencies: - react: 19.0.0 + whatwg-url: 5.0.0 - '@tamagui/use-escape-keydown@1.125.23': + '@supabase/postgrest-js@1.19.2': dependencies: - '@tamagui/use-callback-ref': 1.125.23 + '@supabase/node-fetch': 2.6.15 - '@tamagui/use-event@1.125.23(react@19.0.0)': + '@supabase/realtime-js@2.11.2': dependencies: - '@tamagui/constants': 1.125.23(react@19.0.0) - react: 19.0.0 + '@supabase/node-fetch': 2.6.15 + '@types/phoenix': 1.6.6 + '@types/ws': 8.18.0 + ws: 8.18.1 + transitivePeerDependencies: + - bufferutil + - utf-8-validate - '@tamagui/use-force-update@1.125.23(react@19.0.0)': + '@supabase/ssr@0.6.1(@supabase/supabase-js@2.49.1)': dependencies: - react: 19.0.0 + '@supabase/supabase-js': 2.49.1 + cookie: 1.0.2 - '@tamagui/use-keyboard-visible@1.125.23(react@19.0.0)': + '@supabase/storage-js@2.7.1': dependencies: - react: 19.0.0 + '@supabase/node-fetch': 2.6.15 - '@tamagui/use-presence@1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@supabase/supabase-js@2.49.1': dependencies: - '@tamagui/web': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react: 19.0.0 + '@supabase/auth-js': 2.68.0 + '@supabase/functions-js': 2.4.4 + '@supabase/node-fetch': 2.6.15 + '@supabase/postgrest-js': 1.19.2 + '@supabase/realtime-js': 2.11.2 + '@supabase/storage-js': 2.7.1 transitivePeerDependencies: - - react-dom + - bufferutil + - utf-8-validate - '@tamagui/use-previous@1.125.23': {} + '@swc/counter@0.1.3': {} - '@tamagui/use-window-dimensions@1.125.23(react@19.0.0)': + '@swc/helpers@0.5.15': dependencies: - '@tamagui/constants': 1.125.23(react@19.0.0) - react: 19.0.0 + tslib: 2.8.1 - '@tamagui/visually-hidden@1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@tailwindcss/node@4.0.15': dependencies: - '@tamagui/web': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react: 19.0.0 - transitivePeerDependencies: - - react-dom + enhanced-resolve: 5.18.1 + jiti: 2.4.2 + tailwindcss: 4.0.15 + + '@tailwindcss/oxide-android-arm64@4.0.15': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.0.15': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.0.15': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.0.15': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.0.15': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.0.15': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.0.15': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.0.15': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.0.15': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.0.15': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.0.15': + optional: true - '@tamagui/web@1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': - dependencies: - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/helpers': 1.125.23(react@19.0.0) - '@tamagui/normalize-css-color': 1.125.23 - '@tamagui/timer': 1.125.23 - '@tamagui/types': 1.125.23 - '@tamagui/use-did-finish-ssr': 1.125.23(react@19.0.0) - '@tamagui/use-event': 1.125.23(react@19.0.0) - '@tamagui/use-force-update': 1.125.23(react@19.0.0) + '@tailwindcss/oxide@4.0.15': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.0.15 + '@tailwindcss/oxide-darwin-arm64': 4.0.15 + '@tailwindcss/oxide-darwin-x64': 4.0.15 + '@tailwindcss/oxide-freebsd-x64': 4.0.15 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.0.15 + '@tailwindcss/oxide-linux-arm64-gnu': 4.0.15 + '@tailwindcss/oxide-linux-arm64-musl': 4.0.15 + '@tailwindcss/oxide-linux-x64-gnu': 4.0.15 + '@tailwindcss/oxide-linux-x64-musl': 4.0.15 + '@tailwindcss/oxide-win32-arm64-msvc': 4.0.15 + '@tailwindcss/oxide-win32-x64-msvc': 4.0.15 + + '@tailwindcss/postcss@4.0.15': + dependencies: + '@alloc/quick-lru': 5.2.0 + '@tailwindcss/node': 4.0.15 + '@tailwindcss/oxide': 4.0.15 + lightningcss: 1.29.2 + postcss: 8.5.3 + tailwindcss: 4.0.15 + + '@tanstack/query-core@5.68.0': {} + + '@tanstack/query-devtools@5.67.2': {} + + '@tanstack/react-query-devtools@5.68.0(@tanstack/react-query@5.68.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@tanstack/query-devtools': 5.67.2 + '@tanstack/react-query': 5.68.0(react@19.0.0) react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - '@tamagui/z-index-stack@1.125.23': {} + '@tanstack/react-query@5.68.0(react@19.0.0)': + dependencies: + '@tanstack/query-core': 5.68.0 + react: 19.0.0 '@tootallnate/once@2.0.0': {} '@tootallnate/quickjs-emscripten@0.23.0': {} + '@trivago/prettier-plugin-sort-imports@5.2.2(prettier@3.5.3)': + dependencies: + '@babel/generator': 7.26.10 + '@babel/parser': 7.26.10 + '@babel/traverse': 7.26.10 + '@babel/types': 7.26.10 + javascript-natural-sort: 0.7.1 + lodash: 4.17.21 + prettier: 3.5.3 + transitivePeerDependencies: + - supports-color + '@tsconfig/node10@1.0.11': {} '@tsconfig/node12@1.0.11': {} @@ -9298,11 +10130,11 @@ snapshots: '@types/glob@7.2.0': dependencies: '@types/minimatch': 5.1.2 - '@types/node': 22.13.9 + '@types/node': 22.13.10 '@types/graceful-fs@4.1.9': dependencies: - '@types/node': 22.13.9 + '@types/node': 22.13.10 '@types/hammerjs@2.0.46': {} @@ -9328,7 +10160,7 @@ snapshots: '@types/jsdom@20.0.1': dependencies: - '@types/node': 22.13.9 + '@types/node': 22.13.10 '@types/tough-cookie': 4.0.5 parse5: 7.2.1 @@ -9340,7 +10172,7 @@ snapshots: '@types/node-forge@1.3.11': dependencies: - '@types/node': 22.13.9 + '@types/node': 22.13.10 '@types/node@20.17.24': dependencies: @@ -9354,6 +10186,8 @@ snapshots: dependencies: undici-types: 6.20.0 + '@types/phoenix@1.6.6': {} + '@types/prop-types@15.7.14': {} '@types/react-dom@19.0.4(@types/react@19.0.10)': @@ -9377,27 +10211,31 @@ snapshots: '@types/through@0.0.33': dependencies: - '@types/node': 22.13.9 + '@types/node': 22.13.10 '@types/tinycolor2@1.4.6': {} '@types/tough-cookie@4.0.5': {} + '@types/ws@8.18.0': + dependencies: + '@types/node': 22.13.10 + '@types/yargs-parser@21.0.3': {} '@types/yargs@17.0.33': dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0)(typescript@5.8.2))(eslint@9.22.0)(typescript@5.8.2)': + '@typescript-eslint/eslint-plugin@8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.26.0(eslint@9.22.0)(typescript@5.8.2) + '@typescript-eslint/parser': 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) '@typescript-eslint/scope-manager': 8.26.0 - '@typescript-eslint/type-utils': 8.26.0(eslint@9.22.0)(typescript@5.8.2) - '@typescript-eslint/utils': 8.26.0(eslint@9.22.0)(typescript@5.8.2) + '@typescript-eslint/type-utils': 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) + '@typescript-eslint/utils': 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) '@typescript-eslint/visitor-keys': 8.26.0 - eslint: 9.22.0 + eslint: 9.22.0(jiti@2.4.2) graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 @@ -9406,14 +10244,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.26.0(eslint@9.22.0)(typescript@5.8.2)': + '@typescript-eslint/parser@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)': dependencies: '@typescript-eslint/scope-manager': 8.26.0 '@typescript-eslint/types': 8.26.0 '@typescript-eslint/typescript-estree': 8.26.0(typescript@5.8.2) '@typescript-eslint/visitor-keys': 8.26.0 debug: 4.4.0 - eslint: 9.22.0 + eslint: 9.22.0(jiti@2.4.2) typescript: 5.8.2 transitivePeerDependencies: - supports-color @@ -9423,12 +10261,12 @@ snapshots: '@typescript-eslint/types': 8.26.0 '@typescript-eslint/visitor-keys': 8.26.0 - '@typescript-eslint/type-utils@8.26.0(eslint@9.22.0)(typescript@5.8.2)': + '@typescript-eslint/type-utils@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)': dependencies: '@typescript-eslint/typescript-estree': 8.26.0(typescript@5.8.2) - '@typescript-eslint/utils': 8.26.0(eslint@9.22.0)(typescript@5.8.2) + '@typescript-eslint/utils': 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) debug: 4.4.0 - eslint: 9.22.0 + eslint: 9.22.0(jiti@2.4.2) ts-api-utils: 2.0.1(typescript@5.8.2) typescript: 5.8.2 transitivePeerDependencies: @@ -9450,13 +10288,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.26.0(eslint@9.22.0)(typescript@5.8.2)': + '@typescript-eslint/utils@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)': dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.22.0) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.22.0(jiti@2.4.2)) '@typescript-eslint/scope-manager': 8.26.0 '@typescript-eslint/types': 8.26.0 '@typescript-eslint/typescript-estree': 8.26.0(typescript@5.8.2) - eslint: 9.22.0 + eslint: 9.22.0(jiti@2.4.2) typescript: 5.8.2 transitivePeerDependencies: - supports-color @@ -9478,6 +10316,16 @@ snapshots: '@urql/core': 5.1.1 wonka: 6.3.5 + '@vercel/analytics@1.5.0(next@15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)': + optionalDependencies: + next: 15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react: 19.0.0 + + '@vercel/speed-insights@1.2.0(next@15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)': + optionalDependencies: + next: 15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react: 19.0.0 + '@webassemblyjs/ast@1.14.1': dependencies: '@webassemblyjs/helper-numbers': 1.13.2 @@ -9765,6 +10613,16 @@ snapshots: at-least-node@1.0.0: {} + autoprefixer@10.4.21(postcss@8.5.3): + dependencies: + browserslist: 4.24.4 + caniuse-lite: 1.0.30001707 + fraction.js: 4.3.7 + normalize-range: 0.1.2 + picocolors: 1.1.1 + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.1.0 @@ -9914,6 +10772,8 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 + boolbase@1.0.0: {} + bplist-creator@0.0.7: dependencies: stream-buffers: 2.2.0 @@ -9945,7 +10805,7 @@ snapshots: browserslist@4.24.4: dependencies: - caniuse-lite: 1.0.30001701 + caniuse-lite: 1.0.30001707 electron-to-chromium: 1.5.114 node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.24.4) @@ -9970,12 +10830,19 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 + bundle-require@5.1.0(esbuild@0.25.1): + dependencies: + esbuild: 0.25.1 + load-tsconfig: 0.2.5 + busboy@1.6.0: dependencies: streamsearch: 1.1.0 bytes@3.1.2: {} + cac@6.7.14: {} + cacache@18.0.4: dependencies: '@npmcli/fs': 3.1.1 @@ -10031,6 +10898,8 @@ snapshots: caniuse-lite@1.0.30001701: {} + caniuse-lite@1.0.30001707: {} + chalk@2.4.2: dependencies: ansi-styles: 3.2.1 @@ -10076,11 +10945,38 @@ snapshots: charenc@0.0.2: {} + cheerio-select@2.1.0: + dependencies: + boolbase: 1.0.0 + css-select: 5.1.0 + css-what: 6.1.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + + cheerio@1.0.0: + dependencies: + cheerio-select: 2.1.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + domutils: 3.2.2 + encoding-sniffer: 0.2.0 + htmlparser2: 9.1.0 + parse5: 7.2.1 + parse5-htmlparser2-tree-adapter: 7.1.0 + parse5-parser-stream: 7.1.2 + undici: 6.21.1 + whatwg-mimetype: 4.0.0 + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + chownr@2.0.0: {} chrome-launcher@0.15.2: dependencies: - '@types/node': 22.13.9 + '@types/node': 22.13.10 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 lighthouse-logger: 1.4.2 @@ -10091,7 +10987,7 @@ snapshots: chromium-edge-launcher@0.2.0: dependencies: - '@types/node': 22.13.9 + '@types/node': 22.13.10 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 lighthouse-logger: 1.4.2 @@ -10106,6 +11002,10 @@ snapshots: cjs-module-lexer@1.4.3: {} + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + clean-stack@2.2.0: {} cli-cursor@2.1.0: @@ -10136,6 +11036,8 @@ snapshots: clone@1.0.4: {} + clsx@2.1.1: {} + co@4.6.0: {} collect-v8-coverage@1.0.2: {} @@ -10209,6 +11111,8 @@ snapshots: transitivePeerDependencies: - supports-color + consola@3.4.0: {} + constant-case@2.0.0: dependencies: snake-case: 2.1.0 @@ -10216,6 +11120,8 @@ snapshots: convert-source-map@2.0.0: {} + cookie@1.0.2: {} + core-js-compat@3.41.0: dependencies: browserslist: 4.24.4 @@ -10229,13 +11135,13 @@ snapshots: js-yaml: 3.14.1 parse-json: 4.0.0 - create-jest@29.7.0(@types/node@22.13.9)(ts-node@10.9.2(@types/node@22.13.9)(typescript@5.8.2)): + create-jest@29.7.0(@types/node@22.13.10)(ts-node@10.9.2(@types/node@22.13.10)(typescript@5.8.2)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@22.13.9)(ts-node@10.9.2(@types/node@22.13.9)(typescript@5.8.2)) + jest-config: 29.7.0(@types/node@22.13.10)(ts-node@10.9.2(@types/node@22.13.10)(typescript@5.8.2)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -10274,6 +11180,16 @@ snapshots: dependencies: hyphenate-style-name: 1.1.0 + css-select@5.1.0: + dependencies: + boolbase: 1.0.0 + css-what: 6.1.0 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + + css-what@6.1.0: {} + cssom@0.3.8: {} cssom@0.5.0: {} @@ -10395,8 +11311,7 @@ snapshots: detect-libc@1.0.3: {} - detect-libc@2.0.3: - optional: true + detect-libc@2.0.3: {} detect-newline@3.1.0: {} @@ -10414,10 +11329,28 @@ snapshots: dependencies: esutils: 2.0.3 + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + domelementtype@2.3.0: {} + domexception@4.0.0: dependencies: webidl-conversions: 7.0.0 + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + dot-case@2.1.1: dependencies: no-case: 2.3.2 @@ -10452,6 +11385,11 @@ snapshots: encodeurl@2.0.0: {} + encoding-sniffer@0.2.0: + dependencies: + iconv-lite: 0.6.3 + whatwg-encoding: 3.1.1 + end-of-stream@1.4.4: dependencies: once: 1.4.0 @@ -10575,6 +11513,34 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 + esbuild@0.25.1: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.1 + '@esbuild/android-arm': 0.25.1 + '@esbuild/android-arm64': 0.25.1 + '@esbuild/android-x64': 0.25.1 + '@esbuild/darwin-arm64': 0.25.1 + '@esbuild/darwin-x64': 0.25.1 + '@esbuild/freebsd-arm64': 0.25.1 + '@esbuild/freebsd-x64': 0.25.1 + '@esbuild/linux-arm': 0.25.1 + '@esbuild/linux-arm64': 0.25.1 + '@esbuild/linux-ia32': 0.25.1 + '@esbuild/linux-loong64': 0.25.1 + '@esbuild/linux-mips64el': 0.25.1 + '@esbuild/linux-ppc64': 0.25.1 + '@esbuild/linux-riscv64': 0.25.1 + '@esbuild/linux-s390x': 0.25.1 + '@esbuild/linux-x64': 0.25.1 + '@esbuild/netbsd-arm64': 0.25.1 + '@esbuild/netbsd-x64': 0.25.1 + '@esbuild/openbsd-arm64': 0.25.1 + '@esbuild/openbsd-x64': 0.25.1 + '@esbuild/sunos-x64': 0.25.1 + '@esbuild/win32-arm64': 0.25.1 + '@esbuild/win32-ia32': 0.25.1 + '@esbuild/win32-x64': 0.25.1 + escalade@3.2.0: {} escape-html@1.0.3: {} @@ -10593,19 +11559,19 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-config-next@15.2.2(eslint@9.22.0)(typescript@5.8.2): + eslint-config-next@15.2.2(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2): dependencies: '@next/eslint-plugin-next': 15.2.2 '@rushstack/eslint-patch': 1.11.0 - '@typescript-eslint/eslint-plugin': 8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0)(typescript@5.8.2))(eslint@9.22.0)(typescript@5.8.2) - '@typescript-eslint/parser': 8.26.0(eslint@9.22.0)(typescript@5.8.2) - eslint: 9.22.0 + '@typescript-eslint/eslint-plugin': 8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) + '@typescript-eslint/parser': 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) + eslint: 9.22.0(jiti@2.4.2) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.8.5(eslint-plugin-import@2.31.0)(eslint@9.22.0) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0)(typescript@5.8.2))(eslint-import-resolver-typescript@3.8.5)(eslint@9.22.0) - eslint-plugin-jsx-a11y: 6.10.2(eslint@9.22.0) - eslint-plugin-react: 7.37.4(eslint@9.22.0) - eslint-plugin-react-hooks: 5.2.0(eslint@9.22.0) + eslint-import-resolver-typescript: 3.8.5(eslint-plugin-import@2.31.0)(eslint@9.22.0(jiti@2.4.2)) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint-import-resolver-typescript@3.8.5)(eslint@9.22.0(jiti@2.4.2)) + eslint-plugin-jsx-a11y: 6.10.2(eslint@9.22.0(jiti@2.4.2)) + eslint-plugin-react: 7.37.4(eslint@9.22.0(jiti@2.4.2)) + eslint-plugin-react-hooks: 5.2.0(eslint@9.22.0(jiti@2.4.2)) optionalDependencies: typescript: 5.8.2 transitivePeerDependencies: @@ -10613,9 +11579,9 @@ snapshots: - eslint-plugin-import-x - supports-color - eslint-config-prettier@10.1.1(eslint@9.22.0): + eslint-config-prettier@10.1.1(eslint@9.22.0(jiti@2.4.2)): dependencies: - eslint: 9.22.0 + eslint: 9.22.0(jiti@2.4.2) eslint-import-resolver-node@0.3.9: dependencies: @@ -10625,33 +11591,33 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.8.5(eslint-plugin-import@2.31.0)(eslint@9.22.0): + eslint-import-resolver-typescript@3.8.5(eslint-plugin-import@2.31.0)(eslint@9.22.0(jiti@2.4.2)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.0 enhanced-resolve: 5.18.1 - eslint: 9.22.0 + eslint: 9.22.0(jiti@2.4.2) get-tsconfig: 4.10.0 is-bun-module: 1.3.0 stable-hash: 0.0.4 tinyglobby: 0.2.12 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0)(typescript@5.8.2))(eslint-import-resolver-typescript@3.8.5)(eslint@9.22.0) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint-import-resolver-typescript@3.8.5)(eslint@9.22.0(jiti@2.4.2)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.5(eslint-plugin-import@2.31.0)(eslint@9.22.0))(eslint@9.22.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.5(eslint-plugin-import@2.31.0)(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.26.0(eslint@9.22.0)(typescript@5.8.2) - eslint: 9.22.0 + '@typescript-eslint/parser': 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) + eslint: 9.22.0(jiti@2.4.2) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.8.5(eslint-plugin-import@2.31.0)(eslint@9.22.0) + eslint-import-resolver-typescript: 3.8.5(eslint-plugin-import@2.31.0)(eslint@9.22.0(jiti@2.4.2)) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0)(typescript@5.8.2))(eslint-import-resolver-typescript@3.8.5)(eslint@9.22.0): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint-import-resolver-typescript@3.8.5)(eslint@9.22.0(jiti@2.4.2)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -10660,9 +11626,9 @@ snapshots: array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.22.0 + eslint: 9.22.0(jiti@2.4.2) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.5(eslint-plugin-import@2.31.0)(eslint@9.22.0))(eslint@9.22.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.5(eslint-plugin-import@2.31.0)(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -10674,13 +11640,13 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.26.0(eslint@9.22.0)(typescript@5.8.2) + '@typescript-eslint/parser': 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-jsx-a11y@6.10.2(eslint@9.22.0): + eslint-plugin-jsx-a11y@6.10.2(eslint@9.22.0(jiti@2.4.2)): dependencies: aria-query: 5.3.2 array-includes: 3.1.8 @@ -10690,7 +11656,7 @@ snapshots: axobject-query: 4.1.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - eslint: 9.22.0 + eslint: 9.22.0(jiti@2.4.2) hasown: 2.0.2 jsx-ast-utils: 3.3.5 language-tags: 1.0.9 @@ -10701,11 +11667,11 @@ snapshots: eslint-plugin-only-warn@1.1.0: {} - eslint-plugin-react-hooks@5.2.0(eslint@9.22.0): + eslint-plugin-react-hooks@5.2.0(eslint@9.22.0(jiti@2.4.2)): dependencies: - eslint: 9.22.0 + eslint: 9.22.0(jiti@2.4.2) - eslint-plugin-react@7.37.4(eslint@9.22.0): + eslint-plugin-react@7.37.4(eslint@9.22.0(jiti@2.4.2)): dependencies: array-includes: 3.1.8 array.prototype.findlast: 1.2.5 @@ -10713,7 +11679,7 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.2.1 - eslint: 9.22.0 + eslint: 9.22.0(jiti@2.4.2) estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 @@ -10727,10 +11693,10 @@ snapshots: string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 - eslint-plugin-turbo@2.4.4(eslint@9.22.0)(turbo@2.4.4): + eslint-plugin-turbo@2.4.4(eslint@9.22.0(jiti@2.4.2))(turbo@2.4.4): dependencies: dotenv: 16.0.3 - eslint: 9.22.0 + eslint: 9.22.0(jiti@2.4.2) turbo: 2.4.4 eslint-scope@5.1.1: @@ -10747,9 +11713,9 @@ snapshots: eslint-visitor-keys@4.2.0: {} - eslint@9.22.0: + eslint@9.22.0(jiti@2.4.2): dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.22.0) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.22.0(jiti@2.4.2)) '@eslint-community/regexpp': 4.12.1 '@eslint/config-array': 0.19.2 '@eslint/config-helpers': 0.1.0 @@ -10784,6 +11750,8 @@ snapshots: minimatch: 3.1.2 natural-compare: 1.4.0 optionator: 0.9.4 + optionalDependencies: + jiti: 2.4.2 transitivePeerDependencies: - supports-color @@ -11172,6 +12140,8 @@ snapshots: es-set-tostringtag: 2.1.0 mime-types: 2.1.35 + fraction.js@4.3.7: {} + freeport-async@2.0.0: {} fresh@0.5.2: {} @@ -11416,6 +12386,13 @@ snapshots: html-escaper@2.0.2: {} + htmlparser2@9.1.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + entities: 4.5.0 + http-errors@2.0.0: dependencies: depd: 2.0.0 @@ -11473,6 +12450,8 @@ snapshots: dependencies: queue: 6.0.2 + immer@10.1.1: {} + import-fresh@2.0.0: dependencies: caller-path: 2.0.0 @@ -11781,6 +12760,8 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 + javascript-natural-sort@0.7.1: {} + jest-changed-files@29.7.0: dependencies: execa: 5.1.1 @@ -11793,7 +12774,7 @@ snapshots: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 22.13.9 + '@types/node': 22.13.10 chalk: 4.1.2 co: 4.6.0 dedent: 1.5.3 @@ -11813,16 +12794,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@22.13.9)(ts-node@10.9.2(@types/node@22.13.9)(typescript@5.8.2)): + jest-cli@29.7.0(@types/node@22.13.10)(ts-node@10.9.2(@types/node@22.13.10)(typescript@5.8.2)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.13.9)(typescript@5.8.2)) + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.13.10)(typescript@5.8.2)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@22.13.9)(ts-node@10.9.2(@types/node@22.13.9)(typescript@5.8.2)) + create-jest: 29.7.0(@types/node@22.13.10)(ts-node@10.9.2(@types/node@22.13.10)(typescript@5.8.2)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@22.13.9)(ts-node@10.9.2(@types/node@22.13.9)(typescript@5.8.2)) + jest-config: 29.7.0(@types/node@22.13.10)(ts-node@10.9.2(@types/node@22.13.10)(typescript@5.8.2)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -11832,7 +12813,7 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@22.13.9)(ts-node@10.9.2(@types/node@22.13.9)(typescript@5.8.2)): + jest-config@29.7.0(@types/node@22.13.10)(ts-node@10.9.2(@types/node@22.13.10)(typescript@5.8.2)): dependencies: '@babel/core': 7.26.10 '@jest/test-sequencer': 29.7.0 @@ -11857,8 +12838,8 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 22.13.9 - ts-node: 10.9.2(@types/node@22.13.9)(typescript@5.8.2) + '@types/node': 22.13.10 + ts-node: 10.9.2(@types/node@22.13.10)(typescript@5.8.2) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -11888,7 +12869,7 @@ snapshots: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 '@types/jsdom': 20.0.1 - '@types/node': 22.13.9 + '@types/node': 22.13.10 jest-mock: 29.7.0 jest-util: 29.7.0 jsdom: 20.0.3 @@ -11902,11 +12883,11 @@ snapshots: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 22.13.9 + '@types/node': 22.13.10 jest-mock: 29.7.0 jest-util: 29.7.0 - jest-expo@52.0.6(@babel/core@7.26.10)(expo@52.0.38(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1)))(react-native-webview@13.12.5(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(jest@29.7.0(@types/node@22.13.9)(ts-node@10.9.2(@types/node@22.13.9)(typescript@5.8.2)))(react-dom@18.3.1(react@18.3.1))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1)(webpack@5.98.0): + jest-expo@52.0.6(@babel/core@7.26.10)(expo@52.0.38(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1)))(react-native-webview@13.12.5(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(jest@29.7.0(@types/node@22.13.10)(ts-node@10.9.2(@types/node@22.13.10)(typescript@5.8.2)))(react-dom@18.3.1(react@18.3.1))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1)(webpack@5.98.0): dependencies: '@expo/config': 10.0.11 '@expo/json-file': 9.0.2 @@ -11919,7 +12900,7 @@ snapshots: jest-environment-jsdom: 29.7.0 jest-snapshot: 29.7.0 jest-watch-select-projects: 2.0.0 - jest-watch-typeahead: 2.2.1(jest@29.7.0(@types/node@22.13.9)(ts-node@10.9.2(@types/node@22.13.9)(typescript@5.8.2))) + jest-watch-typeahead: 2.2.1(jest@29.7.0(@types/node@22.13.10)(ts-node@10.9.2(@types/node@22.13.10)(typescript@5.8.2))) json5: 2.2.3 lodash: 4.17.21 react-native: 0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.18)(react@18.3.1) @@ -11945,7 +12926,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.9 - '@types/node': 22.13.9 + '@types/node': 22.13.10 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -11984,7 +12965,7 @@ snapshots: jest-mock@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 22.13.9 + '@types/node': 22.13.10 jest-util: 29.7.0 jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): @@ -12019,7 +13000,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 22.13.9 + '@types/node': 22.13.10 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -12047,7 +13028,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 22.13.9 + '@types/node': 22.13.10 chalk: 4.1.2 cjs-module-lexer: 1.4.3 collect-v8-coverage: 1.0.2 @@ -12093,7 +13074,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 22.13.9 + '@types/node': 22.13.10 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -12114,11 +13095,11 @@ snapshots: chalk: 3.0.0 prompts: 2.4.2 - jest-watch-typeahead@2.2.1(jest@29.7.0(@types/node@22.13.9)(ts-node@10.9.2(@types/node@22.13.9)(typescript@5.8.2))): + jest-watch-typeahead@2.2.1(jest@29.7.0(@types/node@22.13.10)(ts-node@10.9.2(@types/node@22.13.10)(typescript@5.8.2))): dependencies: ansi-escapes: 6.2.1 chalk: 4.1.2 - jest: 29.7.0(@types/node@22.13.9)(ts-node@10.9.2(@types/node@22.13.9)(typescript@5.8.2)) + jest: 29.7.0(@types/node@22.13.10)(ts-node@10.9.2(@types/node@22.13.10)(typescript@5.8.2)) jest-regex-util: 29.6.3 jest-watcher: 29.7.0 slash: 5.1.0 @@ -12129,7 +13110,7 @@ snapshots: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 22.13.9 + '@types/node': 22.13.10 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -12144,17 +13125,17 @@ snapshots: jest-worker@29.7.0: dependencies: - '@types/node': 22.13.9 + '@types/node': 22.13.10 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@22.13.9)(ts-node@10.9.2(@types/node@22.13.9)(typescript@5.8.2)): + jest@29.7.0(@types/node@22.13.10)(ts-node@10.9.2(@types/node@22.13.10)(typescript@5.8.2)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.13.9)(typescript@5.8.2)) + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.13.10)(typescript@5.8.2)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@22.13.9)(ts-node@10.9.2(@types/node@22.13.9)(typescript@5.8.2)) + jest-cli: 29.7.0(@types/node@22.13.10)(ts-node@10.9.2(@types/node@22.13.10)(typescript@5.8.2)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -12163,8 +13144,12 @@ snapshots: jimp-compact@0.16.1: {} + jiti@2.4.2: {} + join-component@1.1.0: {} + joycon@3.1.1: {} + js-tokens@4.0.0: {} js-yaml@3.14.1: @@ -12310,33 +13295,63 @@ snapshots: lightningcss-darwin-arm64@1.27.0: optional: true + lightningcss-darwin-arm64@1.29.2: + optional: true + lightningcss-darwin-x64@1.27.0: optional: true + lightningcss-darwin-x64@1.29.2: + optional: true + lightningcss-freebsd-x64@1.27.0: optional: true + lightningcss-freebsd-x64@1.29.2: + optional: true + lightningcss-linux-arm-gnueabihf@1.27.0: optional: true + lightningcss-linux-arm-gnueabihf@1.29.2: + optional: true + lightningcss-linux-arm64-gnu@1.27.0: optional: true + lightningcss-linux-arm64-gnu@1.29.2: + optional: true + lightningcss-linux-arm64-musl@1.27.0: optional: true + lightningcss-linux-arm64-musl@1.29.2: + optional: true + lightningcss-linux-x64-gnu@1.27.0: optional: true + lightningcss-linux-x64-gnu@1.29.2: + optional: true + lightningcss-linux-x64-musl@1.27.0: optional: true + lightningcss-linux-x64-musl@1.29.2: + optional: true + lightningcss-win32-arm64-msvc@1.27.0: optional: true + lightningcss-win32-arm64-msvc@1.29.2: + optional: true + lightningcss-win32-x64-msvc@1.27.0: optional: true + lightningcss-win32-x64-msvc@1.29.2: + optional: true + lightningcss@1.27.0: dependencies: detect-libc: 1.0.3 @@ -12352,8 +13367,27 @@ snapshots: lightningcss-win32-arm64-msvc: 1.27.0 lightningcss-win32-x64-msvc: 1.27.0 + lightningcss@1.29.2: + dependencies: + detect-libc: 2.0.3 + optionalDependencies: + lightningcss-darwin-arm64: 1.29.2 + lightningcss-darwin-x64: 1.29.2 + lightningcss-freebsd-x64: 1.29.2 + lightningcss-linux-arm-gnueabihf: 1.29.2 + lightningcss-linux-arm64-gnu: 1.29.2 + lightningcss-linux-arm64-musl: 1.29.2 + lightningcss-linux-x64-gnu: 1.29.2 + lightningcss-linux-x64-musl: 1.29.2 + lightningcss-win32-arm64-msvc: 1.29.2 + lightningcss-win32-x64-msvc: 1.29.2 + + lilconfig@3.1.3: {} + lines-and-columns@1.2.4: {} + load-tsconfig@0.2.5: {} + loader-runner@4.3.0: {} locate-path@3.0.0: @@ -12375,6 +13409,8 @@ snapshots: lodash.merge@4.6.2: {} + lodash.sortby@4.7.0: {} + lodash.throttle@4.1.1: {} lodash@4.17.21: {} @@ -12410,6 +13446,10 @@ snapshots: lru-cache@7.18.3: {} + lucide-react@0.483.0(react@19.0.0): + dependencies: + react: 19.0.0 + make-dir@2.1.0: dependencies: pify: 4.0.1 @@ -12705,7 +13745,12 @@ snapshots: netmask@2.0.2: {} - next@15.2.2(@babel/core@7.26.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + next-themes@0.4.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + dependencies: + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + + next@15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: '@next/env': 15.2.2 '@swc/counter': 0.1.3 @@ -12715,7 +13760,7 @@ snapshots: postcss: 8.4.31 react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - styled-jsx: 5.1.6(@babel/core@7.26.10)(react@19.0.0) + styled-jsx: 5.1.6(react@19.0.0) optionalDependencies: '@next/swc-darwin-arm64': 15.2.2 '@next/swc-darwin-x64': 15.2.2 @@ -12766,6 +13811,8 @@ snapshots: normalize-path@3.0.0: {} + normalize-range@0.1.2: {} + npm-package-arg@11.0.3: dependencies: hosted-git-info: 7.0.2 @@ -12781,6 +13828,10 @@ snapshots: dependencies: path-key: 3.1.1 + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + nullthrows@1.1.1: {} nwsapi@2.2.18: {} @@ -12988,6 +14039,15 @@ snapshots: dependencies: pngjs: 3.4.0 + parse5-htmlparser2-tree-adapter@7.1.0: + dependencies: + domhandler: 5.0.3 + parse5: 7.2.1 + + parse5-parser-stream@7.1.2: + dependencies: + parse5: 7.2.1 + parse5@7.2.1: dependencies: entities: 4.5.0 @@ -13059,6 +14119,13 @@ snapshots: possible-typed-array-names@1.1.0: {} + postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.3): + dependencies: + lilconfig: 3.1.3 + optionalDependencies: + jiti: 2.4.2 + postcss: 8.5.3 + postcss-value-parser@4.2.0: {} postcss@8.4.31: @@ -13073,8 +14140,20 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + postcss@8.5.3: + dependencies: + nanoid: 3.3.8 + picocolors: 1.1.1 + source-map-js: 1.2.1 + prelude-ls@1.2.1: {} + prettier-plugin-tailwindcss@0.6.11(@trivago/prettier-plugin-sort-imports@5.2.2(prettier@3.5.3))(prettier@3.5.3): + dependencies: + prettier: 3.5.3 + optionalDependencies: + '@trivago/prettier-plugin-sort-imports': 5.2.2(prettier@3.5.3) + prettier@3.5.3: {} pretty-bytes@5.6.0: {} @@ -13191,10 +14270,6 @@ snapshots: dependencies: react: 18.3.1 - react-freeze@1.0.4(react@19.0.0): - dependencies: - react: 19.0.0 - react-helmet-async@1.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@babel/runtime': 7.26.10 @@ -13335,58 +14410,6 @@ snapshots: - supports-color - utf-8-validate - react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0): - dependencies: - '@jest/create-cache-key-function': 29.7.0 - '@react-native/assets-registry': 0.76.7 - '@react-native/codegen': 0.76.7(@babel/preset-env@7.26.9(@babel/core@7.26.10)) - '@react-native/community-cli-plugin': 0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10)) - '@react-native/gradle-plugin': 0.76.7 - '@react-native/js-polyfills': 0.76.7 - '@react-native/normalize-colors': 0.76.7 - '@react-native/virtualized-lists': 0.76.7(@types/react@19.0.10)(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - abort-controller: 3.0.0 - anser: 1.4.10 - ansi-regex: 5.0.1 - babel-jest: 29.7.0(@babel/core@7.26.10) - babel-plugin-syntax-hermes-parser: 0.23.1 - base64-js: 1.5.1 - chalk: 4.1.2 - commander: 12.1.0 - event-target-shim: 5.0.1 - flow-enums-runtime: 0.0.6 - glob: 7.2.3 - invariant: 2.2.4 - jest-environment-node: 29.7.0 - jsc-android: 250231.0.0 - memoize-one: 5.2.1 - metro-runtime: 0.81.3 - metro-source-map: 0.81.3 - mkdirp: 0.5.6 - nullthrows: 1.1.1 - pretty-format: 29.7.0 - promise: 8.3.0 - react: 19.0.0 - react-devtools-core: 5.3.2 - react-refresh: 0.14.2 - regenerator-runtime: 0.13.11 - scheduler: 0.24.0-canary-efb381bbf-20230505 - semver: 7.7.1 - stacktrace-parser: 0.1.11 - whatwg-fetch: 3.6.20 - ws: 6.2.3 - yargs: 17.7.2 - optionalDependencies: - '@types/react': 19.0.10 - transitivePeerDependencies: - - '@babel/core' - - '@babel/preset-env' - - '@react-native-community/cli-server-api' - - bufferutil - - encoding - - supports-color - - utf-8-validate - react-refresh@0.14.2: {} react-remove-scroll-bar@2.3.8(@types/react@19.0.10)(react@19.0.0): @@ -13449,6 +14472,8 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 + readdirp@4.1.2: {} + readline@1.3.0: {} recast@0.21.5: @@ -13582,6 +14607,31 @@ snapshots: dependencies: glob: 7.2.3 + rollup@4.35.0: + dependencies: + '@types/estree': 1.0.6 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.35.0 + '@rollup/rollup-android-arm64': 4.35.0 + '@rollup/rollup-darwin-arm64': 4.35.0 + '@rollup/rollup-darwin-x64': 4.35.0 + '@rollup/rollup-freebsd-arm64': 4.35.0 + '@rollup/rollup-freebsd-x64': 4.35.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.35.0 + '@rollup/rollup-linux-arm-musleabihf': 4.35.0 + '@rollup/rollup-linux-arm64-gnu': 4.35.0 + '@rollup/rollup-linux-arm64-musl': 4.35.0 + '@rollup/rollup-linux-loongarch64-gnu': 4.35.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.35.0 + '@rollup/rollup-linux-riscv64-gnu': 4.35.0 + '@rollup/rollup-linux-s390x-gnu': 4.35.0 + '@rollup/rollup-linux-x64-gnu': 4.35.0 + '@rollup/rollup-linux-x64-musl': 4.35.0 + '@rollup/rollup-win32-arm64-msvc': 4.35.0 + '@rollup/rollup-win32-ia32-msvc': 4.35.0 + '@rollup/rollup-win32-x64-msvc': 4.35.0 + fsevents: 2.3.3 + run-async@2.4.1: {} run-parallel@1.2.0: @@ -13859,6 +14909,11 @@ snapshots: ip-address: 9.0.5 smart-buffer: 4.2.0 + sonner@2.0.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + dependencies: + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + source-map-js@1.2.1: {} source-map-support@0.5.13: @@ -13877,6 +14932,10 @@ snapshots: source-map@0.6.1: {} + source-map@0.8.0-beta.0: + dependencies: + whatwg-url: 7.1.0 + split-on-first@1.1.0: {} split@1.0.1: @@ -14030,12 +15089,10 @@ snapshots: structured-headers@0.4.1: {} - styled-jsx@5.1.6(@babel/core@7.26.10)(react@19.0.0): + styled-jsx@5.1.6(react@19.0.0): dependencies: client-only: 0.0.1 react: 19.0.0 - optionalDependencies: - '@babel/core': 7.26.10 styleq@0.1.3: {} @@ -14079,68 +15136,9 @@ snapshots: symbol-tree@3.2.4: {} - tabbable@6.2.0: {} - - tamagui@1.125.23(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0): - dependencies: - '@tamagui/accordion': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/adapt': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/alert-dialog': 1.125.23(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/animate-presence': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/avatar': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/button': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/card': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/checkbox': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/compose-refs': 1.125.23(react@19.0.0) - '@tamagui/constants': 1.125.23(react@19.0.0) - '@tamagui/core': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/create-context': 1.125.23(react@19.0.0) - '@tamagui/dialog': 1.125.23(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/elements': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/fake-react-native': 1.125.23 - '@tamagui/focusable': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/font-size': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/form': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/get-button-sized': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/get-font-sized': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/get-token': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/group': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/helpers-tamagui': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/image': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/label': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/linear-gradient': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/list-item': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/polyfill-dev': 1.125.23 - '@tamagui/popover': 1.125.23(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/popper': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/portal': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/progress': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/radio-group': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/react-native-media-driver': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/scroll-view': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/select': 1.125.23(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/separator': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/shapes': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/sheet': 1.125.23(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/slider': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/stacks': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/switch': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/tabs': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/text': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/theme': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/toggle-group': 1.125.23(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/tooltip': 1.125.23(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react-native@0.76.7(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) - '@tamagui/use-controllable-state': 1.125.23(react@19.0.0) - '@tamagui/use-debounce': 1.125.23(react@19.0.0) - '@tamagui/use-force-update': 1.125.23(react@19.0.0) - '@tamagui/use-window-dimensions': 1.125.23(react@19.0.0) - '@tamagui/visually-hidden': 1.125.23(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tamagui/z-index-stack': 1.125.23 - react: 19.0.0 - transitivePeerDependencies: - - '@types/react' - - react-dom - - react-native + tailwind-merge@3.0.2: {} + + tailwindcss@4.0.15: {} tapable@2.2.1: {} @@ -14208,6 +15206,8 @@ snapshots: tinycolor2@1.6.0: {} + tinyexec@0.3.2: {} + tinyglobby@0.2.12: dependencies: fdir: 6.4.3(picomatch@4.0.2) @@ -14244,10 +15244,16 @@ snapshots: tr46@0.0.3: {} + tr46@1.0.1: + dependencies: + punycode: 2.3.1 + tr46@3.0.0: dependencies: punycode: 2.3.1 + tree-kill@1.2.2: {} + ts-api-utils@2.0.1(typescript@5.8.2): dependencies: typescript: 5.8.2 @@ -14301,6 +15307,33 @@ snapshots: tslib@2.8.1: {} + tsup@8.4.0(jiti@2.4.2)(postcss@8.5.3)(typescript@5.8.2): + dependencies: + bundle-require: 5.1.0(esbuild@0.25.1) + cac: 6.7.14 + chokidar: 4.0.3 + consola: 3.4.0 + debug: 4.4.0 + esbuild: 0.25.1 + joycon: 3.1.1 + picocolors: 1.1.1 + postcss-load-config: 6.0.1(jiti@2.4.2)(postcss@8.5.3) + resolve-from: 5.0.0 + rollup: 4.35.0 + source-map: 0.8.0-beta.0 + sucrase: 3.35.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.12 + tree-kill: 1.2.2 + optionalDependencies: + postcss: 8.5.3 + typescript: 5.8.2 + transitivePeerDependencies: + - jiti + - supports-color + - tsx + - yaml + turbo-darwin-64@2.4.4: optional: true @@ -14328,6 +15361,8 @@ snapshots: turbo-windows-64: 2.4.4 turbo-windows-arm64: 2.4.4 + tw-animate-css@1.2.4: {} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 @@ -14373,12 +15408,12 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 - typescript-eslint@8.26.0(eslint@9.22.0)(typescript@5.8.2): + typescript-eslint@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2): dependencies: - '@typescript-eslint/eslint-plugin': 8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0)(typescript@5.8.2))(eslint@9.22.0)(typescript@5.8.2) - '@typescript-eslint/parser': 8.26.0(eslint@9.22.0)(typescript@5.8.2) - '@typescript-eslint/utils': 8.26.0(eslint@9.22.0)(typescript@5.8.2) - eslint: 9.22.0 + '@typescript-eslint/eslint-plugin': 8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) + '@typescript-eslint/parser': 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) + '@typescript-eslint/utils': 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) + eslint: 9.22.0(jiti@2.4.2) typescript: 5.8.2 transitivePeerDependencies: - supports-color @@ -14487,6 +15522,11 @@ snapshots: dependencies: react: 18.3.1 + use-sync-external-store@1.4.0(react@19.0.0): + dependencies: + react: 19.0.0 + optional: true + util-deprecate@1.0.2: {} utils-merge@1.0.1: {} @@ -14532,6 +15572,8 @@ snapshots: webidl-conversions@3.0.1: {} + webidl-conversions@4.0.2: {} + webidl-conversions@5.0.0: {} webidl-conversions@7.0.0: {} @@ -14572,10 +15614,16 @@ snapshots: dependencies: iconv-lite: 0.6.3 + whatwg-encoding@3.1.1: + dependencies: + iconv-lite: 0.6.3 + whatwg-fetch@3.6.20: {} whatwg-mimetype@3.0.0: {} + whatwg-mimetype@4.0.0: {} + whatwg-url-without-unicode@8.0.0-3: dependencies: buffer: 5.7.1 @@ -14592,6 +15640,12 @@ snapshots: tr46: 0.0.3 webidl-conversions: 3.0.1 + whatwg-url@7.1.0: + dependencies: + lodash.sortby: 4.7.0 + tr46: 1.0.1 + webidl-conversions: 4.0.2 + which-boxed-primitive@1.1.1: dependencies: is-bigint: 1.1.0 @@ -14726,3 +15780,10 @@ snapshots: yn@3.1.1: {} yocto-queue@0.1.0: {} + + zustand@5.0.3(@types/react@19.0.10)(immer@10.1.1)(react@19.0.0)(use-sync-external-store@1.4.0(react@19.0.0)): + optionalDependencies: + '@types/react': 19.0.10 + immer: 10.1.1 + react: 19.0.0 + use-sync-external-store: 1.4.0(react@19.0.0) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 3ff5faa..e9b0dad 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,3 @@ packages: - - "apps/*" - - "packages/*" + - 'apps/*' + - 'packages/*' diff --git a/turbo.json b/turbo.json index d6a7fe0..2107653 100644 --- a/turbo.json +++ b/turbo.json @@ -5,15 +5,19 @@ "build": { "dependsOn": ["^build"], "inputs": ["$TURBO_DEFAULT$", ".env*"], - "outputs": [".next/**", "!.next/cache/**"] + "outputs": [".next/**", "!.next/cache/**", "dist/**"] }, "lint": { "dependsOn": ["^lint"] }, + "format": { + "dependsOn": ["^format"] + }, "check-types": { "dependsOn": ["^check-types"] }, "dev": { + "dependsOn": ["^build"], "cache": false, "persistent": true }