diff --git a/app/component/[slug]/CodeSnippet.tsx b/app/component/[slug]/CodeSnippet.tsx new file mode 100644 index 00000000..e8ca616a --- /dev/null +++ b/app/component/[slug]/CodeSnippet.tsx @@ -0,0 +1,46 @@ +"use client"; + +import * as React from "react"; +import { Button } from "@/registry/mini-app/ui/button"; +import { Clipboard as ClipboardIcon, Check as CheckIcon } from "lucide-react"; + +type CodeSnippetProps = { + code: string; + title?: string; +}; + +export function CodeSnippet({ code, title = "Example Code" }: CodeSnippetProps) { + const [copied, setCopied] = React.useState(false); + + const handleCopy = () => { + navigator.clipboard.writeText(code); + setCopied(true); + setTimeout(() => setCopied(false), 3000); + }; + + return ( +
+
+

{title}

+ +
+
+
+          {code}
+        
+
+
+ ); +} \ No newline at end of file diff --git a/app/component/[slug]/page.tsx b/app/component/[slug]/page.tsx index fac7ab03..b0fa5e9b 100644 --- a/app/component/[slug]/page.tsx +++ b/app/component/[slug]/page.tsx @@ -7,7 +7,8 @@ import { notFound, useParams } from "next/navigation"; import { componentItems } from "@/lib/components-config"; import { ArrowLeft } from "lucide-react"; import { ComponentWrapper } from "./component-wrapper"; -import { InstallSnippet } from "./InstallSnippet"; // Import the new InstallSnippet component +import { InstallSnippet } from "./InstallSnippet"; +import { CodeSnippet } from "./CodeSnippet"; export default function ComponentPage() { const params = useParams(); @@ -17,7 +18,9 @@ export default function ComponentPage() { notFound(); } - const item = componentItems.find((item) => item.installName === slug); + const item = componentItems.find((item) => + item.installName === slug || item.slug === slug + ); if (!item) { notFound(); @@ -28,18 +31,17 @@ export default function ComponentPage() {
{/* Header */}
-
- + +
- +

hellno/mini-app-ui

-
+
@@ -58,8 +60,11 @@ export default function ComponentPage() {
- {" "} - {/* Use the new InstallSnippet component */} + {item.isDemo && item.demoCode ? ( + + ) : ( + item.installName && + )}
diff --git a/app/dashboard/page.tsx b/app/dashboard/page.tsx new file mode 100644 index 00000000..b7873789 --- /dev/null +++ b/app/dashboard/page.tsx @@ -0,0 +1,55 @@ +"use client"; + +import { AppSidebar } from "@/components/app-sidebar" +import { componentGroups } from "@/lib/components-config" +import { + Breadcrumb, + BreadcrumbItem, + BreadcrumbLink, + BreadcrumbList, + BreadcrumbPage, + BreadcrumbSeparator, +} from "@/components/ui/breadcrumb" +import { Separator } from "@/components/ui/separator" +import { + SidebarInset, + SidebarProvider, + SidebarTrigger, +} from "@/components/ui/sidebar" + +export default function Page() { + return ( + + + +
+
+ + + + + + + Building Your Application + + + + + Data Fetching + + + +
+
+
+
+
+
+
+
+
+
+ + + ) +} diff --git a/app/page.tsx b/app/page.tsx index df17a7cf..496ec5f8 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -5,7 +5,7 @@ import Link from "next/link"; import Image from "next/image"; import { OpenInVibesEngineeringButton } from "@/components/open-in-vibes-engineering-button"; import { useMiniAppSdk } from "@/registry/mini-app/hooks/use-miniapp-sdk"; -import { componentItems } from "@/lib/components-config"; +import { componentGroups } from "@/lib/components-config"; import { Clipboard as ClipboardIcon, Check as CheckIcon, @@ -13,6 +13,8 @@ import { Github, } from "lucide-react"; import { Button } from "@/registry/mini-app/ui/button"; +import { AppSidebar } from "@/components/app-sidebar"; +import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"; function InstallSnippet({ installName }: { installName: string }) { const [tab, setTab] = React.useState<"pnpm" | "npm" | "bun">("pnpm"); @@ -81,96 +83,134 @@ function InstallSnippet({ installName }: { installName: string }) { export default function Home() { useMiniAppSdk(); + const handleComponentClick = (componentId: string) => { + const element = document.getElementById(`component-${componentId}`); + if (element) { + const headerOffset = 80; // Approximate header height + const elementPosition = element.getBoundingClientRect().top; + const offsetPosition = elementPosition + window.pageYOffset - headerOffset; + + window.scrollTo({ + top: offsetPosition, + behavior: "smooth" + }); + } + }; + return ( -
- {/* Header */} -
-
-

- hellno/mini-app-ui -

-
+ +
+ +
+ {/* Header */} +
+
+ +

+ hellno/mini-app-ui +

+
- {/* Action Icons */} -
+
-
-
-

- A collection of components, hooks and utilities for mini apps using - shadcn. Build beautiful and functional mini-apps with these - ready-to-use components. -

-
+
+
+

+ A collection of components, hooks and utilities for mini apps + using shadcn. Build beautiful and functional mini-apps with + these ready-to-use components. +

+
-
- {componentItems.map((item, index) => ( -
-
-

- {item.title} -

-
- - -
-
+
+ {componentGroups.map((group, groupIndex) => ( +
+

{group.title}

+
+ {group.items.map((item, index) => ( +
+
+ + {item.title} + +
+ + +
+
-
-
-
- {item.component} -
-
+
+
+
+ {item.component} +
+
-
- -
+ {item.installName && ( +
+ +
+ )} +
+ ))} +
+
+ ))}
- ))} +
- -
+
+ ); } diff --git a/components/app-sidebar.tsx b/components/app-sidebar.tsx new file mode 100644 index 00000000..cbc9528f --- /dev/null +++ b/components/app-sidebar.tsx @@ -0,0 +1,67 @@ +import * as React from "react"; +import { + GalleryVerticalEnd, +} from "lucide-react"; + +import { + Sidebar, + SidebarContent, + SidebarGroup, + SidebarGroupLabel, + SidebarHeader, + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + SidebarRail, +} from "@/components/ui/sidebar"; +import type { ComponentGroup } from "@/lib/components-config"; + +interface AppSidebarProps extends React.ComponentProps { + onComponentClick?: (componentId: string) => void; + componentGroups: ComponentGroup[]; +} + +export function AppSidebar({ onComponentClick, componentGroups, ...props }: AppSidebarProps) { + return ( + + + + + window.scrollTo({ top: 0, behavior: "smooth" })} + > +
+ +
+
+ hellno/mini-app-ui + Component Registry +
+
+
+
+
+ + {componentGroups.map((group, groupIndex) => ( + + {group.title} + + {group.items.map((item, index) => ( + + onComponentClick?.(item.installName || item.slug || `${groupIndex}-${index}`)} + className="text-sm" + > + {item.title} + + + ))} + + + ))} + + +
+ ); +} diff --git a/components/ui/breadcrumb.tsx b/components/ui/breadcrumb.tsx new file mode 100644 index 00000000..eb88f321 --- /dev/null +++ b/components/ui/breadcrumb.tsx @@ -0,0 +1,109 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { ChevronRight, MoreHorizontal } from "lucide-react" + +import { cn } from "@/lib/utils" + +function Breadcrumb({ ...props }: React.ComponentProps<"nav">) { + return