commit 242161dcdb15dfa2eaaf8537fc6942249df7131c Author: ahmadrezabd Date: Wed Dec 3 16:48:15 2025 +0330 Initial commit: Next.js project with Persian content and custom styling 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/about/page.tsx b/app/about/page.tsx new file mode 100644 index 0000000..6e3bdfc --- /dev/null +++ b/app/about/page.tsx @@ -0,0 +1,79 @@ +import ContentSection from "@/components/content-1"; +import Features from "@/components/features-12"; +import HeroSection from "@/components/hero-section"; + +export default function AboutPage() { + return ( + <> +
+
+
+

+ درباره ما +

+

+ کنترل پی یک پلتفرم یکپارچه‌سازی و ارتباطات هوشمند است که به کسب‌وکارها کمک می‌کند تا سیستم‌ها، داده‌ها و فرآیندهای خود را به شکلی کارآمد و قابل‌اعتماد بهم متصل کنند. +

+
+ +
+
+
+

+ ماموریت ما +

+

+ ما باور داریم که ارتباطات و یکپارچه‌سازی باید ساده، سریع و قابل‌اعتماد باشد. هدف ما این است که به کسب‌وکارها کمک کنیم تا بدون پیچیدگی‌های فنی، سیستم‌های خود را بهم متصل کنند و از قدرت اتوماسیون و ارتباطات هوشمند بهره‌مند شوند. +

+
+
+

+ چشم‌انداز ما +

+

+ ما می‌خواهیم به پلتفرم پیشرو در حوزه یکپارچه‌سازی و ارتباطات هوشمند تبدیل شویم. چشم‌انداز ما این است که هر کسب‌وکاری، از کوچک تا بزرگ، بتواند به راحتی از خدمات ما استفاده کند و به اهداف خود برسد. +

+
+
+ +
+

+ چرا کنترل پی؟ +

+
+
+

سادگی

+

+ رابط کاربری ساده و قابل فهم که نیاز به تخصص فنی ندارد +

+
+
+

قابلیت اطمینان

+

+ زیرساخت قدرتمند و پایدار که همیشه در دسترس است +

+
+
+

مقیاس‌پذیری

+

+ قابلیت رشد همراه با نیازهای کسب‌وکار شما +

+
+
+
+ +
+

+ تیم ما +

+

+ تیم کنترل پی متشکل از متخصصان با تجربه در حوزه‌های فناوری اطلاعات، توسعه نرم‌افزار و مدیریت کسب‌وکار است. ما با همکاری یکدیگر، راهکارهای نوآورانه و کاربردی برای چالش‌های یکپارچه‌سازی ارائه می‌دهیم. +

+
+
+
+
+ + ); +} + 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..85c45c6 --- /dev/null +++ b/app/globals.css @@ -0,0 +1,209 @@ +@import "tailwindcss"; +@import "tw-animate-css"; + +/* IRANSansX Font Faces */ +@font-face { + font-family: IRANSansX; + font-style: normal; + font-weight: 100; + src: url("/assets/irsansx/Woff/IRANSansXFaNum-Thin.woff") format("woff"), + url("/assets/irsansx/Woff2/IRANSansXFaNum-Thin.woff2") format("woff2"); +} + +@font-face { + font-family: IRANSansX; + font-style: normal; + font-weight: 200; + src: url("/assets/irsansx/Woff/IRANSansXFaNum-UltraLight.woff") format("woff"), + url("/assets/irsansx/Woff2/IRANSansXFaNum-UltraLight.woff2") format("woff2"); +} + +@font-face { + font-family: IRANSansX; + font-style: normal; + font-weight: 300; + src: url("/assets/irsansx/Woff/IRANSansXFaNum-Light.woff") format("woff"), + url("/assets/irsansx/Woff2/IRANSansXFaNum-Light.woff2") format("woff2"); +} + +@font-face { + font-family: IRANSansX; + font-style: normal; + font-weight: 500; + src: url("/assets/irsansx/Woff/IRANSansXFaNum-Medium.woff") format("woff"), + url("/assets/irsansx/Woff2/IRANSansXFaNum-Medium.woff2") format("woff2"); +} + +@font-face { + font-family: IRANSansX; + font-style: normal; + font-weight: 600; + src: url("/assets/irsansx/Woff/IRANSansXFaNum-DemiBold.woff") format("woff"), + url("/assets/irsansx/Woff2/IRANSansXFaNum-DemiBold.woff2") format("woff2"); +} + +@font-face { + font-family: IRANSansX; + font-style: normal; + font-weight: 800; + src: url("/assets/irsansx/Woff/IRANSansXFaNum-ExtraBold.woff") format("woff"), + url("/assets/irsansx/Woff2/IRANSansXFaNum-ExtraBold.woff2") format("woff2"); +} + +@font-face { + font-family: IRANSansX; + font-style: normal; + font-weight: 900; + src: url("/assets/irsansx/Woff/IRANSansXFaNum-Black.woff") format("woff"), + url("/assets/irsansx/Woff2/IRANSansXFaNum-Black.woff2") format("woff2"); +} + +@font-face { + font-family: IRANSansX; + font-style: normal; + font-weight: bold; + src: url("/assets/irsansx/Woff/IRANSansXFaNum-Bold.woff") format("woff"), + url("/assets/irsansx/Woff2/IRANSansXFaNum-Bold.woff2") format("woff2"); +} + +@font-face { + font-family: IRANSansX; + font-style: normal; + font-weight: normal; + src: url("/assets/irsansx/Woff/IRANSansXFaNum-Regular.woff") format("woff"), + url("/assets/irsansx/Woff2/IRANSansXFaNum-Regular.woff2") format("woff2"); +} + +@custom-variant dark (&:is(.dark *)); + +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + --font-sans: var(--font-geist-sans); + --font-mono: var(--font-geist-mono); + --font-iran-sans: "IRANSansX", "system-ui", "Avenir", "Helvetica", "Arial", + "sans-serif"; + --color-sidebar-ring: var(--sidebar-ring); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar: var(--sidebar); + --color-chart-5: var(--chart-5); + --color-chart-4: var(--chart-4); + --color-chart-3: var(--chart-3); + --color-chart-2: var(--chart-2); + --color-chart-1: var(--chart-1); + --color-ring: var(--ring); + --color-input: var(--input); + --color-border: var(--border); + --color-destructive: var(--destructive); + --color-accent-foreground: var(--accent-foreground); + --color-accent: var(--accent); + --color-muted-foreground: var(--muted-foreground); + --color-muted: var(--muted); + --color-secondary-foreground: var(--secondary-foreground); + --color-secondary: var(--secondary); + --color-primary-foreground: var(--primary-foreground); + --color-primary: var(--primary); + --color-popover-foreground: var(--popover-foreground); + --color-popover: var(--popover); + --color-card-foreground: var(--card-foreground); + --color-card: var(--card); + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); +} + +:root { + --font-iran-sans: "IRANSansX", var(--font-geist-sans); + --radius: 0.625rem; + --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: #216583; + --primary-foreground: oklch(0.985 0 0); + --secondary: #00818A; + --secondary-foreground: oklch(0.985 0 0); + --muted: #f5f5f5; + --muted-foreground: #293462; + --accent: #F7BE16; + --accent-foreground: #293462; + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 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); + --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.708 0 0); + --background: #ffffff; + --foreground: #293462; +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: #216583; + --primary-foreground: oklch(0.985 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: #F7BE16; + --accent-foreground: #293462; + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 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(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + font-family: "IRANSansX", var(--font-geist-sans); + letter-spacing: normal; + line-height: 1.6; + } + h1, h2, h3, h4, h5, h6 { + letter-spacing: normal; + line-height: 1.5; + } + p { + letter-spacing: normal; + line-height: 1.7; + } +} diff --git a/app/layout.tsx b/app/layout.tsx new file mode 100644 index 0000000..9bbf024 --- /dev/null +++ b/app/layout.tsx @@ -0,0 +1,36 @@ +import type { Metadata } from "next"; +import { Geist, Geist_Mono } from "next/font/google"; +import "./globals.css"; +import { ConditionalLayout } from "@/components/conditional-layout"; + +const geistSans = Geist({ + variable: "--font-geist-sans", + subsets: ["latin"], +}); + +const geistMono = Geist_Mono({ + variable: "--font-geist-mono", + subsets: ["latin"], +}); + +export const metadata: Metadata = { + title: "کنترل پی", + description: + "کنترل پی یک سامانه برای ایجاد و طراحی راهکارهای مناسب برای کسب و کار شما است.", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + {children} + + + ); +} diff --git a/app/login/page.tsx b/app/login/page.tsx new file mode 100644 index 0000000..3d82022 --- /dev/null +++ b/app/login/page.tsx @@ -0,0 +1,11 @@ +import { LoginForm } from "@/components/login-form"; + +export default function LoginPage() { + return ( +
+
+ +
+
+ ); +} diff --git a/app/page.tsx b/app/page.tsx new file mode 100644 index 0000000..05292d0 --- /dev/null +++ b/app/page.tsx @@ -0,0 +1,14 @@ +import ContentSection from "@/components/content-1"; +import Features from "@/components/features-12"; +import HeroSection from "@/components/hero-section"; +import Image from "next/image"; + +export default function Home() { + return ( + <> + + + + + ); +} diff --git a/app/pricing/page.tsx b/app/pricing/page.tsx new file mode 100644 index 0000000..41c0c63 --- /dev/null +++ b/app/pricing/page.tsx @@ -0,0 +1,14 @@ +import Pricing from "@/components/pricing"; +import PricingComparator from "@/components/pricing-comparator"; + +export default function PricingPage() { + return ( + <> + +
+ +
+ + ); +} + diff --git a/app/solutions/page.tsx b/app/solutions/page.tsx new file mode 100644 index 0000000..6cd1b52 --- /dev/null +++ b/app/solutions/page.tsx @@ -0,0 +1,161 @@ +import { Button } from "@/components/ui/button"; +import { Database, Fingerprint, IdCard, ChartBarIncreasingIcon, MessageSquare, Zap, Shield, Link as LinkIcon } from "lucide-react"; +import Link from "next/link"; + +const solutions = [ + { + icon: Database, + title: "تجمیع پایگاه داده", + description: "جمع‌آوری و هماهنگ‌سازی داده‌ها از سیستم‌های مختلف برای ایجاد یک نمای واحد از اطلاعات کسب‌وکار شما", + features: [ + "اتصال به دیتابیس‌های مختلف", + "همگام‌سازی خودکار داده‌ها", + "گزارش‌گیری یکپارچه", + "پشتیبانی از APIهای خارجی" + ] + }, + { + icon: Fingerprint, + title: "احراز هویت پیشرفته", + description: "سیستم امن و منعطف برای مدیریت احراز هویت کاربران و سرویس‌ها با پشتیبانی از روش‌های مختلف", + features: [ + "پشتیبانی از OAuth", + "توکن‌های اختصاصی", + "احراز هویت چندمرحله‌ای", + "مدیریت دسترسی‌ها" + ] + }, + { + icon: IdCard, + title: "مدیریت هویت", + description: "مدیریت یکپارچه کاربران، نقش‌ها و مجوزها در همه سیستم‌های متصل به پلتفرم", + features: [ + "مدیریت کاربران مرکزی", + "تعریف نقش‌ها و مجوزها", + "همگام‌سازی خودکار", + "لاگ تغییرات" + ] + }, + { + icon: ChartBarIncreasingIcon, + title: "داشبورد تحلیل", + description: "تبدیل داده‌های خام به گزارش‌ها و نمودارهای قابل‌درک برای تصمیم‌گیری بهتر", + features: [ + "گزارش‌های سفارشی", + "نمودارهای تعاملی", + "تحلیل روندها", + "خروجی در فرمت‌های مختلف" + ] + }, + { + icon: MessageSquare, + title: "ارتباطات چندکاناله", + description: "ارسال و دریافت پیام از کانال‌های مختلف مانند تلگرام، واتساپ و سرویس‌های اختصاصی", + features: [ + "پشتیبانی از تلگرام", + "پشتیبانی از واتساپ", + "کانال‌های اختصاصی", + "مدیریت مکالمات" + ] + }, + { + icon: Zap, + title: "اتوماسیون فرآیندها", + description: "خودکارسازی فرآیندهای کسب‌وکار با استفاده از رویدادها و ترiggerهای قابل تنظیم", + features: [ + "تعریف workflow", + "اتوماسیون بر اساس رویداد", + "زمان‌بندی کارها", + "اعلان‌های خودکار" + ] + }, + { + icon: Shield, + title: "امنیت و حریم خصوصی", + description: "محافظت از داده‌ها و ارتباطات با استفاده از آخرین استانداردهای امنیتی", + features: [ + "رمزنگاری end-to-end", + "بکاپ خودکار", + "مانیتورینگ امنیتی", + "رعایت استانداردهای GDPR" + ] + }, + { + icon: LinkIcon, + title: "یکپارچه‌سازی API", + description: "اتصال آسان به APIهای مختلف و سرویس‌های داخلی و خارجی", + features: [ + "REST API", + "GraphQL", + "Webhooks", + "مستندات کامل" + ] + } +]; + +export default function SolutionsPage() { + return ( + <> +
+
+
+

+ راه‌حل‌های ما +

+

+ مجموعه‌ای از ابزارهای قدرتمند برای یکپارچه‌سازی، اتوماسیون و ارتباطات هوشمند که به کسب‌وکار شما کمک می‌کند تا کارآمدتر و سریع‌تر عمل کند. +

+
+ +
+ {solutions.map((solution, index) => { + const Icon = solution.icon; + return ( +
+
+
+ +
+

+ {solution.title} +

+
+

+ {solution.description} +

+
    + {solution.features.map((feature, featureIndex) => ( +
  • + + {feature} +
  • + ))} +
+
+ ); + })} +
+ +
+

+ آماده شروع هستید؟ +

+

+ همین حالا شروع کنید و از قدرت یکپارچه‌سازی و ارتباطات هوشمند بهره‌مند شوید +

+ +
+
+
+ + ); +} + diff --git a/components.json b/components.json new file mode 100644 index 0000000..77c1af0 --- /dev/null +++ b/components.json @@ -0,0 +1,24 @@ +{ + "$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": "" + }, + "iconLibrary": "lucide", + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "registries": { + "@tailark": "https://tailark.com/r/{name}.json" + } +} diff --git a/components/call-to-action.tsx b/components/call-to-action.tsx new file mode 100644 index 0000000..a90efe8 --- /dev/null +++ b/components/call-to-action.tsx @@ -0,0 +1,34 @@ +import { Button } from '@/components/ui/button' +import Link from 'next/link' + +export default function CallToAction() { + return ( +
+
+
+

Start Building

+

Libero sapiente aliquam quibusdam aspernatur.

+ +
+ + + +
+
+
+
+ ) +} diff --git a/components/conditional-layout.tsx b/components/conditional-layout.tsx new file mode 100644 index 0000000..ec3533b --- /dev/null +++ b/components/conditional-layout.tsx @@ -0,0 +1,19 @@ +'use client' + +import { usePathname } from 'next/navigation' +import FooterSection from '@/components/footer' +import { HeroHeader } from '@/components/header' + +export function ConditionalLayout({ children }: { children: React.ReactNode }) { + const pathname = usePathname() + const isLoginPage = pathname === '/login' + + return ( + <> + {!isLoginPage && } + {children} + {!isLoginPage && } + + ) +} + diff --git a/components/content-1.tsx b/components/content-1.tsx new file mode 100644 index 0000000..f46e479 --- /dev/null +++ b/components/content-1.tsx @@ -0,0 +1,70 @@ +import Image from "next/image"; + +export default function ContentSection() { + return ( +
+
+

+ اکوسیستم کنترل پی مدل‌های ما را گرد هم می‌آورد. +

+
+
+
+ payments illustration dark + payments illustration light +
+
+ +
+

+ کنترل پی در حال تکامل است تا فراتر از مدل‌ها باشد.{" "} + + این پلتفرم از کل اکوسیستم پشتیبانی می‌کند + {" "} + — از محصولات تا نوآوری. +

+

+ این پلتفرم از کل اکوسیستم پشتیبانی می‌کند — از محصولات تا APIها و + پلتفرم‌هایی که به توسعه‌دهندگان و کسب‌وکارها کمک می‌کنند تا نوآوری + کنند +

+ +
+
+

+ استفاده از کنترل پی مانند باز کردن یک قدرت فوق‌العاده طراحی + مخفی بوده است. این ترکیب کامل سادگی و تطبیق‌پذیری است که به ما + امکان می‌دهد رابط‌های کاربری بسازیم که هم زیبا و هم کاربرپسند + هستند. +

+ +
+ جان دو، مدیرعامل + Nvidia Logo +
+
+
+
+
+
+
+ ); +} diff --git a/components/faqs-4.tsx b/components/faqs-4.tsx new file mode 100644 index 0000000..63fccff --- /dev/null +++ b/components/faqs-4.tsx @@ -0,0 +1,77 @@ +'use client' + +import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion' +import Link from 'next/link' + +export default function FAQsFour() { + const faqItems = [ + { + id: 'item-1', + question: 'How long does shipping take?', + answer: 'Standard shipping takes 3-5 business days, depending on your location. Express shipping options are available at checkout for 1-2 business day delivery.', + }, + { + id: 'item-2', + question: 'What payment methods do you accept?', + answer: 'We accept all major credit cards (Visa, Mastercard, American Express), PayPal, Apple Pay, and Google Pay. For enterprise customers, we also offer invoicing options.', + }, + { + id: 'item-3', + question: 'Can I change or cancel my order?', + answer: 'You can modify or cancel your order within 1 hour of placing it. After this window, please contact our customer support team who will assist you with any changes.', + }, + { + id: 'item-4', + question: 'Do you ship internationally?', + answer: "Yes, we ship to over 50 countries worldwide. International shipping typically takes 7-14 business days. Additional customs fees may apply depending on your country's import regulations.", + }, + { + id: 'item-5', + question: 'What is your return policy?', + answer: 'We offer a 30-day return policy for most items. Products must be in original condition with tags attached. Some specialty items may have different return terms, which will be noted on the product page.', + }, + ] + + return ( +
+
+
+

Frequently Asked Questions

+

Discover quick and comprehensive answers to common questions about our platform, services, and features.

+
+ +
+ + {faqItems.map((item) => ( +
+ + {item.question} + +

{item.answer}

+
+
+
+
+ ))} +
+ +

+ Can't find what you're looking for? Contact our{' '} + + customer support team + +

+
+
+
+ ) +} diff --git a/components/features-12.tsx b/components/features-12.tsx new file mode 100644 index 0000000..3e6dc81 --- /dev/null +++ b/components/features-12.tsx @@ -0,0 +1,149 @@ +"use client"; +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from "@/components/ui/accordion"; +import { + ChartBarIncreasingIcon, + Database, + Fingerprint, + IdCard, +} from "lucide-react"; +import Image from "next/image"; +import { useState } from "react"; +import { motion, AnimatePresence } from "motion/react"; +import { BorderBeam } from "./ui/border-beam"; + +export default function Features() { + type ImageKey = "item-1" | "item-2" | "item-3" | "item-4"; + const [activeItem, setActiveItem] = useState("item-1"); + + const images = { + "item-1": { + image: "/charts.png", + alt: "Database visualization", + }, + "item-2": { + image: "/music.png", + alt: "Security authentication", + }, + "item-3": { + image: "/mail2.png", + alt: "Identity management", + }, + "item-4": { + image: "/payments.png", + alt: "Analytics dashboard", + }, + }; + + return ( +
+
+
+
+

+ پایه و اساس ارتباطات هوشمند +

+

+ پلتفرم ما برای اتصال آسان میان سیستم‌ها، APIها و سرویس‌های داخلی شما طراحی شده است. + از یکپارچه‌سازی داده‌ها و احراز هویت گرفته تا پردازش رویدادها و ارسال پیام در کانال‌هایی مثل تلگرام، واتساپ یا حتی سرویس‌های اختصاصی — همه‌چیز با دقت و مقیاس‌پذیری بالا مدیریت می‌شود تا توسعه‌دهندگان و کسب‌وکارها بتوانند سریع‌تر نوآوری کنند. +

+
+ +
+ setActiveItem(value as ImageKey)} + className="w-full" + > + + +
+ + تجمیع پایگاه داده +
+
+ +

+ ما داده‌های موردنیاز شما را از سیستم‌های مختلف جمع‌آوری و هماهنگ می‌کنیم؛ از دیتابیس‌های محلی تا APIهای خارجی. این قابلیت برای گزارش‌گیری، اتوماسیون و ایجاد یک نمای واحد از اطلاعات کلیدی کسب‌وکار ضروری است. +

+
+
+ + +
+ + احراز هویت پیشرفته +
+
+ +

+ سیستم احراز هویت امن و منعطف که از انواع روش‌ها پشتیبانی می‌کند—از OAuth تا توکن‌های اختصاصی—تا بتوانید کاربران، سرویس‌ها و اپلیکیشن‌های خود را با کمترین پیچیدگی مدیریت کنید. +

+
+
+ + +
+ + مدیریت هویت +
+
+ +

+ مدیریت یکپارچه کاربران، نقش‌ها و مجوزها در همه سیستم‌ها. هر تغییری در یک سرویس، بلافاصله در سایر سرویس‌های متصل هم منعکس می‌شود. +

+
+
+ + +
+ + داشبورد تحلیل +
+
+ +

+ داده‌های شما به گزارش‌ها و نمودارهای قابل‌درک تبدیل می‌شود؛ چه برای نمایش فروش ماهانه یک فروشگاه، چه برای نشان دادن آمار بازدید یک سایت، یا تحلیل رفتار کاربران در یک ربات تلگرام. +

+
+
+
+ +
+
+
+ + + {images[activeItem].alt} + + +
+ +
+
+
+
+ ); +} diff --git a/components/footer.tsx b/components/footer.tsx new file mode 100644 index 0000000..b516e89 --- /dev/null +++ b/components/footer.tsx @@ -0,0 +1,120 @@ +import { Logo } from "@/components/logo"; +import Link from "next/link"; + +const links = [ + { + title: "ویژگی‌ها", + href: "#", + }, + { + title: "راه‌حل", + href: "#", + }, + { + title: "مشتریان", + href: "#", + }, + { + title: "قیمت‌گذاری", + href: "/pricing", + }, + { + title: "راهنما", + href: "#", + }, + { + title: "درباره", + href: "#", + }, +]; + +export default function FooterSection() { + return ( +
+
+ + + + +
+ {links.map((link, index) => ( + + {link.title} + + ))} +
+
+ + + + + + + + + + + + + + + + +
+ + {" "} + © {new Date().getFullYear()} کنترل پی، تمامی حقوق محفوظ است + +
+
+ ); +} diff --git a/components/header.tsx b/components/header.tsx new file mode 100644 index 0000000..10eca36 --- /dev/null +++ b/components/header.tsx @@ -0,0 +1,103 @@ +'use client' +import Link from 'next/link' +import { Logo } from '@/components/logo' +import { Menu, X } from 'lucide-react' +import { Button } from '@/components/ui/button' +import React from 'react' +import { cn } from '@/lib/utils' + +const menuItems = [ + { name: 'صفحه اصلی', href: '/' }, + { name: 'درباره ما', href: '/about' }, + { name: 'راه حل‌ها', href: '/solutions' }, + { name: 'قیمت‌گذاری', href: '/pricing' }, +] + +export const HeroHeader = () => { + const [menuState, setMenuState] = React.useState(false) + const [isScrolled, setIsScrolled] = React.useState(false) + + React.useEffect(() => { + const handleScroll = () => { + setIsScrolled(window.scrollY > 50) + } + window.addEventListener('scroll', handleScroll) + return () => window.removeEventListener('scroll', handleScroll) + }, []) + return ( +
+ +
+ ) +} diff --git a/components/hero-section.tsx b/components/hero-section.tsx new file mode 100644 index 0000000..b8f2dd5 --- /dev/null +++ b/components/hero-section.tsx @@ -0,0 +1,288 @@ +import React from "react"; +import Link from "next/link"; +import { ArrowLeft, ArrowRight, ChevronRight } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import Image from "next/image"; +import { TextEffect } from "@/components/ui/text-effect"; +import { AnimatedGroup } from "@/components/ui/animated-group"; +import { HeroHeader } from "./header"; + +const transitionVariants = { + item: { + hidden: { + opacity: 0, + filter: "blur(12px)", + y: 12, + }, + visible: { + opacity: 1, + filter: "blur(0px)", + y: 0, + transition: { + type: "spring", + bounce: 0.3, + duration: 1.5, + }, + }, + }, +}; + +export default function HeroSection() { + return ( + <> +
+
+
+
+
+
+
+
+ + background + + +
+ +
+
+ + + + معرفی نسل جدید یکپارچه‌سازی و ارتباطات هوشمند + + + +
+
+ + + + + + +
+
+ +
+ + + راه‌حل‌های مدرن برای تعامل هوشمند با مشتری و سیستم‌های شما + + + ما مجموعه‌ای از ابزارهای یکپارچه‌سازی، اتوماسیون و ارتباطات ارائه می‌کنیم که به شما کمک می‌کند داده‌ها، کاربران و فرآیندهای کسب‌وکارتان را از هر سیستم یا پلتفرمی — از وب‌سایت و CRM گرفته تا تلگرام و سرویس‌های سفارشی — به شکلی دقیق، سریع و قابل‌اعتماد بهم متصل کنید. + + + +
+ +
+
+
+
+ + +
+
+ app screen + app screen +
+
+
+
+
+
+
+
+ + با مشتریان ما آشنا شوید + + + +
+
+
+ Nvidia Logo +
+ +
+ Column Logo +
+
+ GitHub Logo +
+
+ Nike Logo +
+
+ Lemon Squeezy Logo +
+
+ Laravel Logo +
+
+ Lilly Logo +
+ +
+ OpenAI Logo +
+
+
+
+
+ + ); +} diff --git a/components/login-form.tsx b/components/login-form.tsx new file mode 100644 index 0000000..63bfa3a --- /dev/null +++ b/components/login-form.tsx @@ -0,0 +1,110 @@ +import { cn } from "@/lib/utils"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent } from "@/components/ui/card"; +import { + Field, + FieldDescription, + FieldGroup, + FieldLabel, + FieldSeparator, +} from "@/components/ui/field"; +import { Input } from "@/components/ui/input"; + +export function LoginForm({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ + +
+ +
+

خوش آمدید

+

+ به حساب کنترل پی خود وارد شوید +

+
+ + + ایمیل + + + + + + + + + + + + یا ادامه با + + + + +
+
+
+ Image +
+
+
+ + با کلیک روی ادامه، شما با شرایط استفاده و{" "} + سیاست حریم خصوصی ما موافقت می‌کنید. + +
+ ); +} diff --git a/components/logo.tsx b/components/logo.tsx new file mode 100644 index 0000000..367d9f6 --- /dev/null +++ b/components/logo.tsx @@ -0,0 +1,46 @@ +import { cn } from "@/lib/utils"; +import Image from "next/image"; +import Link from "next/link"; + +export const Logo = ({ + className, + uniColor, +}: { + className?: string; + uniColor?: boolean; +}) => { + return ( + + + کنترل پی + + ); +}; + +export const LogoIcon = ({ + className, + uniColor, +}: { + className?: string; + uniColor?: boolean; +}) => { + return Logo; +}; + +export const LogoStroke = ({ className }: { className?: string }) => { + return ( + + + + ); +}; diff --git a/components/pricing-comparator.tsx b/components/pricing-comparator.tsx new file mode 100644 index 0000000..c292214 --- /dev/null +++ b/components/pricing-comparator.tsx @@ -0,0 +1,237 @@ +import { Button } from "@/components/ui/button"; +import { Cpu, Sparkles } from "lucide-react"; +import Link from "next/link"; + +const tableData = [ + { + feature: "ویژگی ۱", + free: true, + pro: true, + startup: true, + }, + { + feature: "ویژگی ۲", + free: true, + pro: true, + startup: true, + }, + { + feature: "ویژگی ۳", + free: false, + pro: true, + startup: true, + }, + { + feature: "توکن‌ها", + free: "", + pro: "۲۰ کاربر", + startup: "نامحدود", + }, + { + feature: "تماس ویدیویی", + free: "", + pro: "۱۲ هفته", + startup: "۵۶", + }, + { + feature: "پشتیبانی", + free: "", + pro: "ثانیه‌ها", + startup: "نامحدود", + }, + { + feature: "امنیت", + free: "", + pro: "۲۰ کاربر", + startup: "نامحدود", + }, +]; + +export default function PricingComparator() { + return ( +
+
+
+ + + + + + + + + + + + + + + + + {tableData.slice(-4).map((row, index) => ( + + + + + + + ))} + + + + + + + {tableData.map((row, index) => ( + + + + + + + ))} + + + + + + + +
+ رایگان + + + + حرفه‌ای + + + استارتاپ + +
+ + ویژگی‌ها +
{row.feature} + {row.free === true ? ( + + + + ) : ( + row.free + )} + +
+ {row.pro === true ? ( + + + + ) : ( + row.pro + )} +
+
+ {row.startup === true ? ( + + + + ) : ( + row.startup + )} +
+ + مدل‌های هوش مصنوعی +
{row.feature} + {row.free === true ? ( + + + + ) : ( + row.free + )} + +
+ {row.pro === true ? ( + + + + ) : ( + row.pro + )} +
+
+ {row.startup === true ? ( + + + + ) : ( + row.startup + )} +
+
+
+
+ ); +} diff --git a/components/pricing.tsx b/components/pricing.tsx new file mode 100644 index 0000000..469a12e --- /dev/null +++ b/components/pricing.tsx @@ -0,0 +1,117 @@ +import { Button } from "@/components/ui/button"; +import { Check } from "lucide-react"; +import Link from "next/link"; + +export default function Pricing() { + return ( +
+
+
+

+ قیمت‌گذاری +

+

+ قیمت‌ها بر اساس نوع سرویس و بازه زمانی تعیین می‌شوند +

+
+
+
+
+
+

پکیج سازمانی

+

برای شرکت شما با هر اندازه‌ای

+ +
+

+ قیمت‌گذاری ما بر اساس نیازهای خاص شما انجام می‌شود. عوامل موثر در تعیین قیمت شامل: +

+
    +
  • + + نوع و تعداد سرویس‌های مورد نیاز +
  • +
  • + + بازه زمانی استفاده (ماهانه، سالانه) +
  • +
  • + + حجم داده و ترافیک +
  • +
  • + + نیاز به پشتیبانی و سفارشی‌سازی +
  • +
+
+ +
+ +
+ +

+ برای دریافت پیشنهاد قیمت دقیق، با ما تماس بگیرید تا بر اساس نیازهای شما بهترین راهکار را پیشنهاد دهیم. +

+
+
+
    + {[ + "تجمیع پایگاه داده و یکپارچه‌سازی", + "احراز هویت و مدیریت هویت پیشرفته", + "داشبورد تحلیل و گزارش‌گیری", + "ارتباطات چندکاناله (تلگرام، واتساپ و ...)", + "اتوماسیون فرآیندها و workflow", + "پشتیبانی ۲۴/۷ و مستندات کامل", + "ذخیره‌سازی نامحدود", + "API و Webhooks نامحدود" + ].map((item, index) => ( +
  • + + {item} +
  • + ))} +
+

+ ما راهکارهای سفارشی برای کسب‌وکارهای مختلف ارائه می‌دهیم. + تیم ما آماده است تا بر اساس نیازهای خاص شما، بهترین پکیج را طراحی کند. +

+
+ Nvidia Logo + Column Logo + GitHub Logo + Nike Logo +
+
+
+
+
+
+
+ ); +} diff --git a/components/ui/accordion.tsx b/components/ui/accordion.tsx new file mode 100644 index 0000000..4a8cca4 --- /dev/null +++ b/components/ui/accordion.tsx @@ -0,0 +1,66 @@ +"use client" + +import * as React from "react" +import * as AccordionPrimitive from "@radix-ui/react-accordion" +import { ChevronDownIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function Accordion({ + ...props +}: React.ComponentProps) { + return +} + +function AccordionItem({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AccordionTrigger({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + svg]:rotate-180", + className + )} + {...props} + > + {children} + + + + ) +} + +function AccordionContent({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + +
{children}
+
+ ) +} + +export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } diff --git a/components/ui/alert-dialog.tsx b/components/ui/alert-dialog.tsx new file mode 100644 index 0000000..0863e40 --- /dev/null +++ b/components/ui/alert-dialog.tsx @@ -0,0 +1,157 @@ +"use client" + +import * as React from "react" +import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog" + +import { cn } from "@/lib/utils" +import { buttonVariants } from "@/components/ui/button" + +function AlertDialog({ + ...props +}: React.ComponentProps) { + return +} + +function AlertDialogTrigger({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogPortal({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + + ) +} + +function AlertDialogHeader({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function AlertDialogFooter({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function AlertDialogTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogAction({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogCancel({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + AlertDialog, + AlertDialogPortal, + AlertDialogOverlay, + AlertDialogTrigger, + AlertDialogContent, + AlertDialogHeader, + AlertDialogFooter, + AlertDialogTitle, + AlertDialogDescription, + AlertDialogAction, + AlertDialogCancel, +} diff --git a/components/ui/alert.tsx b/components/ui/alert.tsx new file mode 100644 index 0000000..1421354 --- /dev/null +++ b/components/ui/alert.tsx @@ -0,0 +1,66 @@ +import * as React from "react" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const alertVariants = cva( + "relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current", + { + variants: { + variant: { + default: "bg-card text-card-foreground", + destructive: + "text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +function Alert({ + className, + variant, + ...props +}: React.ComponentProps<"div"> & VariantProps) { + return ( +
+ ) +} + +function AlertTitle({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function AlertDescription({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ) +} + +export { Alert, AlertTitle, AlertDescription } diff --git a/components/ui/animated-group.tsx b/components/ui/animated-group.tsx new file mode 100644 index 0000000..ba1cc08 --- /dev/null +++ b/components/ui/animated-group.tsx @@ -0,0 +1,143 @@ +'use client'; +import { ReactNode } from 'react'; +import { motion, Variants } from 'motion/react'; +import React from 'react'; + +export type PresetType = + | 'fade' + | 'slide' + | 'scale' + | 'blur' + | 'blur-slide' + | 'zoom' + | 'flip' + | 'bounce' + | 'rotate' + | 'swing'; + +export type AnimatedGroupProps = { + children: ReactNode; + className?: string; + variants?: { + container?: Variants; + item?: Variants; + }; + preset?: PresetType; + as?: React.ElementType; + asChild?: React.ElementType; +}; + +const defaultContainerVariants: Variants = { + visible: { + transition: { + staggerChildren: 0.1, + }, + }, +}; + +const defaultItemVariants: Variants = { + hidden: { opacity: 0 }, + visible: { opacity: 1 }, +}; + +const presetVariants: Record = { + fade: {}, + slide: { + hidden: { y: 20 }, + visible: { y: 0 }, + }, + scale: { + hidden: { scale: 0.8 }, + visible: { scale: 1 }, + }, + blur: { + hidden: { filter: 'blur(4px)' }, + visible: { filter: 'blur(0px)' }, + }, + 'blur-slide': { + hidden: { filter: 'blur(4px)', y: 20 }, + visible: { filter: 'blur(0px)', y: 0 }, + }, + zoom: { + hidden: { scale: 0.5 }, + visible: { + scale: 1, + transition: { type: 'spring', stiffness: 300, damping: 20 }, + }, + }, + flip: { + hidden: { rotateX: -90 }, + visible: { + rotateX: 0, + transition: { type: 'spring', stiffness: 300, damping: 20 }, + }, + }, + bounce: { + hidden: { y: -50 }, + visible: { + y: 0, + transition: { type: 'spring', stiffness: 400, damping: 10 }, + }, + }, + rotate: { + hidden: { rotate: -180 }, + visible: { + rotate: 0, + transition: { type: 'spring', stiffness: 200, damping: 15 }, + }, + }, + swing: { + hidden: { rotate: -10 }, + visible: { + rotate: 0, + transition: { type: 'spring', stiffness: 300, damping: 8 }, + }, + }, +}; + +const addDefaultVariants = (variants: Variants) => ({ + hidden: { ...defaultItemVariants.hidden, ...variants.hidden }, + visible: { ...defaultItemVariants.visible, ...variants.visible }, +}); + +function AnimatedGroup({ + children, + className, + variants, + preset, + as = 'div', + asChild = 'div', +}: AnimatedGroupProps) { + const selectedVariants = { + item: addDefaultVariants(preset ? presetVariants[preset] : {}), + container: addDefaultVariants(defaultContainerVariants), + }; + const containerVariants = variants?.container || selectedVariants.container; + const itemVariants = variants?.item || selectedVariants.item; + + const MotionComponent = React.useMemo( + () => motion.create(as as keyof JSX.IntrinsicElements), + [as] + ); + const MotionChild = React.useMemo( + () => motion.create(asChild as keyof JSX.IntrinsicElements), + [asChild] + ); + + return ( + + {React.Children.map(children, (child, index) => ( + + {child} + + ))} + + ); +} + +export { AnimatedGroup }; diff --git a/components/ui/aspect-ratio.tsx b/components/ui/aspect-ratio.tsx new file mode 100644 index 0000000..3df3fd0 --- /dev/null +++ b/components/ui/aspect-ratio.tsx @@ -0,0 +1,11 @@ +"use client" + +import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio" + +function AspectRatio({ + ...props +}: React.ComponentProps) { + return +} + +export { AspectRatio } 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/badge.tsx b/components/ui/badge.tsx new file mode 100644 index 0000000..fd3a406 --- /dev/null +++ b/components/ui/badge.tsx @@ -0,0 +1,46 @@ +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 badgeVariants = cva( + "inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-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 transition-[color,box-shadow] overflow-hidden", + { + variants: { + variant: { + default: + "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90", + secondary: + "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90", + destructive: + "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +function Badge({ + className, + variant, + asChild = false, + ...props +}: React.ComponentProps<"span"> & + VariantProps & { asChild?: boolean }) { + const Comp = asChild ? Slot : "span" + + return ( + + ) +} + +export { Badge, badgeVariants } diff --git a/components/ui/border-beam.tsx b/components/ui/border-beam.tsx new file mode 100644 index 0000000..4fbc775 --- /dev/null +++ b/components/ui/border-beam.tsx @@ -0,0 +1,107 @@ +"use client" + +import { motion, MotionStyle, Transition } from "motion/react" + +import { cn } from "@/lib/utils" + +interface BorderBeamProps { + /** + * The size of the border beam. + */ + size?: number + /** + * The duration of the border beam. + */ + duration?: number + /** + * The delay of the border beam. + */ + delay?: number + /** + * The color of the border beam from. + */ + colorFrom?: string + /** + * The color of the border beam to. + */ + colorTo?: string + /** + * The motion transition of the border beam. + */ + transition?: Transition + /** + * The class name of the border beam. + */ + className?: string + /** + * The style of the border beam. + */ + style?: React.CSSProperties + /** + * Whether to reverse the animation direction. + */ + reverse?: boolean + /** + * The initial offset position (0-100). + */ + initialOffset?: number + /** + * The border width of the beam. + */ + borderWidth?: number +} + +export const BorderBeam = ({ + className, + size = 50, + delay = 0, + duration = 6, + colorFrom = "#ffaa40", + colorTo = "#9c40ff", + transition, + style, + reverse = false, + initialOffset = 0, + borderWidth = 1, +}: BorderBeamProps) => { + return ( +
+ +
+ ) +} diff --git a/components/ui/breadcrumb.tsx b/components/ui/breadcrumb.tsx new file mode 100644 index 0000000..eb88f32 --- /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