Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions apps/app/src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,12 @@ body, html {

@media (max-width: 768px) {
.brand-shell { padding: 8px; }
.brand-glass-container { border-radius: var(--radius-lg); }
}

@media (max-width: 480px) {
.brand-shell { padding: 4px; }
.brand-glass-container { border-radius: var(--radius-md); }
}

/* === Gradient Utilities === */
Expand Down Expand Up @@ -602,6 +608,35 @@ body, html {
flex-shrink: 0;
}

/* === Demo Gallery Drawer === */
/* Mobile: full-screen, slides up from bottom */
.demo-gallery-drawer {
inset: 0;
border-radius: 0;
transform: translateY(100%);
}
.demo-gallery-drawer--open {
transform: translateY(0);
}

/* Desktop (sm+): right side panel, slides in from right */
@media (min-width: 640px) {
.demo-gallery-drawer {
inset: auto;
top: 0;
right: 0;
height: 100%;
width: 480px;
max-width: 90vw;
border-left: 1px solid var(--color-border-glass, rgba(0,0,0,0.1));
transform: translateX(100%);
}
.demo-gallery-drawer--open {
transform: translateX(0);
box-shadow: -8px 0 30px rgba(0,0,0,0.1);
}
}

/* === Flash Animation === */
.content-flash {
animation: content-flash 700ms ease-out;
Expand Down
1 change: 1 addition & 0 deletions apps/app/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@
return (
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Open Generative UI</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🪁</text></svg>" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
<link

Check warning on line 18 in apps/app/src/app/layout.tsx

View workflow job for this annotation

GitHub Actions / Lint

Custom fonts not added in `pages/_document.js` will only load for a single page. This is discouraged. See: https://nextjs.org/docs/messages/no-page-custom-font
href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
Expand Down
23 changes: 13 additions & 10 deletions apps/app/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useGenerativeUIExamples, useExampleSuggestions } from "@/hooks";
import { ExplainerCardsPortal } from "@/components/explainer-cards";
import { DemoGallery, type DemoItem } from "@/components/demo-gallery";
import { GridIcon } from "@/components/demo-gallery/grid-icon";
import { DesktopTipModal } from "@/components/desktop-tip-modal";
import { CopilotChat, useAgent, useCopilotKit } from "@copilotkit/react-core/v2";

export default function HomePage() {
Expand Down Expand Up @@ -51,25 +52,25 @@ export default function HomePage() {
background: "linear-gradient(135deg, rgba(190,194,255,0.08) 0%, rgba(133,224,206,0.06) 100%)",
}}
>
<div className="flex items-center justify-between gap-4 px-5 py-3">
<div className="flex items-center gap-3 min-w-0 flex-1">
<div className="flex items-center justify-between gap-2 sm:gap-4 px-3 sm:px-5 py-2.5 sm:py-3">
<div className="flex items-center gap-2 sm:gap-3 min-w-0 flex-1">
<div
className="flex items-center justify-center shrink-0 w-9 h-9 rounded-lg"
className="flex items-center justify-center shrink-0 w-8 h-8 sm:w-9 sm:h-9 rounded-lg"
style={{
background: "linear-gradient(135deg, rgba(190,194,255,0.15), rgba(133,224,206,0.12))",
}}
>
<span className="text-xl leading-none" role="img" aria-label="CopilotKit">🪁</span>
<span className="text-lg sm:text-xl leading-none" role="img" aria-label="CopilotKit">🪁</span>
</div>
<p className="text-base font-semibold m-0 leading-snug" style={{ color: "var(--text-primary)" }}>
<p className="text-sm sm:text-base font-semibold m-0 leading-snug" style={{ color: "var(--text-primary)" }}>
Open Generative UI
<span className="font-normal" style={{ color: "var(--text-secondary)" }}> — powered by CopilotKit</span>
<span className="hidden sm:inline font-normal" style={{ color: "var(--text-secondary)" }}> — powered by CopilotKit</span>
</p>
</div>
<div className="flex items-center gap-2">
<div className="flex items-center gap-1.5 sm:gap-2">
<button
onClick={() => setDemoDrawerOpen(true)}
className="inline-flex items-center gap-1.5 px-3 py-2 rounded-full text-sm font-medium no-underline whitespace-nowrap transition-all duration-150 hover:-translate-y-px cursor-pointer"
className="inline-flex items-center gap-1.5 px-2.5 sm:px-3 py-1.5 sm:py-2 rounded-full text-xs sm:text-sm font-medium no-underline whitespace-nowrap transition-all duration-150 hover:-translate-y-px cursor-pointer"
style={{
color: "var(--text-secondary)",
border: "1px solid var(--color-border-glass, rgba(0,0,0,0.1))",
Expand All @@ -79,13 +80,13 @@ export default function HomePage() {
title="Open Demo Gallery"
>
<GridIcon size={15} />
Demos
<span className="hidden sm:inline">Demos</span>
</button>
<a
href="https://github.com/CopilotKit/OpenGenerativeUI"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center px-5 py-2 rounded-full text-sm font-semibold text-white no-underline whitespace-nowrap transition-all duration-150 hover:-translate-y-px"
className="inline-flex items-center px-3 sm:px-5 py-1.5 sm:py-2 rounded-full text-xs sm:text-sm font-semibold text-white no-underline whitespace-nowrap transition-all duration-150 hover:-translate-y-px"
style={{
background: "linear-gradient(135deg, var(--color-lilac-dark), var(--color-mint-dark))",
boxShadow: "0 1px 4px rgba(149,153,204,0.3)",
Expand Down Expand Up @@ -115,6 +116,8 @@ export default function HomePage() {
onClose={() => setDemoDrawerOpen(false)}
onTryDemo={handleTryDemo}
/>

<DesktopTipModal />
</>
);
}
21 changes: 7 additions & 14 deletions apps/app/src/components/demo-gallery/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,14 @@ export function DemoGallery({ open, onClose, onTryDemo }: DemoGalleryProps) {
/>
)}

{/* Drawer panel */}
{/* Drawer: full-screen bottom sheet on mobile, right side panel on sm+ */}
<div
className="fixed top-0 right-0 h-full z-50 flex flex-col transition-transform duration-300 ease-in-out"
style={{
width: 480,
maxWidth: "90vw",
transform: open ? "translateX(0)" : "translateX(100%)",
background: "var(--surface-primary, #fff)",
borderLeft: "1px solid var(--color-border-glass, rgba(0,0,0,0.1))",
boxShadow: open ? "-8px 0 30px rgba(0,0,0,0.1)" : "none",
}}
className={`demo-gallery-drawer fixed z-50 flex flex-col transition-transform duration-300 ease-in-out ${open ? "demo-gallery-drawer--open" : ""}`}
style={{ background: "var(--surface-primary, #fff)" }}
>
{/* Header */}
<div
className="flex items-center justify-between px-5 py-4 shrink-0"
className="flex items-center justify-between px-4 sm:px-5 py-3 sm:py-4 shrink-0"
style={{
borderBottom:
"1px solid var(--color-border-glass, rgba(0,0,0,0.1))",
Expand All @@ -82,7 +75,7 @@ export function DemoGallery({ open, onClose, onTryDemo }: DemoGalleryProps) {
</div>
<button
onClick={onClose}
className="p-1.5 rounded-lg transition-colors duration-150 cursor-pointer"
className="p-2 -mr-1 rounded-lg transition-colors duration-150 cursor-pointer"
style={{ color: "var(--text-secondary, #666)" }}
>
<svg
Expand All @@ -102,15 +95,15 @@ export function DemoGallery({ open, onClose, onTryDemo }: DemoGalleryProps) {
</div>

{/* Category filter */}
<div className="px-5 pt-4 pb-2 shrink-0">
<div className="px-4 sm:px-5 pt-3 sm:pt-4 pb-2 shrink-0">
<CategoryFilter
selected={selectedCategory}
onSelect={setSelectedCategory}
/>
</div>

{/* Card list */}
<div className="flex-1 overflow-y-auto px-5 pb-5">
<div className="flex-1 overflow-y-auto px-4 sm:px-5 pb-5 overscroll-contain">
<div className="flex flex-col gap-3 pt-2">
{filtered.map((demo) => (
<DemoCard key={demo.id} demo={demo} onTry={onTryDemo} />
Expand Down
143 changes: 143 additions & 0 deletions apps/app/src/components/desktop-tip-modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
"use client";

import { useEffect, useSyncExternalStore } from "react";

const DISMISSED_KEY = "desktop-tip-dismissed";

let listeners: Array<() => void> = [];
function emitChange() {
listeners.forEach((l) => l());
}

export function DesktopTipModal() {
const notDismissed = useSyncExternalStore(
(listener) => {
listeners.push(listener);
return () => {
listeners = listeners.filter((l) => l !== listener);
};
},
() => {
try { return !sessionStorage.getItem(DISMISSED_KEY); }
catch { return false; }
},
() => false,
);

const dismiss = () => {
try { sessionStorage.setItem(DISMISSED_KEY, "1"); }
catch { /* privacy-restricted context */ }
emitChange();
};

useEffect(() => {
if (!notDismissed) return;
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === "Escape") dismiss();
};
document.addEventListener("keydown", handleKeyDown);
return () => document.removeEventListener("keydown", handleKeyDown);
});

if (!notDismissed) return null;

return (
<div
onClick={dismiss}
className="fixed inset-0 z-[9999] flex items-center justify-center p-6 sm:hidden"
style={{
background: "rgba(0,0,0,0.45)",
backdropFilter: "blur(6px)",
WebkitBackdropFilter: "blur(6px)",
}}
>
<div
onClick={(e) => e.stopPropagation()}
style={{
background: "var(--color-glass-dark, rgba(255,255,255,0.9))",
backdropFilter: "blur(16px)",
WebkitBackdropFilter: "blur(16px)",
border: "1px solid var(--color-border-glass, rgba(255,255,255,0.3))",
borderRadius: "var(--radius-xl, 16px)",
boxShadow: "var(--shadow-glass, 0 4px 30px rgba(0,0,0,0.1))",
padding: "32px 28px",
maxWidth: 340,
width: "100%",
textAlign: "center",
fontFamily: "var(--font-family)",
}}
>
{/* Monitor icon */}
<div
style={{
width: 56,
height: 56,
margin: "0 auto 20px",
borderRadius: 14,
background: "linear-gradient(135deg, rgba(190,194,255,0.15), rgba(133,224,206,0.12))",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
<svg
width="28"
height="28"
viewBox="0 0 24 24"
fill="none"
stroke="var(--color-lilac-dark, #9599CC)"
strokeWidth="1.8"
strokeLinecap="round"
strokeLinejoin="round"
>
<rect x="2" y="3" width="20" height="14" rx="2" />
<path d="M8 21h8" />
<path d="M12 17v4" />
</svg>
</div>

<h2
style={{
fontSize: 18,
fontWeight: 700,
color: "var(--text-primary, #374151)",
margin: "0 0 8px",
letterSpacing: "-0.01em",
}}
>
Best viewed on desktop
</h2>

<p
style={{
fontSize: 14,
color: "var(--text-secondary, #6b7280)",
margin: "0 0 24px",
lineHeight: 1.5,
}}
>
This experience includes interactive visualizations that work best on larger screens.
</p>

<button
onClick={dismiss}
style={{
width: "100%",
padding: "10px 20px",
borderRadius: 999,
fontSize: 14,
fontWeight: 600,
fontFamily: "var(--font-family)",
color: "#fff",
background: "linear-gradient(135deg, var(--color-lilac-dark, #9599CC), var(--color-mint-dark, #1B936F))",
border: "none",
boxShadow: "0 1px 4px rgba(149,153,204,0.3)",
cursor: "pointer",
}}
>
Continue anyway
</button>
</div>
</div>
);
}
Loading