diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/git_toolbox_blame.xml b/.idea/git_toolbox_blame.xml
new file mode 100644
index 0000000..7dc1249
--- /dev/null
+++ b/.idea/git_toolbox_blame.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..03d9549
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..8e62468
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/prettier.xml b/.idea/prettier.xml
new file mode 100644
index 0000000..b0c1c68
--- /dev/null
+++ b/.idea/prettier.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/subscribers-chat.iml b/.idea/subscribers-chat.iml
new file mode 100644
index 0000000..24643cc
--- /dev/null
+++ b/.idea/subscribers-chat.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..bcfcf8b
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index e8afdff..780fd9a 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,12 @@
-
-### Next.js Enterprise Boilerplate
+### Next.js Enterprise Boilerplate
- [![GitHub Actions Workflow Status][check-workflow-badge]][check-workflow-badge-link] [![GitHub License][github-license-badge]][github-license-badge-link] [![GitHub contributors][github-contributors-badge]][github-contributors-badge-link] [![Discord][discord-badge]][discord-badge-link] [![Blazity][made-by-blazity-badge]][made-by-blazity-badge-link]
+[![GitHub Actions Workflow Status][check-workflow-badge]][check-workflow-badge-link] [![GitHub License][github-license-badge]][github-license-badge-link] [![GitHub contributors][github-contributors-badge]][github-contributors-badge-link] [![Discord][discord-badge]][discord-badge-link] [![Blazity][made-by-blazity-badge]][made-by-blazity-badge-link]
Welcome to the _Next.js Enterprise Boilerplate_, an open-source template for enterprise projects! It's loaded with features that'll help you build a high-performance, maintainable, and enjoyable app. We've done all the heavy lifting for you, so sit back, relax, and get ready to conquer the world with your incredible app! 🌍
-> [!NOTE]
-> **Blazity** is a group of Next.js/Headless experts. Contact us at [contact@blazity.com](https://blazity.com) if you’d like to talk about your project or just to have a chat with us
+> [!NOTE] > **Blazity** is a group of Next.js/Headless experts. Contact us at [contact@blazity.com](https://blazity.com) if you’d like to talk about your project or just to have a chat with us
### Integrated features
@@ -39,16 +37,14 @@ With this template you will get all the awesomeness you need:
### More features
-**nefi** (next-enterprise feature integrations) is an AI agent that will help configuring the boilerplate to your needs using natural language. It can remove/install dependencies, modify files, manage git and integrate various solutions into your project.
+**nefi** (next-enterprise feature integrations) is an AI agent that will help configuring the boilerplate to your needs using natural language. It can remove/install dependencies, modify files, manage git and integrate various solutions into your project.
Simply set up the boilerplate, follow guide [in the getting started section](#getting-started) and type `npx nefi` in your terminal!
Here's an example video of [nefi](https://nefi.ai/) integrating [Clerk](https://clerk.com/) auth solutions with one command, no API keys and no manual configuration needed!
-
https://github.com/user-attachments/assets/5c13a110-7389-4859-909f-60a7f623e47d
-
Leave a ⭐ for [nefi on GitHub](https://github.com/blazity/nefi) and check out the [nefi.ai docs](https://nefi.ai/)!
## Table of Contents
@@ -279,7 +275,6 @@ If you're looking for help or simply want to share your thoughts about the proje
-
## 📜 License
This project is licensed under the MIT License. For more information, see the [LICENSE](./LICENSE) file.
@@ -320,7 +315,6 @@ This project is licensed under the MIT License. For more information, see the [L
[github-contributors-badge]: https://img.shields.io/github/contributors/blazity/next-enterprise?link=https%3A%2F%2Fgithub.com%2FBlazity%2Fnext-enterprise%2Fgraphs%2Fcontributors
[discord-badge]: https://img.shields.io/discord/1111676875782234175?color=7b8dcd&link=https%3A%2F%2Fblazity.com%2Fdiscord
[made-by-blazity-badge]: https://img.shields.io/badge/made_by-Blazity-blue?color=FF782B&link=https://blazity.com/
-
[check-workflow-badge-link]: https://github.com/Blazity/next-enterprise/actions/workflows/check.yml
[github-license-badge-link]: https://github.com/Blazity/next-enterprise/blob/main/LICENSE
[github-contributors-badge-link]: https://github.com/Blazity/next-enterprise/graphs/contributors
diff --git a/app/(dev)/showcase/data.json b/app/(dev)/showcase/data.json
new file mode 100644
index 0000000..ec08736
--- /dev/null
+++ b/app/(dev)/showcase/data.json
@@ -0,0 +1,614 @@
+[
+ {
+ "id": 1,
+ "header": "Cover page",
+ "type": "Cover page",
+ "status": "In Process",
+ "target": "18",
+ "limit": "5",
+ "reviewer": "Eddie Lake"
+ },
+ {
+ "id": 2,
+ "header": "Table of contents",
+ "type": "Table of contents",
+ "status": "Done",
+ "target": "29",
+ "limit": "24",
+ "reviewer": "Eddie Lake"
+ },
+ {
+ "id": 3,
+ "header": "Executive summary",
+ "type": "Narrative",
+ "status": "Done",
+ "target": "10",
+ "limit": "13",
+ "reviewer": "Eddie Lake"
+ },
+ {
+ "id": 4,
+ "header": "Technical approach",
+ "type": "Narrative",
+ "status": "Done",
+ "target": "27",
+ "limit": "23",
+ "reviewer": "Jamik Tashpulatov"
+ },
+ {
+ "id": 5,
+ "header": "Design",
+ "type": "Narrative",
+ "status": "In Process",
+ "target": "2",
+ "limit": "16",
+ "reviewer": "Jamik Tashpulatov"
+ },
+ {
+ "id": 6,
+ "header": "Capabilities",
+ "type": "Narrative",
+ "status": "In Process",
+ "target": "20",
+ "limit": "8",
+ "reviewer": "Jamik Tashpulatov"
+ },
+ {
+ "id": 7,
+ "header": "Integration with existing systems",
+ "type": "Narrative",
+ "status": "In Process",
+ "target": "19",
+ "limit": "21",
+ "reviewer": "Jamik Tashpulatov"
+ },
+ {
+ "id": 8,
+ "header": "Innovation and Advantages",
+ "type": "Narrative",
+ "status": "Done",
+ "target": "25",
+ "limit": "26",
+ "reviewer": "Assign reviewer"
+ },
+ {
+ "id": 9,
+ "header": "Overview of EMR's Innovative Solutions",
+ "type": "Technical content",
+ "status": "Done",
+ "target": "7",
+ "limit": "23",
+ "reviewer": "Assign reviewer"
+ },
+ {
+ "id": 10,
+ "header": "Advanced Algorithms and Machine Learning",
+ "type": "Narrative",
+ "status": "Done",
+ "target": "30",
+ "limit": "28",
+ "reviewer": "Assign reviewer"
+ },
+ {
+ "id": 11,
+ "header": "Adaptive Communication Protocols",
+ "type": "Narrative",
+ "status": "Done",
+ "target": "9",
+ "limit": "31",
+ "reviewer": "Assign reviewer"
+ },
+ {
+ "id": 12,
+ "header": "Advantages Over Current Technologies",
+ "type": "Narrative",
+ "status": "Done",
+ "target": "12",
+ "limit": "0",
+ "reviewer": "Assign reviewer"
+ },
+ {
+ "id": 13,
+ "header": "Past Performance",
+ "type": "Narrative",
+ "status": "Done",
+ "target": "22",
+ "limit": "33",
+ "reviewer": "Assign reviewer"
+ },
+ {
+ "id": 14,
+ "header": "Customer Feedback and Satisfaction Levels",
+ "type": "Narrative",
+ "status": "Done",
+ "target": "15",
+ "limit": "34",
+ "reviewer": "Assign reviewer"
+ },
+ {
+ "id": 15,
+ "header": "Implementation Challenges and Solutions",
+ "type": "Narrative",
+ "status": "Done",
+ "target": "3",
+ "limit": "35",
+ "reviewer": "Assign reviewer"
+ },
+ {
+ "id": 16,
+ "header": "Security Measures and Data Protection Policies",
+ "type": "Narrative",
+ "status": "In Process",
+ "target": "6",
+ "limit": "36",
+ "reviewer": "Assign reviewer"
+ },
+ {
+ "id": 17,
+ "header": "Scalability and Future Proofing",
+ "type": "Narrative",
+ "status": "Done",
+ "target": "4",
+ "limit": "37",
+ "reviewer": "Assign reviewer"
+ },
+ {
+ "id": 18,
+ "header": "Cost-Benefit Analysis",
+ "type": "Plain language",
+ "status": "Done",
+ "target": "14",
+ "limit": "38",
+ "reviewer": "Assign reviewer"
+ },
+ {
+ "id": 19,
+ "header": "User Training and Onboarding Experience",
+ "type": "Narrative",
+ "status": "Done",
+ "target": "17",
+ "limit": "39",
+ "reviewer": "Assign reviewer"
+ },
+ {
+ "id": 20,
+ "header": "Future Development Roadmap",
+ "type": "Narrative",
+ "status": "Done",
+ "target": "11",
+ "limit": "40",
+ "reviewer": "Assign reviewer"
+ },
+ {
+ "id": 21,
+ "header": "System Architecture Overview",
+ "type": "Technical content",
+ "status": "In Process",
+ "target": "24",
+ "limit": "18",
+ "reviewer": "Maya Johnson"
+ },
+ {
+ "id": 22,
+ "header": "Risk Management Plan",
+ "type": "Narrative",
+ "status": "Done",
+ "target": "15",
+ "limit": "22",
+ "reviewer": "Carlos Rodriguez"
+ },
+ {
+ "id": 23,
+ "header": "Compliance Documentation",
+ "type": "Legal",
+ "status": "In Process",
+ "target": "31",
+ "limit": "27",
+ "reviewer": "Sarah Chen"
+ },
+ {
+ "id": 24,
+ "header": "API Documentation",
+ "type": "Technical content",
+ "status": "Done",
+ "target": "8",
+ "limit": "12",
+ "reviewer": "Raj Patel"
+ },
+ {
+ "id": 25,
+ "header": "User Interface Mockups",
+ "type": "Visual",
+ "status": "In Process",
+ "target": "19",
+ "limit": "25",
+ "reviewer": "Leila Ahmadi"
+ },
+ {
+ "id": 26,
+ "header": "Database Schema",
+ "type": "Technical content",
+ "status": "Done",
+ "target": "22",
+ "limit": "20",
+ "reviewer": "Thomas Wilson"
+ },
+ {
+ "id": 27,
+ "header": "Testing Methodology",
+ "type": "Technical content",
+ "status": "In Process",
+ "target": "17",
+ "limit": "14",
+ "reviewer": "Assign reviewer"
+ },
+ {
+ "id": 28,
+ "header": "Deployment Strategy",
+ "type": "Narrative",
+ "status": "Done",
+ "target": "26",
+ "limit": "30",
+ "reviewer": "Eddie Lake"
+ },
+ {
+ "id": 29,
+ "header": "Budget Breakdown",
+ "type": "Financial",
+ "status": "In Process",
+ "target": "13",
+ "limit": "16",
+ "reviewer": "Jamik Tashpulatov"
+ },
+ {
+ "id": 30,
+ "header": "Market Analysis",
+ "type": "Research",
+ "status": "Done",
+ "target": "29",
+ "limit": "32",
+ "reviewer": "Sophia Martinez"
+ },
+ {
+ "id": 31,
+ "header": "Competitor Comparison",
+ "type": "Research",
+ "status": "In Process",
+ "target": "21",
+ "limit": "19",
+ "reviewer": "Assign reviewer"
+ },
+ {
+ "id": 32,
+ "header": "Maintenance Plan",
+ "type": "Technical content",
+ "status": "Done",
+ "target": "16",
+ "limit": "23",
+ "reviewer": "Alex Thompson"
+ },
+ {
+ "id": 33,
+ "header": "User Personas",
+ "type": "Research",
+ "status": "In Process",
+ "target": "27",
+ "limit": "24",
+ "reviewer": "Nina Patel"
+ },
+ {
+ "id": 34,
+ "header": "Accessibility Compliance",
+ "type": "Legal",
+ "status": "Done",
+ "target": "18",
+ "limit": "21",
+ "reviewer": "Assign reviewer"
+ },
+ {
+ "id": 35,
+ "header": "Performance Metrics",
+ "type": "Technical content",
+ "status": "In Process",
+ "target": "23",
+ "limit": "26",
+ "reviewer": "David Kim"
+ },
+ {
+ "id": 36,
+ "header": "Disaster Recovery Plan",
+ "type": "Technical content",
+ "status": "Done",
+ "target": "14",
+ "limit": "17",
+ "reviewer": "Jamik Tashpulatov"
+ },
+ {
+ "id": 37,
+ "header": "Third-party Integrations",
+ "type": "Technical content",
+ "status": "In Process",
+ "target": "25",
+ "limit": "28",
+ "reviewer": "Eddie Lake"
+ },
+ {
+ "id": 38,
+ "header": "User Feedback Summary",
+ "type": "Research",
+ "status": "Done",
+ "target": "20",
+ "limit": "15",
+ "reviewer": "Assign reviewer"
+ },
+ {
+ "id": 39,
+ "header": "Localization Strategy",
+ "type": "Narrative",
+ "status": "In Process",
+ "target": "12",
+ "limit": "19",
+ "reviewer": "Maria Garcia"
+ },
+ {
+ "id": 40,
+ "header": "Mobile Compatibility",
+ "type": "Technical content",
+ "status": "Done",
+ "target": "28",
+ "limit": "31",
+ "reviewer": "James Wilson"
+ },
+ {
+ "id": 41,
+ "header": "Data Migration Plan",
+ "type": "Technical content",
+ "status": "In Process",
+ "target": "19",
+ "limit": "22",
+ "reviewer": "Assign reviewer"
+ },
+ {
+ "id": 42,
+ "header": "Quality Assurance Protocols",
+ "type": "Technical content",
+ "status": "Done",
+ "target": "30",
+ "limit": "33",
+ "reviewer": "Priya Singh"
+ },
+ {
+ "id": 43,
+ "header": "Stakeholder Analysis",
+ "type": "Research",
+ "status": "In Process",
+ "target": "11",
+ "limit": "14",
+ "reviewer": "Eddie Lake"
+ },
+ {
+ "id": 44,
+ "header": "Environmental Impact Assessment",
+ "type": "Research",
+ "status": "Done",
+ "target": "24",
+ "limit": "27",
+ "reviewer": "Assign reviewer"
+ },
+ {
+ "id": 45,
+ "header": "Intellectual Property Rights",
+ "type": "Legal",
+ "status": "In Process",
+ "target": "17",
+ "limit": "20",
+ "reviewer": "Sarah Johnson"
+ },
+ {
+ "id": 46,
+ "header": "Customer Support Framework",
+ "type": "Narrative",
+ "status": "Done",
+ "target": "22",
+ "limit": "25",
+ "reviewer": "Jamik Tashpulatov"
+ },
+ {
+ "id": 47,
+ "header": "Version Control Strategy",
+ "type": "Technical content",
+ "status": "In Process",
+ "target": "15",
+ "limit": "18",
+ "reviewer": "Assign reviewer"
+ },
+ {
+ "id": 48,
+ "header": "Continuous Integration Pipeline",
+ "type": "Technical content",
+ "status": "Done",
+ "target": "26",
+ "limit": "29",
+ "reviewer": "Michael Chen"
+ },
+ {
+ "id": 49,
+ "header": "Regulatory Compliance",
+ "type": "Legal",
+ "status": "In Process",
+ "target": "13",
+ "limit": "16",
+ "reviewer": "Assign reviewer"
+ },
+ {
+ "id": 50,
+ "header": "User Authentication System",
+ "type": "Technical content",
+ "status": "Done",
+ "target": "28",
+ "limit": "31",
+ "reviewer": "Eddie Lake"
+ },
+ {
+ "id": 51,
+ "header": "Data Analytics Framework",
+ "type": "Technical content",
+ "status": "In Process",
+ "target": "21",
+ "limit": "24",
+ "reviewer": "Jamik Tashpulatov"
+ },
+ {
+ "id": 52,
+ "header": "Cloud Infrastructure",
+ "type": "Technical content",
+ "status": "Done",
+ "target": "16",
+ "limit": "19",
+ "reviewer": "Assign reviewer"
+ },
+ {
+ "id": 53,
+ "header": "Network Security Measures",
+ "type": "Technical content",
+ "status": "In Process",
+ "target": "29",
+ "limit": "32",
+ "reviewer": "Lisa Wong"
+ },
+ {
+ "id": 54,
+ "header": "Project Timeline",
+ "type": "Planning",
+ "status": "Done",
+ "target": "14",
+ "limit": "17",
+ "reviewer": "Eddie Lake"
+ },
+ {
+ "id": 55,
+ "header": "Resource Allocation",
+ "type": "Planning",
+ "status": "In Process",
+ "target": "27",
+ "limit": "30",
+ "reviewer": "Assign reviewer"
+ },
+ {
+ "id": 56,
+ "header": "Team Structure and Roles",
+ "type": "Planning",
+ "status": "Done",
+ "target": "20",
+ "limit": "23",
+ "reviewer": "Jamik Tashpulatov"
+ },
+ {
+ "id": 57,
+ "header": "Communication Protocols",
+ "type": "Planning",
+ "status": "In Process",
+ "target": "15",
+ "limit": "18",
+ "reviewer": "Assign reviewer"
+ },
+ {
+ "id": 58,
+ "header": "Success Metrics",
+ "type": "Planning",
+ "status": "Done",
+ "target": "30",
+ "limit": "33",
+ "reviewer": "Eddie Lake"
+ },
+ {
+ "id": 59,
+ "header": "Internationalization Support",
+ "type": "Technical content",
+ "status": "In Process",
+ "target": "23",
+ "limit": "26",
+ "reviewer": "Jamik Tashpulatov"
+ },
+ {
+ "id": 60,
+ "header": "Backup and Recovery Procedures",
+ "type": "Technical content",
+ "status": "Done",
+ "target": "18",
+ "limit": "21",
+ "reviewer": "Assign reviewer"
+ },
+ {
+ "id": 61,
+ "header": "Monitoring and Alerting System",
+ "type": "Technical content",
+ "status": "In Process",
+ "target": "25",
+ "limit": "28",
+ "reviewer": "Daniel Park"
+ },
+ {
+ "id": 62,
+ "header": "Code Review Guidelines",
+ "type": "Technical content",
+ "status": "Done",
+ "target": "12",
+ "limit": "15",
+ "reviewer": "Eddie Lake"
+ },
+ {
+ "id": 63,
+ "header": "Documentation Standards",
+ "type": "Technical content",
+ "status": "In Process",
+ "target": "27",
+ "limit": "30",
+ "reviewer": "Jamik Tashpulatov"
+ },
+ {
+ "id": 64,
+ "header": "Release Management Process",
+ "type": "Planning",
+ "status": "Done",
+ "target": "22",
+ "limit": "25",
+ "reviewer": "Assign reviewer"
+ },
+ {
+ "id": 65,
+ "header": "Feature Prioritization Matrix",
+ "type": "Planning",
+ "status": "In Process",
+ "target": "19",
+ "limit": "22",
+ "reviewer": "Emma Davis"
+ },
+ {
+ "id": 66,
+ "header": "Technical Debt Assessment",
+ "type": "Technical content",
+ "status": "Done",
+ "target": "24",
+ "limit": "27",
+ "reviewer": "Eddie Lake"
+ },
+ {
+ "id": 67,
+ "header": "Capacity Planning",
+ "type": "Planning",
+ "status": "In Process",
+ "target": "21",
+ "limit": "24",
+ "reviewer": "Jamik Tashpulatov"
+ },
+ {
+ "id": 68,
+ "header": "Service Level Agreements",
+ "type": "Legal",
+ "status": "Done",
+ "target": "26",
+ "limit": "29",
+ "reviewer": "Assign reviewer"
+ }
+]
diff --git a/app/(dev)/showcase/layout.tsx b/app/(dev)/showcase/layout.tsx
new file mode 100644
index 0000000..e28f780
--- /dev/null
+++ b/app/(dev)/showcase/layout.tsx
@@ -0,0 +1,24 @@
+import { AppSidebar } from "@components/app-sidebar"
+import { SidebarInset, SidebarProvider } from "@components/ui/sidebar"
+import { SiteHeader } from "@components/site-header"
+
+export default function ShowcaseLayout({ children }: { children: React.ReactNode }) {
+ return (
+
+
+
+
+
+
+
+ )
+}
diff --git a/app/(dev)/showcase/page.tsx b/app/(dev)/showcase/page.tsx
new file mode 100644
index 0000000..363fcb1
--- /dev/null
+++ b/app/(dev)/showcase/page.tsx
@@ -0,0 +1,19 @@
+import { ChartAreaInteractive } from "@components/chart-area-interactive"
+import { DataTable } from "@components/data-table"
+import { SectionCards } from "@components/section-cards"
+import { SiteHeader } from "@components/site-header"
+import { SidebarInset, SidebarProvider } from "@components/ui/sidebar"
+
+import data from "./data.json"
+
+export default function Page() {
+ return (
+
+ )
+}
diff --git a/app/error.tsx b/app/error.tsx
new file mode 100644
index 0000000..5480532
--- /dev/null
+++ b/app/error.tsx
@@ -0,0 +1,40 @@
+"use client" // Error boundaries must be Client Components
+
+import { AlertCircle } from "lucide-react"
+import { useEffect } from "react"
+import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
+
+interface ErrorProps {
+ title: string
+ description: string
+}
+
+function ErrorAlert(errorProps: ErrorProps) {
+ return (
+
+
+ {errorProps.title}
+ {errorProps.description}
+
+ )
+}
+
+export default function Error({ error, reset }: { error: Error & { digest?: string }; reset: () => void }) {
+ useEffect(() => {
+ // Log the error to an error reporting service
+ console.error(error)
+ }, [error])
+
+ return (
+
+
+
+ reset()}
+ >
+ Try again
+
+
+ )
+}
diff --git a/app/forbidden.tsx b/app/forbidden.tsx
new file mode 100644
index 0000000..afc11a2
--- /dev/null
+++ b/app/forbidden.tsx
@@ -0,0 +1,42 @@
+"use client"
+
+import { AlertCircle, ArrowLeft, ShieldX } from "lucide-react"
+import Link from "next/link"
+import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
+import { Button } from "@/components/ui/button"
+import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
+
+export default function Forbidden() {
+ return (
+
+
+
+
+
+ Access Forbidden
+
+ You don't have permission to access this resource
+
+
+
+
+ Error 403
+
+ You lack the necessary permissions to view this page. If you believe this is an error, please contact your
+ administrator.
+
+
+
+
+ window.history.back()}>
+
+ Go Back
+
+
+ Return Home
+
+
+
+
+ )
+}
diff --git a/app/icon.svg b/app/icon.svg
new file mode 100644
index 0000000..ccb7d8f
--- /dev/null
+++ b/app/icon.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/app/layout.tsx b/app/layout.tsx
index a872374..8b8a66f 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,5 +1,19 @@
import "styles/tailwind.css"
+// app/layout.tsx
+export const metadata = {
+ openGraph: {
+ images: [
+ {
+ url: "/social-icon.svg", // Place it in public folder
+ width: 800,
+ height: 600,
+ alt: "Social share image",
+ },
+ ],
+ },
+}
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
diff --git a/app/loading.tsx b/app/loading.tsx
new file mode 100644
index 0000000..745cadb
--- /dev/null
+++ b/app/loading.tsx
@@ -0,0 +1,41 @@
+import { Card, CardContent, CardFooter, CardHeader } from "@/components/ui/card"
+import { Skeleton } from "@/components/ui/skeleton"
+
+export default function Loading() {
+ return (
+
+
+
+
+
+
+ {/* Skeleton cards - repeat for multiple items */}
+ {Array(3)
+ .fill(0)
+ .map((_, index) => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ))}
+
+ )
+}
diff --git a/app/not-found.tsx b/app/not-found.tsx
new file mode 100644
index 0000000..95a5964
--- /dev/null
+++ b/app/not-found.tsx
@@ -0,0 +1,37 @@
+"use client"
+import { ArrowLeft, FileQuestion, Home } from "lucide-react"
+import Link from "next/link"
+import { Button } from "@/components/ui/button"
+import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
+
+export default function NotFound() {
+ return (
+
+
+
+
+
+ Page Not Found
+
+ We couldn't find the page you were looking for
+
+
+ The page you requested doesn't exist or may have been moved.
+ Error 404
+
+
+ window.history.back()}>
+
+ Go Back
+
+
+
+
+ Return Home
+
+
+
+
+
+ )
+}
diff --git a/app/unauthorized.tsx b/app/unauthorized.tsx
new file mode 100644
index 0000000..30075dd
--- /dev/null
+++ b/app/unauthorized.tsx
@@ -0,0 +1,25 @@
+import { Lock } from "lucide-react"
+
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
+
+export default function Unauthorized() {
+ return (
+
+
+
+
+
+ Unauthorized Access
+
+ Please log in to access this page
+
+
+
+
You need to be authenticated to view the requested resource.
+
Error 401
+
+
+
+
+ )
+}
diff --git a/app/under-development/page.tsx b/app/under-development/page.tsx
new file mode 100644
index 0000000..9c664f6
--- /dev/null
+++ b/app/under-development/page.tsx
@@ -0,0 +1,77 @@
+import { ArrowRight, Construction, MessageCircle, Send, Share2 } from "lucide-react"
+import Image from "next/image"
+import Link from "next/link"
+import { Badge } from "@/components/ui/badge"
+import { Button } from "@/components/ui/button"
+import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
+import { Separator } from "@/components/ui/separator"
+
+export default function UnderDevelopment() {
+ return (
+
+
+
+
+
+
+
+
+
+
+ Chat Guide Coming Soon
+
+
+ Soon
+
+
+
+ I'm creating a blog to share my chat techniques, tips, and personal experiences from OnlyFans
+
+
+
+
+
+
+
+
+
My blog is almost ready!
+
+ I'm putting together my best chat strategies, engagement tips, and stories from my personal experience
+ to help other creators connect better with their fans.
+
+
+
+
+
+
What I'll be sharing:
+
+ Chat techniques that increase engagement
+ How to build genuine connections
+ Tips for managing conversations
+ Real examples from my experience
+
+
+
+
+
+
+ Email me
+
+
+
+
+ Telegram
+
+
+
+
+
+ )
+}
diff --git a/components.json b/components.json
new file mode 100644
index 0000000..eca2c74
--- /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": "tailwind.config.js",
+ "css": "styles/tailwind.css",
+ "baseColor": "stone",
+ "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/app-sidebar.tsx b/components/app-sidebar.tsx
new file mode 100644
index 0000000..d325a5a
--- /dev/null
+++ b/components/app-sidebar.tsx
@@ -0,0 +1,178 @@
+"use client"
+
+import {
+ IconCamera,
+ IconChartBar,
+ IconDashboard,
+ IconDatabase,
+ IconFileAi,
+ IconFileDescription,
+ IconFileWord,
+ IconFolder,
+ IconHelp,
+ IconInnerShadowTop,
+ IconListDetails,
+ IconReport,
+ IconSearch,
+ IconSettings,
+ IconUsers,
+} from "@tabler/icons-react"
+import * as React from "react"
+
+import { NavDocuments } from "@/components/nav-documents"
+import { NavMain } from "@/components/nav-main"
+import { NavSecondary } from "@/components/nav-secondary"
+import { NavUser } from "@/components/nav-user"
+import {
+ Sidebar,
+ SidebarContent,
+ SidebarFooter,
+ SidebarHeader,
+ SidebarMenu,
+ SidebarMenuButton,
+ SidebarMenuItem,
+} from "@/components/ui/sidebar"
+
+const data = {
+ user: {
+ name: "shadcn",
+ email: "m@example.com",
+ avatar: "/avatars/shadcn.jpg",
+ },
+ navMain: [
+ {
+ title: "Dashboard",
+ url: "#",
+ icon: IconDashboard,
+ },
+ {
+ title: "Lifecycle",
+ url: "#",
+ icon: IconListDetails,
+ },
+ {
+ title: "Analytics",
+ url: "#",
+ icon: IconChartBar,
+ },
+ {
+ title: "Projects",
+ url: "#",
+ icon: IconFolder,
+ },
+ {
+ title: "Team",
+ url: "#",
+ icon: IconUsers,
+ },
+ ],
+ navClouds: [
+ {
+ title: "Capture",
+ icon: IconCamera,
+ isActive: true,
+ url: "#",
+ items: [
+ {
+ title: "Active Proposals",
+ url: "#",
+ },
+ {
+ title: "Archived",
+ url: "#",
+ },
+ ],
+ },
+ {
+ title: "Proposal",
+ icon: IconFileDescription,
+ url: "#",
+ items: [
+ {
+ title: "Active Proposals",
+ url: "#",
+ },
+ {
+ title: "Archived",
+ url: "#",
+ },
+ ],
+ },
+ {
+ title: "Prompts",
+ icon: IconFileAi,
+ url: "#",
+ items: [
+ {
+ title: "Active Proposals",
+ url: "#",
+ },
+ {
+ title: "Archived",
+ url: "#",
+ },
+ ],
+ },
+ ],
+ navSecondary: [
+ {
+ title: "Settings",
+ url: "#",
+ icon: IconSettings,
+ },
+ {
+ title: "Get Help",
+ url: "#",
+ icon: IconHelp,
+ },
+ {
+ title: "Search",
+ url: "#",
+ icon: IconSearch,
+ },
+ ],
+ documents: [
+ {
+ name: "Data Library",
+ url: "#",
+ icon: IconDatabase,
+ },
+ {
+ name: "Reports",
+ url: "#",
+ icon: IconReport,
+ },
+ {
+ name: "Word Assistant",
+ url: "#",
+ icon: IconFileWord,
+ },
+ ],
+}
+
+export function AppSidebar({ ...props }: React.ComponentProps) {
+ return (
+
+
+
+
+
+
+
+ Acme Inc.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/components/chart-area-interactive.tsx b/components/chart-area-interactive.tsx
new file mode 100644
index 0000000..18fefaa
--- /dev/null
+++ b/components/chart-area-interactive.tsx
@@ -0,0 +1,238 @@
+"use client"
+
+import * as React from "react"
+import { Area, AreaChart, CartesianGrid, XAxis } from "recharts"
+
+import { useIsMobile } from "@/hooks/use-mobile"
+import { Card, CardAction, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
+import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from "@/components/ui/chart"
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
+import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
+
+export const description = "An interactive area chart"
+
+const chartData = [
+ { date: "2024-04-01", desktop: 222, mobile: 150 },
+ { date: "2024-04-02", desktop: 97, mobile: 180 },
+ { date: "2024-04-03", desktop: 167, mobile: 120 },
+ { date: "2024-04-04", desktop: 242, mobile: 260 },
+ { date: "2024-04-05", desktop: 373, mobile: 290 },
+ { date: "2024-04-06", desktop: 301, mobile: 340 },
+ { date: "2024-04-07", desktop: 245, mobile: 180 },
+ { date: "2024-04-08", desktop: 409, mobile: 320 },
+ { date: "2024-04-09", desktop: 59, mobile: 110 },
+ { date: "2024-04-10", desktop: 261, mobile: 190 },
+ { date: "2024-04-11", desktop: 327, mobile: 350 },
+ { date: "2024-04-12", desktop: 292, mobile: 210 },
+ { date: "2024-04-13", desktop: 342, mobile: 380 },
+ { date: "2024-04-14", desktop: 137, mobile: 220 },
+ { date: "2024-04-15", desktop: 120, mobile: 170 },
+ { date: "2024-04-16", desktop: 138, mobile: 190 },
+ { date: "2024-04-17", desktop: 446, mobile: 360 },
+ { date: "2024-04-18", desktop: 364, mobile: 410 },
+ { date: "2024-04-19", desktop: 243, mobile: 180 },
+ { date: "2024-04-20", desktop: 89, mobile: 150 },
+ { date: "2024-04-21", desktop: 137, mobile: 200 },
+ { date: "2024-04-22", desktop: 224, mobile: 170 },
+ { date: "2024-04-23", desktop: 138, mobile: 230 },
+ { date: "2024-04-24", desktop: 387, mobile: 290 },
+ { date: "2024-04-25", desktop: 215, mobile: 250 },
+ { date: "2024-04-26", desktop: 75, mobile: 130 },
+ { date: "2024-04-27", desktop: 383, mobile: 420 },
+ { date: "2024-04-28", desktop: 122, mobile: 180 },
+ { date: "2024-04-29", desktop: 315, mobile: 240 },
+ { date: "2024-04-30", desktop: 454, mobile: 380 },
+ { date: "2024-05-01", desktop: 165, mobile: 220 },
+ { date: "2024-05-02", desktop: 293, mobile: 310 },
+ { date: "2024-05-03", desktop: 247, mobile: 190 },
+ { date: "2024-05-04", desktop: 385, mobile: 420 },
+ { date: "2024-05-05", desktop: 481, mobile: 390 },
+ { date: "2024-05-06", desktop: 498, mobile: 520 },
+ { date: "2024-05-07", desktop: 388, mobile: 300 },
+ { date: "2024-05-08", desktop: 149, mobile: 210 },
+ { date: "2024-05-09", desktop: 227, mobile: 180 },
+ { date: "2024-05-10", desktop: 293, mobile: 330 },
+ { date: "2024-05-11", desktop: 335, mobile: 270 },
+ { date: "2024-05-12", desktop: 197, mobile: 240 },
+ { date: "2024-05-13", desktop: 197, mobile: 160 },
+ { date: "2024-05-14", desktop: 448, mobile: 490 },
+ { date: "2024-05-15", desktop: 473, mobile: 380 },
+ { date: "2024-05-16", desktop: 338, mobile: 400 },
+ { date: "2024-05-17", desktop: 499, mobile: 420 },
+ { date: "2024-05-18", desktop: 315, mobile: 350 },
+ { date: "2024-05-19", desktop: 235, mobile: 180 },
+ { date: "2024-05-20", desktop: 177, mobile: 230 },
+ { date: "2024-05-21", desktop: 82, mobile: 140 },
+ { date: "2024-05-22", desktop: 81, mobile: 120 },
+ { date: "2024-05-23", desktop: 252, mobile: 290 },
+ { date: "2024-05-24", desktop: 294, mobile: 220 },
+ { date: "2024-05-25", desktop: 201, mobile: 250 },
+ { date: "2024-05-26", desktop: 213, mobile: 170 },
+ { date: "2024-05-27", desktop: 420, mobile: 460 },
+ { date: "2024-05-28", desktop: 233, mobile: 190 },
+ { date: "2024-05-29", desktop: 78, mobile: 130 },
+ { date: "2024-05-30", desktop: 340, mobile: 280 },
+ { date: "2024-05-31", desktop: 178, mobile: 230 },
+ { date: "2024-06-01", desktop: 178, mobile: 200 },
+ { date: "2024-06-02", desktop: 470, mobile: 410 },
+ { date: "2024-06-03", desktop: 103, mobile: 160 },
+ { date: "2024-06-04", desktop: 439, mobile: 380 },
+ { date: "2024-06-05", desktop: 88, mobile: 140 },
+ { date: "2024-06-06", desktop: 294, mobile: 250 },
+ { date: "2024-06-07", desktop: 323, mobile: 370 },
+ { date: "2024-06-08", desktop: 385, mobile: 320 },
+ { date: "2024-06-09", desktop: 438, mobile: 480 },
+ { date: "2024-06-10", desktop: 155, mobile: 200 },
+ { date: "2024-06-11", desktop: 92, mobile: 150 },
+ { date: "2024-06-12", desktop: 492, mobile: 420 },
+ { date: "2024-06-13", desktop: 81, mobile: 130 },
+ { date: "2024-06-14", desktop: 426, mobile: 380 },
+ { date: "2024-06-15", desktop: 307, mobile: 350 },
+ { date: "2024-06-16", desktop: 371, mobile: 310 },
+ { date: "2024-06-17", desktop: 475, mobile: 520 },
+ { date: "2024-06-18", desktop: 107, mobile: 170 },
+ { date: "2024-06-19", desktop: 341, mobile: 290 },
+ { date: "2024-06-20", desktop: 408, mobile: 450 },
+ { date: "2024-06-21", desktop: 169, mobile: 210 },
+ { date: "2024-06-22", desktop: 317, mobile: 270 },
+ { date: "2024-06-23", desktop: 480, mobile: 530 },
+ { date: "2024-06-24", desktop: 132, mobile: 180 },
+ { date: "2024-06-25", desktop: 141, mobile: 190 },
+ { date: "2024-06-26", desktop: 434, mobile: 380 },
+ { date: "2024-06-27", desktop: 448, mobile: 490 },
+ { date: "2024-06-28", desktop: 149, mobile: 200 },
+ { date: "2024-06-29", desktop: 103, mobile: 160 },
+ { date: "2024-06-30", desktop: 446, mobile: 400 },
+]
+
+const chartConfig = {
+ visitors: {
+ label: "Visitors",
+ },
+ desktop: {
+ label: "Desktop",
+ color: "var(--primary)",
+ },
+ mobile: {
+ label: "Mobile",
+ color: "var(--primary)",
+ },
+} satisfies ChartConfig
+
+export function ChartAreaInteractive() {
+ const isMobile = useIsMobile()
+ const [timeRange, setTimeRange] = React.useState("90d")
+
+ React.useEffect(() => {
+ if (isMobile) {
+ setTimeRange("7d")
+ }
+ }, [isMobile])
+
+ const filteredData = chartData.filter((item) => {
+ const date = new Date(item.date)
+ const referenceDate = new Date("2024-06-30")
+ let daysToSubtract = 90
+ if (timeRange === "30d") {
+ daysToSubtract = 30
+ } else if (timeRange === "7d") {
+ daysToSubtract = 7
+ }
+ const startDate = new Date(referenceDate)
+ startDate.setDate(startDate.getDate() - daysToSubtract)
+ return date >= startDate
+ })
+
+ return (
+
+
+ Total Visitors
+
+ Total for the last 3 months
+ Last 3 months
+
+
+
+ Last 3 months
+ Last 30 days
+ Last 7 days
+
+
+
+
+
+
+
+ Last 3 months
+
+
+ Last 30 days
+
+
+ Last 7 days
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ const date = new Date(value)
+ return date.toLocaleDateString("en-US", {
+ month: "short",
+ day: "numeric",
+ })
+ }}
+ />
+ {
+ return new Date(value).toLocaleDateString("en-US", {
+ month: "short",
+ day: "numeric",
+ })
+ }}
+ indicator="dot"
+ />
+ }
+ />
+
+
+
+
+
+
+ )
+}
diff --git a/components/data-table.tsx b/components/data-table.tsx
new file mode 100644
index 0000000..6bc1b92
--- /dev/null
+++ b/components/data-table.tsx
@@ -0,0 +1,703 @@
+"use client"
+
+import * as React from "react"
+import {
+ DndContext,
+ KeyboardSensor,
+ MouseSensor,
+ TouchSensor,
+ closestCenter,
+ useSensor,
+ useSensors,
+ type DragEndEvent,
+ type UniqueIdentifier,
+} from "@dnd-kit/core"
+import { restrictToVerticalAxis } from "@dnd-kit/modifiers"
+import { SortableContext, arrayMove, useSortable, verticalListSortingStrategy } from "@dnd-kit/sortable"
+import { CSS } from "@dnd-kit/utilities"
+import {
+ IconChevronDown,
+ IconChevronLeft,
+ IconChevronRight,
+ IconChevronsLeft,
+ IconChevronsRight,
+ IconCircleCheckFilled,
+ IconDotsVertical,
+ IconGripVertical,
+ IconLayoutColumns,
+ IconLoader,
+ IconPlus,
+ IconTrendingUp,
+} from "@tabler/icons-react"
+import {
+ ColumnDef,
+ ColumnFiltersState,
+ Row,
+ SortingState,
+ VisibilityState,
+ flexRender,
+ getCoreRowModel,
+ getFacetedRowModel,
+ getFacetedUniqueValues,
+ getFilteredRowModel,
+ getPaginationRowModel,
+ getSortedRowModel,
+ useReactTable,
+} from "@tanstack/react-table"
+import { Area, AreaChart, CartesianGrid, XAxis } from "recharts"
+import { toast } from "sonner"
+import { z } from "zod"
+
+import { useIsMobile } from "@/hooks/use-mobile"
+import { Badge } from "@/components/ui/badge"
+import { Button } from "@/components/ui/button"
+import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from "@/components/ui/chart"
+import { Checkbox } from "@/components/ui/checkbox"
+import {
+ Drawer,
+ DrawerClose,
+ DrawerContent,
+ DrawerDescription,
+ DrawerFooter,
+ DrawerHeader,
+ DrawerTitle,
+ DrawerTrigger,
+} from "@/components/ui/drawer"
+import {
+ DropdownMenu,
+ DropdownMenuCheckboxItem,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuSeparator,
+ DropdownMenuTrigger,
+} from "@/components/ui/dropdown-menu"
+import { Input } from "@/components/ui/input"
+import { Label } from "@/components/ui/label"
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
+import { Separator } from "@/components/ui/separator"
+import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
+import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
+
+export const schema = z.object({
+ id: z.number(),
+ header: z.string(),
+ type: z.string(),
+ status: z.string(),
+ target: z.string(),
+ limit: z.string(),
+ reviewer: z.string(),
+})
+
+// Create a separate component for the drag handle
+function DragHandle({ id }: { id: number }) {
+ const { attributes, listeners } = useSortable({
+ id,
+ })
+
+ return (
+
+
+ Drag to reorder
+
+ )
+}
+
+const columns: ColumnDef>[] = [
+ {
+ id: "drag",
+ header: () => null,
+ cell: ({ row }) => ,
+ },
+ {
+ id: "select",
+ header: ({ table }) => (
+
+ table.toggleAllPageRowsSelected(!!value)}
+ aria-label="Select all"
+ />
+
+ ),
+ cell: ({ row }) => (
+
+ row.toggleSelected(!!value)}
+ aria-label="Select row"
+ />
+
+ ),
+ enableSorting: false,
+ enableHiding: false,
+ },
+ {
+ accessorKey: "header",
+ header: "Header",
+ cell: ({ row }) => {
+ return
+ },
+ enableHiding: false,
+ },
+ {
+ accessorKey: "type",
+ header: "Section Type",
+ cell: ({ row }) => (
+
+
+ {row.original.type}
+
+
+ ),
+ },
+ {
+ accessorKey: "status",
+ header: "Status",
+ cell: ({ row }) => (
+
+ {row.original.status === "Done" ? (
+
+ ) : (
+
+ )}
+ {row.original.status}
+
+ ),
+ },
+ {
+ accessorKey: "target",
+ header: () => Target
,
+ cell: ({ row }) => (
+
+ ),
+ },
+ {
+ accessorKey: "limit",
+ header: () => Limit
,
+ cell: ({ row }) => (
+
+ ),
+ },
+ {
+ accessorKey: "reviewer",
+ header: "Reviewer",
+ cell: ({ row }) => {
+ const isAssigned = row.original.reviewer !== "Assign reviewer"
+
+ if (isAssigned) {
+ return row.original.reviewer
+ }
+
+ return (
+ <>
+
+ Reviewer
+
+
+
+
+
+
+ Eddie Lake
+ Jamik Tashpulatov
+
+
+ >
+ )
+ },
+ },
+ {
+ id: "actions",
+ cell: () => (
+
+
+
+
+ Open menu
+
+
+
+ Edit
+ Make a copy
+ Favorite
+
+ Delete
+
+
+ ),
+ },
+]
+
+function DraggableRow({ row }: { row: Row> }) {
+ const { transform, transition, setNodeRef, isDragging } = useSortable({
+ id: row.original.id,
+ })
+
+ return (
+
+ {row.getVisibleCells().map((cell) => (
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
+ ))}
+
+ )
+}
+
+export function DataTable({ data: initialData }: { data: z.infer[] }) {
+ const [data, setData] = React.useState(() => initialData)
+ const [rowSelection, setRowSelection] = React.useState({})
+ const [columnVisibility, setColumnVisibility] = React.useState({})
+ const [columnFilters, setColumnFilters] = React.useState([])
+ const [sorting, setSorting] = React.useState([])
+ const [pagination, setPagination] = React.useState({
+ pageIndex: 0,
+ pageSize: 10,
+ })
+ const sortableId = React.useId()
+ const sensors = useSensors(useSensor(MouseSensor, {}), useSensor(TouchSensor, {}), useSensor(KeyboardSensor, {}))
+
+ const dataIds = React.useMemo(() => data?.map(({ id }) => id) || [], [data])
+
+ const table = useReactTable({
+ data,
+ columns,
+ state: {
+ sorting,
+ columnVisibility,
+ rowSelection,
+ columnFilters,
+ pagination,
+ },
+ getRowId: (row) => row.id.toString(),
+ enableRowSelection: true,
+ onRowSelectionChange: setRowSelection,
+ onSortingChange: setSorting,
+ onColumnFiltersChange: setColumnFilters,
+ onColumnVisibilityChange: setColumnVisibility,
+ onPaginationChange: setPagination,
+ getCoreRowModel: getCoreRowModel(),
+ getFilteredRowModel: getFilteredRowModel(),
+ getPaginationRowModel: getPaginationRowModel(),
+ getSortedRowModel: getSortedRowModel(),
+ getFacetedRowModel: getFacetedRowModel(),
+ getFacetedUniqueValues: getFacetedUniqueValues(),
+ })
+
+ function handleDragEnd(event: DragEndEvent) {
+ const { active, over } = event
+ if (active && over && active.id !== over.id) {
+ setData((data) => {
+ const oldIndex = dataIds.indexOf(active.id)
+ const newIndex = dataIds.indexOf(over.id)
+ return arrayMove(data, oldIndex, newIndex)
+ })
+ }
+ }
+
+ return (
+
+
+
+ View
+
+
+
+
+
+
+ Outline
+ Past Performance
+ Key Personnel
+ Focus Documents
+
+
+
+ Outline
+
+ Past Performance 3
+
+
+ Key Personnel 2
+
+ Focus Documents
+
+
+
+
+
+
+ Customize Columns
+ Columns
+
+
+
+
+ {table
+ .getAllColumns()
+ .filter((column) => typeof column.accessorFn !== "undefined" && column.getCanHide())
+ .map((column) => {
+ return (
+ column.toggleVisibility(!!value)}
+ >
+ {column.id}
+
+ )
+ })}
+
+
+
+
+ Add Section
+
+
+
+
+
+
+
+
+ {table.getHeaderGroups().map((headerGroup) => (
+
+ {headerGroup.headers.map((header) => {
+ return (
+
+ {header.isPlaceholder
+ ? null
+ : flexRender(header.column.columnDef.header, header.getContext())}
+
+ )
+ })}
+
+ ))}
+
+
+ {table.getRowModel().rows?.length ? (
+
+ {table.getRowModel().rows.map((row) => (
+
+ ))}
+
+ ) : (
+
+
+ No results.
+
+
+ )}
+
+
+
+
+
+
+ {table.getFilteredSelectedRowModel().rows.length} of {table.getFilteredRowModel().rows.length} row(s)
+ selected.
+
+
+
+
+ Rows per page
+
+ {
+ table.setPageSize(Number(value))
+ }}
+ >
+
+
+
+
+ {[10, 20, 30, 40, 50].map((pageSize) => (
+
+ {pageSize}
+
+ ))}
+
+
+
+
+ Page {table.getState().pagination.pageIndex + 1} of {table.getPageCount()}
+
+
+ table.setPageIndex(0)}
+ disabled={!table.getCanPreviousPage()}
+ >
+ Go to first page
+
+
+ table.previousPage()}
+ disabled={!table.getCanPreviousPage()}
+ >
+ Go to previous page
+
+
+ table.nextPage()}
+ disabled={!table.getCanNextPage()}
+ >
+ Go to next page
+
+
+ table.setPageIndex(table.getPageCount() - 1)}
+ disabled={!table.getCanNextPage()}
+ >
+ Go to last page
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+const chartData = [
+ { month: "January", desktop: 186, mobile: 80 },
+ { month: "February", desktop: 305, mobile: 200 },
+ { month: "March", desktop: 237, mobile: 120 },
+ { month: "April", desktop: 73, mobile: 190 },
+ { month: "May", desktop: 209, mobile: 130 },
+ { month: "June", desktop: 214, mobile: 140 },
+]
+
+const chartConfig = {
+ desktop: {
+ label: "Desktop",
+ color: "var(--primary)",
+ },
+ mobile: {
+ label: "Mobile",
+ color: "var(--primary)",
+ },
+} satisfies ChartConfig
+
+function TableCellViewer({ item }: { item: z.infer }) {
+ const isMobile = useIsMobile()
+
+ return (
+
+
+
+ {item.header}
+
+
+
+
+ {item.header}
+ Showing total visitors for the last 6 months
+
+
+ {!isMobile && (
+ <>
+
+
+
+ value.slice(0, 3)}
+ hide
+ />
+ } />
+
+
+
+
+
+
+
+ Trending up by 5.2% this month
+
+
+ Showing total visitors for the last 6 months. This is just some random text to test the layout. It
+ spans multiple lines and should wrap around.
+
+
+
+ >
+ )}
+
+
+
+ Submit
+
+ Done
+
+
+
+
+ )
+}
diff --git a/components/nav-documents.tsx b/components/nav-documents.tsx
new file mode 100644
index 0000000..dd2d74c
--- /dev/null
+++ b/components/nav-documents.tsx
@@ -0,0 +1,83 @@
+"use client"
+
+import { IconDots, IconFolder, IconShare3, IconTrash, type Icon } from "@tabler/icons-react"
+
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuSeparator,
+ DropdownMenuTrigger,
+} from "@/components/ui/dropdown-menu"
+import {
+ SidebarGroup,
+ SidebarGroupLabel,
+ SidebarMenu,
+ SidebarMenuAction,
+ SidebarMenuButton,
+ SidebarMenuItem,
+ useSidebar,
+} from "@/components/ui/sidebar"
+
+export function NavDocuments({
+ items,
+}: {
+ items: {
+ name: string
+ url: string
+ icon: Icon
+ }[]
+}) {
+ const { isMobile } = useSidebar()
+
+ return (
+
+ Documents
+
+ {items.map((item) => (
+
+
+
+
+ {item.name}
+
+
+
+
+
+
+ More
+
+
+
+
+
+ Open
+
+
+
+ Share
+
+
+
+
+ Delete
+
+
+
+
+ ))}
+
+
+
+ More
+
+
+
+
+ )
+}
diff --git a/components/nav-main.tsx b/components/nav-main.tsx
new file mode 100644
index 0000000..7a4ffb5
--- /dev/null
+++ b/components/nav-main.tsx
@@ -0,0 +1,54 @@
+"use client"
+
+import { IconCirclePlusFilled, IconMail, type Icon } from "@tabler/icons-react"
+
+import { Button } from "@/components/ui/button"
+import {
+ SidebarGroup,
+ SidebarGroupContent,
+ SidebarMenu,
+ SidebarMenuButton,
+ SidebarMenuItem,
+} from "@/components/ui/sidebar"
+
+export function NavMain({
+ items,
+}: {
+ items: {
+ title: string
+ url: string
+ icon?: Icon
+ }[]
+}) {
+ return (
+
+
+
+
+
+
+ Quick Create
+
+
+
+ Inbox
+
+
+
+
+ {items.map((item) => (
+
+
+ {item.icon && }
+ {item.title}
+
+
+ ))}
+
+
+
+ )
+}
diff --git a/components/nav-secondary.tsx b/components/nav-secondary.tsx
new file mode 100644
index 0000000..3f3636f
--- /dev/null
+++ b/components/nav-secondary.tsx
@@ -0,0 +1,42 @@
+"use client"
+
+import * as React from "react"
+import { type Icon } from "@tabler/icons-react"
+
+import {
+ SidebarGroup,
+ SidebarGroupContent,
+ SidebarMenu,
+ SidebarMenuButton,
+ SidebarMenuItem,
+} from "@/components/ui/sidebar"
+
+export function NavSecondary({
+ items,
+ ...props
+}: {
+ items: {
+ title: string
+ url: string
+ icon: Icon
+ }[]
+} & React.ComponentPropsWithoutRef) {
+ return (
+
+
+
+ {items.map((item) => (
+
+
+
+
+ {item.title}
+
+
+
+ ))}
+
+
+
+ )
+}
diff --git a/components/nav-user.tsx b/components/nav-user.tsx
new file mode 100644
index 0000000..924e138
--- /dev/null
+++ b/components/nav-user.tsx
@@ -0,0 +1,91 @@
+"use client"
+
+import { IconCreditCard, IconDotsVertical, IconLogout, IconNotification, IconUserCircle } from "@tabler/icons-react"
+
+import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuGroup,
+ DropdownMenuItem,
+ DropdownMenuLabel,
+ DropdownMenuSeparator,
+ DropdownMenuTrigger,
+} from "@/components/ui/dropdown-menu"
+import { SidebarMenu, SidebarMenuButton, SidebarMenuItem, useSidebar } from "@/components/ui/sidebar"
+
+export function NavUser({
+ user,
+}: {
+ user: {
+ name: string
+ email: string
+ avatar: string
+ }
+}) {
+ const { isMobile } = useSidebar()
+
+ return (
+
+
+
+
+
+
+
+ CN
+
+
+ {user.name}
+ {user.email}
+
+
+
+
+
+
+
+
+
+ CN
+
+
+ {user.name}
+ {user.email}
+
+
+
+
+
+
+
+ Account
+
+
+
+ Billing
+
+
+
+ Notifications
+
+
+
+
+
+ Log out
+
+
+
+
+
+ )
+}
diff --git a/components/section-cards.tsx b/components/section-cards.tsx
new file mode 100644
index 0000000..a277d46
--- /dev/null
+++ b/components/section-cards.tsx
@@ -0,0 +1,83 @@
+import { IconTrendingDown, IconTrendingUp } from "@tabler/icons-react"
+
+import { Badge } from "@/components/ui/badge"
+import { Card, CardAction, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
+
+export function SectionCards() {
+ return (
+
+
+
+ Total Revenue
+ $1,250.00
+
+
+
+ +12.5%
+
+
+
+
+
+ Trending up this month
+
+ Visitors for the last 6 months
+
+
+
+
+ New Customers
+ 1,234
+
+
+
+ -20%
+
+
+
+
+
+ Down 20% this period
+
+ Acquisition needs attention
+
+
+
+
+ Active Accounts
+ 45,678
+
+
+
+ +12.5%
+
+
+
+
+
+ Strong user retention
+
+ Engagement exceed targets
+
+
+
+
+ Growth Rate
+ 4.5%
+
+
+
+ +4.5%
+
+
+
+
+
+ Steady performance increase
+
+ Meets growth projections
+
+
+
+ )
+}
diff --git a/components/site-header.tsx b/components/site-header.tsx
new file mode 100644
index 0000000..33808c9
--- /dev/null
+++ b/components/site-header.tsx
@@ -0,0 +1,27 @@
+import { Button } from "@/components/ui/button"
+import { Separator } from "@/components/ui/separator"
+import { SidebarTrigger } from "@/components/ui/sidebar"
+
+export function SiteHeader() {
+ return (
+
+ )
+}
diff --git a/components/ui/alert.tsx b/components/ui/alert.tsx
new file mode 100644
index 0000000..89c3709
--- /dev/null
+++ b/components/ui/alert.tsx
@@ -0,0 +1,50 @@
+import { cva, type VariantProps } from "class-variance-authority"
+import { AlertCircle } from "lucide-react"
+import * as React from "react"
+
+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",
+ },
+ } as const
+)
+
+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/avatar.tsx b/components/ui/avatar.tsx
new file mode 100644
index 0000000..5c56785
--- /dev/null
+++ b/components/ui/avatar.tsx
@@ -0,0 +1,34 @@
+"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..db28608
--- /dev/null
+++ b/components/ui/badge.tsx
@@ -0,0 +1,36 @@
+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-md 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/breadcrumb.tsx b/components/ui/breadcrumb.tsx
new file mode 100644
index 0000000..392c009
--- /dev/null
+++ b/components/ui/breadcrumb.tsx
@@ -0,0 +1,92 @@
+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
+}
+
+function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
+ return (
+
+ )
+}
+
+function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
+ return
+}
+
+function BreadcrumbLink({
+ asChild,
+ className,
+ ...props
+}: React.ComponentProps<"a"> & {
+ asChild?: boolean
+}) {
+ const Comp = asChild ? Slot : "a"
+
+ return (
+
+ )
+}
+
+function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
+ return (
+
+ )
+}
+
+function BreadcrumbSeparator({ children, className, ...props }: React.ComponentProps<"li">) {
+ return (
+ svg]:size-3.5", className)}
+ {...props}
+ >
+ {children ?? }
+
+ )
+}
+
+function BreadcrumbEllipsis({ className, ...props }: React.ComponentProps<"span">) {
+ return (
+
+
+ More
+
+ )
+}
+
+export {
+ Breadcrumb,
+ BreadcrumbList,
+ BreadcrumbItem,
+ BreadcrumbLink,
+ BreadcrumbPage,
+ BreadcrumbSeparator,
+ BreadcrumbEllipsis,
+}
diff --git a/components/ui/button.tsx b/components/ui/button.tsx
new file mode 100644
index 0000000..87e3f53
--- /dev/null
+++ b/components/ui/button.tsx
@@ -0,0 +1,50 @@
+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-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_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 dark:bg-destructive/60",
+ outline:
+ "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
+ secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
+ ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
+ 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..3a65dbf
--- /dev/null
+++ b/components/ui/card.tsx
@@ -0,0 +1,54 @@
+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 CardAction({ 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, CardAction, CardDescription, CardContent }
diff --git a/components/ui/chart.tsx b/components/ui/chart.tsx
new file mode 100644
index 0000000..a6fc97d
--- /dev/null
+++ b/components/ui/chart.tsx
@@ -0,0 +1,291 @@
+"use client"
+
+import * as React from "react"
+import * as RechartsPrimitive from "recharts"
+
+import { cn } from "@/lib/utils"
+
+// Format: { THEME_NAME: CSS_SELECTOR }
+const THEMES = { light: "", dark: ".dark" } as const
+
+export type ChartConfig = {
+ [k in string]: {
+ label?: React.ReactNode
+ icon?: React.ComponentType
+ } & ({ color?: string; theme?: never } | { color?: never; theme: Record })
+}
+
+type ChartContextProps = {
+ config: ChartConfig
+}
+
+const ChartContext = React.createContext(null)
+
+function useChart() {
+ const context = React.useContext(ChartContext)
+
+ if (!context) {
+ throw new Error("useChart must be used within a ")
+ }
+
+ return context
+}
+
+function ChartContainer({
+ id,
+ className,
+ children,
+ config,
+ ...props
+}: React.ComponentProps<"div"> & {
+ config: ChartConfig
+ children: React.ComponentProps["children"]
+}) {
+ const uniqueId = React.useId()
+ const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`
+
+ return (
+
+
+
+ {children}
+
+
+ )
+}
+
+const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
+ const colorConfig = Object.entries(config).filter(([, config]) => config.theme || config.color)
+
+ if (!colorConfig.length) {
+ return null
+ }
+
+ return (
+