feat(frontend): add podman.live landing page + route split
Add a public marketing landing at "/" celebrating the Top-3 finish at the AI Engineer World's Fair 2026 hackathon (2nd overall of 95+ teams, LiveKit track + DigitalOcean Best Use), with a scroll-to-read hero, feature/tech sections, and the demo embed. Introduce react-router: "/" serves the public landing (no auth) and "/app" mounts the existing Clerk-gated app. The app route degrades gracefully to a "deploying" placeholder when no Clerk publishable key is configured, so the site renders without secrets. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -30,6 +30,7 @@
|
|||||||
"react-day-picker": "^10.0.1",
|
"react-day-picker": "^10.0.1",
|
||||||
"react-dom": "^19.2.7",
|
"react-dom": "^19.2.7",
|
||||||
"react-resizable-panels": "^4.11.2",
|
"react-resizable-panels": "^4.11.2",
|
||||||
|
"react-router-dom": "^7.18.1",
|
||||||
"recharts": "3.8.0",
|
"recharts": "3.8.0",
|
||||||
"shadcn": "^4.12.0",
|
"shadcn": "^4.12.0",
|
||||||
"sonner": "^2.0.7",
|
"sonner": "^2.0.7",
|
||||||
|
|||||||
@@ -0,0 +1,274 @@
|
|||||||
|
import { useCallback } from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import {
|
||||||
|
TrophyIcon,
|
||||||
|
ArrowRightIcon,
|
||||||
|
ChevronDownIcon,
|
||||||
|
EyeIcon,
|
||||||
|
GitMergeIcon,
|
||||||
|
UsersIcon,
|
||||||
|
BellIcon,
|
||||||
|
RadioIcon,
|
||||||
|
DatabaseIcon,
|
||||||
|
SparklesIcon,
|
||||||
|
PlayIcon,
|
||||||
|
MicIcon,
|
||||||
|
} from 'lucide-react';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public marketing landing page for podman.live.
|
||||||
|
* Rendered at "/" without ClerkProvider — needs no secrets.
|
||||||
|
* The live app lives at "/app".
|
||||||
|
*/
|
||||||
|
export function Landing() {
|
||||||
|
const scrollToStory = useCallback(() => {
|
||||||
|
document.getElementById('story')?.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen scroll-smooth bg-[#0b0f17] text-white/90 antialiased">
|
||||||
|
{/* ambient glows */}
|
||||||
|
<div className="pointer-events-none fixed inset-0 overflow-hidden">
|
||||||
|
<div className="absolute -top-40 left-1/2 h-[38rem] w-[38rem] -translate-x-1/2 rounded-full bg-indigo-600/20 blur-[120px]" />
|
||||||
|
<div className="absolute top-1/3 -right-32 h-[26rem] w-[26rem] rounded-full bg-cyan-500/10 blur-[110px]" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* top nav */}
|
||||||
|
<header className="relative z-20 mx-auto flex max-w-6xl items-center justify-between px-6 py-5">
|
||||||
|
<a href="#top" className="flex items-center gap-2.5">
|
||||||
|
<img src="/podman-logo.svg" alt="PodMan" className="h-7 w-7" />
|
||||||
|
<span className="text-[15px] font-semibold tracking-tight text-white">PodMan</span>
|
||||||
|
</a>
|
||||||
|
<Link
|
||||||
|
to="/app"
|
||||||
|
className="inline-flex items-center gap-1.5 rounded-full border border-white/15 bg-white/5 px-4 py-1.5 text-sm font-medium text-white/90 transition-colors hover:bg-white/10"
|
||||||
|
>
|
||||||
|
Launch app <ArrowRightIcon className="size-4" />
|
||||||
|
</Link>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
{/* hero */}
|
||||||
|
<section id="top" className="relative z-10 mx-auto flex max-w-3xl flex-col items-center px-6 pt-16 pb-24 text-center sm:pt-24">
|
||||||
|
<button
|
||||||
|
onClick={scrollToStory}
|
||||||
|
className="group mb-8 inline-flex items-center gap-2 rounded-full border border-amber-300/30 bg-gradient-to-r from-amber-400/15 to-amber-200/5 px-4 py-1.5 text-sm font-medium text-amber-200 transition-colors hover:border-amber-300/50"
|
||||||
|
>
|
||||||
|
<TrophyIcon className="size-4" />
|
||||||
|
Top 3 — AI Engineer World's Fair Hackathon 2026
|
||||||
|
<ChevronDownIcon className="size-4 transition-transform group-hover:translate-y-0.5" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<h1 className="text-5xl font-semibold leading-[1.05] tracking-tight text-white sm:text-7xl">
|
||||||
|
PodMan
|
||||||
|
</h1>
|
||||||
|
<p className="mt-5 bg-gradient-to-r from-indigo-300 via-sky-300 to-cyan-200 bg-clip-text text-2xl font-medium text-transparent sm:text-3xl">
|
||||||
|
The teammate that sees what git can't.
|
||||||
|
</p>
|
||||||
|
<p className="mx-auto mt-6 max-w-xl text-base leading-relaxed text-white/60 sm:text-lg">
|
||||||
|
An ambient AI teammate that watches your pod's screens in realtime — catching merge
|
||||||
|
collisions, duplicated work, and missed handoffs before anyone pushes.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{/* award chips */}
|
||||||
|
<div className="mt-9 flex flex-wrap items-center justify-center gap-2.5">
|
||||||
|
{[
|
||||||
|
{ label: '2nd Overall · 95+ teams', accent: 'text-amber-200 border-amber-300/25 bg-amber-400/10' },
|
||||||
|
{ label: 'LiveKit Track — Winner', accent: 'text-sky-200 border-sky-300/25 bg-sky-400/10' },
|
||||||
|
{ label: 'DigitalOcean — Best Use', accent: 'text-cyan-200 border-cyan-300/25 bg-cyan-400/10' },
|
||||||
|
].map((c) => (
|
||||||
|
<span
|
||||||
|
key={c.label}
|
||||||
|
className={`rounded-full border px-3.5 py-1.5 text-[13px] font-medium ${c.accent}`}
|
||||||
|
>
|
||||||
|
{c.label}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* CTAs */}
|
||||||
|
<div className="mt-10 flex flex-col items-center gap-3 sm:flex-row">
|
||||||
|
<button
|
||||||
|
onClick={scrollToStory}
|
||||||
|
className="inline-flex h-11 items-center justify-center gap-2 rounded-full bg-gradient-to-r from-indigo-500 to-cyan-400 px-7 text-sm font-semibold text-[#0b0f17] shadow-lg shadow-indigo-500/20 transition-transform hover:scale-[1.02]"
|
||||||
|
>
|
||||||
|
Read the story <ChevronDownIcon className="size-4" />
|
||||||
|
</button>
|
||||||
|
<Link
|
||||||
|
to="/app"
|
||||||
|
className="inline-flex h-11 items-center justify-center gap-2 rounded-full border border-white/15 px-7 text-sm font-semibold text-white/90 transition-colors hover:bg-white/5"
|
||||||
|
>
|
||||||
|
Launch PodMan <ArrowRightIcon className="size-4" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={scrollToStory}
|
||||||
|
aria-label="Scroll to read"
|
||||||
|
className="mt-20 animate-bounce text-white/40 transition-colors hover:text-white/70"
|
||||||
|
>
|
||||||
|
<ChevronDownIcon className="size-7" />
|
||||||
|
</button>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* story */}
|
||||||
|
<Section id="story" eyebrow="How it happened" title="Built on stage, in about 24 hours.">
|
||||||
|
<div className="space-y-5 text-[15px] leading-relaxed text-white/70">
|
||||||
|
<p>
|
||||||
|
PodMan was built at the{' '}
|
||||||
|
<span className="text-white">AI Engineer World's Fair 2026 Hackathon</span> (June
|
||||||
|
27–28) against 95+ teams. It took{' '}
|
||||||
|
<span className="text-amber-200">2nd place overall</span>, and won both the{' '}
|
||||||
|
<span className="text-sky-200">LiveKit</span> track and{' '}
|
||||||
|
<span className="text-cyan-200">DigitalOcean's Best Use</span> award.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
We shipped the live demo in a single sprint — a LiveKit room, Gemini watching the
|
||||||
|
screen-share, and a voice that speaks up the moment two engineers drift toward the same
|
||||||
|
code. There wasn't time on the clock to give it a proper home.
|
||||||
|
</p>
|
||||||
|
<p className="text-white/90">
|
||||||
|
So this is that home — and we're actively building PodMan out from the hackathon
|
||||||
|
prototype into something a team can actually run every day.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* what it does */}
|
||||||
|
<Section id="what" eyebrow="What it does" title="A teammate in the room, not another dashboard.">
|
||||||
|
<div className="grid gap-4 sm:grid-cols-2">
|
||||||
|
<Feature
|
||||||
|
icon={<EyeIcon className="size-5" />}
|
||||||
|
title="Ambient awareness"
|
||||||
|
body="Joins your pod's LiveKit room and samples every screen-share in realtime — no bots to invoke, no commands to remember."
|
||||||
|
/>
|
||||||
|
<Feature
|
||||||
|
icon={<GitMergeIcon className="size-5" />}
|
||||||
|
title="Merge-collision radar"
|
||||||
|
body="Recognizes when two people are converging on the same files or feature and warns them before the conflict ever reaches a push."
|
||||||
|
/>
|
||||||
|
<Feature
|
||||||
|
icon={<UsersIcon className="size-5" />}
|
||||||
|
title="Duplicated-work detection"
|
||||||
|
body="Notices when effort overlaps across the team and surfaces it early, so two engineers don't quietly build the same thing."
|
||||||
|
/>
|
||||||
|
<Feature
|
||||||
|
icon={<BellIcon className="size-5" />}
|
||||||
|
title="Handoff nudges"
|
||||||
|
body="Speaks up about missed handoffs and stalled threads — and learns which nudges actually helped, so it stays useful, not noisy."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* how it works */}
|
||||||
|
<Section id="how" eyebrow="Under the hood" title="Realtime vision, memory, and a voice.">
|
||||||
|
<div className="grid gap-4 sm:grid-cols-3">
|
||||||
|
<Stack icon={<RadioIcon className="size-5" />} name="LiveKit" note="Realtime transport for the shared room and voice delivery." />
|
||||||
|
<Stack icon={<SparklesIcon className="size-5" />} name="Gemini" note="Vision + event detection + the live voice that nudges the team." />
|
||||||
|
<Stack icon={<DatabaseIcon className="size-5" />} name="MongoDB" note="Engineer state, ownership map, events, and which nudges landed." />
|
||||||
|
</div>
|
||||||
|
<div className="mt-6 flex flex-wrap gap-2 text-[13px] text-white/50">
|
||||||
|
{['LiveKit', 'Gemini Live', 'MongoDB Atlas', 'Voyage embeddings', 'Modular MAX', 'Hermes ops'].map((t) => (
|
||||||
|
<span key={t} className="rounded-md border border-white/10 bg-white/[0.03] px-2.5 py-1">
|
||||||
|
{t}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* demo */}
|
||||||
|
<Section id="demo" eyebrow="See it" title="The 60-second demo.">
|
||||||
|
<div className="overflow-hidden rounded-2xl border border-white/10 bg-black/40 shadow-2xl">
|
||||||
|
<div className="relative w-full" style={{ paddingBottom: '56.25%' }}>
|
||||||
|
<iframe
|
||||||
|
className="absolute inset-0 h-full w-full"
|
||||||
|
src="https://www.youtube-nocookie.com/embed/bWJIsIWTgr0"
|
||||||
|
title="PodMan demo"
|
||||||
|
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||||
|
allowFullScreen
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="mt-4 flex items-center gap-2 text-sm text-white/40">
|
||||||
|
<PlayIcon className="size-4" /> Watch the pod get its warning before the collision.
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* final CTA */}
|
||||||
|
<section className="relative z-10 mx-auto max-w-3xl px-6 py-24 text-center">
|
||||||
|
<div className="rounded-3xl border border-white/10 bg-gradient-to-b from-white/[0.06] to-transparent px-8 py-14">
|
||||||
|
<MicIcon className="mx-auto size-8 text-cyan-300" />
|
||||||
|
<h2 className="mt-5 text-3xl font-semibold tracking-tight text-white sm:text-4xl">
|
||||||
|
Put PodMan in your pod.
|
||||||
|
</h2>
|
||||||
|
<p className="mx-auto mt-4 max-w-md text-[15px] leading-relaxed text-white/60">
|
||||||
|
Open a room and let it watch the work. It's an early build we're actively
|
||||||
|
shaping — jump in and try it.
|
||||||
|
</p>
|
||||||
|
<Link
|
||||||
|
to="/app"
|
||||||
|
className="mt-8 inline-flex h-12 items-center justify-center gap-2 rounded-full bg-gradient-to-r from-indigo-500 to-cyan-400 px-8 text-sm font-semibold text-[#0b0f17] shadow-lg shadow-indigo-500/20 transition-transform hover:scale-[1.02]"
|
||||||
|
>
|
||||||
|
Launch PodMan <ArrowRightIcon className="size-4" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* footer */}
|
||||||
|
<footer className="relative z-10 border-t border-white/10">
|
||||||
|
<div className="mx-auto flex max-w-6xl flex-col items-center justify-between gap-3 px-6 py-8 text-sm text-white/40 sm:flex-row">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<img src="/podman-logo.svg" alt="" className="h-5 w-5 opacity-70" />
|
||||||
|
<span>PodMan · podman.live</span>
|
||||||
|
</div>
|
||||||
|
<span>Built at AI Engineer World's Fair 2026 · 2nd Overall</span>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Section({
|
||||||
|
id,
|
||||||
|
eyebrow,
|
||||||
|
title,
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
id: string;
|
||||||
|
eyebrow: string;
|
||||||
|
title: string;
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<section id={id} className="relative z-10 border-t border-white/[0.06] py-20">
|
||||||
|
<div className="mx-auto max-w-3xl px-6">
|
||||||
|
<p className="text-sm font-medium tracking-wide text-cyan-300/80 uppercase">{eyebrow}</p>
|
||||||
|
<h2 className="mt-3 text-3xl font-semibold tracking-tight text-white sm:text-4xl">{title}</h2>
|
||||||
|
<div className="mt-8">{children}</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Feature({ icon, title, body }: { icon: React.ReactNode; title: string; body: string }) {
|
||||||
|
return (
|
||||||
|
<div className="rounded-2xl border border-white/10 bg-white/[0.03] p-6 transition-colors hover:border-white/20">
|
||||||
|
<div className="flex size-10 items-center justify-center rounded-xl bg-gradient-to-br from-indigo-500/20 to-cyan-400/20 text-cyan-200">
|
||||||
|
{icon}
|
||||||
|
</div>
|
||||||
|
<h3 className="mt-4 text-lg font-semibold text-white">{title}</h3>
|
||||||
|
<p className="mt-2 text-[14px] leading-relaxed text-white/60">{body}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Stack({ icon, name, note }: { icon: React.ReactNode; name: string; note: string }) {
|
||||||
|
return (
|
||||||
|
<div className="rounded-2xl border border-white/10 bg-white/[0.03] p-6">
|
||||||
|
<div className="flex items-center gap-2.5 text-white">
|
||||||
|
<span className="text-cyan-200">{icon}</span>
|
||||||
|
<span className="text-base font-semibold">{name}</span>
|
||||||
|
</div>
|
||||||
|
<p className="mt-3 text-[14px] leading-relaxed text-white/60">{note}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
+35
-6
@@ -1,24 +1,53 @@
|
|||||||
import { StrictMode } from 'react';
|
import { StrictMode } from 'react';
|
||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
|
import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
||||||
import { ClerkProvider } from '@clerk/react';
|
import { ClerkProvider } from '@clerk/react';
|
||||||
import { shadcn } from '@clerk/ui/themes';
|
import { shadcn } from '@clerk/ui/themes';
|
||||||
import App from './App.js';
|
import App from './App.js';
|
||||||
|
import { Landing } from './Landing.js';
|
||||||
import './index.css';
|
import './index.css';
|
||||||
import '@clerk/ui/themes/shadcn.css';
|
import '@clerk/ui/themes/shadcn.css';
|
||||||
import { TooltipProvider } from '@/components/ui/tooltip';
|
import { TooltipProvider } from '@/components/ui/tooltip';
|
||||||
|
|
||||||
const clerkPublishableKey = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY;
|
const clerkPublishableKey = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY;
|
||||||
|
const hasClerk = typeof clerkPublishableKey === 'string' && clerkPublishableKey.startsWith('pk_');
|
||||||
|
|
||||||
if (!clerkPublishableKey) {
|
function AppRoute() {
|
||||||
throw new Error('Missing VITE_CLERK_PUBLISHABLE_KEY');
|
if (!hasClerk) {
|
||||||
|
// Secrets not provisioned yet — show a graceful placeholder instead of crashing.
|
||||||
|
return (
|
||||||
|
<div className="flex min-h-screen flex-col items-center justify-center gap-3 bg-[#0b0f17] px-6 text-center text-white/80">
|
||||||
|
<img src="/podman-logo.svg" alt="PodMan" className="h-10 w-10" />
|
||||||
|
<h1 className="text-xl font-semibold text-white">PodMan is deploying</h1>
|
||||||
|
<p className="max-w-sm text-sm text-white/50">
|
||||||
|
The live app is being provisioned. Check back shortly.
|
||||||
|
</p>
|
||||||
|
<a href="/" className="mt-2 text-sm text-cyan-300 hover:underline">
|
||||||
|
← Back to home
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
return (
|
||||||
createRoot(document.getElementById('root')!).render(
|
<ClerkProvider
|
||||||
<StrictMode>
|
publishableKey={clerkPublishableKey}
|
||||||
<ClerkProvider publishableKey={clerkPublishableKey} appearance={{ theme: shadcn }}>
|
appearance={{ theme: shadcn }}
|
||||||
|
afterSignOutUrl="/"
|
||||||
|
>
|
||||||
<TooltipProvider>
|
<TooltipProvider>
|
||||||
<App />
|
<App />
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
</ClerkProvider>
|
</ClerkProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
createRoot(document.getElementById('root')!).render(
|
||||||
|
<StrictMode>
|
||||||
|
<BrowserRouter>
|
||||||
|
<Routes>
|
||||||
|
<Route path="/" element={<Landing />} />
|
||||||
|
<Route path="/app/*" element={<AppRoute />} />
|
||||||
|
</Routes>
|
||||||
|
</BrowserRouter>
|
||||||
</StrictMode>,
|
</StrictMode>,
|
||||||
);
|
);
|
||||||
|
|||||||
Generated
+45
@@ -154,6 +154,9 @@ importers:
|
|||||||
react-resizable-panels:
|
react-resizable-panels:
|
||||||
specifier: ^4.11.2
|
specifier: ^4.11.2
|
||||||
version: 4.11.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
version: 4.11.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||||
|
react-router-dom:
|
||||||
|
specifier: ^7.18.1
|
||||||
|
version: 7.18.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||||
recharts:
|
recharts:
|
||||||
specifier: 3.8.0
|
specifier: 3.8.0
|
||||||
version: 3.8.0(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)
|
version: 3.8.0(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react-is@19.2.7)(react@19.2.7)(redux@5.0.1)
|
||||||
@@ -3838,6 +3841,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
|
resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
|
cookie@1.1.1:
|
||||||
|
resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
copy-to-clipboard@3.3.3:
|
copy-to-clipboard@3.3.3:
|
||||||
resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==}
|
resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==}
|
||||||
|
|
||||||
@@ -5784,6 +5791,23 @@ packages:
|
|||||||
react: ^18.0.0 || ^19.0.0
|
react: ^18.0.0 || ^19.0.0
|
||||||
react-dom: ^18.0.0 || ^19.0.0
|
react-dom: ^18.0.0 || ^19.0.0
|
||||||
|
|
||||||
|
react-router-dom@7.18.1:
|
||||||
|
resolution: {integrity: sha512-KaZh+X/6UtEp28x51AUYZDMg9NGoz2ja3dNHa+ta/tk40vCzKhQ/RypCWBMLbmDr6//E24Vv5uPsrqXFozdkAg==}
|
||||||
|
engines: {node: '>=20.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>=18'
|
||||||
|
react-dom: '>=18'
|
||||||
|
|
||||||
|
react-router@7.18.1:
|
||||||
|
resolution: {integrity: sha512-GDLgg3i3uM0aeJO3Fm+TCS+sDQ7gu12T6x0qdTEzcwqEfleci7JwugVNIF3U//0FWKnJT7ptG+20B2jfDqnZAg==}
|
||||||
|
engines: {node: '>=20.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>=18'
|
||||||
|
react-dom: '>=18'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
react-dom:
|
||||||
|
optional: true
|
||||||
|
|
||||||
react-style-singleton@2.2.3:
|
react-style-singleton@2.2.3:
|
||||||
resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==}
|
resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@@ -5987,6 +6011,9 @@ packages:
|
|||||||
set-blocking@2.0.0:
|
set-blocking@2.0.0:
|
||||||
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
|
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
|
||||||
|
|
||||||
|
set-cookie-parser@2.7.2:
|
||||||
|
resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==}
|
||||||
|
|
||||||
set-function-length@1.2.2:
|
set-function-length@1.2.2:
|
||||||
resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
|
resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -10670,6 +10697,8 @@ snapshots:
|
|||||||
|
|
||||||
cookie@0.7.2: {}
|
cookie@0.7.2: {}
|
||||||
|
|
||||||
|
cookie@1.1.1: {}
|
||||||
|
|
||||||
copy-to-clipboard@3.3.3:
|
copy-to-clipboard@3.3.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
toggle-selection: 1.0.6
|
toggle-selection: 1.0.6
|
||||||
@@ -12806,6 +12835,20 @@ snapshots:
|
|||||||
react: 19.2.7
|
react: 19.2.7
|
||||||
react-dom: 19.2.7(react@19.2.7)
|
react-dom: 19.2.7(react@19.2.7)
|
||||||
|
|
||||||
|
react-router-dom@7.18.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7):
|
||||||
|
dependencies:
|
||||||
|
react: 19.2.7
|
||||||
|
react-dom: 19.2.7(react@19.2.7)
|
||||||
|
react-router: 7.18.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
|
||||||
|
|
||||||
|
react-router@7.18.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7):
|
||||||
|
dependencies:
|
||||||
|
cookie: 1.1.1
|
||||||
|
react: 19.2.7
|
||||||
|
set-cookie-parser: 2.7.2
|
||||||
|
optionalDependencies:
|
||||||
|
react-dom: 19.2.7(react@19.2.7)
|
||||||
|
|
||||||
react-style-singleton@2.2.3(@types/react@19.2.17)(react@19.2.7):
|
react-style-singleton@2.2.3(@types/react@19.2.17)(react@19.2.7):
|
||||||
dependencies:
|
dependencies:
|
||||||
get-nonce: 1.0.1
|
get-nonce: 1.0.1
|
||||||
@@ -13104,6 +13147,8 @@ snapshots:
|
|||||||
|
|
||||||
set-blocking@2.0.0: {}
|
set-blocking@2.0.0: {}
|
||||||
|
|
||||||
|
set-cookie-parser@2.7.2: {}
|
||||||
|
|
||||||
set-function-length@1.2.2:
|
set-function-length@1.2.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
define-data-property: 1.1.4
|
define-data-property: 1.1.4
|
||||||
|
|||||||
Reference in New Issue
Block a user