diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 224b4fe..e98e793 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.0", "dependencies": { "@hookform/resolvers": "^3.9.1", + "@radix-ui/react-accordion": "^1.2.3", "@radix-ui/react-alert-dialog": "^1.1.2", "@radix-ui/react-avatar": "^1.1.1", "@radix-ui/react-checkbox": "^1.1.2", @@ -1199,6 +1200,36 @@ "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz", "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==" }, + "node_modules/@radix-ui/react-accordion": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.3.tgz", + "integrity": "sha512-RIQ15mrcvqIkDARJeERSuXSry2N8uYnxkdDetpfmalT/+0ntOXLkFOsh9iwlAsCv+qcmhZjbdJogIm6WBa6c4A==", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-collapsible": "1.1.3", + "@radix-ui/react-collection": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-alert-dialog": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.6.tgz", diff --git a/frontend/package.json b/frontend/package.json index b1a0db5..ca824eb 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@hookform/resolvers": "^3.9.1", + "@radix-ui/react-accordion": "^1.2.3", "@radix-ui/react-alert-dialog": "^1.1.2", "@radix-ui/react-avatar": "^1.1.1", "@radix-ui/react-checkbox": "^1.1.2", diff --git a/frontend/src/components/layout/data/sidebar-data.ts b/frontend/src/components/layout/data/sidebar-data.ts index 6b6a4b8..2e7192b 100644 --- a/frontend/src/components/layout/data/sidebar-data.ts +++ b/frontend/src/components/layout/data/sidebar-data.ts @@ -30,7 +30,7 @@ export const sidebarData: SidebarData = { }, teams: [ { - name: "Shadcn Admin", + name: "SwagShop Admin", logo: Command, plan: "Vite + ShadcnUI" }, diff --git a/frontend/src/components/main-navbar.tsx b/frontend/src/components/main-navbar.tsx new file mode 100644 index 0000000..d0a8e23 --- /dev/null +++ b/frontend/src/components/main-navbar.tsx @@ -0,0 +1,125 @@ +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger +} from "@/components/ui/dropdown-menu"; +import { Menu } from "lucide-react"; +import { Card } from "@/components/ui/card"; +import { ThemeSwitch } from "./theme-switch"; +import { Button } from "@/components/ui/button"; +import { nanoid } from "nanoid"; +import { Link } from "@tanstack/react-router"; + +const MainNavbar = () => { + return ( +
+ + + +
+ + + +
+ + + + + + + + + Home + + + Features + + + Pricing + + + FAQs + + + + + + + + + +
+ + +
+
+
+ ); +}; + +const landings = [ + { + id: nanoid(), + title: "Landing 01", + route: "/project-management" + }, + { + id: nanoid(), + title: "Landing 02", + route: "/crm-landing" + }, + { + id: nanoid(), + title: "Landing 03", + route: "/ai-content-landing" + }, + { + id: nanoid(), + title: "Landing 04", + route: "/new-intro-landing" + }, + { + id: nanoid(), + title: "Landing 05", + route: "/about-us-landing" + }, + { + id: nanoid(), + title: "Landing 06", + route: "/contact-us-landing" + }, + { + id: nanoid(), + title: "Landing 07", + route: "/faqs-landing" + }, + { + id: nanoid(), + title: "Landing 08", + route: "/pricing-landing" + }, + { + id: nanoid(), + title: "Landing 09", + route: "/career-landing" + } +]; + +export default MainNavbar; diff --git a/frontend/src/components/ui/accordion.tsx b/frontend/src/components/ui/accordion.tsx new file mode 100644 index 0000000..e6a723d --- /dev/null +++ b/frontend/src/components/ui/accordion.tsx @@ -0,0 +1,56 @@ +import * as React from "react" +import * as AccordionPrimitive from "@radix-ui/react-accordion" +import { ChevronDown } from "lucide-react" + +import { cn } from "@/lib/utils" + +const Accordion = AccordionPrimitive.Root + +const AccordionItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AccordionItem.displayName = "AccordionItem" + +const AccordionTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + svg]:rotate-180", + className + )} + {...props} + > + {children} + + + +)) +AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName + +const AccordionContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + +
{children}
+
+)) + +AccordionContent.displayName = AccordionPrimitive.Content.displayName + +export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } diff --git a/frontend/src/config/manifest.ts b/frontend/src/config/manifest.ts new file mode 100644 index 0000000..973f3f2 --- /dev/null +++ b/frontend/src/config/manifest.ts @@ -0,0 +1,2 @@ +export const AppName = "SwagShop" +export const AdminAppName = "SwagShop Admin" \ No newline at end of file diff --git a/frontend/src/index.css b/frontend/src/index.css index 75c007c..5a61c1f 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -141,3 +141,14 @@ @apply min-h-svh w-full bg-background text-foreground; } } + + + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/frontend/src/pages/auth/auth-layout.tsx b/frontend/src/pages/auth/auth-layout.tsx index b27b565..09d17f1 100644 --- a/frontend/src/pages/auth/auth-layout.tsx +++ b/frontend/src/pages/auth/auth-layout.tsx @@ -1,3 +1,5 @@ +import {AdminAppName} from "@/config/manifest" + interface Props { children: React.ReactNode; } @@ -18,7 +20,7 @@ export default function AuthLayout({ children }: Props) { className="mr-2 h-6 w-6"> -

Shadcn Admin

+

{AdminAppName}

{children} diff --git a/frontend/src/pages/auth/sign-in/sign-in-2.tsx b/frontend/src/pages/auth/sign-in/sign-in-2.tsx index c40cc93..0ab9dfa 100644 --- a/frontend/src/pages/auth/sign-in/sign-in-2.tsx +++ b/frontend/src/pages/auth/sign-in/sign-in-2.tsx @@ -1,5 +1,6 @@ import ViteLogo from "@/assets/vite.svg"; import { UserAuthForm } from "./components/user-auth-form"; +import { AdminAppName } from "@/config/manifest"; export default function SignIn2() { return ( @@ -18,7 +19,7 @@ export default function SignIn2() { className="mr-2 h-6 w-6"> - Shadcn Admin + {AdminAppName} +

Ready to Get Started?

+

Join today and start managing your shop with ease.

+ + + ); + }; \ No newline at end of file diff --git a/frontend/src/pages/home/components/faq.tsx b/frontend/src/pages/home/components/faq.tsx new file mode 100644 index 0000000..7806af3 --- /dev/null +++ b/frontend/src/pages/home/components/faq.tsx @@ -0,0 +1,25 @@ +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger +} from "@/components/ui/accordion"; +import { faqs } from "../data/faq-data"; + +export default function FAQ() { + return ( +
+

+ Frequently Asked Questions +

+ + {faqs.map((faq, index) => ( + + {faq.question} + {faq.answer} + + ))} + +
+ ); +} diff --git a/frontend/src/pages/home/components/features.tsx b/frontend/src/pages/home/components/features.tsx new file mode 100644 index 0000000..43717aa --- /dev/null +++ b/frontend/src/pages/home/components/features.tsx @@ -0,0 +1,19 @@ +import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; +import { features } from "../data/feature-data"; + +export default function Features() { + return ( +
+ {features.map((feature, index) => ( + + + {feature.title} + + +

{feature.description}

+
+
+ ))} +
+ ); +} diff --git a/frontend/src/pages/home/components/hero.tsx b/frontend/src/pages/home/components/hero.tsx new file mode 100644 index 0000000..d23ce32 --- /dev/null +++ b/frontend/src/pages/home/components/hero.tsx @@ -0,0 +1,11 @@ +export default function Hero() { + return ( +
+

Manage Your Shop with Ease

+

+ A powerful multitenant API for inventory and product management. Define + your products, manage stock, and handle purchases effortlessly. +

+
+ ); +} diff --git a/frontend/src/pages/home/components/pricing.tsx b/frontend/src/pages/home/components/pricing.tsx new file mode 100644 index 0000000..dd4c497 --- /dev/null +++ b/frontend/src/pages/home/components/pricing.tsx @@ -0,0 +1,35 @@ +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { plans } from "../data/pricing-data"; +import { Button } from "@/components/ui/button"; + +export default function Pricing() { + return ( +
+

Pricing Plans

+

+ Prices are subject to change. These estimates help guide your decision. +

+
+ {plans.map((plan, index) => ( + + + {plan.title} + + +

{plan.price}

+

{plan.description}

+
    + {plan.features.map((feature, i) => ( +
  • + {feature} +
  • + ))} +
+ +
+
+ ))} +
+
+ ); +} diff --git a/frontend/src/pages/home/data/faq-data.ts b/frontend/src/pages/home/data/faq-data.ts new file mode 100644 index 0000000..786d310 --- /dev/null +++ b/frontend/src/pages/home/data/faq-data.ts @@ -0,0 +1,15 @@ +export const faqs = [ + { + question: "How do I get started?", + answer: + "Sign up for a free account and start integrating our API into your shop." + }, + { + question: "Can I upgrade or downgrade my plan?", + answer: "Yes, you can change your plan anytime from your dashboard." + }, + { + question: "Is there customer support?", + answer: "Yes, we offer different levels of support depending on your plan." + } +]; diff --git a/frontend/src/pages/home/data/feature-data.ts b/frontend/src/pages/home/data/feature-data.ts new file mode 100644 index 0000000..4c06595 --- /dev/null +++ b/frontend/src/pages/home/data/feature-data.ts @@ -0,0 +1,31 @@ +export const features = [ + { + title: "Inventory Control", + description: + "Easily manage product stock, availability, and updates in real time." + }, + { + title: "Flexible API", + description: + "Build custom storefronts with a backend that adapts to your needs." + }, + { + title: "Seamless Transactions", + description: "Handle purchases smoothly with minimal backend complexity." + }, + { + title: "User Roles & Permissions", + description: + "Predefined roles (Owner, Manager, Employee) with different access levels to manage store operations efficiently." + }, + { + title: "Multi-Currency Support", + description: + "Each shop can define its default currency to handle transactions in the appropriate financial context." + }, + { + title: "Future-Ready Analytics", + description: + "Upcoming analytics and statistics to help businesses track performance and make data-driven decisions." + } +]; \ No newline at end of file diff --git a/frontend/src/pages/home/data/pricing-data.ts b/frontend/src/pages/home/data/pricing-data.ts new file mode 100644 index 0000000..9e8b85e --- /dev/null +++ b/frontend/src/pages/home/data/pricing-data.ts @@ -0,0 +1,20 @@ +export const plans = [ + { + title: "Free Plan", + price: "$0/month", + description: "Basic features for small shops starting out.", + features: ["Basic Inventory Management", "Limited API Requests", "Community Support"] + }, + { + title: "Pro Plan", + price: "$29/month", + description: "For growing businesses needing more control.", + features: ["Advanced Inventory Management", "Higher API Limits", "Email Support"] + }, + { + title: "Enterprise Plan", + price: "$99/month", + description: "For high-scale businesses requiring full access.", + features: ["Unlimited API Access", "Priority Support", "Custom Integrations"] + } + ]; \ No newline at end of file diff --git a/frontend/src/pages/home/index.tsx b/frontend/src/pages/home/index.tsx index a487dd0..3fc42af 100644 --- a/frontend/src/pages/home/index.tsx +++ b/frontend/src/pages/home/index.tsx @@ -1,100 +1,26 @@ -import { useState } from "react"; -import { Button } from "@/components/ui/button"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { Input } from "@/components/ui/input"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import { Label } from "@/components/ui/label"; +import MainNavbar from "@/components/main-navbar"; +import Features from "./components/features"; +import Hero from "./components/hero"; +import Pricing from "./components/pricing"; +import FAQ from "./components/faq"; +import CallToAction from "./components/call-to-action"; export default function MainPage() { - const [email, setEmail] = useState(""); - const [password, setPassword] = useState(""); - const [username, setUsername] = useState(""); - return ( -
- {/* Showcase Section */} -
-

Welcome to Our Platform

-

- A place where you can explore, connect, and engage. Sign up or log in - to get started. -

- -
+ <> + +
- {/* Authentication Section */} - - - Join Us - - - - - Login - Register - + {/* Top screen padding */} +
+ + + + + - {/* Login Tab */} - -
-
- - setEmail(e.target.value)} - placeholder="Enter your email" - /> -
-
- - setPassword(e.target.value)} - placeholder="Enter your password" - /> -
- -
-
- - {/* Register Tab */} - -
-
- - setUsername(e.target.value)} - placeholder="Choose a username" - /> -
-
- - setEmail(e.target.value)} - placeholder="Enter your email" - /> -
-
- - setPassword(e.target.value)} - placeholder="Create a password" - /> -
- -
-
-
-
-
-
+ {/* [Optional] Consider inserting an image or illustration here to reinforce the platform’s purpose. */} +
+ ); } diff --git a/frontend/src/routes/_authenticated/route.tsx b/frontend/src/routes/_authenticated/route.tsx index 87ee918..4baf216 100644 --- a/frontend/src/routes/_authenticated/route.tsx +++ b/frontend/src/routes/_authenticated/route.tsx @@ -8,9 +8,9 @@ import SkipToMain from "@/components/skip-to-main"; export const Route = createFileRoute("/_authenticated")({ beforeLoad: async ({ location }) => { - if (true) { + if (false) { throw redirect({ - to: "/sign-in", + to: "/401", search: { redirect: location.href } diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index 730acd0..d162b1a 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -50,6 +50,28 @@ export default { '4': 'hsl(var(--chart-4))', '5': 'hsl(var(--chart-5))' } + }, + keyframes: { + 'accordion-down': { + from: { + height: '0' + }, + to: { + height: 'var(--radix-accordion-content-height)' + } + }, + 'accordion-up': { + from: { + height: 'var(--radix-accordion-content-height)' + }, + to: { + height: '0' + } + } + }, + animation: { + 'accordion-down': 'accordion-down 0.2s ease-out', + 'accordion-up': 'accordion-up 0.2s ease-out' } } },