commit bfe7515aa6470fe252dc7a653b822472ec9a9926 Author: Mobin Firooz Date: Sun Mar 2 00:58:28 2025 +0330 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ef6a52 --- /dev/null +++ b/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/README.md b/README.md new file mode 100644 index 0000000..e215bc4 --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. + +This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. diff --git a/app/favicon.ico b/app/favicon.ico new file mode 100644 index 0000000..718d6fe Binary files /dev/null and b/app/favicon.ico differ diff --git a/app/globals.css b/app/globals.css new file mode 100644 index 0000000..f6f3dac --- /dev/null +++ b/app/globals.css @@ -0,0 +1,152 @@ +@import "tailwindcss"; + +@plugin "tailwindcss-animate"; + +@custom-variant dark (&:is(.dark *)); + +@theme { + --font-sans: var(--font-geist-sans); + --font-mono: var(--font-geist-mono); +} + +:root { + --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); + --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.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --destructive-foreground: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.87 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); + --radius: 0.625rem; + --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.87 0 0); +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.145 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.145 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.985 0 0); + --primary-foreground: oklch(0.205 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.396 0.141 25.723); + --destructive-foreground: oklch(0.637 0.237 25.331); + --border: oklch(0.269 0 0); + --input: oklch(0.269 0 0); + --ring: oklch(0.439 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(0.269 0 0); + --sidebar-ring: oklch(0.439 0 0); +} + +@theme inline { + --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-destructive-foreground: var(--destructive-foreground); + --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); + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --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); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } +} + +@utility container { + margin-inline: auto; + padding-inline: 1rem; + + @media (width >= theme(--breakpoint-sm)) { + padding-inline: 2rem; + } +} + +.bg-parch { + background: linear-gradient(90deg, #21c796 15%, #0385ce 95%, #0d40bf 120%); +} + +.text-parch { + background: linear-gradient(90deg, #21c796 40%, #0385ce 85%, #0d40bf 120%); + color: transparent; + background-clip: text; +} + +.bg-image { + background-image: url("/public/background.jpg"); +} diff --git a/app/layout.tsx b/app/layout.tsx new file mode 100644 index 0000000..490f64f --- /dev/null +++ b/app/layout.tsx @@ -0,0 +1,40 @@ +import type { Metadata } from "next"; +import { Geist, Geist_Mono } from "next/font/google"; +import "./globals.css"; +import Header from "@/components/header"; +import { Footer } from "@/components/ui/footer"; +import FooterSection from "@/components/sections/footer/default"; + +const geistSans = Geist({ + variable: "--font-geist-sans", + subsets: ["latin"], +}); + +const geistMono = Geist_Mono({ + variable: "--font-geist-mono", + subsets: ["latin"], +}); + +export const metadata: Metadata = { + title: "Create Next App", + description: "Generated by create next app", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + +
+ {children} + + + + ); +} diff --git a/app/page.tsx b/app/page.tsx new file mode 100644 index 0000000..d40b1c1 --- /dev/null +++ b/app/page.tsx @@ -0,0 +1,15 @@ +import { AboutPodcast } from "@/components/about-podcast"; +import { EpisodeCards } from "@/components/episode-cards"; +import { PodcastHero } from "@/components/podcast-hero"; +import { SubscribeSection } from "@/components/subscribe-section"; + +export default function Home() { + return ( +
+ + + + +
+ ); +} diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000..527ae84 Binary files /dev/null and b/bun.lockb differ diff --git a/components.json b/components.json new file mode 100644 index 0000000..335484f --- /dev/null +++ b/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/components/about-podcast.tsx b/components/about-podcast.tsx new file mode 100644 index 0000000..7151a62 --- /dev/null +++ b/components/about-podcast.tsx @@ -0,0 +1,82 @@ +import Image from "next/image"; + +export function AboutPodcast() { + return ( +
+
+
+
+

+ درباره پادکست +

+

+ پادکست “پارچ کست” یک برنامه صوتی جذاب و متنوع است که به بررسی + موضوعات مختلف فرهنگی، اجتماعی و علمی می‌پردازد. این پادکست با + میزبانی متخصصان و مهمانان مختلف، تلاش می‌کند تا با ارائه بحث‌ها و + نظرات عمیق، شنوندگان را به تفکر وادارد و آگاهی آن‌ها را در + زمینه‌های مختلف افزایش دهد. هر قسمت از “پارچ کست” با رویکردی + خلاقانه و engaging تولید می‌شود و هدف آن ایجاد فضایی است که در آن + گوش دادن به اطلاعات جدید همزمان با لذت و سرگرمی همراه باشد. +

+

+ پادکست “پارچ کست” یک برنامه صوتی جذاب و متنوع است که به بررسی + موضوعات مختلف فرهنگی، اجتماعی و علمی می‌پردازد. این پادکست با + میزبانی متخصصان و مهمانان مختلف، تلاش می‌کند تا با ارائه بحث‌ها و + نظرات عمیق، شنوندگان را به تفکر وادارد و آگاهی آن‌ها را در + زمینه‌های مختلف افزایش دهد. هر قسمت از “پارچ کست” با رویکردی + خلاقانه و engaging تولید می‌شود و هدف آن ایجاد فضایی است که در آن + گوش دادن به اطلاعات جدید همزمان با لذت و سرگرمی همراه باشد. +

+ {/*
+ + +
+ +
+

100+ Episodes

+

+ And counting, with new content every week +

+
+
+ + +
+ + + + +
+

50K+ Listeners

+

+ Join our growing community of podcast fans +

+
+
+
*/} +
+
+ Podcast Cover Art +
+
+
+
+ ); +} diff --git a/components/episode-cards.tsx b/components/episode-cards.tsx new file mode 100644 index 0000000..bb78784 --- /dev/null +++ b/components/episode-cards.tsx @@ -0,0 +1,110 @@ +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Clock, Play } from "lucide-react"; +import Image from "next/image"; + +export function EpisodeCards() { + // Sample episode data + const episodes = [ + { + id: 1, + title: "قسمت سوم", + description: + "هر قسمت از “پارچ کست” با رویکردی خلاقانه و engaging تولید می‌شود و هدف آن ایجاد فضایی است که در آن گوش دادن به اطلاعات جدید همزمان با لذت و سرگرمی همراه باشد.", + duration: "52 دقیقه", + date: "18 آذر, 1403", + image: "https://picsum.photos/200", + }, + { + id: 2, + title: "قسمت دوم", + description: + "هر قسمت از “پارچ کست” با رویکردی خلاقانه و engaging تولید می‌شود و هدف آن ایجاد فضایی است که در آن گوش دادن به اطلاعات جدید همزمان با لذت و سرگرمی همراه باشد.", + duration: "43 دقیقه", + date: "18 آذر, 1403", + image: "https://picsum.photos/200", + }, + { + id: 3, + title: "قسمت اول", + description: + "هر قسمت از “پارچ کست” با رویکردی خلاقانه و engaging تولید می‌شود و هدف آن ایجاد فضایی است که در آن گوش دادن به اطلاعات جدید همزمان با لذت و سرگرمی همراه باشد.", + duration: "30 دقیقه", + date: "18 آذر, 1403", + image: "https://picsum.photos/200", + }, + { + id: 4, + title: "قسمت اول", + description: + "هر قسمت از “پارچ کست” با رویکردی خلاقانه و engaging تولید می‌شود و هدف آن ایجاد فضایی است که در آن گوش دادن به اطلاعات جدید همزمان با لذت و سرگرمی همراه باشد.", + duration: "30 دقیقه", + date: "18 آذر, 1403", + image: "https://picsum.photos/200", + }, + ]; + + return ( +
+
+
+
+

+ آخرین قسمت ها +

+

+ از جدیدترین مکالمات ما مطلع شوید +

+
+ +
+
+ {episodes.map((episode) => ( + +
+ {episode.title} +
+ + {episode.title} + {episode.date} + + +

+ {episode.description} +

+
+ +
+ + {episode.duration} +
+ +
+
+ ))} +
+
+
+ ); +} diff --git a/components/header.tsx b/components/header.tsx new file mode 100644 index 0000000..09a94cd --- /dev/null +++ b/components/header.tsx @@ -0,0 +1,33 @@ +"use client"; + +import { Button } from "@/components/ui/button"; +import { Menu, Search } from "lucide-react"; +import Image from "next/image"; + +export default function Header() { + return ( +
+
+
+ + +
+
+ logo +
+
+ + +
+
+
+ ); +} diff --git a/components/podcast-hero.tsx b/components/podcast-hero.tsx new file mode 100644 index 0000000..a10ea17 --- /dev/null +++ b/components/podcast-hero.tsx @@ -0,0 +1,58 @@ +import { Button } from "@/components/ui/button"; +import { Play } from "lucide-react"; +import Image from "next/image"; + +export function PodcastHero() { + return ( +
+
+
+
+
+
+ logo +

+ پارچ کست +

+
+ +

+ پادکست “پارچ کست” یک برنامه صوتی جذاب و متنوع است که به بررسی + موضوعات مختلف فرهنگی، اجتماعی و علمی می‌پردازد. این پادکست با + میزبانی متخصصان و مهمانان مختلف، تلاش می‌کند تا با ارائه بحث‌ها + و نظرات عمیق، شنوندگان را به تفکر وادارد و آگاهی آن‌ها را در + زمینه‌های مختلف افزایش دهد. هر قسمت از “پارچ کست” با رویکردی + خلاقانه و engaging تولید می‌شود و هدف آن ایجاد فضایی است که در + آن گوش دادن به اطلاعات جدید همزمان با لذت و سرگرمی همراه باشد. +

+
+
+ + {/* */} +
+
+
+ Podcast Cover Art +
+
+
+
+ ); +} diff --git a/components/sections/footer/default.tsx b/components/sections/footer/default.tsx new file mode 100644 index 0000000..5859b2a --- /dev/null +++ b/components/sections/footer/default.tsx @@ -0,0 +1,68 @@ +import Image from "next/image"; +import LaunchUI from "../../logos/launch-ui"; +import { + Footer, + FooterBottom, + FooterColumn, + FooterContent, +} from "../../ui/footer"; + +export default function FooterSection() { + return ( + + ); +} diff --git a/components/subscribe-section.tsx b/components/subscribe-section.tsx new file mode 100644 index 0000000..e5657d5 --- /dev/null +++ b/components/subscribe-section.tsx @@ -0,0 +1,37 @@ +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Headphones, Mail } from "lucide-react"; + +export function SubscribeSection() { + return ( +
+
+
+
+
+ +
+
+

+ هرگز یک قسمت را از دست ندهید +

+

+ در خبرنامه ما مشترک شوید و از انتشار قسمت های جدید مطلع شوید منتشر + شد. +

+
+ + +
+
+
+
+ ); +} diff --git a/components/ui/avatar.tsx b/components/ui/avatar.tsx new file mode 100644 index 0000000..71e428b --- /dev/null +++ b/components/ui/avatar.tsx @@ -0,0 +1,53 @@ +"use client" + +import * as React from "react" +import * as AvatarPrimitive from "@radix-ui/react-avatar" + +import { cn } from "@/lib/utils" + +function Avatar({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AvatarImage({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AvatarFallback({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { Avatar, AvatarImage, AvatarFallback } diff --git a/components/ui/button.tsx b/components/ui/button.tsx new file mode 100644 index 0000000..e1b5d8a --- /dev/null +++ b/components/ui/button.tsx @@ -0,0 +1,58 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const buttonVariants = cva( + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-[color,box-shadow] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_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", + outline: + "border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground", + secondary: + "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + 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/components/ui/card.tsx b/components/ui/card.tsx new file mode 100644 index 0000000..5e960a6 --- /dev/null +++ b/components/ui/card.tsx @@ -0,0 +1,68 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +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 CardContent({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } diff --git a/components/ui/dropdown-menu.tsx b/components/ui/dropdown-menu.tsx new file mode 100644 index 0000000..9dc361e --- /dev/null +++ b/components/ui/dropdown-menu.tsx @@ -0,0 +1,205 @@ +"use client"; + +import * as React from "react"; +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; +import { + CheckIcon, + ChevronRightIcon, + DotFilledIcon, +} from "@radix-ui/react-icons"; + +import { cn } from "@/lib/utils"; + +const DropdownMenu = DropdownMenuPrimitive.Root; + +const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger; + +const DropdownMenuGroup = DropdownMenuPrimitive.Group; + +const DropdownMenuPortal = DropdownMenuPrimitive.Portal; + +const DropdownMenuSub = DropdownMenuPrimitive.Sub; + +const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup; + +const DropdownMenuSubTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, children, ...props }, ref) => ( + + {children} + + +)); +DropdownMenuSubTrigger.displayName = + DropdownMenuPrimitive.SubTrigger.displayName; + +const DropdownMenuSubContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DropdownMenuSubContent.displayName = + DropdownMenuPrimitive.SubContent.displayName; + +const DropdownMenuContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + + + +)); +DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName; + +const DropdownMenuItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, ...props }, ref) => ( + +)); +DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName; + +const DropdownMenuCheckboxItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, checked, ...props }, ref) => ( + + + + + + + {children} + +)); +DropdownMenuCheckboxItem.displayName = + DropdownMenuPrimitive.CheckboxItem.displayName; + +const DropdownMenuRadioItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + {children} + +)); +DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName; + +const DropdownMenuLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, ...props }, ref) => ( + +)); +DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName; + +const DropdownMenuSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName; + +const DropdownMenuShortcut = ({ + className, + ...props +}: React.HTMLAttributes) => { + return ( + + ); +}; +DropdownMenuShortcut.displayName = "DropdownMenuShortcut"; + +export { + DropdownMenu, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuGroup, + DropdownMenuPortal, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuRadioGroup, +}; diff --git a/components/ui/footer.tsx b/components/ui/footer.tsx new file mode 100644 index 0000000..f38e548 --- /dev/null +++ b/components/ui/footer.tsx @@ -0,0 +1,54 @@ +import * as React from "react"; +import { cn } from "@/lib/utils"; + +const Footer = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +Footer.displayName = "Footer"; + +const FooterContent = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +FooterContent.displayName = "FooterContent"; + +const FooterColumn = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +FooterColumn.displayName = "FooterColumn"; + +const FooterBottom = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +FooterBottom.displayName = "FooterBottom"; + +export { Footer, FooterColumn, FooterBottom, FooterContent }; diff --git a/components/ui/input.tsx b/components/ui/input.tsx new file mode 100644 index 0000000..4bfe9cc --- /dev/null +++ b/components/ui/input.tsx @@ -0,0 +1,21 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +function Input({ className, type, ...props }: React.ComponentProps<"input">) { + return ( + + ) +} + +export { Input } diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..c85fb67 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,16 @@ +import { dirname } from "path"; +import { fileURLToPath } from "url"; +import { FlatCompat } from "@eslint/eslintrc"; + +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"), +]; + +export default eslintConfig; diff --git a/lib/utils.ts b/lib/utils.ts new file mode 100644 index 0000000..bd0c391 --- /dev/null +++ b/lib/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/next.config.ts b/next.config.ts new file mode 100644 index 0000000..5fb74d7 --- /dev/null +++ b/next.config.ts @@ -0,0 +1,17 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + images: { + remotePatterns: [ + { + protocol: "https", + hostname: "picsum.photos", + port: "", + pathname: "**", + }, + ], + }, + /* config options here */ +}; + +export default nextConfig; diff --git a/package.json b/package.json new file mode 100644 index 0000000..c8e8786 --- /dev/null +++ b/package.json @@ -0,0 +1,36 @@ +{ + "name": "parch-cast", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev --turbopack", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "@radix-ui/react-avatar": "^1.1.3", + "@radix-ui/react-dropdown-menu": "^2.1.6", + "@radix-ui/react-icons": "^1.3.2", + "@radix-ui/react-slot": "^1.1.2", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "lucide-react": "^0.476.0", + "next": "15.2.0", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "tailwind-merge": "^3.0.2", + "tailwindcss-animate": "^1.0.7" + }, + "devDependencies": { + "typescript": "^5", + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "@tailwindcss/postcss": "^4", + "tailwindcss": "^4", + "eslint": "^9", + "eslint-config-next": "15.2.0", + "@eslint/eslintrc": "^3" + } +} diff --git a/postcss.config.mjs b/postcss.config.mjs new file mode 100644 index 0000000..c7bcb4b --- /dev/null +++ b/postcss.config.mjs @@ -0,0 +1,5 @@ +const config = { + plugins: ["@tailwindcss/postcss"], +}; + +export default config; diff --git a/public/background.jpg b/public/background.jpg new file mode 100644 index 0000000..f6f0fa4 Binary files /dev/null and b/public/background.jpg differ diff --git a/public/file.svg b/public/file.svg new file mode 100644 index 0000000..004145c --- /dev/null +++ b/public/file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/globe.svg b/public/globe.svg new file mode 100644 index 0000000..567f17b --- /dev/null +++ b/public/globe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/logo.png b/public/logo.png new file mode 100644 index 0000000..ff37ba8 Binary files /dev/null and b/public/logo.png differ diff --git a/public/next.svg b/public/next.svg new file mode 100644 index 0000000..5174b28 --- /dev/null +++ b/public/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/vercel.svg b/public/vercel.svg new file mode 100644 index 0000000..7705396 --- /dev/null +++ b/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/window.svg b/public/window.svg new file mode 100644 index 0000000..b2b2a44 --- /dev/null +++ b/public/window.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..d8b9323 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +}