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
17 changes: 10 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,16 @@ npm run dev

## 📦 Available Components

| Component | Status | Category | Description |
| ------------------------ | --------- | ------------- | ------------------------------------------------- |
| **Announcement Badge** | ✅ Stable | Components | Badge with icon and title for announcements |
| **Button** | ✅ Stable | Actions | Accessible button with multiple variants |
| **Copy Button** | ✅ Stable | Actions | Button that copies text to clipboard when clicked |
| **Installation Section** | ✅ Stable | Documentation | Installation instructions with code snippets |
| **Orbit Images** | ✅ Stable | Components | Set of images displayed in orbiting motion |
| Component | Status | Category | Description |
| ------------------------ | --------- | ------------- | ----------------------------------------------------------------- |
| **Announcement Badge** | ✅ Stable | Components | Displays a badge with an icon and a title |
| **Button** | ✅ Stable | Actions | Displays a button or a component that looks like a button |
| **Card** | ✅ Stable | Components | Displays a card with a title, description, content and footer |
| **Carousel** | ✅ Stable | Components | Displays a carousel of images or content |
| **Copy Button** | ✅ Stable | Actions | Displays a copy button that copies text to clipboard when clicked |
| **Installation Section** | ✅ Stable | Documentation | Displays installation instructions with code snippets |
| **Orbit Images** | ✅ Stable | Components | Displays a set of images in an orbiting motion |
| **Tabs** | ✅ Stable | Navigation | A set of layered sections of content displayed one at a time |

> 🚧 More components coming soon! Check our [roadmap](https://github.com/pittaya-ui/ui-kit/issues) for planned features.

Expand Down
10 changes: 10 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"next-themes": "^0.4.6",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-icons": "^5.5.0",
"react-syntax-highlighter": "^15.6.6",
"sonner": "^2.0.7",
"tailwind-merge": "^3.3.1",
Expand All @@ -53,4 +54,4 @@
"tw-animate-css": "^1.3.6",
"typescript": "^5"
}
}
}
4 changes: 3 additions & 1 deletion src/app/docs/components/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Link from "next/link";

import { BreadcrumbContent } from "@/components/breadcrumb-content";
import { DocsShell } from "@/components/docs/docs-shell";
import { SidebarGeneral } from "@/components/docs/sidebar-general";
import { Button } from "@/components/ui/button";
Expand All @@ -20,7 +21,8 @@ export default function Components() {
>
<div className="mt-2 flex flex-col gap-8">
<div className="flex flex-col gap-2">
<h1 className="text-3xl font-semibold">Components</h1>
<BreadcrumbContent />
<h1 className="text-4xl font-semibold">Components</h1>
<span className="text-md max-w-lg opacity-80">
Here you’ll discover all the components currently available in our
library and we’re continuously expanding it with even more to come.
Expand Down
2 changes: 2 additions & 0 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { FeatureSection } from "@/components/cta";
import { Hero } from "@/components/home/hero";
import { WhyPittaya } from "@/components/home/why-pittaya";

Expand All @@ -6,6 +7,7 @@ export default function Home() {
<>
<Hero />
<WhyPittaya />
<FeatureSection />
</>
);
}
51 changes: 51 additions & 0 deletions src/components/breadcrumb-content.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"use client";

import { usePathname } from "next/navigation";

import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from "./ui/breadcrumb";

export function BreadcrumbContent() {
const pathname = usePathname();
const pathPages = pathname.split("/").filter(Boolean);
return (
<Breadcrumb>
<BreadcrumbList>
{pathPages.map((pathPage, index) => {
const href = `/${pathPages.slice(0, index + 1).join("/")}`;
const isLast = index === pathPages.length - 1;
const isDocs = pathPage.toLowerCase() === "docs";

return (
<div
key={`${pathPage}-${index}`}
className="flex items-center gap-2"
>
<BreadcrumbItem>
{isLast ? (
<BreadcrumbPage className="capitalize">
{pathPage}
</BreadcrumbPage>
) : (
<BreadcrumbLink
href={isDocs ? "/docs/introduction" : href}
className="capitalize"
>
{pathPage}
</BreadcrumbLink>
)}
</BreadcrumbItem>
{!isLast && <BreadcrumbSeparator />}
</div>
);
})}
</BreadcrumbList>
</Breadcrumb>
);
}
141 changes: 141 additions & 0 deletions src/components/cta.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import { ArrowUpRight, BookOpen, Github } from "lucide-react";
import Image from "next/image";
import Link from "next/link";
import { BiLogoTypescript } from "react-icons/bi";
import { DiNpm } from "react-icons/di";
import { DiTerminal } from "react-icons/di";
import { FaGithub, FaNodeJs, FaReact } from "react-icons/fa";
import { RiTailwindCssFill } from "react-icons/ri";
import { RiJavascriptFill } from "react-icons/ri";
import { SiNextdotjs, SiVercel } from "react-icons/si";

import { Button } from "@/components/ui/button";
import { REPO_URL } from "@/constants/repo-url";
import { cn } from "@/lib/utils";

const iconConfigs = [
{ Icon: FaReact, color: "text-[#61DAFB]" },
{ Icon: FaNodeJs, color: "text-[#339933]" },
{ Icon: SiNextdotjs, color: "text-[#FFFFFF] " },
{ Icon: SiVercel, color: "text-[#FFFFFF]" },
{ Icon: FaGithub, color: "text-[#FFFFFF]" },
{ Icon: RiTailwindCssFill, color: "text-[#2496ED]" },
{ Icon: RiJavascriptFill, color: "text-[#F7DF1E]" },
{ Icon: BiLogoTypescript, color: "text-[#3178C6]" },
{ Icon: DiNpm, color: "text-[#FFFFFF]" },
{ Icon: DiTerminal, color: "text-[#FFFFFF]" },
];

export function FeatureSection() {
const orbitCount = 3;
const iconsPerOrbit = Math.ceil(iconConfigs.length / orbitCount);

return (
<section className="mx-auto w-full max-w-screen-xl px-4 pb-20">
<div className="border-border bg-card/30 relative flex flex-col overflow-hidden rounded-3xl border px-4 py-12 shadow-2xl md:h-[25rem] md:flex-row md:items-center md:justify-between md:px-8 md:py-0 dark:bg-black/20">
<div className="bg-pittaya/20 dark:bg-pittaya/10 absolute -top-20 -left-20 h-64 w-64 rounded-full blur-[100px]" />
<div className="absolute -right-20 -bottom-20 h-64 w-64 rounded-full bg-blue-500/10 blur-[100px]" />

<div className="relative z-10 w-full md:w-1/2">
<h1 className="text-foreground mt-4 text-3xl leading-tight font-normal tracking-tight md:text-5xl lg:text-5xl">
Boost Your Frontend With{" "}
<span className="text-pittaya">Pittaya UI</span>
</h1>

<p className="text-muted-foreground mt-4 max-w-lg text-lg">
A fully open-source UI library for React, powered by TypeScript and
Tailwind CSS. Fast, composable, and ready for production.
</p>

<div className="mt-8 flex flex-col gap-3 sm:flex-row">
<Button
asChild
size="lg"
className="bg-foreground text-background hover:bg-foreground/90 w-full md:w-fit"
>
<Link href="/docs/components">
<BookOpen className="mr-2 h-4 w-4" />
View Components
</Link>
</Button>

<Button
asChild
size="lg"
variant="outline"
className="group border-border bg-background/50 hover:bg-accent hover:text-accent-foreground w-full backdrop-blur-sm md:w-fit"
>
<Link href={REPO_URL} target="_blank" rel="noopener noreferrer">
<Github className="mr-2 h-4 w-4" />
CLI Documentation
<ArrowUpRight className="ml-1 h-3 w-3 transition-transform group-hover:translate-x-0.5 group-hover:-translate-y-0.5" />
</Link>
</Button>
</div>
</div>

<div className="relative mt-8 flex h-64 w-full items-center justify-center md:mt-0 md:h-full md:w-1/2 md:justify-end">
<div className="relative flex h-[40rem] w-[40rem] scale-[0.6] items-center justify-center sm:scale-[0.8] md:translate-x-1/4 md:scale-100">
<div className="border-border bg-background shadow-pittaya/10 ring-background/50 relative z-20 flex h-24 w-24 items-center justify-center rounded-full border shadow-2xl ring-4">
<Image
src="/pittaya-logo.png"
alt="Pittaya UI Logo"
width={80}
height={80}
priority
quality={100}
className="h-14 w-14 object-contain"
/>
<div className="bg-pittaya/20 absolute inset-0 -z-10 rounded-full blur-xl" />
</div>

{[...Array(orbitCount)].map((_, orbitIdx) => {
const sizeClass = [
"h-[16rem] w-[16rem]",
"h-[24rem] w-[24rem]",
"h-[32rem] w-[32rem]",
][orbitIdx];

const durationClass = [
"animate-[spin_20s_linear_infinite]",
"animate-[spin_30s_linear_infinite_reverse]",
"animate-[spin_40s_linear_infinite]",
][orbitIdx];

return (
<div
key={orbitIdx}
className={cn(
"border-muted-foreground/20 absolute flex items-center justify-center rounded-full border border-dashed",
sizeClass,
durationClass
)}
>
{iconConfigs
.slice(
orbitIdx * iconsPerOrbit,
orbitIdx * iconsPerOrbit + iconsPerOrbit
)
.map((cfg, iconIdx) => {
const angle = (360 / iconsPerOrbit) * iconIdx;
return (
<div
key={iconIdx}
className="border-border bg-background absolute flex h-10 w-10 origin-center items-center justify-center rounded-full border shadow-sm transition-transform hover:scale-110"
style={{
transform: `rotate(${angle}deg) translate(${8 + orbitIdx * 4}rem) rotate(-${angle}deg)`,
}}
>
<cfg.Icon className={cn("h-5 w-5", cfg.color)} />
</div>
);
})}
</div>
);
})}
</div>
</div>
</div>
</section>
);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"use client";

import { BreadcrumbContent } from "@/components/breadcrumb-content";
import type { ComponentDoc } from "@/lib/docs/types";

import { Badge } from "../../ui/badge";
Expand All @@ -16,18 +15,21 @@ export function ComponentContent({ doc }: ComponentContentProps) {
return (
<div className="max-w-none">
<header className="space-y-4">
<div className="text-muted-foreground flex items-center gap-3 text-sm">
<Badge className="rounded-full tracking-wide" variant="secondary">
{doc.metadata.category}
</Badge>
{doc.metadata.status ? (
<Badge
variant={doc.metadata.status}
className="rounded-full tracking-wide"
>
{doc.metadata.status}
<div className="text-muted-foreground flex flex-col items-start justify-between gap-3 text-sm md:flex-row md:items-center">
<BreadcrumbContent />
<div className="flex items-center gap-2">
<Badge className="rounded-full tracking-wide" variant="secondary">
{doc.metadata.category}
</Badge>
) : null}
{doc.metadata.status ? (
<Badge
variant={doc.metadata.status}
className="rounded-full tracking-wide"
>
{doc.metadata.status}
</Badge>
) : null}
</div>
</div>
<div>
<h1
Expand Down
Loading