From ae87807a783612e3c605fd4bcffe49ff94c72009 Mon Sep 17 00:00:00 2001 From: devlopersabbir Date: Wed, 6 Aug 2025 22:29:28 +0600 Subject: [PATCH 1/8] =?UTF-8?q?[chore=20=F0=9F=9A=93]=20schema=20defined?= =?UTF-8?q?=20with=20types=20=F0=9F=90=B1=E2=80=8D=F0=9F=8F=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 +- pnpm-lock.yaml | 8 +++ server/package.json | 5 +- .../data-transfer-object/extension.dto.ts | 52 +++++++++++-------- .../extensions/extension.repository.ts | 5 +- .../modules/extensions/extensions.schema.ts | 6 +++ server/src/utils/db-utility/base.schema.ts | 3 -- server/src/utils/index.ts | 1 + server/src/utils/zod-utils.ts | 49 +++++++++++++++++ src/@types/extension/browser.ts | 9 ++-- src/@types/extension/extension.ts | 40 -------------- src/@types/index.ts | 5 -- .../_components/extensions/ext-card.tsx | 50 +++++++----------- .../_components/extensions/ext-grid.tsx | 7 ++- .../_components/extensions/extension.tsx | 8 +-- .../(public)/_components/toggle-wish-list.tsx | 14 ++--- src/app/(public)/schemas/extension.schema.ts | 44 ++++++++++++++++ src/constants/extension.data.ts | 4 +- tsconfig.json | 2 +- 19 files changed, 186 insertions(+), 129 deletions(-) create mode 100644 server/src/utils/zod-utils.ts delete mode 100644 src/@types/extension/extension.ts create mode 100644 src/app/(public)/schemas/extension.schema.ts diff --git a/package.json b/package.json index c36510b..a2b4aad 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,8 @@ "react-dom": "^19.0.0", "sonner": "^2.0.6", "tailwind-merge": "^3.3.1", - "tailwindcss-animate": "^1.0.7" + "tailwindcss-animate": "^1.0.7", + "zod": "^4.0.14" }, "devDependencies": { "@eslint/eslintrc": "^3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8c284ac..c3323ff 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -77,6 +77,9 @@ importers: tailwindcss-animate: specifier: ^1.0.7 version: 1.0.7(tailwindcss@4.1.11) + zod: + specifier: ^4.0.14 + version: 4.0.14 devDependencies: '@eslint/eslintrc': specifier: ^3 @@ -2418,6 +2421,9 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + zod@4.0.14: + resolution: {integrity: sha512-nGFJTnJN6cM2v9kXL+SOBq3AtjQby3Mv5ySGFof5UGRHrRioSJ5iG680cYNjE/yWk671nROcpPj4hAS8nyLhSw==} + snapshots: '@alloc/quick-lru@5.2.0': {} @@ -4927,3 +4933,5 @@ snapshots: yallist@5.0.0: {} yocto-queue@0.1.0: {} + + zod@4.0.14: {} diff --git a/server/package.json b/server/package.json index 95a321f..becc52b 100644 --- a/server/package.json +++ b/server/package.json @@ -4,7 +4,7 @@ "description": "", "author": "", "private": true, - "license": "UNLICENSED", + "license": "MIT", "scripts": { "build": "nest build", "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", @@ -20,8 +20,7 @@ "test:e2e": "jest --config ./test/jest-e2e.json", "seed": "tsx src/drizzle/seed.ts", "clean": "rm -rf src/drizzle/out && tsx src/drizzle/clean.ts", - "migrate": "drizzle-kit generate && cross-env DB_MIGRATING=true tsx src/drizzle/migrate.ts", - "generate": "drizzle-kit generate" + "migrate": "drizzle-kit generate && cross-env DB_MIGRATING=true tsx src/drizzle/migrate.ts" }, "dependencies": { "@nestjs/common": "^11.0.1", diff --git a/server/src/modules/extensions/data-transfer-object/extension.dto.ts b/server/src/modules/extensions/data-transfer-object/extension.dto.ts index 722b417..84291b5 100644 --- a/server/src/modules/extensions/data-transfer-object/extension.dto.ts +++ b/server/src/modules/extensions/data-transfer-object/extension.dto.ts @@ -1,34 +1,42 @@ import { z } from "zod"; +import { + zId, + zOptionalId, + zDecimalString, + zEnum, + zSlug, + zSemver, + zOptionalUrl, + zStringArray, +} from "@/utils"; import { browsers, extensionStatus } from "../extensions.schema"; export const extensionSchema = z.object({ - name: z.string().min(1), - slug: z.string().optional(), + sellerId: zId("Seller ID"), + categoryId: zOptionalId("Category ID"), - sellerId: z.number(), - categoryId: z.number(), + name: z.string().min(3, "Name must be at least 3 characters"), + slug: zSlug(), - description: z.string().min(1), - shortDescription: z.string().optional(), + description: z.string().min(10, "Description must be at least 10 characters"), + shortDescription: z.string().max(255).optional(), - price: z.string().regex(/^\d{1,8}(\.\d{1,2})?$/, "Invalid price format"), - version: z.string().min(1), + price: zDecimalString(2), + originalPrice: zDecimalString(2), - browsers: z.array(z.enum(browsers)).default(["chrome"]), - tags: z.array(z.string()).optional(), - iconUrl: z.url().optional(), - screenshots: z.array(z.string()).optional(), - videoUrl: z.url().optional(), - downloadUrl: z.url().optional(), + version: zSemver(), + browsers: z.array(zEnum(browsers, "Browser")).default([]), + tags: zStringArray(), + screenshots: zStringArray(), - downloadCount: z.number().int().nonnegative().default(0), - rating: z - .string() - .regex(/^\d{1}(\.\d{1,2})?$/, "Invalid rating format") - .default("0.00"), + iconUrl: zOptionalUrl(), + videoUrl: zOptionalUrl(), + downloadUrl: zOptionalUrl().optional(), - reviewCount: z.number().int().nonnegative().optional(), - status: z.enum(extensionStatus).optional(), -}); + downloadCount: z.number().int().min(0).default(0), + rating: zDecimalString(2).default("0.00"), + reviewCount: z.number().int().min(0).default(0), + status: zEnum(extensionStatus, "Status").default("draft"), +}); export type ExtensionSchema = z.infer; diff --git a/server/src/modules/extensions/extension.repository.ts b/server/src/modules/extensions/extension.repository.ts index 4fef4e5..e19877e 100644 --- a/server/src/modules/extensions/extension.repository.ts +++ b/server/src/modules/extensions/extension.repository.ts @@ -7,10 +7,7 @@ import extensions from "./extensions.schema"; @Injectable() export class ExtensionRepository { async create(input: ExtensionSchema) { - const [extension] = await db - .insert(extensions) - .values({ ...input, slug: String(input.slug) }) - .returning(); + const [extension] = await db.insert(extensions).values(input).returning(); return extension; } async fetch() { diff --git a/server/src/modules/extensions/extensions.schema.ts b/server/src/modules/extensions/extensions.schema.ts index 0154cb5..8e8a165 100644 --- a/server/src/modules/extensions/extensions.schema.ts +++ b/server/src/modules/extensions/extensions.schema.ts @@ -46,7 +46,13 @@ const extensions = pgTable( description: text("description").notNull(), shortDescription: text("short_description"), + price: decimal("price", { precision: 10, scale: 2 }).notNull(), + originalPrice: decimal("original_price", { + precision: 10, + scale: 2, + }).notNull(), + version: text("version").notNull(), browsers: json("browsers").$type<(typeof browsers)[number][]>().default([]), tags: json("tags").$type().default([]), diff --git a/server/src/utils/db-utility/base.schema.ts b/server/src/utils/db-utility/base.schema.ts index abd27c4..27a1d3e 100644 --- a/server/src/utils/db-utility/base.schema.ts +++ b/server/src/utils/db-utility/base.schema.ts @@ -2,7 +2,6 @@ import { sql } from "drizzle-orm"; import { serial, timestamp } from "drizzle-orm/pg-core"; export const baseSchema = { - // id: primaryId(), id: serial("id").primaryKey(), createdAt: timestamp("createdAt", { @@ -15,6 +14,4 @@ export const baseSchema = { }) .$defaultFn(() => sql`NULL`) .$onUpdateFn(() => new Date()), - // createdAt: createdAt(), - // updatedAt: updatedAt(), }; diff --git a/server/src/utils/index.ts b/server/src/utils/index.ts index e69de29..cbfbf06 100644 --- a/server/src/utils/index.ts +++ b/server/src/utils/index.ts @@ -0,0 +1 @@ +export * from "./zod-utils"; diff --git a/server/src/utils/zod-utils.ts b/server/src/utils/zod-utils.ts new file mode 100644 index 0000000..d364df9 --- /dev/null +++ b/server/src/utils/zod-utils.ts @@ -0,0 +1,49 @@ +import { z } from "zod"; + +/* Generic decimal validator (as string) */ +export const zDecimalString = (precision = 2) => + z.string().regex(new RegExp(`^\\d+(\\.\\d{1,${precision}})?$`), { + message: `Must be a valid decimal with up to ${precision} decimal places`, + }); + +// Generic integer ID +export const zId = (field = "ID") => + z + .number({ error: `${field} is required` }) + .int(`${field} must be an integer`) + .positive(`${field} must be a positive number`); + +// Optional ID (used for nullable foreign keys) +export const zOptionalId = (field = "ID") => + z.number().int(`${field} must be an integer`).positive().optional(); + +// Generic semantic version string +export const zSemver = () => + z.string().regex(/^\d+(\.\d+){0,2}$/, { + message: "Version must follow semantic versioning (e.g. 1.0.0)", + }); + +// Generic slug +export const zSlug = () => + z + .string() + .min(3, "Slug must be at least 3 characters") + .regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, { + message: "Slug must be lowercase and hyphen-separated", + }); + +// Generic optional URL +export const zOptionalUrl = () => z.url("Must be a valid URL").optional(); + +// Generic enum (based on const array) +export const zEnum = ( + values: T, + label = "Value", +) => + z.enum(values, { + error: `${label} must be one of: ${values.join(", ")}`, + }); + +// Generic string array +export const zStringArray = () => + z.array(z.string().min(1, "Empty strings are not allowed")).default([]); diff --git a/src/@types/extension/browser.ts b/src/@types/extension/browser.ts index c1dd46c..d1e09a8 100644 --- a/src/@types/extension/browser.ts +++ b/src/@types/extension/browser.ts @@ -1,8 +1,7 @@ -export const browser = [ +export const browsers = [ "chrome", "firefox", - "microsoft-edge", - "safary", - "all", + "microsoft edge", + "safari", ] as const; -export type Browser = (typeof browser)[number]; +export type Browser = (typeof browsers)[number]; diff --git a/src/@types/extension/extension.ts b/src/@types/extension/extension.ts deleted file mode 100644 index 7252740..0000000 --- a/src/@types/extension/extension.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Browser } from "./browser"; -import { Category } from "./category"; -import { Developer } from "./developer"; -import { Media } from "./media"; -import { Stats } from "./stats"; - -export type Extension = { - id: number; - name: string; - description: string; - longDescription: string; - price: number; - originalPrice?: number; - category: Category; - browsers: Browser[]; - rating: number; - totalRatings: number; - users: string; - features: string[]; - tags: string[]; - media: Media[]; - screenshots: string[]; - version: string; - size: string; - lastUpdated: string; - permissions: string[]; - developer: Developer; - stats: Stats; - isPopular: boolean; - isFeatured: boolean; - isNew: boolean; - gradientFrom?: string; - gradientTo?: string; - - changelog?: { - version: string; - date: string; - changes: string[]; - }[]; -}; diff --git a/src/@types/index.ts b/src/@types/index.ts index 060ec41..b35b4e3 100644 --- a/src/@types/index.ts +++ b/src/@types/index.ts @@ -1,9 +1,4 @@ -import { Extension } from "./extension/extension"; - export type LooseAutocomplete = T | Omit; -export type ExtensionProps = { - extension: Extension; -}; export * from "./extension/browser"; export * from "./extension/category"; export * from "./extension/developer"; diff --git a/src/app/(public)/_components/extensions/ext-card.tsx b/src/app/(public)/_components/extensions/ext-card.tsx index f591655..76e162c 100644 --- a/src/app/(public)/_components/extensions/ext-card.tsx +++ b/src/app/(public)/_components/extensions/ext-card.tsx @@ -1,11 +1,11 @@ -import { Extension } from "@/@types"; import { Play, Chrome, Globe, Star, Users, Eye } from "lucide-react"; import ToggleWishlist from "../toggle-wish-list"; import { Badge } from "@/components/ui/badge"; import PlayButton from "../play-button"; +import { ExtensionSchema } from "../../schemas/extension.schema"; type Props = { - extension: Extension; + extension: ExtensionSchema; index: number; }; export default function ExtCard({ extension, index }: Props) { @@ -17,9 +17,9 @@ export default function ExtCard({ extension, index }: Props) { {/* Unique Glassy Card */}
{/* Gradient Overlay */} - + {/* Status Badges */} -
+ {/*
{extension.isFeatured && ( ⭐ Featured @@ -35,23 +35,15 @@ export default function ExtCard({ extension, index }: Props) { 🔥 Popular )} -
+
*/} {/* Media Section with Gradient Overlay */}
- {/* Gradient Background */} -
- {/* Media Content */} - {extension.media[0]?.type === "video" ? ( + {extension?.videoUrl ? (
{extension.name} @@ -67,7 +59,7 @@ export default function ExtCard({ extension, index }: Props) { ) : (
{extension.name} @@ -98,7 +90,7 @@ export default function ExtCard({ extension, index }: Props) { {extension.name}

- {extension.description} + {extension.shortDescription}

@@ -109,24 +101,22 @@ export default function ExtCard({ extension, index }: Props) { {extension.rating} - - ({extension.totalRatings}) - + ({5})
- {extension.users} + {/* {extension.user} */}
-
+ {/*
{(extension.stats.views / 1000).toFixed(1)}K -
+
*/}
{/* Features */} -
+ {/*
{extension.features.slice(0, 2).map((feature) => ( )} -
+
*/} {/* Price and Actions */}
- {extension.originalPrice && ( + {extension.price && ( - ${extension.originalPrice} + ${extension.price} )} ${extension.price} @@ -168,12 +158,12 @@ export default function ExtCard({ extension, index }: Props) { ); } -function GradientOverlay({ extension }: Props) { +function GradientOverlay() { return (
); diff --git a/src/app/(public)/_components/extensions/ext-grid.tsx b/src/app/(public)/_components/extensions/ext-grid.tsx index 1e0c24a..9ab86d9 100644 --- a/src/app/(public)/_components/extensions/ext-grid.tsx +++ b/src/app/(public)/_components/extensions/ext-grid.tsx @@ -1,9 +1,12 @@ -import { extensions } from "@/constants"; import { Search } from "lucide-react"; import ExtGridHeader from "./ext-grid-header"; import ExtCard from "./ext-card"; +import { ExtensionSchema } from "../../schemas/extension.schema"; -export default function ExtGrid() { +type Props = { + extensions: ExtensionSchema[]; +}; +export default async function ExtGrid({ extensions }: Props) { return (
diff --git a/src/app/(public)/_components/extensions/extension.tsx b/src/app/(public)/_components/extensions/extension.tsx index 033ab36..5307ec4 100644 --- a/src/app/(public)/_components/extensions/extension.tsx +++ b/src/app/(public)/_components/extensions/extension.tsx @@ -1,11 +1,11 @@ import { baseURI } from "@/utils"; import SearchFilters from "../filters/search-filters"; import ExtGrid from "./ext-grid"; +import { ExtensionSchema } from "../../schemas/extension.schema"; export default async function Extension() { - const data = await fetch(`${baseURI}/extension`); - const extensions = await data.json(); - console.log(extensions); + const data = await fetch(`${baseURI}/extensions`); + const extensions = (await data.json()) as ExtensionSchema[]; return ( <>
@@ -15,7 +15,7 @@ export default async function Extension() { {/* Extensions Grid */}
- +
); diff --git a/src/app/(public)/_components/toggle-wish-list.tsx b/src/app/(public)/_components/toggle-wish-list.tsx index 23a049c..e2fd7a4 100644 --- a/src/app/(public)/_components/toggle-wish-list.tsx +++ b/src/app/(public)/_components/toggle-wish-list.tsx @@ -1,13 +1,13 @@ "use client"; -import { Extension } from "@/@types"; import { Button } from "@/components/ui/button"; import { Heart, Download } from "lucide-react"; import Link from "next/link"; import { useEffect, useState } from "react"; import { toast } from "sonner"; +import { ExtensionSchema } from "../schemas/extension.schema"; type Props = { - extension: Extension; + extension: ExtensionSchema; }; export default function ToggleWishlist({ extension }: Props) { const [wishlist, setWishlist] = useState([]); @@ -40,23 +40,25 @@ export default function ToggleWishlist({ extension }: Props) { - - ); -} diff --git a/src/app/(auth)/_components/register-form.tsx b/src/app/(auth)/_components/register-form.tsx deleted file mode 100644 index 37af9c7..0000000 --- a/src/app/(auth)/_components/register-form.tsx +++ /dev/null @@ -1,85 +0,0 @@ -"use client"; - -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { FormEvent } from "react"; - -export default function RegisterForm() { - const handleSubmit = async (event: FormEvent) => { - event.preventDefault(); - const formData = new FormData(event.target as HTMLFormElement); - console.log(Object.fromEntries(formData)); - }; - - return ( -
-
- - -
-
- - -
- -
- - -
- - {/*
- setAgreeToTerms(checked as boolean)} - className="border-border data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground" - /> - -
*/} - - -
- ); -} diff --git a/src/app/(auth)/layout.tsx b/src/app/(auth)/layout.tsx deleted file mode 100644 index 7709c87..0000000 --- a/src/app/(auth)/layout.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { Metadata } from "next"; -import { ReactNode } from "react"; - -export const metadata: Metadata = { - title: "Auth", -}; -export default function AuthLayout({ - children, -}: Readonly<{ - children: ReactNode; -}>) { - return
{children}
; -} diff --git a/src/app/(auth)/loading.tsx b/src/app/(auth)/loading.tsx deleted file mode 100644 index 8565bd3..0000000 --- a/src/app/(auth)/loading.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function Loading() { - return

loading...

; -} diff --git a/src/app/(auth)/login/page.tsx b/src/app/(auth)/login/page.tsx deleted file mode 100644 index 4b34bc6..0000000 --- a/src/app/(auth)/login/page.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@/components/ui/card"; -import { Separator } from "@/components/ui/separator"; -import Link from "next/link"; -import AuthLogo from "../_components/auth-logo"; -import Loginform from "../_components/login-form"; - -export default function LoginPage() { - return ( -
-
-
- - - - - Welcome back - - Sign in to your account to access your extensions - - - - -
- - Forgot your password? - -
- - - -
-

- Dont have an account?{" "} - - Sign up - -

-
-
-
-
-
-
- ); -} diff --git a/src/app/(auth)/register/page.tsx b/src/app/(auth)/register/page.tsx deleted file mode 100644 index a1216ec..0000000 --- a/src/app/(auth)/register/page.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@/components/ui/card"; -import { Separator } from "@/components/ui/separator"; -import Link from "next/link"; -import AuthLogo from "../_components/auth-logo"; -import RegisterForm from "../_components/register-form"; - -export default function RegisterPage() { - return ( -
-
-
- - - - - - Create your account - - - Join BrowserPlugins to access premium browser extensions - - - - - - -
-

- Already have an account?{" "} - - Sign in - -

-
-
-
-
-
-
- ); -} diff --git a/src/app/(dashboard)/dashboard/page.tsx b/src/app/(dashboard)/dashboard/page.tsx deleted file mode 100644 index ff2b6b7..0000000 --- a/src/app/(dashboard)/dashboard/page.tsx +++ /dev/null @@ -1,375 +0,0 @@ -"use client"; - -import { Button } from "@/components/ui/button"; -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@/components/ui/card"; -import { Badge } from "@/components/ui/badge"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import { - Chrome, - ChromeIcon as Firefox, - Download, - Key, - Calendar, - Mail, - Heart, -} from "lucide-react"; -import { useState, useEffect } from "react"; -import Link from "next/link"; -import { allExtensions } from "@/constants/all-extensions"; - -export default function DashboardPage() { - const [mobileMenuOpen, setMobileMenuOpen] = useState(false); - const [wishlist, setWishlist] = useState([]); - - // Mock data - in real app, fetch based on user's purchases - const user = { - email: "user@example.com", - joinDate: "Dec 2024", - }; - - const purchases = allExtensions.filter((ext) => ext.status === "active"); - - // Load wishlist from localStorage on mount - useEffect(() => { - const storedWishlist = localStorage.getItem("browserplugins_wishlist"); - if (storedWishlist) { - setWishlist(JSON.parse(storedWishlist)); - } - }, []); - - // Save wishlist to localStorage whenever it changes - useEffect(() => { - localStorage.setItem("browserplugins_wishlist", JSON.stringify(wishlist)); - }, [wishlist]); - - const toggleWishlist = (id: number) => { - setWishlist((prevWishlist) => { - if (prevWishlist.includes(id)) { - return prevWishlist.filter((itemId) => itemId !== id); - } else { - return [...prevWishlist, id]; - } - }); - }; - - const wishlistExtensions = allExtensions.filter((ext) => - wishlist.includes(ext.id) - ); - - return ( -
-
-
-

- My Dashboard -

-

- Manage your purchased extensions and downloads -

-
- -
- {/* Sidebar */} -
- - - - Account Info - - - -
- - {user.email} -
-
- - Joined {user.joinDate} -
-
- - {purchases.length} Extensions - -
-
-
-
- - {/* Main Content */} -
- - - - My Extensions - - - Downloads - - - License Keys - - - Wishlist - - - - -
- {purchases.map((purchase) => ( - - -
-
- {purchase.browser === "chrome" ? ( - - ) : ( - - )} -
-

{purchase.name}

-

- {purchase.browser} Extension -

-

- Purchased on{" "} - {new Date( - purchase.purchaseDate - ).toLocaleDateString()} -

-
-
-
- - {purchase.status} - - -
-
-
-
- ))} -
-
- - - - - - Download History - - - All your extension downloads in one place - - - -
- {purchases.map((purchase) => ( -
-
- {purchase.browser === "chrome" ? ( - - ) : ( - - )} -
-

{purchase.name}

-

- Last downloaded:{" "} - {new Date( - purchase.purchaseDate - ).toLocaleDateString()} -

-
-
- -
- ))} -
-
-
-
- - - - - - License Keys - - - Your extension license keys for activation - - - -
- {purchases.map((purchase) => ( -
-
-
- - - {purchase.name} - -
- - {purchase.browser} - -
-
- {purchase.licenseKey} -
-

- Use this key to activate your extension after - installation -

-
- ))} -
-
-
-
- - - - - - My Wishlist - - - Extensions you've saved for later - - - - {wishlistExtensions.length === 0 ? ( -
- -

- Your wishlist is empty. Start adding some extensions! -

- - Browse Extensions - -
- ) : ( -
- {wishlistExtensions.map((ext) => ( -
-
- {ext.browser === "chrome" ? ( - - ) : ( - - )} -
-

{ext.name}

-

- {ext.description} -

-

- ${ext.price} -

-
-
-
- - - - -
-
- ))} -
- )} -
-
-
-
-
-
-
-
- ); -} diff --git a/src/app/(dashboard)/layout.tsx b/src/app/(dashboard)/layout.tsx deleted file mode 100644 index be88bdd..0000000 --- a/src/app/(dashboard)/layout.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import Header from "@/components/shared/header"; -import { ReactNode } from "react"; - -export default function DashboardLayout({ - children, -}: Readonly<{ - children: ReactNode; -}>) { - return ( -
-
- {children} -
- ); -} diff --git a/src/app/(public)/_components/Stats.tsx b/src/app/(public)/_components/Stats.tsx deleted file mode 100644 index cfcb989..0000000 --- a/src/app/(public)/_components/Stats.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { Extension } from "@/@types"; - -type Props = { - extensions: Extension[]; -}; -export default function Stats({ extensions }: Props) { - return ( -
-
-
-
-
-
- 50K+ -
-
- Happy Users -
-
-
-
- {extensions.length} -
-
- Premium Extensions -
-
-
-
- 4.8★ -
-
- Average Rating -
-
-
-
- 24/7 -
-
- Support -
-
-
-
-
-
- ); -} diff --git a/src/app/(public)/_components/checkout/checkout-page.tsx b/src/app/(public)/_components/checkout/checkout-page.tsx deleted file mode 100644 index c93899f..0000000 --- a/src/app/(public)/_components/checkout/checkout-page.tsx +++ /dev/null @@ -1,217 +0,0 @@ -"use client"; - -import type React from "react"; - -import { Button } from "@/components/ui/button"; -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@/components/ui/card"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { Separator } from "@/components/ui/separator"; -import { - Chrome, - ChromeIcon as Firefox, - CreditCard, - Shield, - Menu, - X, -} from "lucide-react"; -import Link from "next/link"; -import { useState } from "react"; -import { ThemeToggle } from "@/components/theme-toggle"; -import { Browser } from "@/@types"; - -type Props = { - browser: Browser; - id: string; -}; -export default function CheckoutPage({ browser, id }: Props) { - const [email, setEmail] = useState(""); - const [processing, setProcessing] = useState(false); - - const extension = { - name: "ProductivityPro", - price: 29.99, - browser: browser || "chrome", - }; - - const handlePayment = async (e: React.FormEvent) => { - e.preventDefault(); - setProcessing(true); - - // Simulate payment processing - setTimeout(() => { - setProcessing(false); - // Redirect to success page - window.location.href = `/success?extension=${id}&email=${email}`; - }, 2000); - }; - - return ( -
- {/* Order Summary */} - - - Order Summary - - -
-
- {extension.browser === "chrome" ? ( - - ) : ( - - )} -
-

{extension.name}

-

- {extension.browser} Extension -

-
-
- ${extension.price} -
- - - -
- Subtotal - ${extension.price} -
-
- Tax - $0.00 -
- - - -
- Total - ${extension.price} -
- -
-
- - What you get: -
-
    -
  • • Instant download access
  • -
  • • Lifetime license
  • -
  • • Free updates
  • -
  • • 30-day money-back guarantee
  • -
-
-
-
- - {/* Payment Form */} - - - - - Payment Details - - - Your payment information is secure and encrypted - - - -
-
- - setEmail(e.target.value)} - placeholder="your@email.com" - required - className="bg-input/10 border-input text-foreground placeholder-muted-foreground" - /> -

- Download link will be sent to this email -

-
- -
- - -
- -
-
- - -
-
- - -
-
- -
- - -
- - - -
- By completing this purchase, you agree to our{" "} - - Terms of Service - {" "} - and{" "} - - Privacy Policy - -
-
-
-
-
- ); -} diff --git a/src/app/(public)/_components/extensions/ext-card.tsx b/src/app/(public)/_components/extensions/ext-card.tsx deleted file mode 100644 index 76e162c..0000000 --- a/src/app/(public)/_components/extensions/ext-card.tsx +++ /dev/null @@ -1,170 +0,0 @@ -import { Play, Chrome, Globe, Star, Users, Eye } from "lucide-react"; -import ToggleWishlist from "../toggle-wish-list"; -import { Badge } from "@/components/ui/badge"; -import PlayButton from "../play-button"; -import { ExtensionSchema } from "../../schemas/extension.schema"; - -type Props = { - extension: ExtensionSchema; - index: number; -}; -export default function ExtCard({ extension, index }: Props) { - return ( -
- {/* Unique Glassy Card */} -
- {/* Gradient Overlay */} - - {/* Status Badges */} - {/*
- {extension.isFeatured && ( - - ⭐ Featured - - )} - {extension.isNew && ( - - 🆕 New - - )} - {extension.isPopular && ( - - 🔥 Popular - - )} -
*/} - - {/* Media Section with Gradient Overlay */} -
- {/* Media Content */} - {extension?.videoUrl ? ( -
- {extension.name} -
-
- -
- - - Video - -
- ) : ( -
- {extension.name} -
-
- )} - - {/* Browser Icons */} -
- {extension.browsers.includes("chrome") && ( -
- -
- )} - {extension.browsers.includes("firefox") && ( -
- -
- )} -
-
- - {/* Content Section */} -
- {/* Title and Description */} -
-

- {extension.name} -

-

- {extension.shortDescription} -

-
- - {/* Stats */} -
-
- - - {extension.rating} - - ({5}) -
-
- - {/* {extension.user} */} -
- {/*
- - - {(extension.stats.views / 1000).toFixed(1)}K - -
*/} -
- - {/* Features */} - {/*
- {extension.features.slice(0, 2).map((feature) => ( - - {feature} - - ))} - {extension.features.length > 2 && ( - - +{extension.features.length - 2} - - )} -
*/} - - {/* Price and Actions */} -
-
- {extension.price && ( - - ${extension.price} - - )} - - ${extension.price} - -
- -
-
-
-
- ); -} - -function GradientOverlay() { - return ( -
- ); -} diff --git a/src/app/(public)/_components/extensions/ext-grid-header.tsx b/src/app/(public)/_components/extensions/ext-grid-header.tsx deleted file mode 100644 index 9ddfc23..0000000 --- a/src/app/(public)/_components/extensions/ext-grid-header.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { extensions } from "@/constants"; -import { Filter } from "lucide-react"; - -export default function ExtGridHeader() { - return ( -
-
-

- Featured Extensions - ({extensions.length}) -

-

- Handpicked premium extensions for power users -

-
-
- - - {extensions.length} results - -
-
- ); -} diff --git a/src/app/(public)/_components/extensions/ext-grid.tsx b/src/app/(public)/_components/extensions/ext-grid.tsx deleted file mode 100644 index 9ab86d9..0000000 --- a/src/app/(public)/_components/extensions/ext-grid.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { Search } from "lucide-react"; -import ExtGridHeader from "./ext-grid-header"; -import ExtCard from "./ext-card"; -import { ExtensionSchema } from "../../schemas/extension.schema"; - -type Props = { - extensions: ExtensionSchema[]; -}; -export default async function ExtGrid({ extensions }: Props) { - return ( -
-
- {/* grid header */} - - -
- {extensions.map((extension, index) => ( - - ))} -
- - {extensions.length === 0 && ( -
-
- -
-

- No extensions found -

-

- Try adjusting your search criteria or filters -

-
- )} -
-
- ); -} diff --git a/src/app/(public)/_components/extensions/extension.tsx b/src/app/(public)/_components/extensions/extension.tsx deleted file mode 100644 index 5307ec4..0000000 --- a/src/app/(public)/_components/extensions/extension.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { baseURI } from "@/utils"; -import SearchFilters from "../filters/search-filters"; -import ExtGrid from "./ext-grid"; -import { ExtensionSchema } from "../../schemas/extension.schema"; - -export default async function Extension() { - const data = await fetch(`${baseURI}/extensions`); - const extensions = (await data.json()) as ExtensionSchema[]; - return ( - <> -
- - {/* */} -
- - {/* Extensions Grid */} -
- -
- - ); -} diff --git a/src/app/(public)/_components/filters/base-filters.tsx b/src/app/(public)/_components/filters/base-filters.tsx deleted file mode 100644 index 2c2836e..0000000 --- a/src/app/(public)/_components/filters/base-filters.tsx +++ /dev/null @@ -1,35 +0,0 @@ -"use client"; - -import { useState } from "react"; -import CategoryFilter from "./category-filter"; -import { Category } from "@/@types/extension/category"; -import PriceFilter from "./price-filter"; -import SortByFilter from "./sort-by-filter"; -import { SortBy } from "@/@types/extension/filter"; -import BrowserFilter from "./browser-filter"; -import { Browser } from "@/@types"; - -export default function BaseFilters() { - const [selectedCategory, setSelectedCategory] = useState("all"); - const [selectedBrowser, setSelectedBrowser] = useState("all"); - const [priceRange, setPriceRange] = useState([0, 100]); - const [sortBy, setSortBy] = useState("popular"); - - return ( -
- - - - - - - -
- ); -} diff --git a/src/app/(public)/_components/filters/browser-filter.tsx b/src/app/(public)/_components/filters/browser-filter.tsx deleted file mode 100644 index 54393f2..0000000 --- a/src/app/(public)/_components/filters/browser-filter.tsx +++ /dev/null @@ -1,49 +0,0 @@ -"use client"; -import { Browser } from "@/@types"; -import { - Select, - SelectTrigger, - SelectValue, - SelectContent, - SelectItem, -} from "@/components/ui/select"; -import { browsers } from "@/constants"; -import { Dispatch, SetStateAction } from "react"; -type Props = { - selectedBrowser: Browser; - setSelectedBrowser: Dispatch>; -}; -export default function BrowserFilter({ - selectedBrowser, - setSelectedBrowser, -}: Props) { - return ( -
- - -
- ); -} diff --git a/src/app/(public)/_components/filters/category-filter.tsx b/src/app/(public)/_components/filters/category-filter.tsx deleted file mode 100644 index a2f0650..0000000 --- a/src/app/(public)/_components/filters/category-filter.tsx +++ /dev/null @@ -1,51 +0,0 @@ -"use client"; -import { Category } from "@/@types/extension/category"; -import { categories } from "@/constants/categories.data"; -import { - Select, - SelectTrigger, - SelectValue, - SelectContent, - SelectItem, -} from "@/components/ui/select"; -import { Dispatch, SetStateAction } from "react"; - -type Props = { - selectedCategory: Category; - setSelectedCategory: Dispatch>; -}; -export default function CategoryFilter({ - selectedCategory, - setSelectedCategory, -}: Props) { - return ( -
- - -
- ); -} diff --git a/src/app/(public)/_components/filters/price-filter.tsx b/src/app/(public)/_components/filters/price-filter.tsx deleted file mode 100644 index a265343..0000000 --- a/src/app/(public)/_components/filters/price-filter.tsx +++ /dev/null @@ -1,26 +0,0 @@ -"use client"; -import { Slider } from "@/components/ui/slider"; -import { Dispatch, SetStateAction } from "react"; - -type Props = { - priceRange: number[]; - setPriceRange: Dispatch>; -}; -export default function PriceFilter({ priceRange, setPriceRange }: Props) { - return ( -
- -
- -
-
- ); -} diff --git a/src/app/(public)/_components/filters/search-filters.tsx b/src/app/(public)/_components/filters/search-filters.tsx deleted file mode 100644 index 9b8cc2f..0000000 --- a/src/app/(public)/_components/filters/search-filters.tsx +++ /dev/null @@ -1,26 +0,0 @@ -"use client"; -import SearchForm from "./search-form"; -import BaseFilters from "./base-filters"; - -export default function SearchFilters() { - return ( -
-
- {/* Search Bar */} -
-
-
-
- -
-
-
- - {/* Filters */} -
- -
-
-
- ); -} diff --git a/src/app/(public)/_components/filters/search-form.tsx b/src/app/(public)/_components/filters/search-form.tsx deleted file mode 100644 index abe8810..0000000 --- a/src/app/(public)/_components/filters/search-form.tsx +++ /dev/null @@ -1,23 +0,0 @@ -"use client"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Search } from "lucide-react"; -import { useState } from "react"; - -export default function SearchForm() { - const [searchQuery, setSearchQuery] = useState(""); - return ( -
- - setSearchQuery(e.target.value)} - className="pl-16 pr-6 py-6 text-lg bg-transparent border-0 text-foreground placeholder-muted-foreground focus:ring-0 focus:outline-none" - /> - -
- ); -} diff --git a/src/app/(public)/_components/filters/sort-by-filter.tsx b/src/app/(public)/_components/filters/sort-by-filter.tsx deleted file mode 100644 index 07b55c8..0000000 --- a/src/app/(public)/_components/filters/sort-by-filter.tsx +++ /dev/null @@ -1,44 +0,0 @@ -"use client"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; -import { Dispatch, SetStateAction } from "react"; -import { sortsBy as sortByConstants } from "@/constants"; -import { SortBy } from "@/@types/extension/filter"; - -type Props = { - sortBy: SortBy["value"]; - setSortBy: Dispatch>; -}; -export default function SortByFilter({ sortBy, setSortBy }: Props) { - return ( -
- - -
- ); -} diff --git a/src/app/(public)/_components/hero.tsx b/src/app/(public)/_components/hero.tsx deleted file mode 100644 index e55cbaf..0000000 --- a/src/app/(public)/_components/hero.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { Button } from "@/components/ui/button"; -import { Sparkles, Zap, ArrowRight } from "lucide-react"; - -export default function Hero() { - return ( -
-
-
- - - Premium Extensions Marketplace - -
- -

- - Supercharge - -
- - Your Browser - -

- -

- Discover handcrafted, premium browser extensions that transform your - digital experience. No store restrictions, direct from developers who - care about quality. -

- - -
-
- ); -} diff --git a/src/app/(public)/_components/play-button.tsx b/src/app/(public)/_components/play-button.tsx deleted file mode 100644 index 44190d5..0000000 --- a/src/app/(public)/_components/play-button.tsx +++ /dev/null @@ -1,25 +0,0 @@ -"use client"; -import { ExtensionProps } from "@/@types"; -import { VideoModal } from "@/components/video-modal"; -import { Play } from "lucide-react"; -import { useState } from "react"; - -export default function PlayButton({ extension }: ExtensionProps) { - const [isModalOpen, setIsModalOpen] = useState(false); - - return ( - <> -
setIsModalOpen(true)} - > - -
- - - ); -} diff --git a/src/app/(public)/_components/single-ext/developer-info.tsx b/src/app/(public)/_components/single-ext/developer-info.tsx deleted file mode 100644 index 8815d4e..0000000 --- a/src/app/(public)/_components/single-ext/developer-info.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { Extension } from "@/@types"; -import { Badge } from "@/components/ui/badge"; -import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; -import { Star } from "lucide-react"; - -type Props = { - extension: Extension; -}; -export default function DeveloperInfo({ extension }: Props) { - return ( - - - - {extension.developer.name} -
-
- {extension.developer.name} - {extension.developer.verified && ( - - ✓ Verified - - )} -
-

Software Engineer

-
-
-
- -
-
- Total Extensions: - 6 -
-
- Total Downloads: - 84K+ -
-
- Average Rating: -
- - 4.7 -
-
-
-
-
- ); -} diff --git a/src/app/(public)/_components/single-ext/ext-details.tsx b/src/app/(public)/_components/single-ext/ext-details.tsx deleted file mode 100644 index 2c6165e..0000000 --- a/src/app/(public)/_components/single-ext/ext-details.tsx +++ /dev/null @@ -1,172 +0,0 @@ -import { ExtensionProps } from "@/@types"; -import { Badge } from "@/components/ui/badge"; -import { Tabs, TabsList, TabsTrigger, TabsContent } from "@radix-ui/react-tabs"; -import { Check, Shield } from "lucide-react"; - -export default function ExtensionDetails({ extension }: ExtensionProps) { - return ( -
- - - - Overview - - - Features - - - Screenshots - - - Permissions - - - Changelog - - - - -
-
-

- About this extension -

-

- {extension.longDescription} -

-
-
-

- Key Highlights -

-
- {extension.features.slice(0, 6).map((feature, index) => ( -
- - {feature} -
- ))} -
-
-
-
- - -
-

- Complete Feature List -

-
- {extension.features.map((feature, index) => ( -
- - - {feature} - -
- ))} -
-
-
- - -
-

- Screenshots -

-
- {extension.screenshots.map((screenshot, index) => ( -
- {`Screenshot -
-
- ))} -
-
-
- - -
-

- Required Permissions -

-

- This extension requires the following permissions to function - properly: -

-
- {extension.permissions.map((permission, index) => ( -
- - {permission} -
- ))} -
-
-
- - -
-

- Version History -

-
- {extension.changelog && - extension.changelog.map((version, index) => ( -
-
- - v{version.version} - - - {version.date} - -
-
    - {version.changes.map((change, changeIndex) => ( -
  • - - {change} -
  • - ))} -
-
- ))} -
-
-
-
-
- ); -} diff --git a/src/app/(public)/_components/single-ext/ext-header.tsx b/src/app/(public)/_components/single-ext/ext-header.tsx deleted file mode 100644 index e2f2229..0000000 --- a/src/app/(public)/_components/single-ext/ext-header.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { ExtensionProps } from "@/@types"; -import { Badge } from "@/components/ui/badge"; -import { Chrome, Eye, Star, Users, ChromeIcon as Firefox } from "lucide-react"; - -export default function ExtensionHeader({ extension }: ExtensionProps) { - return ( -
-
-
-

- {extension.name} -

-
- {extension.browsers.includes("chrome") && ( - - )} - {extension.browsers.includes("firefox") && ( - - )} -
-
-

- {extension.description} -

-
-
- - - {extension.rating} - - - ({extension.totalRatings} reviews) - -
-
- - - {extension.users} users - -
-
- - - {(extension.stats.views / 1000).toFixed(1)}K views - -
- - v{extension.version} - -
-
-
- {extension.isFeatured && ( - - ⭐ Featured - - )} - {extension.isPopular && ( - - 🔥 Popular - - )} -
-
- ); -} diff --git a/src/app/(public)/_components/single-ext/ext-media-gallery.tsx b/src/app/(public)/_components/single-ext/ext-media-gallery.tsx deleted file mode 100644 index a8e1e41..0000000 --- a/src/app/(public)/_components/single-ext/ext-media-gallery.tsx +++ /dev/null @@ -1,84 +0,0 @@ -"use client"; -import { Extension } from "@/@types"; -import { Play, Badge } from "lucide-react"; -import Image from "next/image"; -import { Dispatch, SetStateAction } from "react"; - -type Props = { - extension: Extension; - setCurrentMediaIndex: Dispatch>; - currentMediaIndex: number; - openVideoModal: () => void; -}; -export default function ExtensionMediaGallery({ - extension, - currentMediaIndex, - setCurrentMediaIndex, - openVideoModal, -}: Props) { - return ( -
-
- {extension.media[currentMediaIndex]?.type === "video" ? ( -
- {extension.name} -
-
- -
-
- - - Video Preview - -
- ) : ( - {extension.name} - )} -
- - {/* Media Thumbnails */} -
- {extension.media.map((media, index) => ( - - ))} -
-
- ); -} diff --git a/src/app/(public)/_components/single-ext/ext-purches.tsx b/src/app/(public)/_components/single-ext/ext-purches.tsx deleted file mode 100644 index 4424439..0000000 --- a/src/app/(public)/_components/single-ext/ext-purches.tsx +++ /dev/null @@ -1,74 +0,0 @@ -"use client"; -import { Browser, Extension } from "@/@types"; -import { Button } from "@/components/ui/button"; -import { Download, Heart } from "lucide-react"; -import Link from "next/link"; -import { useEffect, useState } from "react"; -import { toast } from "sonner"; - -type Props = { - extension: Extension; - selectedBrowser: Browser; -}; -export default function ExtensionPurches({ - extension, - selectedBrowser, -}: Props) { - const [wishlist, setWishlist] = useState([]); - - useEffect(() => { - const storedWishlist = localStorage.getItem("browserplugins_wishlist"); - if (storedWishlist) { - setWishlist(JSON.parse(storedWishlist)); - } - }, []); - - // Save wishlist to localStorage whenever it changes - useEffect(() => { - localStorage.setItem("browserplugins_wishlist", JSON.stringify(wishlist)); - }, [wishlist]); - - const toggleWishlist = (id: number) => { - setWishlist((prevWishlist) => { - if (prevWishlist.includes(id)) { - toast.success("Removed from Wishlist"); - return prevWishlist.filter((itemId) => itemId !== id); - } else { - toast.success("Added to Wishlist"); - return [...prevWishlist, id]; - } - }); - }; - - return ( -
- - - - -
- ); -} diff --git a/src/app/(public)/_components/single-ext/ext-stats.tsx b/src/app/(public)/_components/single-ext/ext-stats.tsx deleted file mode 100644 index 411f6db..0000000 --- a/src/app/(public)/_components/single-ext/ext-stats.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { Extension } from "@/@types"; -import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; -import { Download, Heart, Eye, Calendar } from "lucide-react"; - -type Props = { - extension: Extension; -}; -export default function ExtensionStats({ extension }: Props) { - return ( - - - Extension Stats - - -
-
-
- - Downloads -
- - {extension.stats.downloads.toLocaleString()} - -
-
-
- - Likes -
- - {extension.stats.likes.toLocaleString()} - -
-
-
- - Views -
- - {extension.stats.views.toLocaleString()} - -
-
-
- - Last Updated -
- - {new Date(extension.lastUpdated).toLocaleDateString()} - -
-
-
-
- ); -} diff --git a/src/app/(public)/_components/single-ext/extension.tsx b/src/app/(public)/_components/single-ext/extension.tsx deleted file mode 100644 index ebdabec..0000000 --- a/src/app/(public)/_components/single-ext/extension.tsx +++ /dev/null @@ -1,64 +0,0 @@ -"use client"; - -import { Browser, Extension } from "@/@types"; -import { extensions } from "@/constants"; -import { useState, useEffect } from "react"; -import ExtensionDetails from "./ext-details"; -import ExtensionHeader from "./ext-header"; -import ExtensionMediaGallery from "./ext-media-gallery"; -import Sidebar from "./sidebar"; - -type Props = { - id: string; -}; -export default function Extensions({ id }: Props) { - const [selectedBrowser, setSelectedBrowser] = useState("chrome"); - const [currentMediaIndex, setCurrentMediaIndex] = useState(0); - const [isModalOpen, setIsModalOpen] = useState(false); - const [extension, setExtension] = useState(); - - useEffect(() => { - if (!id) return; - const ext = extensions.find((value) => value.id === +id); - if (ext) setExtension(ext); - }, []); - - if (!extension) return

no extension found yet

; - - const openVideoModal = () => { - if (extension.media[currentMediaIndex]?.type === "video") { - setIsModalOpen(true); - } - }; - return ( -
- {/* Main Content */} -
- {/* Extension Header */} -
- - - {/* Media Gallery */} - -
- - {/* Tabs */} - -
- - {/* Sidebar */} -
- -
-
- ); -} diff --git a/src/app/(public)/_components/single-ext/sidebar.tsx b/src/app/(public)/_components/single-ext/sidebar.tsx deleted file mode 100644 index 49b2fe2..0000000 --- a/src/app/(public)/_components/single-ext/sidebar.tsx +++ /dev/null @@ -1,145 +0,0 @@ -import { Browser, Extension } from "@/@types"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; -import { - Card, - CardHeader, - CardTitle, - CardDescription, - CardContent, -} from "@/components/ui/card"; -import { - Chrome, - Shield, - Check, - Users, - ChromeIcon as Firefox, -} from "lucide-react"; -import { Dispatch, SetStateAction } from "react"; -import ExtensionPurches from "./ext-purches"; -import DeveloperInfo from "./developer-info"; -import ExtensionStats from "./ext-stats"; - -type Props = { - extension: Extension; - selectedBrowser: Browser; - setSelectedBrowser: Dispatch>; -}; -export default function Sidebar({ - extension, - selectedBrowser, - setSelectedBrowser, -}: Props) { - return ( -
- {/* Purchase Card */} - - -
-
- {extension.originalPrice && ( - - ${extension.originalPrice} - - )} - - ${extension.price} - -
- - One-time payment - -
- - Lifetime license with free updates - -
- -
- -
- - -
-
- - - -
-
- File size: - {extension.size} -
-
- Version: - {extension.version} -
-
- Last updated: - {extension.lastUpdated} -
-
- Downloads: - - {extension.stats.downloads.toLocaleString()} - -
-
- -
-
- - 30-day money-back guarantee -
-
- - Lifetime updates included -
-
- - Premium support included -
-
-
-
- - {/* Developer Info */} - - - {/* Extension Stats */} - -
- ); -} diff --git a/src/app/(public)/_components/toggle-wish-list.tsx b/src/app/(public)/_components/toggle-wish-list.tsx deleted file mode 100644 index e2fd7a4..0000000 --- a/src/app/(public)/_components/toggle-wish-list.tsx +++ /dev/null @@ -1,70 +0,0 @@ -"use client"; -import { Button } from "@/components/ui/button"; -import { Heart, Download } from "lucide-react"; -import Link from "next/link"; -import { useEffect, useState } from "react"; -import { toast } from "sonner"; -import { ExtensionSchema } from "../schemas/extension.schema"; - -type Props = { - extension: ExtensionSchema; -}; -export default function ToggleWishlist({ extension }: Props) { - const [wishlist, setWishlist] = useState([]); - - // Load wishlist from localStorage on mount - useEffect(() => { - const storedWishlist = localStorage.getItem("browserplugins_wishlist"); - if (storedWishlist) { - setWishlist(JSON.parse(storedWishlist)); - } - }, []); - - // Save wishlist to localStorage whenever it changes - useEffect(() => { - localStorage.setItem("browserplugins_wishlist", JSON.stringify(wishlist)); - }, [wishlist]); - const toggleWishlist = (id: number) => { - setWishlist((prevWishlist) => { - if (prevWishlist.includes(id)) { - toast.info("Removed from Wishlist"); - return prevWishlist.filter((itemId) => itemId !== id); - } else { - toast.info("Added to Wishlist"); - return [...prevWishlist, id]; - } - }); - }; - return ( -
- - - - -
- ); -} diff --git a/src/app/(public)/checkout/[id]/page.tsx b/src/app/(public)/checkout/[id]/page.tsx deleted file mode 100644 index 71a3dee..0000000 --- a/src/app/(public)/checkout/[id]/page.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { Browser } from "@/@types"; -import CheckoutPage from "../../_components/checkout/checkout-page"; - -export default async function Page({ - params, - searchParams, -}: { - params: Promise<{ id: string }>; - searchParams: Promise<{ browser?: string }>; -}) { - const { id } = await params; - const { browser } = await searchParams; - - return ( -
-
-
-
-

- Complete Your Purchase -

-

- You're just one step away from getting your extension -

-
- - -
-
-
- ); -} diff --git a/src/app/(public)/extension/[id]/page.tsx b/src/app/(public)/extension/[id]/page.tsx deleted file mode 100644 index 85a091c..0000000 --- a/src/app/(public)/extension/[id]/page.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import Extensions from "../../_components/single-ext/extension"; - -export default async function ExtensionPage({ - params, -}: { - params: Promise<{ id: string }>; -}) { - const { id } = await params; - - return ( -
-
- -
-
- ); -} diff --git a/src/app/(public)/layout.tsx b/src/app/(public)/layout.tsx deleted file mode 100644 index 7396919..0000000 --- a/src/app/(public)/layout.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import Footer from "@/components/shared/footer"; -import Header from "@/components/shared/header"; -import { ReactNode } from "react"; - -export default function PublicLayout({ - children, -}: Readonly<{ - children: ReactNode; -}>) { - return ( -
-
- {children} -
-
- ); -} diff --git a/src/app/(public)/loading.tsx b/src/app/(public)/loading.tsx deleted file mode 100644 index 8565bd3..0000000 --- a/src/app/(public)/loading.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function Loading() { - return

loading...

; -} diff --git a/src/app/(public)/page.tsx b/src/app/(public)/page.tsx deleted file mode 100644 index 6d3c3f3..0000000 --- a/src/app/(public)/page.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { extensions } from "@/constants"; -import Stats from "./_components/Stats"; -import Hero from "./_components/hero"; -import Extension from "./_components/extensions/extension"; - -export default function HomePage() { - return ( -
- {/* Hero Section */} -
- -
- - - {/* Stats Section */} -
- -
-
- ); -} diff --git a/src/app/(public)/schemas/extension.schema.ts b/src/app/(public)/schemas/extension.schema.ts deleted file mode 100644 index f1aa09a..0000000 --- a/src/app/(public)/schemas/extension.schema.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { browsers } from "@/@types"; -import { z } from "zod"; - -export const extensionStatus = [ - "draft", - "pending", - "approved", - "rejected", - "suspended", -] as const; - -export const extensionSchema = z.object({ - id: z.number().optional(), - - name: z.string().min(1), - slug: z.string().optional(), - - sellerId: z.number(), - categoryId: z.number(), - - description: z.string().min(1), - shortDescription: z.string().optional(), - - price: z.string().regex(/^\d{1,8}(\.\d{1,2})?$/, "Invalid price format"), - version: z.string().min(1), - - browsers: z.array(z.enum(browsers)).default(["chrome"]), - tags: z.array(z.string()).optional(), - iconUrl: z.url().optional(), - screenshots: z.array(z.string()).optional(), - videoUrl: z.url().optional(), - downloadUrl: z.url().optional(), - - downloadCount: z.number().int().nonnegative().default(0), - rating: z - .string() - .regex(/^\d{1}(\.\d{1,2})?$/, "Invalid rating format") - .default("0.00"), - - reviewCount: z.number().int().nonnegative().optional(), - status: z.enum(extensionStatus).optional(), -}); - -export type ExtensionSchema = z.infer; diff --git a/src/app/components/index.ts b/src/app/components/index.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/components/toggle-wish-list-button.tsx b/src/app/components/toggle-wish-list-button.tsx deleted file mode 100644 index 0f7d27b..0000000 --- a/src/app/components/toggle-wish-list-button.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function ToggleWishListButton() { - return

wishlist button

; -} diff --git a/src/app/favicon.ico b/src/app/favicon.ico deleted file mode 100644 index 718d6fea4835ec2d246af9800eddb7ffb276240c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25931 zcmeHv30#a{`}aL_*G&7qml|y<+KVaDM2m#dVr!KsA!#An?kSQM(q<_dDNCpjEux83 zLb9Z^XxbDl(w>%i@8hT6>)&Gu{h#Oeyszu?xtw#Zb1mO{pgX9699l+Qppw7jXaYf~-84xW z)w4x8?=youko|}Vr~(D$UXIbiXABHh`p1?nn8Po~fxRJv}|0e(BPs|G`(TT%kKVJAdg5*Z|x0leQq0 zkdUBvb#>9F()jo|T~kx@OM8$9wzs~t2l;K=woNssA3l6|sx2r3+kdfVW@e^8e*E}v zA1y5{bRi+3Z`uD3{F7LgFJDdvm;nJilkzDku>BwXH(8ItVCXk*-lSJnR?-2UN%hJ){&rlvg`CDTj z)Bzo!3v7Ou#83zEDEFcKt(f1E0~=rqeEbTnMvWR#{+9pg%7G8y>u1OVRUSoox-ovF z2Ydma(;=YuBY(eI|04{hXzZD6_f(v~H;C~y5=DhAC{MMS>2fm~1H_t2$56pc$NH8( z5bH|<)71dV-_oCHIrzrT`2s-5w_+2CM0$95I6X8p^r!gHp+j_gd;9O<1~CEQQGS8) zS9Qh3#p&JM-G8rHekNmKVewU;pJRcTAog68KYo^dRo}(M>36U4Us zfgYWSiHZL3;lpWT=zNAW>Dh#mB!_@Lg%$ms8N-;aPqMn+C2HqZgz&9~Eu z4|Kp<`$q)Uw1R?y(~S>ePdonHxpV1#eSP1B;Ogo+-Pk}6#0GsZZ5!||ev2MGdh}_m z{DeR7?0-1^zVs&`AV6Vt;r3`I`OI_wgs*w=eO%_#7Kepl{B@xiyCANc(l zzIyd4y|c6PXWq9-|KM8(zIk8LPk(>a)zyFWjhT!$HJ$qX1vo@d25W<fvZQ2zUz5WRc(UnFMKHwe1| zWmlB1qdbiA(C0jmnV<}GfbKtmcu^2*P^O?MBLZKt|As~ge8&AAO~2K@zbXelK|4T<{|y4`raF{=72kC2Kn(L4YyenWgrPiv z@^mr$t{#X5VuIMeL!7Ab6_kG$&#&5p*Z{+?5U|TZ`B!7llpVmp@skYz&n^8QfPJzL z0G6K_OJM9x+Wu2gfN45phANGt{7=C>i34CV{Xqlx(fWpeAoj^N0Biu`w+MVcCUyU* zDZuzO0>4Z6fbu^T_arWW5n!E45vX8N=bxTVeFoep_G#VmNlQzAI_KTIc{6>c+04vr zx@W}zE5JNSU>!THJ{J=cqjz+4{L4A{Ob9$ZJ*S1?Ggg3klFp!+Y1@K+pK1DqI|_gq z5ZDXVpge8-cs!o|;K73#YXZ3AShj50wBvuq3NTOZ`M&qtjj#GOFfgExjg8Gn8>Vq5 z`85n+9|!iLCZF5$HJ$Iu($dm?8~-ofu}tEc+-pyke=3!im#6pk_Wo8IA|fJwD&~~F zc16osQ)EBo58U7XDuMexaPRjU@h8tXe%S{fA0NH3vGJFhuyyO!Uyl2^&EOpX{9As0 zWj+P>{@}jxH)8|r;2HdupP!vie{sJ28b&bo!8`D^x}TE$%zXNb^X1p@0PJ86`dZyj z%ce7*{^oo+6%&~I!8hQy-vQ7E)0t0ybH4l%KltWOo~8cO`T=157JqL(oq_rC%ea&4 z2NcTJe-HgFjNg-gZ$6!Y`SMHrlj}Etf7?r!zQTPPSv}{so2e>Fjs1{gzk~LGeesX%r(Lh6rbhSo_n)@@G-FTQy93;l#E)hgP@d_SGvyCp0~o(Y;Ee8{ zdVUDbHm5`2taPUOY^MAGOw*>=s7=Gst=D+p+2yON!0%Hk` zz5mAhyT4lS*T3LS^WSxUy86q&GnoHxzQ6vm8)VS}_zuqG?+3td68_x;etQAdu@sc6 zQJ&5|4(I?~3d-QOAODHpZ=hlSg(lBZ!JZWCtHHSj`0Wh93-Uk)_S%zsJ~aD>{`A0~ z9{AG(e|q3g5B%wYKRxiL2Y$8(4w6bzchKuloQW#e&S3n+P- z8!ds-%f;TJ1>)v)##>gd{PdS2Oc3VaR`fr=`O8QIO(6(N!A?pr5C#6fc~Ge@N%Vvu zaoAX2&(a6eWy_q&UwOhU)|P3J0Qc%OdhzW=F4D|pt0E4osw;%<%Dn58hAWD^XnZD= z>9~H(3bmLtxpF?a7su6J7M*x1By7YSUbxGi)Ot0P77`}P3{)&5Un{KD?`-e?r21!4vTTnN(4Y6Lin?UkSM z`MXCTC1@4A4~mvz%Rh2&EwY))LeoT=*`tMoqcEXI>TZU9WTP#l?uFv+@Dn~b(>xh2 z;>B?;Tz2SR&KVb>vGiBSB`@U7VIWFSo=LDSb9F{GF^DbmWAfpms8Sx9OX4CnBJca3 zlj9(x!dIjN?OG1X4l*imJNvRCk}F%!?SOfiOq5y^mZW)jFL@a|r-@d#f7 z2gmU8L3IZq0ynIws=}~m^#@&C%J6QFo~Mo4V`>v7MI-_!EBMMtb%_M&kvAaN)@ZVw z+`toz&WG#HkWDjnZE!6nk{e-oFdL^$YnbOCN}JC&{$#$O27@|Tn-skXr)2ml2~O!5 zX+gYoxhoc7qoU?C^3~&!U?kRFtnSEecWuH0B0OvLodgUAi}8p1 zrO6RSXHH}DMc$&|?D004DiOVMHV8kXCP@7NKB zgaZq^^O<7PoKEp72kby@W0Z!Y*Ay{&vfg#C&gG@YVR9g?FEocMUi1gSN$+V+ayF45{a zuDZDTN}mS|;BO%gEf}pjBfN2-gIrU#G5~cucA;dokXW89%>AyXJJI z9X4UlIWA|ZYHgbI z5?oFk@A=Ik7lrEQPDH!H+b`7_Y~aDb_qa=B2^Y&Ow41cU=4WDd40dp5(QS-WMN-=Y z9g;6_-JdNU;|6cPwf$ak*aJIcwL@1n$#l~zi{c{EW?T;DaW*E8DYq?Umtz{nJ&w-M zEMyTDrC&9K$d|kZe2#ws6)L=7K+{ zQw{XnV6UC$6-rW0emqm8wJoeZK)wJIcV?dST}Z;G0Arq{dVDu0&4kd%N!3F1*;*pW zR&qUiFzK=@44#QGw7k1`3t_d8&*kBV->O##t|tonFc2YWrL7_eqg+=+k;!F-`^b8> z#KWCE8%u4k@EprxqiV$VmmtiWxDLgnGu$Vs<8rppV5EajBXL4nyyZM$SWVm!wnCj-B!Wjqj5-5dNXukI2$$|Bu3Lrw}z65Lc=1G z^-#WuQOj$hwNGG?*CM_TO8Bg-1+qc>J7k5c51U8g?ZU5n?HYor;~JIjoWH-G>AoUP ztrWWLbRNqIjW#RT*WqZgPJXU7C)VaW5}MiijYbABmzoru6EmQ*N8cVK7a3|aOB#O& zBl8JY2WKfmj;h#Q!pN%9o@VNLv{OUL?rixHwOZuvX7{IJ{(EdPpuVFoQqIOa7giLVkBOKL@^smUA!tZ1CKRK}#SSM)iQHk)*R~?M!qkCruaS!#oIL1c z?J;U~&FfH#*98^G?i}pA{ z9Jg36t4=%6mhY(quYq*vSxptes9qy|7xSlH?G=S@>u>Ebe;|LVhs~@+06N<4CViBk zUiY$thvX;>Tby6z9Y1edAMQaiH zm^r3v#$Q#2T=X>bsY#D%s!bhs^M9PMAcHbCc0FMHV{u-dwlL;a1eJ63v5U*?Q_8JO zT#50!RD619#j_Uf))0ooADz~*9&lN!bBDRUgE>Vud-i5ck%vT=r^yD*^?Mp@Q^v+V zG#-?gKlr}Eeqifb{|So?HM&g91P8|av8hQoCmQXkd?7wIJwb z_^v8bbg`SAn{I*4bH$u(RZ6*xUhuA~hc=8czK8SHEKTzSxgbwi~9(OqJB&gwb^l4+m`k*Q;_?>Y-APi1{k zAHQ)P)G)f|AyjSgcCFps)Fh6Bca*Xznq36!pV6Az&m{O8$wGFD? zY&O*3*J0;_EqM#jh6^gMQKpXV?#1?>$ml1xvh8nSN>-?H=V;nJIwB07YX$e6vLxH( zqYwQ>qxwR(i4f)DLd)-$P>T-no_c!LsN@)8`e;W@)-Hj0>nJ-}Kla4-ZdPJzI&Mce zv)V_j;(3ERN3_@I$N<^|4Lf`B;8n+bX@bHbcZTopEmDI*Jfl)-pFDvo6svPRoo@(x z);_{lY<;);XzT`dBFpRmGrr}z5u1=pC^S-{ce6iXQlLGcItwJ^mZx{m$&DA_oEZ)B{_bYPq-HA zcH8WGoBG(aBU_j)vEy+_71T34@4dmSg!|M8Vf92Zj6WH7Q7t#OHQqWgFE3ARt+%!T z?oLovLVlnf?2c7pTc)~cc^($_8nyKwsN`RA-23ed3sdj(ys%pjjM+9JrctL;dy8a( z@en&CQmnV(()bu|Y%G1-4a(6x{aLytn$T-;(&{QIJB9vMox11U-1HpD@d(QkaJdEb zG{)+6Dos_L+O3NpWo^=gR?evp|CqEG?L&Ut#D*KLaRFOgOEK(Kq1@!EGcTfo+%A&I z=dLbB+d$u{sh?u)xP{PF8L%;YPPW53+@{>5W=Jt#wQpN;0_HYdw1{ksf_XhO4#2F= zyPx6Lx2<92L-;L5PD`zn6zwIH`Jk($?Qw({erA$^bC;q33hv!d!>%wRhj# zal^hk+WGNg;rJtb-EB(?czvOM=H7dl=vblBwAv>}%1@{}mnpUznfq1cE^sgsL0*4I zJ##!*B?=vI_OEVis5o+_IwMIRrpQyT_Sq~ZU%oY7c5JMIADzpD!Upz9h@iWg_>>~j zOLS;wp^i$-E?4<_cp?RiS%Rd?i;f*mOz=~(&3lo<=@(nR!_Rqiprh@weZlL!t#NCc zO!QTcInq|%#>OVgobj{~ixEUec`E25zJ~*DofsQdzIa@5^nOXj2T;8O`l--(QyU^$t?TGY^7#&FQ+2SS3B#qK*k3`ye?8jUYSajE5iBbJls75CCc(m3dk{t?- zopcER9{Z?TC)mk~gpi^kbbu>b-+a{m#8-y2^p$ka4n60w;Sc2}HMf<8JUvhCL0B&Btk)T`ctE$*qNW8L$`7!r^9T+>=<=2qaq-;ll2{`{Rg zc5a0ZUI$oG&j-qVOuKa=*v4aY#IsoM+1|c4Z)<}lEDvy;5huB@1RJPquU2U*U-;gu z=En2m+qjBzR#DEJDO`WU)hdd{Vj%^0V*KoyZ|5lzV87&g_j~NCjwv0uQVqXOb*QrQ zy|Qn`hxx(58c70$E;L(X0uZZ72M1!6oeg)(cdKO ze0gDaTz+ohR-#d)NbAH4x{I(21yjwvBQfmpLu$)|m{XolbgF!pmsqJ#D}(ylp6uC> z{bqtcI#hT#HW=wl7>p!38sKsJ`r8}lt-q%Keqy%u(xk=yiIJiUw6|5IvkS+#?JTBl z8H5(Q?l#wzazujH!8o>1xtn8#_w+397*_cy8!pQGP%K(Ga3pAjsaTbbXJlQF_+m+-UpUUent@xM zg%jqLUExj~o^vQ3Gl*>wh=_gOr2*|U64_iXb+-111aH}$TjeajM+I20xw(((>fej-@CIz4S1pi$(#}P7`4({6QS2CaQS4NPENDp>sAqD z$bH4KGzXGffkJ7R>V>)>tC)uax{UsN*dbeNC*v}#8Y#OWYwL4t$ePR?VTyIs!wea+ z5Urmc)X|^`MG~*dS6pGSbU+gPJoq*^a=_>$n4|P^w$sMBBy@f*Z^Jg6?n5?oId6f{ z$LW4M|4m502z0t7g<#Bx%X;9<=)smFolV&(V^(7Cv2-sxbxopQ!)*#ZRhTBpx1)Fc zNm1T%bONzv6@#|dz(w02AH8OXe>kQ#1FMCzO}2J_mST)+ExmBr9cva-@?;wnmWMOk z{3_~EX_xadgJGv&H@zK_8{(x84`}+c?oSBX*Ge3VdfTt&F}yCpFP?CpW+BE^cWY0^ zb&uBN!Ja3UzYHK-CTyA5=L zEMW{l3Usky#ly=7px648W31UNV@K)&Ub&zP1c7%)`{);I4b0Q<)B}3;NMG2JH=X$U zfIW4)4n9ZM`-yRj67I)YSLDK)qfUJ_ij}a#aZN~9EXrh8eZY2&=uY%2N0UFF7<~%M zsB8=erOWZ>Ct_#^tHZ|*q`H;A)5;ycw*IcmVxi8_0Xk}aJA^ath+E;xg!x+As(M#0=)3!NJR6H&9+zd#iP(m0PIW8$ z1Y^VX`>jm`W!=WpF*{ioM?C9`yOR>@0q=u7o>BP-eSHqCgMDj!2anwH?s%i2p+Q7D zzszIf5XJpE)IG4;d_(La-xenmF(tgAxK`Y4sQ}BSJEPs6N_U2vI{8=0C_F?@7<(G; zo$~G=8p+076G;`}>{MQ>t>7cm=zGtfbdDXm6||jUU|?X?CaE?(<6bKDYKeHlz}DA8 zXT={X=yp_R;HfJ9h%?eWvQ!dRgz&Su*JfNt!Wu>|XfU&68iRikRrHRW|ZxzRR^`eIGt zIeiDgVS>IeExKVRWW8-=A=yA`}`)ZkWBrZD`hpWIxBGkh&f#ijr449~m`j6{4jiJ*C!oVA8ZC?$1RM#K(_b zL9TW)kN*Y4%^-qPpMP7d4)o?Nk#>aoYHT(*g)qmRUb?**F@pnNiy6Fv9rEiUqD(^O zzyS?nBrX63BTRYduaG(0VVG2yJRe%o&rVrLjbxTaAFTd8s;<<@Qs>u(<193R8>}2_ zuwp{7;H2a*X7_jryzriZXMg?bTuegABb^87@SsKkr2)0Gyiax8KQWstw^v#ix45EVrcEhr>!NMhprl$InQMzjSFH54x5k9qHc`@9uKQzvL4ihcq{^B zPrVR=o_ic%Y>6&rMN)hTZsI7I<3&`#(nl+3y3ys9A~&^=4?PL&nd8)`OfG#n zwAMN$1&>K++c{^|7<4P=2y(B{jJsQ0a#U;HTo4ZmWZYvI{+s;Td{Yzem%0*k#)vjpB zia;J&>}ICate44SFYY3vEelqStQWFihx%^vQ@Do(sOy7yR2@WNv7Y9I^yL=nZr3mb zXKV5t@=?-Sk|b{XMhA7ZGB@2hqsx}4xwCW!in#C zI@}scZlr3-NFJ@NFaJlhyfcw{k^vvtGl`N9xSo**rDW4S}i zM9{fMPWo%4wYDG~BZ18BD+}h|GQKc-g^{++3MY>}W_uq7jGHx{mwE9fZiPCoxN$+7 zrODGGJrOkcPQUB(FD5aoS4g~7#6NR^ma7-!>mHuJfY5kTe6PpNNKC9GGRiu^L31uG z$7v`*JknQHsYB!Tm_W{a32TM099djW%5e+j0Ve_ct}IM>XLF1Ap+YvcrLV=|CKo6S zb+9Nl3_YdKP6%Cxy@6TxZ>;4&nTneadr z_ES90ydCev)LV!dN=#(*f}|ZORFdvkYBni^aLbUk>BajeWIOcmHP#8S)*2U~QKI%S zyrLmtPqb&TphJ;>yAxri#;{uyk`JJqODDw%(Z=2`1uc}br^V%>j!gS)D*q*f_-qf8&D;W1dJgQMlaH5er zN2U<%Smb7==vE}dDI8K7cKz!vs^73o9f>2sgiTzWcwY|BMYHH5%Vn7#kiw&eItCqa zIkR2~Q}>X=Ar8W|^Ms41Fm8o6IB2_j60eOeBB1Br!boW7JnoeX6Gs)?7rW0^5psc- zjS16yb>dFn>KPOF;imD}e!enuIniFzv}n$m2#gCCv4jM#ArwlzZ$7@9&XkFxZ4n!V zj3dyiwW4Ki2QG{@i>yuZXQizw_OkZI^-3otXC{!(lUpJF33gI60ak;Uqitp74|B6I zgg{b=Iz}WkhCGj1M=hu4#Aw173YxIVbISaoc z-nLZC*6Tgivd5V`K%GxhBsp@SUU60-rfc$=wb>zdJzXS&-5(NRRodFk;Kxk!S(O(a0e7oY=E( zAyS;Ow?6Q&XA+cnkCb{28_1N8H#?J!*$MmIwLq^*T_9-z^&UE@A(z9oGYtFy6EZef LrJugUA?W`A8`#=m diff --git a/src/app/globals.css b/src/app/globals.css deleted file mode 100644 index 51383c8..0000000 --- a/src/app/globals.css +++ /dev/null @@ -1,142 +0,0 @@ -@import "tailwindcss"; -@import "tw-animate-css"; - -@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); - --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 { - --radius: 0.625rem; - --background: oklch(1 0 0); - --foreground: oklch(0.145 0 0); - --card: oklch(1 0 0); - --card-foreground: oklch(0.145 0 0); - --popover: oklch(1 0 0); - --popover-foreground: oklch(0.145 0 0); - --primary: oklch(0.205 0 0); - --primary-foreground: oklch(0.985 0 0); - --secondary: oklch(0.97 0 0); - --secondary-foreground: oklch(0.205 0 0); - --muted: oklch(0.97 0 0); - --muted-foreground: oklch(0.556 0 0); - --accent: oklch(0.97 0 0); - --accent-foreground: oklch(0.205 0 0); - --destructive: oklch(0.577 0.245 27.325); - --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); -} - -.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: oklch(0.922 0 0); - --primary-foreground: oklch(0.205 0 0); - --secondary: oklch(0.269 0 0); - --secondary-foreground: oklch(0.985 0 0); - --muted: oklch(0.269 0 0); - --muted-foreground: oklch(0.708 0 0); - --accent: oklch(0.269 0 0); - --accent-foreground: oklch(0.985 0 0); - --destructive: oklch(0.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; - @apply outline-none focus-visible:border-none focus-visible:outline-none; - } - body { - @apply bg-background text-foreground; - } -} - -/* Custom scrollbar */ -::-webkit-scrollbar { - width: 8px; -} - -::-webkit-scrollbar-track { - background: var(--background); /* Use theme background */ - border-radius: 10px; -} - -::-webkit-scrollbar-thumb { - background: linear-gradient(45deg, #8b5cf6, #ec4899); - border-radius: 10px; -} - -::-webkit-scrollbar-thumb:hover { - background: linear-gradient(45deg, #7c3aed, #db2777); -} diff --git a/src/app/layout.tsx b/src/app/layout.tsx deleted file mode 100644 index d3b43b1..0000000 --- a/src/app/layout.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import type { Metadata } from "next"; -import "./globals.css"; -import BaseProviders from "@/providers/base-providers"; - -export const metadata: Metadata = { - title: "BrowserPlugins", - description: "Premium Browser Extensions Marketplace", -}; - -export default function RootLayout({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { - return ( - - - {children} - - - ); -} diff --git a/src/components/shared/footer.tsx b/src/components/shared/footer.tsx deleted file mode 100644 index 94bf9ad..0000000 --- a/src/components/shared/footer.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import { categories } from "@/constants/categories.data"; -import Link from "next/link"; - -export default function Footer() { - return ( -
-
-
-
-
-
-
- BP -
-
-

- BrowserPlugins -

-

- Premium Store -

-
-
-

- Your trusted source for premium browser extensions. Handcrafted - with care, tested for quality, and designed to enhance your - digital experience. -

-
-
-

- Categories -

-
    - {categories.slice(1).map((cat) => ( -
  • - - {cat.icon} - {cat.label} - -
  • - ))} -
-
-
-

- Support -

-
    -
  • - - Help Center - -
  • -
  • - - Contact Us - -
  • -
  • - - Privacy Policy - -
  • -
  • - - Terms of Service - -
  • -
-
-
-
-

- © 2024 BrowserPlugins.
- All rights reserved. Made with ❤️ by{" "} - - Sabbir Hossian Shuvo - - . -

-
-
-
-
- ); -} diff --git a/src/components/shared/header.tsx b/src/components/shared/header.tsx deleted file mode 100644 index 78b5ef5..0000000 --- a/src/components/shared/header.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import Logo from "./logo"; -import RightSideHeader from "./right-side-header-item"; - -export default function Header() { - return ( -
-
-
- - - -
-
-
- ); -} diff --git a/src/components/shared/logo.tsx b/src/components/shared/logo.tsx deleted file mode 100644 index 0b6998c..0000000 --- a/src/components/shared/logo.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import Link from "next/link"; - -export default function Logo() { - return ( - -
-
- BP -
-
-
-
-

- BrowserPlugins -

-

- Premium Store -

-
- - ); -} diff --git a/src/components/shared/right-side-header-item.tsx b/src/components/shared/right-side-header-item.tsx deleted file mode 100644 index 8743bb8..0000000 --- a/src/components/shared/right-side-header-item.tsx +++ /dev/null @@ -1,41 +0,0 @@ -"use client"; - -import Link from "next/link"; -import { ThemeToggle } from "../theme-toggle"; -import { Button } from "../ui/button"; -import { usePathname } from "next/navigation"; - -export default function RightSideHeader() { - const pathname = usePathname(); - - return pathname.startsWith("/dashboard") ? ( -
- Welcome back! - - -
- ) : ( -
- - - - - - - -
- ); -} diff --git a/src/components/theme-toggle.tsx b/src/components/theme-toggle.tsx deleted file mode 100644 index e3b0cca..0000000 --- a/src/components/theme-toggle.tsx +++ /dev/null @@ -1,53 +0,0 @@ -"use client"; -import { Moon, Sun } from "lucide-react"; -import { useTheme } from "next-themes"; -import { Button } from "@/components/ui/button"; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; - -export function ThemeToggle() { - const { setTheme } = useTheme(); - - return ( - - - - - - setTheme("light")} - className="text-foreground hover:bg-accent rounded-lg" - > - Light - - setTheme("dark")} - className="text-foreground hover:bg-accent rounded-lg" - > - Dark - - setTheme("system")} - className="text-foreground hover:bg-accent rounded-lg" - > - System - - - - ); -} diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx deleted file mode 100644 index 0205413..0000000 --- a/src/components/ui/badge.tsx +++ /dev/null @@ -1,46 +0,0 @@ -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/src/components/ui/button.tsx b/src/components/ui/button.tsx deleted file mode 100644 index a2df8dc..0000000 --- a/src/components/ui/button.tsx +++ /dev/null @@ -1,59 +0,0 @@ -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/src/components/ui/card.tsx b/src/components/ui/card.tsx deleted file mode 100644 index d05bbc6..0000000 --- a/src/components/ui/card.tsx +++ /dev/null @@ -1,92 +0,0 @@ -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/src/components/ui/checkbox.tsx b/src/components/ui/checkbox.tsx deleted file mode 100644 index fa0e4b5..0000000 --- a/src/components/ui/checkbox.tsx +++ /dev/null @@ -1,32 +0,0 @@ -"use client" - -import * as React from "react" -import * as CheckboxPrimitive from "@radix-ui/react-checkbox" -import { CheckIcon } from "lucide-react" - -import { cn } from "@/lib/utils" - -function Checkbox({ - className, - ...props -}: React.ComponentProps) { - return ( - - - - - - ) -} - -export { Checkbox } diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx deleted file mode 100644 index d9ccec9..0000000 --- a/src/components/ui/dialog.tsx +++ /dev/null @@ -1,143 +0,0 @@ -"use client" - -import * as React from "react" -import * as DialogPrimitive from "@radix-ui/react-dialog" -import { XIcon } from "lucide-react" - -import { cn } from "@/lib/utils" - -function Dialog({ - ...props -}: React.ComponentProps) { - return -} - -function DialogTrigger({ - ...props -}: React.ComponentProps) { - return -} - -function DialogPortal({ - ...props -}: React.ComponentProps) { - return -} - -function DialogClose({ - ...props -}: React.ComponentProps) { - return -} - -function DialogOverlay({ - className, - ...props -}: React.ComponentProps) { - return ( - - ) -} - -function DialogContent({ - className, - children, - showCloseButton = true, - ...props -}: React.ComponentProps & { - showCloseButton?: boolean -}) { - return ( - - - - {children} - {showCloseButton && ( - - - Close - - )} - - - ) -} - -function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { - return ( -
- ) -} - -function DialogFooter({ className, ...props }: React.ComponentProps<"div">) { - return ( -
- ) -} - -function DialogTitle({ - className, - ...props -}: React.ComponentProps) { - return ( - - ) -} - -function DialogDescription({ - className, - ...props -}: React.ComponentProps) { - return ( - - ) -} - -export { - Dialog, - DialogClose, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogOverlay, - DialogPortal, - DialogTitle, - DialogTrigger, -} diff --git a/src/components/ui/dropdown-menu.tsx b/src/components/ui/dropdown-menu.tsx deleted file mode 100644 index ec51e9c..0000000 --- a/src/components/ui/dropdown-menu.tsx +++ /dev/null @@ -1,257 +0,0 @@ -"use client" - -import * as React from "react" -import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu" -import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react" - -import { cn } from "@/lib/utils" - -function DropdownMenu({ - ...props -}: React.ComponentProps) { - return -} - -function DropdownMenuPortal({ - ...props -}: React.ComponentProps) { - return ( - - ) -} - -function DropdownMenuTrigger({ - ...props -}: React.ComponentProps) { - return ( - - ) -} - -function DropdownMenuContent({ - className, - sideOffset = 4, - ...props -}: React.ComponentProps) { - return ( - - - - ) -} - -function DropdownMenuGroup({ - ...props -}: React.ComponentProps) { - return ( - - ) -} - -function DropdownMenuItem({ - className, - inset, - variant = "default", - ...props -}: React.ComponentProps & { - inset?: boolean - variant?: "default" | "destructive" -}) { - return ( - - ) -} - -function DropdownMenuCheckboxItem({ - className, - children, - checked, - ...props -}: React.ComponentProps) { - return ( - - - - - - - {children} - - ) -} - -function DropdownMenuRadioGroup({ - ...props -}: React.ComponentProps) { - return ( - - ) -} - -function DropdownMenuRadioItem({ - className, - children, - ...props -}: React.ComponentProps) { - return ( - - - - - - - {children} - - ) -} - -function DropdownMenuLabel({ - className, - inset, - ...props -}: React.ComponentProps & { - inset?: boolean -}) { - return ( - - ) -} - -function DropdownMenuSeparator({ - className, - ...props -}: React.ComponentProps) { - return ( - - ) -} - -function DropdownMenuShortcut({ - className, - ...props -}: React.ComponentProps<"span">) { - return ( - - ) -} - -function DropdownMenuSub({ - ...props -}: React.ComponentProps) { - return -} - -function DropdownMenuSubTrigger({ - className, - inset, - children, - ...props -}: React.ComponentProps & { - inset?: boolean -}) { - return ( - - {children} - - - ) -} - -function DropdownMenuSubContent({ - className, - ...props -}: React.ComponentProps) { - return ( - - ) -} - -export { - DropdownMenu, - DropdownMenuPortal, - DropdownMenuTrigger, - DropdownMenuContent, - DropdownMenuGroup, - DropdownMenuLabel, - DropdownMenuItem, - DropdownMenuCheckboxItem, - DropdownMenuRadioGroup, - DropdownMenuRadioItem, - DropdownMenuSeparator, - DropdownMenuShortcut, - DropdownMenuSub, - DropdownMenuSubTrigger, - DropdownMenuSubContent, -} diff --git a/src/components/ui/hover-card.tsx b/src/components/ui/hover-card.tsx deleted file mode 100644 index e754186..0000000 --- a/src/components/ui/hover-card.tsx +++ /dev/null @@ -1,44 +0,0 @@ -"use client" - -import * as React from "react" -import * as HoverCardPrimitive from "@radix-ui/react-hover-card" - -import { cn } from "@/lib/utils" - -function HoverCard({ - ...props -}: React.ComponentProps) { - return -} - -function HoverCardTrigger({ - ...props -}: React.ComponentProps) { - return ( - - ) -} - -function HoverCardContent({ - className, - align = "center", - sideOffset = 4, - ...props -}: React.ComponentProps) { - return ( - - - - ) -} - -export { HoverCard, HoverCardTrigger, HoverCardContent } diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx deleted file mode 100644 index 03295ca..0000000 --- a/src/components/ui/input.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import * as React from "react" - -import { cn } from "@/lib/utils" - -function Input({ className, type, ...props }: React.ComponentProps<"input">) { - return ( - - ) -} - -export { Input } diff --git a/src/components/ui/label.tsx b/src/components/ui/label.tsx deleted file mode 100644 index fb5fbc3..0000000 --- a/src/components/ui/label.tsx +++ /dev/null @@ -1,24 +0,0 @@ -"use client" - -import * as React from "react" -import * as LabelPrimitive from "@radix-ui/react-label" - -import { cn } from "@/lib/utils" - -function Label({ - className, - ...props -}: React.ComponentProps) { - return ( - - ) -} - -export { Label } diff --git a/src/components/ui/select.tsx b/src/components/ui/select.tsx deleted file mode 100644 index dcbbc0c..0000000 --- a/src/components/ui/select.tsx +++ /dev/null @@ -1,185 +0,0 @@ -"use client" - -import * as React from "react" -import * as SelectPrimitive from "@radix-ui/react-select" -import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react" - -import { cn } from "@/lib/utils" - -function Select({ - ...props -}: React.ComponentProps) { - return -} - -function SelectGroup({ - ...props -}: React.ComponentProps) { - return -} - -function SelectValue({ - ...props -}: React.ComponentProps) { - return -} - -function SelectTrigger({ - className, - size = "default", - children, - ...props -}: React.ComponentProps & { - size?: "sm" | "default" -}) { - return ( - - {children} - - - - - ) -} - -function SelectContent({ - className, - children, - position = "popper", - ...props -}: React.ComponentProps) { - return ( - - - - - {children} - - - - - ) -} - -function SelectLabel({ - className, - ...props -}: React.ComponentProps) { - return ( - - ) -} - -function SelectItem({ - className, - children, - ...props -}: React.ComponentProps) { - return ( - - - - - - - {children} - - ) -} - -function SelectSeparator({ - className, - ...props -}: React.ComponentProps) { - return ( - - ) -} - -function SelectScrollUpButton({ - className, - ...props -}: React.ComponentProps) { - return ( - - - - ) -} - -function SelectScrollDownButton({ - className, - ...props -}: React.ComponentProps) { - return ( - - - - ) -} - -export { - Select, - SelectContent, - SelectGroup, - SelectItem, - SelectLabel, - SelectScrollDownButton, - SelectScrollUpButton, - SelectSeparator, - SelectTrigger, - SelectValue, -} diff --git a/src/components/ui/separator.tsx b/src/components/ui/separator.tsx deleted file mode 100644 index 275381c..0000000 --- a/src/components/ui/separator.tsx +++ /dev/null @@ -1,28 +0,0 @@ -"use client" - -import * as React from "react" -import * as SeparatorPrimitive from "@radix-ui/react-separator" - -import { cn } from "@/lib/utils" - -function Separator({ - className, - orientation = "horizontal", - decorative = true, - ...props -}: React.ComponentProps) { - return ( - - ) -} - -export { Separator } diff --git a/src/components/ui/slider.tsx b/src/components/ui/slider.tsx deleted file mode 100644 index 09391e8..0000000 --- a/src/components/ui/slider.tsx +++ /dev/null @@ -1,63 +0,0 @@ -"use client" - -import * as React from "react" -import * as SliderPrimitive from "@radix-ui/react-slider" - -import { cn } from "@/lib/utils" - -function Slider({ - className, - defaultValue, - value, - min = 0, - max = 100, - ...props -}: React.ComponentProps) { - const _values = React.useMemo( - () => - Array.isArray(value) - ? value - : Array.isArray(defaultValue) - ? defaultValue - : [min, max], - [value, defaultValue, min, max] - ) - - return ( - - - - - {Array.from({ length: _values.length }, (_, index) => ( - - ))} - - ) -} - -export { Slider } diff --git a/src/components/ui/sonner.tsx b/src/components/ui/sonner.tsx deleted file mode 100644 index 957524e..0000000 --- a/src/components/ui/sonner.tsx +++ /dev/null @@ -1,25 +0,0 @@ -"use client" - -import { useTheme } from "next-themes" -import { Toaster as Sonner, ToasterProps } from "sonner" - -const Toaster = ({ ...props }: ToasterProps) => { - const { theme = "system" } = useTheme() - - return ( - - ) -} - -export { Toaster } diff --git a/src/components/ui/tabs.tsx b/src/components/ui/tabs.tsx deleted file mode 100644 index 497ba5e..0000000 --- a/src/components/ui/tabs.tsx +++ /dev/null @@ -1,66 +0,0 @@ -"use client" - -import * as React from "react" -import * as TabsPrimitive from "@radix-ui/react-tabs" - -import { cn } from "@/lib/utils" - -function Tabs({ - className, - ...props -}: React.ComponentProps) { - return ( - - ) -} - -function TabsList({ - className, - ...props -}: React.ComponentProps) { - return ( - - ) -} - -function TabsTrigger({ - className, - ...props -}: React.ComponentProps) { - return ( - - ) -} - -function TabsContent({ - className, - ...props -}: React.ComponentProps) { - return ( - - ) -} - -export { Tabs, TabsList, TabsTrigger, TabsContent } diff --git a/src/components/video-modal.tsx b/src/components/video-modal.tsx deleted file mode 100644 index faf1a41..0000000 --- a/src/components/video-modal.tsx +++ /dev/null @@ -1,45 +0,0 @@ -"use client"; - -import { Dialog, DialogContent, DialogOverlay } from "@/components/ui/dialog"; -import { extractIframeSrc } from "@/lib/utils"; -import { X } from "lucide-react"; -import { Dispatch, SetStateAction } from "react"; - -type VideoModalProps = { - isModalOpen: boolean; - videoUrl: string; - setIsModalOpen: Dispatch>; -}; - -export function VideoModal({ - isModalOpen, - videoUrl, - setIsModalOpen, -}: VideoModalProps) { - return ( - setIsModalOpen(open)}> - - e.stopPropagation()} - > - -
- -
-
-
- ); -} diff --git a/src/constants/all-extensions.ts b/src/constants/all-extensions.ts deleted file mode 100644 index 988178e..0000000 --- a/src/constants/all-extensions.ts +++ /dev/null @@ -1,39 +0,0 @@ -export const allExtensions = [ - { - id: 1, - name: "ProductivityPro Max", - browser: "chrome", - purchaseDate: "2024-12-15", - licenseKey: "PROD-ABC123DEF456", - downloadUrl: "/download/1", - status: "active", - price: 39.99, - description: - "Ultimate productivity suite with AI-powered task management and focus tools", - }, - { - id: 2, - name: "SecureVault", - browser: "firefox", - purchaseDate: "2024-12-10", - licenseKey: "SECURE-XYZ789GHI012", - downloadUrl: "/download/2", - status: "active", - price: 29.99, - description: - "Military-grade password manager with biometric authentication", - }, - { - id: 3, - name: "DevTools Master", - browser: "chrome", - purchaseDate: "2024-12-12", - licenseKey: "DEV-ABC123DEF456", - downloadUrl: "/download/3", - status: "active", - price: 24.99, - description: "Advanced developer tools with code snippets and API testing", - }, -] as const; - -export type AllExtension = (typeof allExtensions)[number]; diff --git a/src/constants/browsers.data.tsx b/src/constants/browsers.data.tsx deleted file mode 100644 index 9d03e6d..0000000 --- a/src/constants/browsers.data.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { Chrome, Compass, Earth, EarthLock, Sparkles } from "lucide-react"; - -export const browsers = [ - { - value: "all", - label: "All Extensions", - icon: , - color: "#8B5CF6", - }, - { - value: "chrome", - label: "Chrome", - icon: , - color: "#8B5CF6", - }, - { - value: "firefox", - label: "FireFox", - icon: , - color: "#10B981", - }, - { - value: "microsoft-edge", - label: "Microsoft Edge", - icon: , - color: "#3B82F6", - }, - { - value: "safary", - label: "Safary", - icon: , - color: "#F59E0B", - }, -]; -export type Browsers = (typeof browsers)[number]; diff --git a/src/constants/categories.data.tsx b/src/constants/categories.data.tsx deleted file mode 100644 index 1de144b..0000000 --- a/src/constants/categories.data.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { Zap, Sparkles, Globe, Code, GamepadIcon, Wrench } from "lucide-react"; - -export const categories = [ - { - value: "all", - label: "All Categories", - icon: , - color: "#8B5CF6", - }, - { - value: "productivity", - label: "Productivity", - icon: , - color: "#8B5CF6", - }, - { - value: "security", - label: "Security", - icon: , - color: "#10B981", - }, - { - value: "developer", - label: "Developer Tools", - icon: , - color: "#3B82F6", - }, - { - value: "social", - label: "Social Media", - icon: , - color: "#F59E0B", - }, - { - value: "entertainment", - label: "Entertainment", - icon: , - color: "#DC2626", - }, - { - value: "utility", - label: "Utilities", - icon: , - color: "#8B5A2B", - }, -]; - -export type Categories = (typeof categories)[number]; diff --git a/src/constants/extension.data.ts b/src/constants/extension.data.ts deleted file mode 100644 index 151c340..0000000 --- a/src/constants/extension.data.ts +++ /dev/null @@ -1,315 +0,0 @@ -export const extensions = [ - { - id: 1, - name: "YouTube Video Downloader", - description: - "A powerful tool allows you to easily download your favorite videos from YouTube with just a few clicks.", - longDescription: - "Introducing the YouTube Video Downloader Chrome Extension - a powerful tool allows you to easily download your favorite videos from YouTube with just a few clicks. With its user-friendly interface and lightning-fast download speeds, this extension is the perfect solution for anyone looking to save their favorite videos for offline viewing. Download now and experience the convenience of having your favorite YouTube videos at your fingertips!", - price: 30, - originalPrice: 45, - category: "social", - browsers: ["chrome"], - rating: 5, - totalRatings: 0, - users: "1+", - features: [ - "Download Popup", - "URL Fetch", - "Download Video From YouTube", - "Able to change video quality", - "Awesome User Interface", - "Fetch YouTube Thumbnail too", - ], - tags: ["social", "youtube", "tools", "video downloader"], - media: [ - { - type: "video", - url: ``, // Example YouTube embed URL - thumbnail: "/placeholder-thumb.jpg", - }, - ], - screenshots: [ - "/placeholder-thumb.jpg", - "/placeholder-thumb.jpg", - "/placeholder-thumb.jpg", - ], - version: "1.2.7", - size: "1.23 MB", - lastUpdated: "Sep 26, 2024", - permissions: ["No Permission Needed"], - developer: { - name: "Sabbir Hossian Shuvo", - avatar: "https://avatars.githubusercontent.com/u/82939905?v=4", - verified: true, - }, - stats: { - downloads: 2, - likes: 5, - views: 10, - }, - isPopular: true, - isFeatured: true, - isNew: true, - gradientFrom: "#8B5CF6", - gradientTo: "#EC4899", - }, - { - id: 2, - name: "SecureVault Pro", - description: - "Military-grade password manager with biometric authentication", - longDescription: - "Keep your digital life secure with advanced encryption, biometric locks, and seamless auto-fill across all your devices.", - price: 29.99, - category: "security", - browsers: ["chrome", "firefox"], - rating: 4.8, - totalRatings: 892, - users: "18K+", - features: [ - "Biometric Auth", - "256-bit Encryption", - "Auto-fill", - "Secure Notes", - "2FA Support", - ], - tags: ["security", "password", "encryption", "privacy"], - media: [ - { - type: "video", - url: ``, // Example YouTube embed URL - thumbnail: "/placeholder.svg?height=400&width=600", - }, - ], - screenshots: ["/placeholder.svg?height=400&width=600"], - version: "2.8.0", - size: "1.8 MB", - lastUpdated: "2024-12-08", - permissions: ["Access to all websites", "Storage permissions"], - developer: { - name: "BrowserPlugins", - avatar: "/placeholder.svg?height=40&width=40", - verified: true, - }, - stats: { - downloads: 18000, - likes: 1650, - views: 32000, - }, - isPopular: true, - isFeatured: false, - isNew: false, - gradientFrom: "#10B981", - gradientTo: "#06B6D4", - changelog: [ - { - version: "3.2.1", - date: "2024-12-10", - changes: [ - "Fixed tab grouping bug", - "Improved AI task suggestions", - "Enhanced dark mode", - ], - }, - { - version: "3.2.0", - date: "2024-12-01", - changes: [ - "Added AI-powered task prioritization", - "New analytics dashboard", - "Performance improvements", - ], - }, - ], - }, - { - id: 3, - name: "DevTools Master", - description: "Advanced developer tools with code snippets and API testing", - longDescription: - "Supercharge your development workflow with advanced debugging tools, code snippets manager, and integrated API testing suite.", - price: 24.99, - category: "developer", - browsers: ["chrome"], - rating: 4.7, - totalRatings: 654, - users: "12K+", - features: [ - "Code Snippets", - "API Testing", - "Console Enhancement", - "Network Monitor", - ], - tags: ["developer", "debugging", "api", "tools"], - media: [ - { - type: "image", - url: "/placeholder.svg?height=400&width=600", - }, - ], - screenshots: ["/placeholder.svg?height=400&width=600"], - version: "1.9.2", - size: "3.2 MB", - lastUpdated: "2024-12-12", - permissions: ["Developer tools access", "Storage permissions"], - developer: { - name: "BrowserPlugins", - avatar: "/placeholder.svg?height=40&width=40", - verified: true, - }, - stats: { - downloads: 12000, - likes: 980, - views: 28000, - }, - isPopular: false, - isFeatured: false, - isNew: true, - gradientFrom: "#3B82F6", - gradientTo: "#1D4ED8", - }, - { - id: 4, - name: "SocialBoost", - description: - "Social media management and analytics in one powerful extension", - longDescription: - "Manage all your social media accounts, schedule posts, and track analytics with this comprehensive social media toolkit.", - price: 19.99, - originalPrice: 34.99, - category: "social", - browsers: ["chrome", "firefox"], - rating: 4.6, - totalRatings: 423, - users: "8K+", - features: [ - "Multi-platform Support", - "Post Scheduling", - "Analytics Dashboard", - "Hashtag Generator", - ], - tags: ["social", "marketing", "analytics", "scheduling"], - media: [ - { - type: "video", - url: ``, // Example YouTube embed URL - thumbnail: "/placeholder.svg?height=400&width=600", - }, - ], - screenshots: ["/placeholder.svg?height=400&width=600"], - version: "1.5.3", - size: "2.8 MB", - lastUpdated: "2024-12-05", - permissions: ["Access to social media sites", "Storage permissions"], - developer: { - name: "BrowserPlugins", - avatar: "/placeholder.svg?height=40&width=40", - verified: true, - }, - stats: { - downloads: 8000, - likes: 720, - views: 15000, - }, - isPopular: false, - isFeatured: true, - isNew: false, - gradientFrom: "#F59E0B", - gradientTo: "#EF4444", - }, - { - id: 5, - name: "StreamlineUI", - description: "Beautiful UI customization for popular websites and web apps", - longDescription: - "Transform your browsing experience with custom themes, layouts, and UI enhancements for your favorite websites.", - price: 14.99, - category: "utility", - browsers: ["chrome", "firefox"], - rating: 4.5, - totalRatings: 789, - users: "15K+", - features: [ - "Custom Themes", - "Layout Control", - "Dark Mode", - "Font Customization", - ], - tags: ["ui", "themes", "customization", "design"], - media: [ - { - type: "image", - url: "/placeholder.svg?height=400&width=600", - }, - ], - screenshots: ["/placeholder.svg?height=400&width=600"], - version: "2.3.1", - size: "1.5 MB", - lastUpdated: "2024-12-07", - permissions: ["Access to all websites", "Storage permissions"], - developer: { - name: "BrowserPlugins", - avatar: "/placeholder.svg?height=40&width=40", - verified: true, - }, - stats: { - downloads: 15000, - likes: 1200, - views: 22000, - }, - isPopular: false, - isFeatured: false, - isNew: false, - gradientFrom: "#8B5A2B", - gradientTo: "#D97706", - }, - { - id: 6, - name: "GameBooster Pro", - description: - "Optimize your browser for gaming with performance enhancements", - longDescription: - "Get the ultimate gaming experience in your browser with performance optimizations, FPS monitoring, and game-specific enhancements.", - price: 22.99, - category: "entertainment", - browsers: ["chrome"], - rating: 4.4, - totalRatings: 312, - users: "6K+", - features: [ - "Performance Boost", - "FPS Monitor", - "Game Profiles", - "Memory Optimization", - ], - tags: ["gaming", "performance", "optimization", "fps"], - media: [ - { - type: "video", - url: ``, // Example YouTube embed URL - thumbnail: "/placeholder.svg?height=400&width=600", - }, - ], - screenshots: ["/placeholder.svg?height=400&width=600"], - version: "1.2.8", - size: "2.4 MB", - lastUpdated: "2024-12-11", - permissions: ["Access to gaming websites", "System performance access"], - developer: { - name: "BrowserPlugins", - avatar: "/placeholder.svg?height=40&width=40", - verified: true, - }, - stats: { - downloads: 6000, - likes: 450, - views: 12000, - }, - isPopular: false, - isFeatured: false, - isNew: true, - gradientFrom: "#DC2626", - gradientTo: "#7C2D12", - }, -]; diff --git a/src/constants/filter.data.ts b/src/constants/filter.data.ts deleted file mode 100644 index 40d1f9d..0000000 --- a/src/constants/filter.data.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const sortsBy = [ - { label: "🔥 Most Popular", value: "popular" }, - { label: "⭐ Highest Rated", value: "rating" }, - { label: "🆕 Newest", value: "newest" }, - { label: "💰 Price: Low to High", value: "price-low" }, - { label: "💎 Price: High to Low", value: "price-high" }, -] as const; diff --git a/src/constants/index.ts b/src/constants/index.ts deleted file mode 100644 index 9e09d4f..0000000 --- a/src/constants/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "./extension.data"; -export * from "./filter.data"; -export * from "./categories.data"; -export * from "./browsers.data"; diff --git a/src/hooks/use-mobile.tsx b/src/hooks/use-mobile.tsx deleted file mode 100644 index 6286a75..0000000 --- a/src/hooks/use-mobile.tsx +++ /dev/null @@ -1,22 +0,0 @@ -"use client"; -import * as React from "react"; - -const MOBILE_BREAKPOINT = 768; - -export function useIsMobile() { - const [isMobile, setIsMobile] = React.useState( - undefined - ); - - React.useEffect(() => { - const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`); - const onChange = () => { - setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); - }; - mql.addEventListener("change", onChange); - setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); - return () => mql.removeEventListener("change", onChange); - }, []); - - return !!isMobile; -} diff --git a/src/lib/utils.ts b/src/lib/utils.ts deleted file mode 100644 index f7e386f..0000000 --- a/src/lib/utils.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { clsx, type ClassValue } from "clsx"; -import { twMerge } from "tailwind-merge"; - -export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)); -} - -export function extractIframeSrc(html: string): string { - const match = html.match(/]+src="([^"]+)"/); - if (!match || !match[1]) throw new Error("Fail to extract source of video"); - return match[1]; -} diff --git a/src/providers/base-providers.tsx b/src/providers/base-providers.tsx deleted file mode 100644 index 1cda362..0000000 --- a/src/providers/base-providers.tsx +++ /dev/null @@ -1,11 +0,0 @@ -"use client"; -import { PropsWithChildren } from "react"; -import { ThemeProvider } from "./theme-provider"; - -export default function BaseProviders({ children }: PropsWithChildren) { - return ( - - {children} - - ); -} diff --git a/src/providers/theme-provider.tsx b/src/providers/theme-provider.tsx deleted file mode 100644 index 93455f9..0000000 --- a/src/providers/theme-provider.tsx +++ /dev/null @@ -1,19 +0,0 @@ -"use client"; - -import { - ThemeProvider as NextThemesProvider, - type ThemeProviderProps, -} from "next-themes"; - -export function ThemeProvider({ children, ...props }: ThemeProviderProps) { - return ( - - {children} - - ); -} diff --git a/src/utils/index.ts b/src/utils/index.ts deleted file mode 100644 index aade640..0000000 --- a/src/utils/index.ts +++ /dev/null @@ -1 +0,0 @@ -export const baseURI = `http://localhost:5000`; diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 0000000..8084832 --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "composite": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "importHelpers": true, + "isolatedModules": true, + "lib": ["es2022"], + "module": "nodenext", + "moduleResolution": "nodenext", + "noEmitOnError": true, + "noFallthroughCasesInSwitch": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noUnusedLocals": true, + "skipLibCheck": true, + "strict": true, + "target": "es2022", + "customConditions": ["development"] + } +} diff --git a/tsconfig.json b/tsconfig.json index a73c6d1..efd510d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,27 +1,16 @@ { - "compilerOptions": { - "target": "ES2017", - "lib": ["dom", "dom.iterable", "esnext"], - "allowJs": true, - "skipLibCheck": true, - "strict": true, - "noEmit": true, - "esModuleInterop": true, - "module": "esnext", - "moduleResolution": "bundler", - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "preserve", - "incremental": true, - "plugins": [ - { - "name": "next" - } - ], - "paths": { - "@/*": ["./src/*"] + "extends": "./tsconfig.base.json", + "compileOnSave": false, + "files": [], + "references": [ + { + "path": "./packages" + }, + { + "path": "./packages" + }, + { + "path": "./packages/zod-schema" } - }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], - "exclude": ["node_modules", "server", "diagram"] + ] } diff --git a/vitest.workspace.ts b/vitest.workspace.ts new file mode 100644 index 0000000..883c608 --- /dev/null +++ b/vitest.workspace.ts @@ -0,0 +1,4 @@ +export default [ + '**/vite.config.{mjs,js,ts,mts}', + '**/vitest.config.{mjs,js,ts,mts}', +]; From 1bb62fb8f14d50f24a96504d38bdaed810855989 Mon Sep 17 00:00:00 2001 From: devlopersabbir Date: Thu, 7 Aug 2025 12:49:26 +0600 Subject: [PATCH 3/8] =?UTF-8?q?[feat=20=F0=9F=9B=B9]=20added=20seller=20|?= =?UTF-8?q?=20admin=20|=20store=20pages=20=F0=9F=94=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .prettierrc | 2 +- apps/server/.env.example | 2 + apps/server/src/main.ts | 2 +- pnpm-lock.yaml | 163 +++++++++++++++++++++++++++++++++++++-- 4 files changed, 159 insertions(+), 10 deletions(-) create mode 100644 apps/server/.env.example diff --git a/.prettierrc b/.prettierrc index 544138b..1ca87ab 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,3 +1,3 @@ { - "singleQuote": true + "singleQuote": false } diff --git a/apps/server/.env.example b/apps/server/.env.example new file mode 100644 index 0000000..b69fb08 --- /dev/null +++ b/apps/server/.env.example @@ -0,0 +1,2 @@ +PORT=5000 +DATABASE_URL='' \ No newline at end of file diff --git a/apps/server/src/main.ts b/apps/server/src/main.ts index af29723..92e093c 100644 --- a/apps/server/src/main.ts +++ b/apps/server/src/main.ts @@ -7,6 +7,6 @@ async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalPipes(new ValidationPipe({ transform: true, whitelist: true })); - await app.listen(process.env.PORT ?? 3000); + await app.listen(process.env.PORT ?? 9000); } bootstrap(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 63cfc52..c94aba3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -192,6 +192,9 @@ importers: apps/web: dependencies: + '@radix-ui/react-avatar': + specifier: ^1.1.10 + version: 1.1.10(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@radix-ui/react-checkbox': specifier: ^1.3.2 version: 1.3.2(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) @@ -207,6 +210,9 @@ importers: '@radix-ui/react-label': specifier: ^2.1.7 version: 2.1.7(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-progress': + specifier: ^1.1.7 + version: 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@radix-ui/react-select': specifier: ^2.2.5 version: 2.2.5(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) @@ -219,9 +225,15 @@ importers: '@radix-ui/react-slot': specifier: ^1.2.3 version: 1.2.3(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-switch': + specifier: ^1.2.5 + version: 1.2.5(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@radix-ui/react-tabs': specifier: ^1.1.12 version: 1.1.12(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-tooltip': + specifier: ^1.2.7 + version: 1.2.7(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) axios: specifier: ^1.11.0 version: 1.11.0 @@ -2096,6 +2108,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-avatar@1.1.10': + resolution: {integrity: sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==} + 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 + '@radix-ui/react-checkbox@1.3.2': resolution: {integrity: sha512-yd+dI56KZqawxKZrJ31eENUwqc1QSqg4OZ15rybGjF2ZNwMO+wCyHzAVLRp9qoYJf7kYy0YpZ2b0JCzJ42HZpA==} peerDependencies: @@ -2310,6 +2335,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-progress@1.1.7': + resolution: {integrity: sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg==} + 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 + '@radix-ui/react-roving-focus@1.1.10': resolution: {integrity: sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q==} peerDependencies: @@ -2371,6 +2409,19 @@ packages: '@types/react': optional: true + '@radix-ui/react-switch@1.2.5': + resolution: {integrity: sha512-5ijLkak6ZMylXsaImpZ8u4Rlf5grRmoc0p0QeX9VJtlrM4f5m3nCTX8tWga/zOA8PZYIR/t0p2Mnvd7InrJ6yQ==} + 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 + '@radix-ui/react-tabs@1.1.12': resolution: {integrity: sha512-GTVAlRVrQrSw3cEARM0nAx73ixrWDPNZAruETn3oHCNP6SbZ/hNxdxp+u7VkIEv3/sFoLq1PfcHrl7Pnp0CDpw==} peerDependencies: @@ -2384,6 +2435,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-tooltip@1.2.7': + resolution: {integrity: sha512-Ap+fNYwKTYJ9pzqW+Xe2HtMRbQ/EeWkj2qykZ6SuEV4iS/o1bZI5ssJbk4D2r8XuDuOBVz/tIx2JObtuqU+5Zw==} + 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 + '@radix-ui/react-use-callback-ref@1.1.1': resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} peerDependencies: @@ -2420,6 +2484,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-use-is-hydrated@0.1.0': + resolution: {integrity: sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-use-layout-effect@1.1.1': resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} peerDependencies: @@ -6763,6 +6836,11 @@ packages: '@types/react': optional: true + use-sync-external-store@1.5.0: + resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -8913,6 +8991,19 @@ snapshots: '@types/react': 19.1.9 '@types/react-dom': 19.1.7(@types/react@19.1.9) + '@radix-ui/react-avatar@1.1.10(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-context': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.9)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.9 + '@types/react-dom': 19.1.7(@types/react@19.1.9) + '@radix-ui/react-checkbox@1.3.2(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: '@radix-ui/primitive': 1.1.2 @@ -9132,6 +9223,16 @@ snapshots: '@types/react': 19.1.9 '@types/react-dom': 19.1.7(@types/react@19.1.9) + '@radix-ui/react-progress@1.1.7(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-context': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.9 + '@types/react-dom': 19.1.7(@types/react@19.1.9) + '@radix-ui/react-roving-focus@1.1.10(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: '@radix-ui/primitive': 1.1.2 @@ -9213,6 +9314,21 @@ snapshots: optionalDependencies: '@types/react': 19.1.9 + '@radix-ui/react-switch@1.2.5(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.9)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.9 + '@types/react-dom': 19.1.7(@types/react@19.1.9) + '@radix-ui/react-tabs@1.1.12(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: '@radix-ui/primitive': 1.1.2 @@ -9229,6 +9345,26 @@ snapshots: '@types/react': 19.1.9 '@types/react-dom': 19.1.7(@types/react@19.1.9) + '@radix-ui/react-tooltip@1.2.7(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-popper': 1.2.7(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.9)(react@19.1.1) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.9 + '@types/react-dom': 19.1.7(@types/react@19.1.9) + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.1.9)(react@19.1.1)': dependencies: react: 19.1.1 @@ -9257,6 +9393,13 @@ snapshots: optionalDependencies: '@types/react': 19.1.9 + '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@19.1.9)(react@19.1.1)': + dependencies: + react: 19.1.1 + use-sync-external-store: 1.5.0(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.9 + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.1.9)(react@19.1.1)': dependencies: react: 19.1.1 @@ -11162,8 +11305,8 @@ snapshots: '@typescript-eslint/parser': 8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3) eslint: 9.32.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.32.0(jiti@2.5.1)))(eslint@9.32.0(jiti@2.5.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.32.0(jiti@2.5.1)))(eslint@9.32.0(jiti@2.5.1)))(eslint@9.32.0(jiti@2.5.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.32.0(jiti@2.5.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.32.0(jiti@2.5.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.32.0(jiti@2.5.1)) eslint-plugin-react: 7.37.5(eslint@9.32.0(jiti@2.5.1)) eslint-plugin-react-hooks: 5.2.0(eslint@9.32.0(jiti@2.5.1)) @@ -11186,7 +11329,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.32.0(jiti@2.5.1)))(eslint@9.32.0(jiti@2.5.1)): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.32.0(jiti@2.5.1)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.1 @@ -11197,22 +11340,22 @@ snapshots: tinyglobby: 0.2.14 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.32.0(jiti@2.5.1)))(eslint@9.32.0(jiti@2.5.1)))(eslint@9.32.0(jiti@2.5.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.32.0(jiti@2.5.1)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.32.0(jiti@2.5.1)))(eslint@9.32.0(jiti@2.5.1)))(eslint@9.32.0(jiti@2.5.1)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.32.0(jiti@2.5.1)): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3) eslint: 9.32.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.32.0(jiti@2.5.1)))(eslint@9.32.0(jiti@2.5.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.32.0(jiti@2.5.1)) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.32.0(jiti@2.5.1)))(eslint@9.32.0(jiti@2.5.1)))(eslint@9.32.0(jiti@2.5.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.32.0(jiti@2.5.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -11223,7 +11366,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.32.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.32.0(jiti@2.5.1)))(eslint@9.32.0(jiti@2.5.1)))(eslint@9.32.0(jiti@2.5.1)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.32.0(jiti@2.5.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -14104,6 +14247,10 @@ snapshots: optionalDependencies: '@types/react': 19.1.9 + use-sync-external-store@1.5.0(react@19.1.1): + dependencies: + react: 19.1.1 + util-deprecate@1.0.2: {} v8-compile-cache-lib@3.0.1: {} From 7225b1c8bb26c59303eb1d3582525a1d6c979afe Mon Sep 17 00:00:00 2001 From: devlopersabbir Date: Thu, 7 Aug 2025 12:52:35 +0600 Subject: [PATCH 4/8] =?UTF-8?q?[feat=20=F0=9F=9B=B9]=20added=20seller=20|?= =?UTF-8?q?=20admin=20|=20store=20pages=20=F0=9F=94=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/client/.gitignore | 41 + apps/client/README.md | 1 + apps/client/components.json | 21 + apps/client/eslint.config.mjs | 16 + apps/client/next.config.ts | 9 + apps/client/notes.md | 3 + apps/client/package.json | 53 ++ apps/client/postcss.config.mjs | 5 + apps/client/public/placeholder-logo.png | Bin 0 -> 568 bytes apps/client/public/placeholder-logo.svg | 1 + apps/client/public/placeholder-thumb.jpg | Bin 0 -> 118638 bytes apps/client/public/placeholder-user.jpg | Bin 0 -> 1635 bytes apps/client/public/placeholder.jpg | Bin 0 -> 1064 bytes apps/client/public/placeholder.svg | 1 + apps/client/src/@types/extension/browser.ts | 7 + apps/client/src/@types/extension/category.ts | 10 + apps/client/src/@types/extension/developer.ts | 5 + apps/client/src/@types/extension/filter.ts | 2 + apps/client/src/@types/extension/media.ts | 5 + apps/client/src/@types/extension/stats.ts | 5 + apps/client/src/@types/index.ts | 8 + .../app/(admin)/admin/extensions/loading.tsx | 3 + .../src/app/(admin)/admin/extensions/page.tsx | 265 +++++++ apps/client/src/app/(admin)/admin/page.tsx | 156 ++++ .../src/app/(admin)/admin/upload/page.tsx | 431 +++++++++++ apps/client/src/app/(admin)/layout.tsx | 137 ++++ .../src/app/(auth)/_components/auth-logo.tsx | 16 + .../src/app/(auth)/_components/login-form.tsx | 57 ++ .../app/(auth)/_components/register-form.tsx | 85 ++ apps/client/src/app/(auth)/layout.tsx | 13 + apps/client/src/app/(auth)/loading.tsx | 3 + apps/client/src/app/(auth)/login/page.tsx | 57 ++ apps/client/src/app/(auth)/register/page.tsx | 50 ++ .../src/app/(dashboard)/dashboard/page.tsx | 375 +++++++++ apps/client/src/app/(dashboard)/layout.tsx | 18 + .../(store)/store/[username]/loading.tsx | 3 + .../(store)/store/[username]/page.tsx | 378 +++++++++ .../src/app/(public)/_components/Stats.tsx | 49 ++ .../_components/checkout/checkout-page.tsx | 217 ++++++ .../_components/extensions/ext-card.tsx | 170 ++++ .../extensions/ext-grid-header.tsx | 24 + .../_components/extensions/ext-grid.tsx | 38 + .../_components/extensions/extension.tsx | 22 + .../_components/filters/base-filters.tsx | 35 + .../_components/filters/browser-filter.tsx | 49 ++ .../_components/filters/category-filter.tsx | 51 ++ .../_components/filters/price-filter.tsx | 26 + .../_components/filters/search-filters.tsx | 26 + .../_components/filters/search-form.tsx | 23 + .../_components/filters/sort-by-filter.tsx | 44 ++ .../src/app/(public)/_components/hero.tsx | 42 + .../app/(public)/_components/play-button.tsx | 25 + .../_components/single-ext/developer-info.tsx | 53 ++ .../_components/single-ext/ext-details.tsx | 172 +++++ .../_components/single-ext/ext-header.tsx | 69 ++ .../single-ext/ext-media-gallery.tsx | 84 ++ .../_components/single-ext/ext-purches.tsx | 74 ++ .../_components/single-ext/ext-stats.tsx | 56 ++ .../_components/single-ext/extension.tsx | 64 ++ .../_components/single-ext/sidebar.tsx | 145 ++++ .../(public)/_components/toggle-wish-list.tsx | 70 ++ .../src/app/(public)/checkout/[id]/page.tsx | 32 + .../src/app/(public)/extension/[id]/page.tsx | 17 + apps/client/src/app/(public)/layout.tsx | 20 + apps/client/src/app/(public)/loading.tsx | 3 + apps/client/src/app/(public)/page.tsx | 21 + .../app/(public)/schemas/extension.schema.ts | 44 ++ apps/client/src/app/(seller)/layout.tsx | 188 +++++ .../(seller)/seller/extensions/loading.tsx | 3 + .../app/(seller)/seller/extensions/page.tsx | 423 ++++++++++ apps/client/src/app/(seller)/seller/page.tsx | 308 ++++++++ .../src/app/(seller)/seller/profile/page.tsx | 365 +++++++++ .../src/app/(seller)/seller/store/page.tsx | 464 +++++++++++ .../src/app/(seller)/seller/upload/page.tsx | 605 +++++++++++++++ .../app/[username]/dashboard/profile/page.tsx | 205 +++++ .../src/app/[username]/store/loading.tsx | 3 + apps/client/src/app/[username]/store/page.tsx | 378 +++++++++ apps/client/src/app/components/index.ts | 0 .../components/toggle-wish-list-button.tsx | 3 + apps/client/src/app/favicon.ico | Bin 0 -> 25931 bytes apps/client/src/app/globals.css | 142 ++++ apps/client/src/app/layout.tsx | 22 + apps/client/src/components/shared/footer.tsx | 105 +++ apps/client/src/components/shared/header.tsx | 16 + apps/client/src/components/shared/logo.tsx | 22 + .../shared/right-side-header-item.tsx | 41 + apps/client/src/components/theme-toggle.tsx | 53 ++ apps/client/src/components/ui/avatar.tsx | 53 ++ apps/client/src/components/ui/badge.tsx | 46 ++ apps/client/src/components/ui/breadcrumb.tsx | 109 +++ apps/client/src/components/ui/button.tsx | 59 ++ apps/client/src/components/ui/card.tsx | 92 +++ apps/client/src/components/ui/checkbox.tsx | 32 + apps/client/src/components/ui/dialog.tsx | 143 ++++ .../src/components/ui/dropdown-menu.tsx | 257 +++++++ apps/client/src/components/ui/hover-card.tsx | 44 ++ apps/client/src/components/ui/input.tsx | 21 + apps/client/src/components/ui/label.tsx | 24 + apps/client/src/components/ui/progress.tsx | 31 + apps/client/src/components/ui/select.tsx | 185 +++++ apps/client/src/components/ui/separator.tsx | 28 + apps/client/src/components/ui/sheet.tsx | 139 ++++ apps/client/src/components/ui/sidebar.tsx | 726 ++++++++++++++++++ apps/client/src/components/ui/skeleton.tsx | 13 + apps/client/src/components/ui/slider.tsx | 63 ++ apps/client/src/components/ui/sonner.tsx | 25 + apps/client/src/components/ui/switch.tsx | 31 + apps/client/src/components/ui/table.tsx | 116 +++ apps/client/src/components/ui/tabs.tsx | 66 ++ apps/client/src/components/ui/textarea.tsx | 18 + apps/client/src/components/ui/tooltip.tsx | 61 ++ apps/client/src/components/video-modal.tsx | 45 ++ apps/client/src/constants/all-extensions.ts | 39 + apps/client/src/constants/browsers.data.tsx | 35 + apps/client/src/constants/categories.data.tsx | 48 ++ apps/client/src/constants/extension.data.ts | 315 ++++++++ apps/client/src/constants/filter.data.ts | 7 + apps/client/src/constants/index.ts | 4 + apps/client/src/hooks/use-mobile.ts | 19 + apps/client/src/hooks/use-mobile.tsx | 22 + apps/client/src/lib/utils.ts | 12 + apps/client/src/providers/base-providers.tsx | 11 + apps/client/src/providers/theme-provider.tsx | 19 + apps/client/src/utils/index.ts | 1 + apps/client/tsconfig.json | 27 + 125 files changed, 10337 insertions(+) create mode 100644 apps/client/.gitignore create mode 100644 apps/client/README.md create mode 100644 apps/client/components.json create mode 100644 apps/client/eslint.config.mjs create mode 100644 apps/client/next.config.ts create mode 100644 apps/client/notes.md create mode 100644 apps/client/package.json create mode 100644 apps/client/postcss.config.mjs create mode 100644 apps/client/public/placeholder-logo.png create mode 100644 apps/client/public/placeholder-logo.svg create mode 100644 apps/client/public/placeholder-thumb.jpg create mode 100644 apps/client/public/placeholder-user.jpg create mode 100644 apps/client/public/placeholder.jpg create mode 100644 apps/client/public/placeholder.svg create mode 100644 apps/client/src/@types/extension/browser.ts create mode 100644 apps/client/src/@types/extension/category.ts create mode 100644 apps/client/src/@types/extension/developer.ts create mode 100644 apps/client/src/@types/extension/filter.ts create mode 100644 apps/client/src/@types/extension/media.ts create mode 100644 apps/client/src/@types/extension/stats.ts create mode 100644 apps/client/src/@types/index.ts create mode 100644 apps/client/src/app/(admin)/admin/extensions/loading.tsx create mode 100644 apps/client/src/app/(admin)/admin/extensions/page.tsx create mode 100644 apps/client/src/app/(admin)/admin/page.tsx create mode 100644 apps/client/src/app/(admin)/admin/upload/page.tsx create mode 100644 apps/client/src/app/(admin)/layout.tsx create mode 100644 apps/client/src/app/(auth)/_components/auth-logo.tsx create mode 100644 apps/client/src/app/(auth)/_components/login-form.tsx create mode 100644 apps/client/src/app/(auth)/_components/register-form.tsx create mode 100644 apps/client/src/app/(auth)/layout.tsx create mode 100644 apps/client/src/app/(auth)/loading.tsx create mode 100644 apps/client/src/app/(auth)/login/page.tsx create mode 100644 apps/client/src/app/(auth)/register/page.tsx create mode 100644 apps/client/src/app/(dashboard)/dashboard/page.tsx create mode 100644 apps/client/src/app/(dashboard)/layout.tsx create mode 100644 apps/client/src/app/(public)/(store)/store/[username]/loading.tsx create mode 100644 apps/client/src/app/(public)/(store)/store/[username]/page.tsx create mode 100644 apps/client/src/app/(public)/_components/Stats.tsx create mode 100644 apps/client/src/app/(public)/_components/checkout/checkout-page.tsx create mode 100644 apps/client/src/app/(public)/_components/extensions/ext-card.tsx create mode 100644 apps/client/src/app/(public)/_components/extensions/ext-grid-header.tsx create mode 100644 apps/client/src/app/(public)/_components/extensions/ext-grid.tsx create mode 100644 apps/client/src/app/(public)/_components/extensions/extension.tsx create mode 100644 apps/client/src/app/(public)/_components/filters/base-filters.tsx create mode 100644 apps/client/src/app/(public)/_components/filters/browser-filter.tsx create mode 100644 apps/client/src/app/(public)/_components/filters/category-filter.tsx create mode 100644 apps/client/src/app/(public)/_components/filters/price-filter.tsx create mode 100644 apps/client/src/app/(public)/_components/filters/search-filters.tsx create mode 100644 apps/client/src/app/(public)/_components/filters/search-form.tsx create mode 100644 apps/client/src/app/(public)/_components/filters/sort-by-filter.tsx create mode 100644 apps/client/src/app/(public)/_components/hero.tsx create mode 100644 apps/client/src/app/(public)/_components/play-button.tsx create mode 100644 apps/client/src/app/(public)/_components/single-ext/developer-info.tsx create mode 100644 apps/client/src/app/(public)/_components/single-ext/ext-details.tsx create mode 100644 apps/client/src/app/(public)/_components/single-ext/ext-header.tsx create mode 100644 apps/client/src/app/(public)/_components/single-ext/ext-media-gallery.tsx create mode 100644 apps/client/src/app/(public)/_components/single-ext/ext-purches.tsx create mode 100644 apps/client/src/app/(public)/_components/single-ext/ext-stats.tsx create mode 100644 apps/client/src/app/(public)/_components/single-ext/extension.tsx create mode 100644 apps/client/src/app/(public)/_components/single-ext/sidebar.tsx create mode 100644 apps/client/src/app/(public)/_components/toggle-wish-list.tsx create mode 100644 apps/client/src/app/(public)/checkout/[id]/page.tsx create mode 100644 apps/client/src/app/(public)/extension/[id]/page.tsx create mode 100644 apps/client/src/app/(public)/layout.tsx create mode 100644 apps/client/src/app/(public)/loading.tsx create mode 100644 apps/client/src/app/(public)/page.tsx create mode 100644 apps/client/src/app/(public)/schemas/extension.schema.ts create mode 100644 apps/client/src/app/(seller)/layout.tsx create mode 100644 apps/client/src/app/(seller)/seller/extensions/loading.tsx create mode 100644 apps/client/src/app/(seller)/seller/extensions/page.tsx create mode 100644 apps/client/src/app/(seller)/seller/page.tsx create mode 100644 apps/client/src/app/(seller)/seller/profile/page.tsx create mode 100644 apps/client/src/app/(seller)/seller/store/page.tsx create mode 100644 apps/client/src/app/(seller)/seller/upload/page.tsx create mode 100644 apps/client/src/app/[username]/dashboard/profile/page.tsx create mode 100644 apps/client/src/app/[username]/store/loading.tsx create mode 100644 apps/client/src/app/[username]/store/page.tsx create mode 100644 apps/client/src/app/components/index.ts create mode 100644 apps/client/src/app/components/toggle-wish-list-button.tsx create mode 100644 apps/client/src/app/favicon.ico create mode 100644 apps/client/src/app/globals.css create mode 100644 apps/client/src/app/layout.tsx create mode 100644 apps/client/src/components/shared/footer.tsx create mode 100644 apps/client/src/components/shared/header.tsx create mode 100644 apps/client/src/components/shared/logo.tsx create mode 100644 apps/client/src/components/shared/right-side-header-item.tsx create mode 100644 apps/client/src/components/theme-toggle.tsx create mode 100644 apps/client/src/components/ui/avatar.tsx create mode 100644 apps/client/src/components/ui/badge.tsx create mode 100644 apps/client/src/components/ui/breadcrumb.tsx create mode 100644 apps/client/src/components/ui/button.tsx create mode 100644 apps/client/src/components/ui/card.tsx create mode 100644 apps/client/src/components/ui/checkbox.tsx create mode 100644 apps/client/src/components/ui/dialog.tsx create mode 100644 apps/client/src/components/ui/dropdown-menu.tsx create mode 100644 apps/client/src/components/ui/hover-card.tsx create mode 100644 apps/client/src/components/ui/input.tsx create mode 100644 apps/client/src/components/ui/label.tsx create mode 100644 apps/client/src/components/ui/progress.tsx create mode 100644 apps/client/src/components/ui/select.tsx create mode 100644 apps/client/src/components/ui/separator.tsx create mode 100644 apps/client/src/components/ui/sheet.tsx create mode 100644 apps/client/src/components/ui/sidebar.tsx create mode 100644 apps/client/src/components/ui/skeleton.tsx create mode 100644 apps/client/src/components/ui/slider.tsx create mode 100644 apps/client/src/components/ui/sonner.tsx create mode 100644 apps/client/src/components/ui/switch.tsx create mode 100644 apps/client/src/components/ui/table.tsx create mode 100644 apps/client/src/components/ui/tabs.tsx create mode 100644 apps/client/src/components/ui/textarea.tsx create mode 100644 apps/client/src/components/ui/tooltip.tsx create mode 100644 apps/client/src/components/video-modal.tsx create mode 100644 apps/client/src/constants/all-extensions.ts create mode 100644 apps/client/src/constants/browsers.data.tsx create mode 100644 apps/client/src/constants/categories.data.tsx create mode 100644 apps/client/src/constants/extension.data.ts create mode 100644 apps/client/src/constants/filter.data.ts create mode 100644 apps/client/src/constants/index.ts create mode 100644 apps/client/src/hooks/use-mobile.ts create mode 100644 apps/client/src/hooks/use-mobile.tsx create mode 100644 apps/client/src/lib/utils.ts create mode 100644 apps/client/src/providers/base-providers.tsx create mode 100644 apps/client/src/providers/theme-provider.tsx create mode 100644 apps/client/src/utils/index.ts create mode 100644 apps/client/tsconfig.json diff --git a/apps/client/.gitignore b/apps/client/.gitignore new file mode 100644 index 0000000..5ef6a52 --- /dev/null +++ b/apps/client/.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/apps/client/README.md b/apps/client/README.md new file mode 100644 index 0000000..e340364 --- /dev/null +++ b/apps/client/README.md @@ -0,0 +1 @@ +## BrowserPlugins diff --git a/apps/client/components.json b/apps/client/components.json new file mode 100644 index 0000000..ffe928f --- /dev/null +++ b/apps/client/components.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "", + "css": "src/app/globals.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "iconLibrary": "lucide" +} \ No newline at end of file diff --git a/apps/client/eslint.config.mjs b/apps/client/eslint.config.mjs new file mode 100644 index 0000000..c85fb67 --- /dev/null +++ b/apps/client/eslint.config.mjs @@ -0,0 +1,16 @@ +import { dirname } from "path"; +import { fileURLToPath } from "url"; +import { FlatCompat } from "@eslint/eslintrc"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const compat = new FlatCompat({ + baseDirectory: __dirname, +}); + +const eslintConfig = [ + ...compat.extends("next/core-web-vitals", "next/typescript"), +]; + +export default eslintConfig; diff --git a/apps/client/next.config.ts b/apps/client/next.config.ts new file mode 100644 index 0000000..f917d61 --- /dev/null +++ b/apps/client/next.config.ts @@ -0,0 +1,9 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + eslint: { + ignoreDuringBuilds: true, + }, +}; + +export default nextConfig; diff --git a/apps/client/notes.md b/apps/client/notes.md new file mode 100644 index 0000000..70a5174 --- /dev/null +++ b/apps/client/notes.md @@ -0,0 +1,3 @@ +## diagram link + +[live diagram](https://www.mermaidchart.com/app/projects/f3e276fc-9321-49ab-a829-79e7cae4ff45/diagrams/5c585bc0-8c20-42d1-acd3-e2a89e7d752c/version/v0.1/edit) diff --git a/apps/client/package.json b/apps/client/package.json new file mode 100644 index 0000000..12a3ec9 --- /dev/null +++ b/apps/client/package.json @@ -0,0 +1,53 @@ +{ + "name": "browserplugins", + "version": "1.1.2", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "@radix-ui/react-avatar": "^1.1.10", + "@radix-ui/react-checkbox": "^1.3.2", + "@radix-ui/react-dialog": "^1.1.14", + "@radix-ui/react-dropdown-menu": "^2.1.15", + "@radix-ui/react-hover-card": "^1.1.14", + "@radix-ui/react-label": "^2.1.7", + "@radix-ui/react-progress": "^1.1.7", + "@radix-ui/react-select": "^2.2.5", + "@radix-ui/react-separator": "^1.1.7", + "@radix-ui/react-slider": "^1.3.5", + "@radix-ui/react-slot": "^1.2.3", + "@radix-ui/react-switch": "^1.2.5", + "@radix-ui/react-tabs": "^1.1.12", + "@radix-ui/react-tooltip": "^1.2.7", + "axios": "^1.11.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "lucide-react": "^0.525.0", + "moment": "^2.30.1", + "next": "15.3.5", + "next-themes": "^0.4.6", + "postcss": "^8.5.6", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "sonner": "^2.0.6", + "tailwind-merge": "^3.3.1", + "tailwindcss-animate": "^1.0.7", + "zod": "^4.0.14" + }, + "devDependencies": { + "@eslint/eslintrc": "^3", + "@tailwindcss/postcss": "^4", + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "eslint": "^9", + "eslint-config-next": "15.3.5", + "tailwindcss": "^4", + "tw-animate-css": "^1.3.5", + "typescript": "^5" + } +} diff --git a/apps/client/postcss.config.mjs b/apps/client/postcss.config.mjs new file mode 100644 index 0000000..c7bcb4b --- /dev/null +++ b/apps/client/postcss.config.mjs @@ -0,0 +1,5 @@ +const config = { + plugins: ["@tailwindcss/postcss"], +}; + +export default config; diff --git a/apps/client/public/placeholder-logo.png b/apps/client/public/placeholder-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8a792ac2ddfbe047639f7907c82f14c73e3de3d9 GIT binary patch literal 568 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5Ca^FANm1Vwi-43tfKP}kNR$*1WiP`GRL@@$ z}KL6V^XjP|gFiXN9MWV@SoVw>S2B83zimJup|_^-FbrjeV3it>ba2M!&I{-9Oz_xPcYF3oFZ=eo>b ztd*bf%*2|<`prCX7bFlbJSYChhATpnZHm_gDmxOE$M3Ov^QCh;k9GZ#-G|g`wsZ1y zY-hCA6Y*4%kP@8PzH+9qgqG>UuX7G~Jv3yxb4X!L$WkVer)+Lao)20%*YwyPoNauk zS!$0_-Kr#3+3w{V4Ccu^47H4DY>jP zOx?nl+kWZD?x4qFw+?-2Jz{$0yTXmVj$U6an>Gc>YVI}tW1#2eCg2#H$RT;W`9jE4 z<(d!P-_Kw0oV0yf*RuH&47YRnuIuc%FZkt*pVIL&DpPv8{ \ No newline at end of file diff --git a/apps/client/public/placeholder-thumb.jpg b/apps/client/public/placeholder-thumb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fde847e69cb352b431d99d600b7b65eea739b34c GIT binary patch literal 118638 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

#4-q{ZoYX7RU$(1*NlrJ@%n>@YUR7lfj)sUuI z$94Y+SLsr`G|zI&e_*UP<$J)Oe_$STHY+z`&R8`1hwG@Qj?e@Cy-tU>uLK_c+1%FB zgjWENg(y1k_0$nh229ojZCmo&>DvuWyOS*Q^IRxFx4H0l+BFB7)KtiQPS>?zcGv8< zDGay0CU+xv*Lku$wzj;PlUx=qNkj9!Oq9Z-5BW4yvJb;wHCio1i!T zvnt0C@4c{wlDnBzJHoqr+uHTg@LY`t3)y-75ML@!m(#}vRoC{?8{g zNyc>*lrnQf>6cgkLHV4IJS4FyNu}R@NQEk&pjP!m(tP?d`uFb>=I}M~7g=p;|AC=n zDVNLK3a$3Q3UT5)7158Vjzx4zr1`uC-d28($kfRBR6Rt>Gkj1j)^@vKxSHTTUohR6 zpJFDL4Kyu0ksQS5cGVYke8U&l!#Lb9TV28>tCh0qmOP<7eLgi>C=~Qj#*@%Bnfdpx zC!CmCI+G5c&FNhgnYl$spR`xgg11N4;NTPCXGPUFhOA=(YLsQl}N26UEHJXfvW2w}zaLZ@BcbH5%zz+KFT@gcu1m4-RcHFi^uoU9i1*hC{L)`|IVv^{fk1W5 z2yc|URpUSS-O1&mUg@z*l{T0G-k9ae=Ocen2@U!E)MCHre1voS%*K>urCkm)_upZd3RvC7UM> zeZ9ZYLGW^?S+oyG^n1v&RBdcXOL7-WP^Mw1Jb_VxN65E!RiCZ7@K=55T`X-!d26+x zr$_pQubvo5x~YA$6siv$K}R$DSaKy6_cG^ z?oEp1teLe9OC1!i2w+&~Y|%H|w-b?UHL*ZqTr63EI0{*$|8E zJT?in2 z)RN57FbQuap)w&~?ETZtip-;9yN{7>Y0vH|a#@|?&4N$WQ_u5JXO(8T57>h5d~E&L zoMh;&do5d|vA3)peIG0;)K$%5cc})}MeAeN8EZ4J7LQOLy;(J?&A^yJOf@|T$HfUojZfRr9xLcG_qHT3@X&in@8^57-NXEy= zuSoSwCexU)n7X1bylDKz` zR~Nr{_UUaHR3@J2Cyl9gq&SC+e}`fZX#Vf)4p|X20<%CB2G=?TcLG_wghq- z?;4}Y4mZoj2tfJj+NgbUU$O^N68u+|8de{b2^h`os_5C{&G~ zRW$TAKPzwm`tvf{%u^jc_V;%f&qw{;@}uPl}>W%D7|Xc%95 zcb-i}74XnsQxvO(NHO_Bc5nV-gv964A+0|!k&&9PuL-W!qj(sStIHR=OdlP28=Pbr zeuiw_4khd<2CyXJ)d8g$@RdyxcKQ9t@y#T8Sk#>(qP{`#V~K?yK1oeC1~o{fKz$iUyjw9Hr<9a9Ju)%SZEO8=2(56Baf=-_ z>~3@u56;-B;5n}Y8O4ndi9U;Gm`6Q;Po7vQ!0OiTHUmIMqToK*hcY@YC`PqI~cnCKN3XWNoF_qbn%YT2~ zR{GrO;=Ck0a_KphHA>-t(7^H~!8fZmL?rF^4R#fqzbtY7x!bcb%GDx9RUa9;tCd z1u&>#>x2bBWJe&uT&&7k=QIy>lLIf0mTus7%X787C<^ z*IQecJ9_D4v{+SASZV!Pz-1S>M6ct8Eect+X{BBL^xAr2GVs!YYH3-w_I#K_A2D)z z@Y5FJ%sYXeq4f*l$TOtP;RPr|rCG|VXu#;6B^7x|P1Ky8qi@P^)f6jz!1ONE zCTia}a?FiT0=bvfJmj&IGt`8d8+x%Df$cMLF;9kqtDetBU<*Ae(C^H8}p4Xg&pe~ZvZf&*=# zuJ{wzELM<;k6!SIM|F|?JTupxM0n!084M7#BtVRH^3<5spxr0oS`TGqN ziyU@$*8P{jOG0uqz~|RtvDuCMnWw70Z$(boZ&0_V%QnOER6&$#as<1zqv4wqT1Zq_REMQ_sKR;Prq|U zJVMX~7;QVx>32PXJEb3)m^vh2fIvZ)rS-Al?Jyh`K8)PcV-dNyR3XicQ1QwX(JQPK^9|uFicU#pBvFfa zh+5_XI7mShxi>1`sEhD98Ar~@5l>b7)9K#-njYy|?$q%gbqAFnF!`6#7enXl2760? zc8eC5d2S?1)N%x0QF6vYa%vXoP%V~*6#Hy5Kj6o~bpjBCvDd zxOLkuJ-t+0A5wrYzG6W&KASH^K>oIL9`p7(3wRq!wAoR;6U^!?)?wmOyR22ZFi;S0 z^Zj75u$~3y!Pqs>1;A%PmmaD4;T*8_RpX927Wc?NqY}IMW>+flBB=}ci>DhuhHbU0 zytJW7(raPQhZD8q)(P`v2vIa%GS3*(*0TErr}6Jnipa;DtXucYGO9qx>0-9Fy+W%f za5Ej5wudTGM{(CxB&jsK*<`x+=W~bdJ07XtGwV~noohY?ODT$v+Q8L}mw&GU>re0I z2Wy{GiN=-(jM}y4NVf6Y3rE%4dBf}7UQw|2Z8DQ@u-RndCbj8|{pssiNrIUBOA8wV zC_Tp45TBBsRJEi^);kNS-3{s_r4KZLX+`PGRmOy*qOM$@i~T9K-~D*-K`# z2)&jwJf86jFGD%J0hg#!Z`^fGImg~4NA;I?hv#EY^wF9261*l2zRDo1 zH21NRfSS`5@7kpU>y3_R@#yI=Ge+K z4rRH`=O!HS=Az8<8|x`lgKU^GF{)f*jmnQGbU9kd&I&})v&&E07SkqHA#qzz-ZAey z^iKJ0I2BQR9{47X4>rSYC2d>K$%J~^2dPt}fVAQGvYGoJGnY`xaJF?7d2)-N<+pST7Q>Vudw>OmqY(n%Gy;ftz3O!GyZfrmYqw z{pGsy6tEIHq!yjiY(61dxH$&>n1+9WMe}VntQ! zADj9ZC)+)vO2Thpe zivMGdtmU?B2E8mbRWzJ8`v16zbL}1>c6u6LuP(S~j;z7J*ui{Q;YOYN@3;1UUEn)4 z7n5xRR=g=Cfhm6081{%&0$Nj!AT=m)fW{U)u~DJ|Y^ixLWYJ9HJ zH2v=^{zBZJDHp^qhoOvdfNaXY&FLi>4JE!|5vHArE1bKWswcsRireJmu2j$!qAqYM zWQSl&fs_P`JC(axyBhU1vAZGnxC}OXsb8ffTWWcdzFxw{nt;`e53nE}tlN$?mk8^9 zmBj;+4Woq@2O`F&my>>Qz#}Kc8ff-rt!~4=G{s)f$>C z&-7!S8qjrDkmu`?eG{OokB74l&;5_JDsrPHf`Lf8$7+n)8>twfy;;pH_BK&J`GxsG zeM_JF#W2m1jz7C&Q2o`tXL++{*O2BDM%-puj<+#~S>4iz^t0Eg>qP|`0f6r!sk#hH zTbev``EBPqyT6-*CtEyaUKiDVBmnGbuikx~lYvm##6DkjzdO+!KB$^k^?b`dr6eHiGYIndZB~aW$Yc?V zqS|}M{ap1&wS3<=e>FK}gB$iMqF9GorQUg~K0FFXF{#Ai4N=US}rY0Xay9nl6Y1ntFzH_S9|O8%;aKVmc}=ZL%9;Fk(zqm zXxiTlD|tO)J4XbA?(d`jn%O5Jl~Ya%KQx&mPIUN_HfqPSJ zq}D2ViWPK@qpsOL3WVnO1f8fXCAbtLTG8cdXA;xZ1X3~mXH)FILKy$=7)jtyXMV?9 zd=b#6D@rZ3RAt=`f|-5xN;l4}*g`e|H=7Fms767oRQwI~JI8kSy!DyluB2;GUwpyG zRWd#tFz1xhAEoCk!N~ja&TaF^E!|rl>PNFJ$(a@hQ3YQ)Z4__o>;=twHU8LY-Io|; z-3Ql0r3%MxkT&iiQw{WhN*Y6{%#OOg$1In+arKN4$u4AD+$$Gdwl^<4LU;TfA<%=>Y{nK+^0-+Iw4w={_CkBZMQs1^PXAj=@;`3dZ(lHhhhZ)wy+;nHo_wb|O0a|# zCFDFCMkg0aUo@=pcri8lha?=RQ-N;{I+ghg2|;?Zq0BmQ`=sU76t(f}86 ztUHd1Tq}KRD}TBxW%VXtlVeN>yJrR#4o3x-vVyWAPq-r^D6bfIXC$J+!aBSCobB!-Y9t3Yn9^g)NyBl-`4Np+0`^ zvBy1!TMPj&&`mK%^M&Ze71TDEih&QJUZ`H`@Y0S;%gv5`KcABuFz3E5-iu&S@|_AL zJTA7ESS=AGOtG0WYx14QWOGKK+geK3;+$?{v(rl6bT4x5TE;H=W%wZ1u+h&r^}-N%!@# zPa{x2SIkiR5`J5uxx=dHOX$q#%?ab?eOkctpIUEZOo52q_`kSVg%)Gw(cL<)mCB=A z)1yxls0jYU{S4Xn1#0z9+Kt$wWcBBdhS!vQQv3q3Hv7M^c6N|NK7W9c zNdB8_=>Ox-E;DzF@mxE{{h3z;pD3o_(Bs;Y%EM__pAE?B#fRf+w3n98u@65;I-zq0 zq+cI4$wCGv&o6NVt)Tp-Ea#$kv-B#%1asYwy~F>&01Ce_A#FZX75i*w3hgsJETq1r zAA6WtE9*niL)ZizUH|u13iu_dR9KK=YFX&qf`btF&MFA+mW;fZ5X|4o*Gud67Gb8s zp_$ll#<-w^JY((gp`)r4b>*mQ$P*T^)4YaypZvpJRUt;7)k!Ew3bym*I>*b0y6haa zVeAo?Jff*$Ey>?o+np^^st`AOwzNq2X|cbfk9{+vEXg8aX4ocGc3(Gqw8PW3LroCr z3J);p@GVEd;M?|Ovy0JLb!{ztmT7!Tuc&T(_37&4zn< zqH0iSu3M*mZoN7GEm!j^v4Xq`4GFD2DGh$`E)a@KJuvbfPqR-6K6iLiK-98 zxS6SLHaXC^aUHHehVWJzMC*J?nE!GAF|+OANhwTY)4XA1yw z&(h-L>(CDnA$fT*zvjGg@Exv-8nbfJUK3Mig7;u6rYu^fG`k13b254W^)UdHG5{nX z%!B&!N@)TF!ghT;z4W;@-Ttgz=(6w-D~eiG4Vq9RzidR!AqGgLI)3_485u4JgNWbY z#+(>Y(XODGk&tytg%0{2xQX#L?)}aE$4sR?wXRvCp{o=ns?J(CiO^bu6*+TBTp;C# z_#05YoURS;7x=ZvZSk2_jj@=Ij9Yf^`Uthy>0|3ni*2v+cBnz~vl3J#;q_deV?2&e z(~gUmXEe#`%<3}M$qc$OMNLu}3e9dm)IdLeF5EK*D{rrq%d_BH<`tO2j|y^I%kCh& zRivR7*@%CD$yx@1PHy1|=7~kBun=P6t{N2~e_dna@I6X`>!X+H!?*m66b{1W4k{w0 zW(OfXxaF#!OR2SyS%nER+_qHi_V@;mG4@yRy}!b=JZ_(&gyZAAkVr<_2|jekRbtSF zNK!{i0HZfh5p*f)xS5`mwcKIYdhD6>un}S$*E+H{&5ZVLCq(Hm@bii3swuUM4AceU;xDOpqlX|FjNEeAly0QapfheW3nPsieUcOZ!}(nNhW_4 zIh293<;bj&n_rv_=F5wlxO3Md^;7&1;PM)*-xK0&&;peP{R6K)li)(M-ql&+$r^Yj zzC;21>O5iwhakihTp#~|QBo+Lj=0hx^&(p1=^98pJ-MVQpjv=RSF!#xqWxcW`2Vzb zhC$tC(BtN-gai##a)zz4=Ml}r%(bWlFYNz2M{Cz&EH0p~?NXc9nvkFyKP(RDkzbMB zCEbgfA#JSP;?s^Fwv;R|eL2|e1W>|O%w0>+ucrR;LkpdfrJakbpEzOwnYW`(y>FWt z5?l>im7KoIUkuRYnp^m$Op!w_JUcPz?xCE3i=DDpcluy8Md=0bo+%A0RXraS9ZJ^- zi$rSse?4~o--#U+)yLh&pl5xy`>;+-E8TLd>_p&Mc{kHMgzq&4V$go;PI(EUy!wMZ z3SH`}KYxywkUTaIYrOCT(QGIB&obSZS*&gE&0)l+PM0p#A|b2FEH$+bAOy(Le}&nS z6$%_U6_DyHq;YN(DSR0zx26qS7q=MdLy2WpSI^Uu)8QqY({kzHRmoBP#6L*(>!SI`+-IV$;WaKgsq1g z_h*-y=ZqSj2pOMon@u?UT%7q%qzFun--7pKw62J&zYyoW&U--%tATDtAy6m7U&5Ct zC($45nsx)_Uj#LpPqdZn){GI|=)WCSl~M#gIHn>M`9~|jc5!p$>Z)_MvxT$|^&e;7 zlpBeH8SG-kQoXLl7F&l~pToep=>Cym%0hdKUwxI-mG>5EZl?EL|i!XPL=WdOE z3Hgx|LPoj#qJGKS)20#KSZ+;+YwK)(%^7pId{z0we20Fz73Ginr^Ln;wTkaghH?LZ ztF1pySC!WR6Xn6_hdmRb34dIiG_O&GF@wZEUnZkpyCVJ=j!d$qYRMctN3U!N3pv8< zzI#MGoKqBev|O@^3fIY=g^QJ9%C8J3l^?$;XHfOMN0<~2tdZ2;oLJF3)O)&3nr`q$ zt>>>Okam9VRf-QSr8x0ZJ}fmb z3;F#nKcJrF{|9FCChT_Zx2F9s8pemUuGFXatgwf&q) zEcM&$6(#@ssylHT3-e{l9Qv~zCH+9Pw_lbu#xOX*zK6E+mP0836eE@b|Fdyo?QF3lC%jxrCc zD{NNf8}6ykzhT@>T;y!Ayzj#1iWHQ#esVPoIM)x6u3xF@o6kKyc~!7}BOF-RZ}d_VUOXC4IKD6!`hA{X zmrxesi2af6<#KmLc-Qdcvkj8XS2WTfcQ1VBOo+-PvrNm(eXa2rCkve}`WnY_iITSH z^0hQ|M31lrM&w?V=rXQ+i$_Z;Q}}o*H=j{wo*oDMNfEBgfv;EsL_P| z$fi(~C7^yYmRKoephmsgIVfv#um&JfO+%@2hB9eC`*vT233srTQPAdD5)4Rg6e5bzH^nPMV{SQd`+l}bbovjVgz68qL2V@BLf4Vbpmo#i-)l=OZQFf;a+~x*OwpOZLD^)Los}q8mzzm! z_yl%-tst8#t230c3YKq@{HKuv1`i+(6wmiLFsP_5@G5UPTRAW;@FyXA8?2q?JMhz2 zow~LyQlwHmDhB#=K~ndp!o3Q%aJi^|5aX3>q>YrFWU=PCU2|w^l>k<)RQv9fVo?dW zg@{QN?se#pqv{VR853*PA8%kY_=5bueWlw3|%>#kc#r&%S-nx2@J=DD<-BQdg#f!WPE?KyasqA<<# z+k3w0N(v&k;0d$H9Z$23d#v1qAeLoShs@f)j_;ZgZ4 zZUa#N2GC)3(u+;AtMv;7U8iK0#!mfsRg9-=b)FGyV{d1>++e*A&;8Z11||MKFv?^o zcW7@vIRs2@Bkz;mX{wg3mo`h~118J&D6Wv5d_|)2BqT>Ne}sko3tRR7o8&?g9;enq z%@QY>(L3S~SZYE|<iK9~jH)Z%dO@ zQ@k-JQ>xjj+-U%~->N;gYbRR3ZQQ1n9;9u&pW0h5{rP#>aGI62;9)3!Abd#Lb6l(U zT0Va~`^DjCaRTDm)SNA-6iT?er&oV&SJR~`V)lKJGuNFv#uIi644Jh5QHQdY7de+t zG|2FO_l;@1Lr5?Y!sg{p^0q6!>~+zEy{_sH9%F0h3M+~h1B zub|%=d$Lk&in97bpaHvE# zgPE;a)VM3r)PZ0DZ>4SU%0aW$L98geTUF+^WAuRoC`(qri_;B?nib%Rmd<$S5Fh`^ z&Hp=Ypf^ZQ8j&Z4Yb7hDnBJvtYqyQ6Jhz#1W~Y^4zx&p9Fb~@Ia-?_HzwCZ|%#sTG zHG-B(PX7Pfr9xr`BdzXW^cKH1v^un$)DK%Xs_t|=yrP}8TK|F5|kCK6A_UzO!Q6K10}9wB34ho zyG0*TyJRaTA2K%>`mmdu^N6z~8$OQC@$P=>tUifcXl7<0LJ=#+)Gme888O3L$C1c}%Rn^HQQyiGd4T1Pu#{_lx#^GDSg&@TjTyaU-+PFb(jlDC(up zK+Zr!*e8!JEkcsybo-_u&&a`fBZ+BsYW`iIBetbBO)Apc8caZhXD1gsq4xLP<=Z1G zQf^42uaMm0%s&`7Y^8F^~CG-pJyGgWJY0ggCi;=>Q@ zYfFGdc`{dLQ>}SULL)!%QG5^xfl>(tykZIQkRjOVa^ak)bLH!~`0yNjh&Kqari`G= zzVNY7dNhfqGmn>=t;}`4Qn0a)wQEO}yA}7g+0Y zmG&#^bVs?X_$$u_Tr+HKmPm$!8_J+(JILA*m5F&{znsDah2%?sL~@GWtk3O2Wsq+)w^z(_M?JJs1-P z)K-EBQ4}K@PSx3J2>V^Dvr#i`dy?PO&xBVE{y4{kzv%($nhdIhbvtr7A@Q!##q$N~4IfakI_%_2KJ+%YK5|1VEeVS-ngOT^<($vC4n zMw{Gdhu8ccGaY9U^l1RX0!GrWfY^HInG`#*)hL!U@bQU4<#R1L#{@_^^|R=d`h?R_ z1@GjsTS_gYB=qsN_*%r7I?t5kAopJkq7)$N7nsvHxj$gDWbqcv{_5<^qr&fBUQ5F^ z8@n=(`-6Q!oL8DZXq&OKpx(4Iry!`Lv4bH2QBA=n-cgsWL`^BOcc9vz{~Ys_X)pvUDv+{s(?SCIQroFB|BmS4y`cxW3|hHQt1xAX- z=SrY1>vpG&r>_n4MW`{VOE*0$W9s(1U=ZI5-1S$-&^I@`jfAaS)tnC+P0#hGbBrgf7ChYDL?fb(1Cv@)TY@vbFmpA$52pt{-F1D8T& zzpJ|YA53qkZ!zzt&hC8`ZLcw1kDF=pTKPFxkns47Pcdh#Y=>TsQ-8kdye73OPOoTu z!qjUl=V!k&;%jM3)?HO)+3v*5_=Kj0?4w+1=qtqFvcefrLw6bj2D)a+&0F7X_@t+t z=LKey#PmC}b4<&nJ3;--a6n&q<5+&{^%p6ugfb$KVFR{qM(xG4ibxM|ku%rjXE{^n z#Ovp4uPzsCL9H@rZInKd=tTK%KsXR-$G^8T-9%y?odL@w}0%hG3pF(vC!u!*| zR2F`ls~tE2k;O8Lo9|{C+|rB63ko=rwsP^rV727NEh+7ruUG*Iwtw3~GxDSZ!W^^A z*sv`I*UudQHkLa*dda)g3zv3Frmt}%@_m*X0&NP^!b-{ZD6Cy);oU7hO*WsR7X?J z2`{bA?q1{mMkFxu5^TVYbIbE%f34hWm2H9FzXEZ#;(R6USmHKsU3HVNX|ZjgDnqa# zvM7W{SAJq-bbX;?G*ge?jbf}qeSE`5gn@pEdpe9g*|iR_rOH<7e8R!BxW(10GL$^t zHR;KVfaqB`|JUgigEi}#MqUq}(drSqc6NvTQu(SO1DxKxat&DuB9Zj9Awi%(kdn`zDWLsrOhRgsV-k zTI~#_+(6R0vcO=z4mm}BIFax_*}D({#TU8C1KpzZvajZS5mtFLkj{h`Y$cJd4#6%u z=RkKMNqNc#^G}*}c?EHM8K}ya9dKlnnIGQ^+3=Vk^J|E(FLDnku&tNQ|KTx-&gv|H zZ_4nvy`{HSY#m{op=}Sh4}QLC z5w7gP*I`wz+uD=%&oI0?J{MptMMA~Ml*DK@q7A)lTEXx1Sz(e)2E6k4jPYJ@A@|{~ z?H&!^ljNK~%N3>eMLF?lg>r2Ez+d6ilxEF$f-8X$l#92@m||YSPM@=$5BfPjmz3^H zVD6llH>=QVYrT#Y!rtqAjOeV2BOf&rPBG=BFyCSNOM~0|W@C2GWt3Hk;Y?Xes8YEC zaG@Qom980JZT0GBhJoQ~G4y{N5Rt)a5RP)q6A>bom0354S``<*#|f?sqGbjNB=3%6 zyR5v`_54i^-NBCSl4+x$?DULUG{XpdKt6V2T4*V2B}tNF^q`m1`8bD^n=V`Ec4lTD zw+u(lXlt-zhtk^2@hD%q+#b@&jIHEa%uHG6Ew^Ex-1tZF+#c1zI4YQ4RZiY#1(={H zbG;)=881tj5wBDb@0rAe0j}x$&jGT*uJgxTF-B3sL7l&0XeWD`HqoqsGwL#q{IJCk z0foQImENad6qkSw?esnW!)P@K3yuazv$1eWO%|nw?<1QiR+McT9a!%^gEx;!*LBN5 zpQ&cmG1%n1lSCWq;=@I#)}hgkKKyq9u4jve*2Um+ps3-e2nY|zU$$*P)*B*dKX1DV zY8tJnE|a4hcGOj$ExvOlmyjIJ`2WB`{;N+e8t3B1940xpjDANX)X<1ixi{QYNwd*Q z_Fjj0%9N*BZ--)^!VPUB^>rcwviWy}gMDT4$S+WNEmi>f3c`=2t_Nw+&q@2*R~;6G zB(LJ=sknY}f4}#%NH3IqAo@tVn9yYwXlppKRmW+)5{bt5$eYqK=HzM?A!YTr?@$5u z85FDW44ED*aBsG&AmEr(1jR#lgY9L9ByGT5&TlY&wkR)8JAVfd+XkGh&^&Fw zx2$0qhnM5n>P)-XO%VVUhpTs#%FrCeBPGJr8qsxzA>jR=T|i!U1Wox2C<%x9ZgZv6r# zy{Z;)y`dwAb~l5(#T{F_uNK_fQ2pA^ouRZ9m;0)({;tY7H7N?ZCe@`)QqK{zW^O8t zI9}sKqX-$8D?RXWKUylARh^jvdrHX*gKsBHX{}df6|7I_A!gA@<)#SSf{F~3zW7>Q zT8Cd;PD=j4j0oag9Xs>93jw|fD$>1!s(6VsC1L2aF~(dYHi!{(!)}_nwc3O4_iwshz_`oovU^+tmr*k%|ESW1FDD=!wVEO9GpE?yf+vJy(#__f1eruByW zsxzYLs}mLj87ZYdBH0|~4-$}4e-KQgy*_M=i|ChNK&liDp5<(5zZrieOKcVzEP zBIfp;uDrXGYO4nI7oO1Krf6+=ZvPSun|GskX}KeP;K2^P0dj{7JB#%JaH z8`80Z?Zd~T>|Q>$nDtS4Jyc*hpg12PED}owpx(c!{)4e)y%IKEB=KQYIw=lFhY-$& zN%_v*QQW0)RYqJ?IA0QA^meZ8?ge-GQB9Q1d5Cd!0bArZoWN55U^+VcFOa!=8(rj{ zQ3M7B85P3k$z3@mRQUKOopuSMP1sIzwZwoy*kbA?O;oM39q0Zb&HApKSoE~qP+&t7 zpiMDWVG3 z)(j`+Arbi2#$_B8<5>0~B1AKudaz(dFiAy(eL7peEC4S74>y|VbvDwi0I^yip2G>= zV9`;h&#<96JQ+XAY(U48cS@M0-TYlhpPM)+FIuo6HOftlpfpAPOG1{Nc^qejzh0Ar z6iQy-5yxECNvXCFHG5EIVxmrfjSl7BSyK69g&C~ z3X&*}tPsy5(2yTyO7!6Ps*$j#J%K73N<{3fXqq2B14`R=vMu#KO20P!4nuG+IB@Pv zjMQ-<)og$eAuBE5&T2l1&xM9-8d!Ckhv! zTCB;G-@mTSV8&WYEs3J`x36bsY5S+SDXeo_^NEjogB>kzGmVP&Z9ZCFM8f(OuEn)B zu^uim$tx;*r=FtcLi4akF^$6LPvf9`^n79)ubv&Q9mBkW*3ISisLv*p?ldn-(bk~QQ)zXVA9V}YBNa% z?|Hs;Vs7t=`YqUPelJCP^C+y-JO#&xZ3{~dLH(x+{y{X^#pF-VeXIG2Yvi&-+KC34 z*}%30S)l!qimDBUi!V;$t{Drl@6Ak%we@uI(;^zl7v~$d@<$G27#J8W7)BVv??<2Y zIhdjY+pe4|;+l?YW&-^vGUv#a|3cM3X zMtsMF8bk)QqT9R&FR%lIJ(gV_OTh_=N=>LB|4cK}29=iLGLM&_yTIJVmCZkw-FjuI zhYm2_%%>Vx(9CRuJv~3qxAzXPQ~;LheC@;`4*<1QJ;O?bO_KC@$hWP7fh=1XKB&#T z>GJLEb8m#0g0j(7x&ybZfr2&=7!9vET8mDq=jRGI=@9JJg1`bhlzGi0rpkhRri%mC}JpSo)03Fg+jE5b~5d8G`F@Gwd-{v zp!P^G-3FSen47C0e<^47TcmemXZs%D*iOy21Tjt4YF*4D;(wknt(KgkWAF)Bx!4!)D_v5 z8@h9w+Yd<$cO%?af^he_RAW24N!g(3cY0rzkeI57NR^Oawh^H0$EJt`f$uh+w{)|7 z-70muL+8EyZzW-7I!utOiR~$D8GLE^81&7+1m#EZT@oxev?O5>1LA z7F!?MtQ!F?*7J3dndA2^aHtlJonYc!9cA5i=Jck~J9(XUonGYR(EtBAI*UUqJ9(0|M zophv&Tj$jO4+h-F&;y)~k;swvlTVR9F}mZN`Xssc&1P2Y*3bChK)Agsx60NjbNbO zEneihGP>spu)IbP&lgotVO!+2AmlgI1u#-@s%23AcCe`lx0uM}V4m@<>jJVq5@3O$ zJL4BN(z{J#a9=C`%ZJicENW3f(?z^aYn`#qZr|24E2!HjTlV*OMVbJ}z)QTs==5%R zG_%G|$VPU*C@X|FH*Q*p&j_VGQQsxG;1uRP#$BGdyyF>(Li zUwhHfYn)U&^mYuMVBm$uy1Zau$>*J+s#x~Bm*$h4XZlVlTtW=6Grla;#z3xf-ZzZz z%0~X10ut7&mK^#aqm>N9iT)1R{~f%+!OFiY)q9Fe*v%`^V@r>(h#)???^|9RcYB91 ztJe8-o5H#@2QS1ErC6$YV@2OQ7t$u-P^3%MMQgaLGSk+WO>t^djM}nVSge%n*>u-gE8V&1f@Y#mMp8gmtu1FPBvB zQN1+d!`j5F+%rYrtAZ6if$`NoNxL;iUVLKh9t=m72>9As?{mPwE~zg8G!i(LfnMCzn0CuwzG7~mk}=Oc*;_~a`b!0Mu;il#zrshC$~|7 zWCtUfa;{7!!)!#&l&pTMh}Wv`YQau9yt*giC*Fob%KH>F|0`Oibvs z>>Yw(9hi}>$WLEVqM;$iC~6+_V?7&xpf-x)40Sv#`Qdopuw6K##9l>lDXYO;0yU2p zjh~s0Z$NjnjBdrYO)&dcWy{9m>b2*Y(ftM&y!~ymOikH3Ae1Tu{tkVF&$&mryCrW#<+%y`E#-ocKbWDt7GA&#Mr#naxjMaE|P`4V6O8RXwvMEhbC4 z+gEZIal8~h{Zcmn+wnEW=P%EJffDP&WiNdI=kHC4Bza)3Dbr@~;=4WL#WN#AJ>zeq zN~WfMpD*{1iGs=b({x|~G};8SD~-n`3)0Of>2HG0rP@yP3y*W|ijQ+Q=(?KD+TzTr zZK%yvvr2+zjrSS=OuwORS!*iC7_6wrF{is=D$i(@DcqF4*^UaqT_E%#>Zab-7 zH}hgO4awKMXubi60K8y^cL$5%=U*haOe>fHZOpE~DNP9R{3U-22JSd|_|dQL+9BOj zJX~^7aG5SFaRKl)m%P=l^I-!$*94qEvRt=#JDj;*>kJf?K5nTgjvc@0>x>-wOAkcG z>&GSoc{zFI_FMgtv+2X;tP#2NU168^IOfh@s0H{wZ{61~2`gp!UcxnAzDB>kAPIcV z_5CVduIU>PM57UN?;s$Ib-dJ3!H{X~>ZvSU7NLd?e^1Ae#FVHj(xk0K*rnW^v{(I&Zc(KQW5K6qT@p{ zSNbk|F&Hnm6&mJZ?>=`K9%wGK?1yV;>=eCjiA7tdm#oAERPaqbbbOT327YBR$%^FQ; zmWHAp)a8Y6m)Q7JVcW>{(q!Yl#`NdM5+2R~;)>31k65B1q!Gn4(Ue?&>i2BYeQIc} z4FiK}1p~A2!)W10v$j2pwr#>@_OBG#(m{(6x}NN+9I>+lEfl>m(I#h9D+kLj2B$E< zYZ(0KH<*p$?Iu!ao_lMm18yb{2eLB}uDEH2Li&m{zc-A#BYkCdHrE9%J;qvT>e7eb zwaTJkSTAN(>XODF?tYrT91dEvyId?XgKjg>~m& zl+fAicWC^f-DyXZFJWP*`D=gVhCPyF+u_C~)fr&dh)KaZ_A~79d|d|Mq8faQ6~3j7 z9c_gbFJogN6z7L_RUQtf_IR1yg?*JZXpU$18*$aGq|Qse@QfX3clIC545-qA0W9Qs z)O$RCcuUA#gb*C{Nm;ADkMvR+j% zZ@@>#+Hm2uG6Kp-!YK#GD&Ho2dQW)ESOBfNzjkgOVf}+C$fCE-mRjckJilH6oK*i5 zbqr)mNX`;;g@qwi+^ji92sTIg0p2QoSb0g#=?+W@jTcrzp8}^wT|LRFGkxTpdP_f@ z9a;~T2N$g9IA`l>%TGBjG#JcT?9bR@AiMG{W8h9od;RbFWt7?Yn)3#lJT7$p%m8&e zlv9{JXn&O8AB^)`?f4C|$I{R$ebLipKugt+K8uUTG@p(k$VA$_klRFSzSg&~)5TeL zF4H$LVQoVkVdSbX>3L=TKNZLU+Ga=}{)fE#a}GxF;qPR|{`NCf=~PDt51a#l$%8u5 z_jy88<%roS<0Xzq3hA{Gg9ks~_*q%FaRIatf`~7J_}<5MM6L}#EnRw@fy!m1J%3?F zwBcmZ?Of3AOZp6<@VFprfFK99GoOXTp#lv0$jkwu7ek(k;!w@_s(z@cO1~(I+fwAb z8poq0s}AiIzD4?7P1AN1P#hdPQ;&&|P+9wh~TjQWauTt`lO)0>x7K z6H;>I70G#1AhP$a(h96^OgC#GOd%C}X&n|Xn5c9IH@0E)llSbE3=p5B3%x}b3n&C# zm~+f3llby|I8Fq>eGCgecJ2(D;ZlvJ-@6_gL_TcTfjBK^t*Lbgb!-FHQD)#Wz< zOH3cY?D?(Om(ZU;b>SbnkYTuCxDil;^sj@$+SS804jMlqiL!<3!@>8cS|;=8Ey`|7 zEe$k&RO+|t;wq{Ji45rt5VRbV+m^ydM?`y*C*37(;G=m+OKiet)Q>wLa}C}L(GUN; zD65Q++9WG3!7xJv>xeVQ#-gdpv?l1+gjoIjx}!eR$M&LkWz0#scO?&1hmU4G_N^Pq zB`H2oy@3_9RkLrbdRZ!}Dg$YE!=wcz&Hd?j>7w&WaRwz0I2vhxJ9(oq+n3u-eVRA4 zZrrJEr8O(CQ|A=>Ioq>MN|D3%x%`3KDN^F$15;sT8P(o9JEqa)uy>K*HET!$imf(f z%EUpK)w0QH#;V`kKN#cdaHFgSXV?1aR(j9Q2y&CCp8g7qj=+Vx619^`KcWslN-0iF zVaxIwqYO>0A&O`&uF^c6NDI~DJw{Wyqq4#nTGFrjCS8cg^r0?M3>h3#+plL>b7~Fq zKu*-Cvj~r&hmS1vH!)V>d&s}`H#k6L-oo)R%NQkjBZCw7#MhOk-4Jj=$wxU~C2rmr z*G&0OBR*KI8%p|=@uQQo8(JmCZsea+AuX*kd$zj=d1dee4=vHCu33pJF`pk4SB|xP zdA*`m%0hcn!c}PKu-4yc`|KIn#g)uCF&Yg#JP_-s=8m7>W6})Pg zpy`H_Us}?`mU)ZoBNRu47sK26E|@zQCRiC40~{O9-~uqJq9a{er0a}$mf4;joi+7k z%syQ$2u zJ*p_|!>39S^;CHnwlaDIyU=fn7fLf9|9#@VC|bxQJ+r2{Y@aGIdJ;3JsE1u@_oBA> zLz&IJEk@EcpOr!+t9mWcsy1>4+^NpND205ku{Z2MSE+BI?caOPTZ}&%&@#HRw?#Bs zhwD$6lD=IT8BL+2-;DcCP71kei|)puw~Kigi334oxhhj3_DVLh^C5+Qxr zBro=?xef@cO)+;a4JR-dI_9+E0**5(e0b$_GUU8>wb4Zbo+){>A6};5ND$}&1XQI~ zEu3%=c4OcX1cCh~Y%>q5WJJ?ZGYv&jpY$;WtO+rAGdHTS(zwJiusR;Cvo_Y2QiQzf zkcO*cdvmf-PDjm?r|ie!D2gGz>d;k+yvPadt|RwGbep&?MW%kH6+(Z*ZRt|uDl!&x zG|S_G2l0q0MzL)S-^`*wdij8~l+2ZF<^ zMqIy{KYRB9mWYYWPR_#l!{yPf5paF@zF=mI zeJXw_y%Ajqtya8`sBTOkyd$|g0(d{XA6GN>TmBqW1lDBzD5__Zw>R_q!x^M3>zQWO zRpqsmi9TMtG<;REmQy8pCbPqy{to)GC^kE|;`5mvRsz^QhsF8LT;L4+z~dG(@YdE- z66j>Vz=*E(K=ZpBoYsojj$w&bStzLjsMHz6j&YEYUFa&nQhv6h{KV4Guq>t=@pE)ivSY}#V6B({ z4e^glU4P;RcLdArYMY!apwKSp*I;Y59S?XC%_bjWQbjLOp^H?fGi{qx8lv$<6d)u% zr@m0cDNEr{MZV1UsT(Hdg*Y(xIT~(6y;EwBdy$!Bb*0SsJBE`3TGO#wgGqhw;dNGT zgK}X+FMGS`kxKN(7^J^zd85sD^s>~|hU%>_Ehli#;9l6!Xl!eJ?Utq%Vv8WiX@Q-PlcR@)Rx4vE1FZakjDd zakFPjM&)=YHSl|rC=vSG7_`}_hePVa#bq1`vgv@2YF0p+F>Q#(wvo~%@5aCV?@ER;TSIV`Z zCSy0EWQRIYl1*(`&PD9@)TMfW7kojLZ}rgLH$##%$@XppS*PCb--7@F#-KrtbK(^W zPx(AF`!<~&x9ci&M;rQ%yN2f2MfxMN_Z=xNPs(I(Am|s=zNNAz{du{qw(kx&QN#^?&b06nZeV zyU9WLNZsv>oFmKoVUNquE_m?w@9{*Bq4}}0Bc=H*ClfVwEKc&ja}uWRP4!0yGOI6* z0-U=Qznvy&38^##7v&{2dWdEeRKH8O_Q;~7Q}h?DHU%Q_1$HDDvwLYkBWsi=3&B8V zhi4D&s**j|c8XwS+GhC}(7OfKe@LjIenUdT7SJ0-(6gZ7QAC5MR6xN}@nA8u-Y(WO z*f+e5MnAd>$fKWM$9_*R`I8v*9*-~vt@Z^|{=u9=iKb+ADUZ+|59lAvT-*@uv+U1* zFfzhzk|GD4u$V^+Mt??s+acL9e^_ju z4GU{E)xyAlJvlAlkLL33(%h-Su}01NzB({pr>0wip~UYvRqxPq)?mP{i;YdlE_37A zzL^n1D&jlSwl=VOA1{JSiLkaxSohc14Qq~LcLlPGIwqM#F$|2?)Lj?cpAg1(T6N9n zMGt3cw?$xvE=D1W*aDgsGU8eVUPijucS`}?57&i^>tC_of#X!N*y(+Tv!K)dMztNq z!g5TRWdI3yl%%1aCzMZy2>6LWJ6hd-)dxtP>oME@Mp)%4Ht2|}ibjIlL2L$p)!6Kb zZw{z$kUr|uY&=gU2v|URoKk~&4YBci$sU5n+KI?XyuRQ{of{AZEbNdFvirw=Hswk| z6F!~G-&H2`Pe@AKss>LLw!sGFlCn{o-Xgl&lbu0+K4%u!eJ$cIB^8Vx@RKxgSYASh zDdaalo@^#I`aYq}k9Jsn&qJaD!fE#(n$0;_y%xJV6UuZjl{OW*BjsWPDqjp0rJ!`t z6%}UtcvJRUZ%?AsN}UxYH;MrVQ3cDrQ)p(-7x+mwuF7?U!^0N1k4C;fcm3M8(}UQH zd)gE87i~G)Tnh}?(m(s_a5W09N=D?ws8i+?P{H1z;*QaHirW`RjSrqYpcC_H3(I~| zclK01pAEQ~k=`|4lJ5ZKx56FAGiSKH&A-^KKSl}Ukf8l0$qz2wRbKzm$h2|BrW_;g zI6X3lIL)C4u3n$fRSdJc;0%|P4^}h5Q=3aJG6xvjLTrc^S}mmkTHxCK)b#?`M13}Z>?5*?zyCVply!A19ND}0sTPbhUT&Agq<%X+Fa zRf{rE3S%&{t*+(O870djtc^b~jtiU(W*`F7c{S`dnHrKD10NMR-0paSB~dv+S5i_V z-S9CnnR#J7=9vdp@Y?wx6Z;av4xG^5mt6CV_KHAT{ip?_=^x>6rqX1lC!gF&o5>3H zP8vokx?ghXN^^eIGP0GlA@))9o(MLQl29DF3we!xpAw9jIuQYI!8p|Goi}7HJfh(n zs)SC8MhtT@P6nF7yH(nnNA9~y^M4y#+4K|}t?o2*vT4O4$WMyVi z=QQps-^b!idJ`GZSE?dZ*>l{YLNgPkC-_J@8w&5|8@WHb@jC`~TuH6zqOvLUQnEhW zvBX2e-f{?0Qox8`5n}NP7&w7*#_>>gECD`z%TpadpT942{br9TAT)X4e%)Na)J+1> za~-Iu$GLumohkKqHbd8)6ev^B4I;{>j11@l>z~lO{I^*L^ed|9dKx!(_2boXba)PL z__Xx%=z-X??Rt#3ih50RArmFroU%Z(D?SP%bKH|Ny{wW(6R5!K33ohQfVk39mWZPP zQwY;q7mH2iC~DN6)Kp1Pl;9Q%;RF518CwyoH>CKd!D2EU1@2MX3a6SCy0gpy4{t$3 z*LtOO4ZH(sRKH#4fkvxh$!~AUlP62pIWz41g{5ldcjYLVsj1V)sLxqQQzm|Xz#M$3ik2OD}t-H z-{v?m`VrYG?a>7LC;WpZ*_tWeJukPQ0wMB5{Dbe&*2(J?ZS2_J)Y3`eWR6^0o8mpa z)x~5eMy~gr|q)DT0p>l>-b=+K)wBh5UWsP?x z{W1maAJw7~BxH$H)6(#$Ry{AJt!c2{`zwxaU9$w1imTdrHT9+Q)t+ak_wF1w+UFE> zQ&aokN_XeeEq>vCJ)<;6pdO(+Yo#h#@(EatB|M6Dt3CLP{uAB4Np3ci`t&wvWZs3b zFmIVc^jsA}b+DPV!jkprf$~kRR_5*wTbds^MAyr+DNAoB;`6du%LulfVs&k;ie@iS z9?{y_KvxLLvJmUGxv$1vxt@er1i}ue%TX;}Ci@$^%sC+*%~%ObGM^@X0YO_o;#$-9 za|2fKiIElK9cjxkFU*d}Tf?!+`Y{;Y-gUMbQB(YUBm4f*`I4v2_-3VXMELVPR@g(%Sm(e9NC2Rh%-eW*FV zBBj_1HrOc`Qd`4WE;ZXQZ8CmN!nzZLmPv;yC4Z#e`|V3%VeQHw9p{G{Et3^`^h4V% zx)#C>F1ohbppg^zWzUAcE%n3O9pN$Rn>F#%7+#+?{+EL2|FP+5ZPN1NibktGG}tmH zUj%w+*Uh&7vJBsI;KH?TQw$ymTqckB6Vj*FJEu;^jn4$qQ*kKdnEBM1%FqW3KXgvr{_m2!1$f^N;QV zJG0#=T@IKM!!T#)2tH_t`)K9l`Qb&S{&Q{|6J-UHsgk zc@$CaDFLmoma6uR{=pRf@KF2+E3S0Kh@}=Q1N%Y7`giyi014d`7N(N(BJ>}Oth4e+ z?>`vD&mFOrEaU9f3qSRkq&>zrf6hK8?pDX327hyS_j`-HTKfm{9&c=z5^zMN&F$U= zrR6m}BM2YUXid6aKFbID>nKmjwef%Hva$h8s7=pIQU!SrAOB8zk~~|R;mAPF;+wT{ zO*Kzz;G6xGb7XIJKA_xX#1exUoQTyy?dFcFYSwv6ijJy6XA8JhKh6V%(u5=!NU^``OX7H zq7YV32*VwdaFubSi)RfM9)KAi>&Ck>k~IiAXhFp)x;nI(#wz2l7S zj17>hbxD|S>f4wt#*>tyABLCEK>qQ+dO|;1SBK2a_-k*9amF5MZS-e=gs&@~89zT| z`61NNFWZx}Mx(R+gTVmKo*r$o7VQgc^w1-!LX_s(b=I_jg2)5COHVBN z>8a9N1MS!#*GQWa-;|h`SkR0yYStNH?#fxe;9vA!|EcF;BKzHY`cx`*LmQ%FBbN+~ zRLOi)RA6Rley0QQ&(E4Zd9E-5v+1p9ijsL~((~XnrIkUHU*}|wEm`F$Tv-G!T*DB( z88pe^%s|(pk#b`ebY#h$T^E_55%o!h4yKCWz|WYvq$k%u?{g~0kvg!Jj# zXUnoiqA3W&4?2fCv4Vn()v?aYei67bkRc?o_Die$l!b9?@HRl`4WpLkZGzHO$l;p2 z33ER78FxFED@+eK1++3pSEM#@`1Y~!6`n=3hKNqIy5@*%0O9ozsv5y5V}Qi0Qw`P; z&*{Y-%$d=j=`bTJKBX-uCec-Y2oxlXbPZUYKHik*jS$(}W&n1ciKp6g`Q%Mn%$J)> z*i61a(KV9BkleWXhB@p6HOqrie1Xfa(=y0GndGLD4|;SjoTDGdd)4b2X4oK=g}pW` znPQ0|BmfSVmMU{KW*~KL;6i=<4=1?;GZA-tVTLwgY<(uI)EwbZS>-TEPIaLVYl4Yi z)g|LUX~V1X$;tq|{Z%R*D%^9JI3MA?sNsT*mbwSbf0y*_m6vdEx=GEWhyQ)#WULF_ zgc&*XN?+Nw-V?!=6ttUuyU;d$j2HYPQR*gQV0~YO6?5s8O-9mJUg9|I(>!~fP_OcK zNivZCm|EfLA32IG@zD{H;YDM7RW>>&CSqau$hT0>`pI(@@4+62(qG{9@EBHS{R^Q* zPOG?m{(8(DNsO{M%`x4`X(Tw&PKQVwulv}R-eQ2|l`Ls$W)h8HMJ^N%n$uIvmXXa? z&$nOc9u-yI>B;buXWq=!bIjeH5z=VzXm;J`+c=t%g*I+$ZJR3;=;GLrq0Qlj)<^Gs zsBX-r*)q4pgQfD_7gic@e$iGt=D!-?@HVig|IS9D~7&%=dLhn8if^r?FJ3aR>DoS%flX=Fi2 z1ML~;rhsNm`a#Lq1Y4Kaw5%Ant@NYg)%^bbf5)vjv>waX2(3Fp!+iKS1^wQ@dur`Nk zo1D^{A$!26gh6Zr8%-9>q;Xy^EiFE{w856wJ-&Mt$QEu6B7yIY11ZHpl^$+f;Tg82nsGW72y6? zuZ!NUQU{F|w_f}x(A!Af?|zn6g|8V%WVf@^J%%XpGG@J%l9CkoX%*J+0HhWi>bAId z75c^u8+wMrKza+&9}k%qsUJ zwBM3YrPMHk+DB?XJG{BNrL*I`QV7-x%^Ig=73fx|tzme?iq3rzh4(X-7FM~@SCLg% zh(8Js%eu#nT3JhxZhbQutdOfgP$HqOg=^=Z5>YShmQ>qT)!8;V(BrKf8#HsT=kKm- zB9ZG{2XR_plB#&SrbLbe%9ag_grQS1qkpzG(EFaBRGO|q|D;nO7*UVxTdu|#IC9C( zp`oX~fS?v8xIHf>y08f!O_6&~0#RoZ``qR1YyB9&s|D-kG{{)TzS&Pm^iWq4yN)h{ z%)T6HkbqTKT=_duUQu=GKzNBN5>N=4-OCUvK*{V-$zb~j~ zfi&*-DXuzJ{6%XXo2sU0nKO{IN(5qW(EUwL@KSYSx&@5jmHx`8zu4@aLxZmRQ&v*V zZBc~tj|h=^p49=QIfjGf!mX_!@&97)Era6fwsz4b2|*Gd1b2tfxI2UpAh-52iuqiX!o)`Z%17emF$O`Hghx2~P6ZS~eC$_m@E6MINq*?A!sJ+l@poayvb zD;OYA0nXv28qz+g?p*Y-HQH4AugjRMi;clRc%Rgt-NxkGn0$l>!lhEjhINWHH>6)y zsMmQ>yX*JIxd%w3!fyeQQvUtpgiSU|ZhKcZq)d19Y|etQVQ`T|M~>vO7KI%LL+VM3 z10)Qt2eyy(t{5XJalHEKz+eKa4zTQvE~XTu)c(6-1(7wxR$uzniam6MX&=dI>ny#a zM|tu)c6&SRI5cGi8k9vL&Cd>t=4qAGPqUX$yPQZX-)&MszOCNh-`;Z*iqde!)mZeP_yE3=f6ez|E8_|OZ;EZ=klQj zge`)=CQLmfM;kTSLs2%IRD~rD*ZNWaWPB63wsOl%(y0`AV2V}#DC#h58w0g?}4s5i$pa$>6#W?DnwuLfPiwThfc`u7x`}-F-31+0$aaa(0^+b)MXZBGQ-nWlczpD#=xE_>lSYsz+wxFvU(%ISN4qW45H&XvRx+cq#)l2^%M8t*qX>&(xB&+6W(6 zO;laKPlbrNR?Ic<`%m>{j`eSVrXAT<4vwI6=k;B9J5cuDFm1rUA>G77x3Y^VHK+Vp zH#D`5{<52so$a#*gY+K6(pO%vibz>0tHQg^i&_oPLNafWeievVDgTmpbI1b^ZeAwe z(1_dCq*w>X@5zl;FjdPx^+QD`o}j=r-hKBPS&+KPNvq2JNZE$>yJ6)RJ>_p_A_{3N z#RisCPed=!HIwCr_e0>Fmo_wwsEn?1FymSK$#7lnTAFGCN*dg##%=D$n57 ztgzow{8aCZF+>|;K4M+DJIW*RX$`+svfw7Rz|xU%b>UTle{t?wCCw`g+%;;+K*4)` zYWN7P1*);ykuq3h7&eAAC@M!+f5^@bDk(_Ss-eCsI5nJ!mG?whG)|PBn3@qA5gj!e z)ZAc&(fP{l>-Mc_PwhybFCRQ9v0j&CFUV7c)t8_4^&#G5S^Vwuv6nK;ktU{g>UfES zn5fL+up2wbxzb6d@g%pP}1{+j<`VUL; zpMcQc3l;PAlsV*PJ~#a~9#ea3#QXT=!`IT_Q##{XedK*Z_y=i-0HguR$Ug5U(_3GJ5;gA?KQq+GsxHCWJ z9`04IcjYfQ86R0}7L)O!hbt_z1RB|J?6>|FO^;UTi*WQ>5l_YE^xuwzdONg81kiZr z_ke4#wduO`(+zbOgJ|j(e)elv4p=`-Zw^{!6JEwiXXv39PMeco*emQ6v2IH-`$zhU zBV5(6qK$aC6J}FbsOCkoga+?ABoERczNy5yBBd9PRbEnA?cS&<(HJTo`o?e?(SMpg z9sss7yTwX?CC-E3(t4v=&I+rs0((?e4!6Zsi@A(rlG>TXIPZ#b+C=$p1z#ZJE2GPW z0x+e!Km*&(Bf<$Dss8-fh2o;$Hnl(3txc9C)G&8WQ;R$MB@IsaoG!YpXT6d7LsrG)l@_qxbYwmOJ(jmipwB#>To!95;j(gvF~?y zNhT>ex((c|c%djRBJsL3S*F#%LJ?{c^|&*zo&O)edcoU0#bmX+IvG&?Ep=23achG| z&ss&(lRL){2?ojBN>gaP6G!gN>t=Y)C*mucI+hlw1gQ|8Pgki8B(=owp%aRy8TI};|Y(C8E&x@;W z0VbeD@035CXbCLTE(FF#3UES_43Mmvd}h?n!LG|!<|hHeZR_(tObJ9g9Ut-0^CpQ% zx3EE|U?%XfB6GHmERaJM7%gTkuMJ&Gqw=d5-_fIcCi(*3J|WhDM+AR|YB~BojeWFlEVVJA?hoJ{Dyl2a?0A{@`5wfYAHqtfX!Jk=H70+A*yD zA}gu(bH~5@YDk07{NnKEit9MZ0|ypXLbGg|du9=tyrxA5nx$J~)2yVa<+L0n8qfsA z0Yk|CG3W6Ror|lrs7jl$0#kM+zsxOv6<)C+0lqU;XT0*;5rrOiZdDBqRvWy5azx$? z3r8akl|gQHjTCOvR1`KDjN=0XXP9x0m`u&Qfz_UgbqCAbT*HAXsA#i&&F96QGcubs zqf?X17#@l0>dQg*$ZE)dNrTsQ>xY8!-%WJ!r0SECG)vP#cJ>vDDg=0@)OgN#+}T;s zo0)&=-K8Vp29%qOyNOXz3Bzt;r%Fi*iz*e_#ilJ88%m@8Qq(Js{4T6h|DX3rpT87# zNk~vXK^suDJ7QAO6rZ5r=AKAdVnP^U^s}K9(*7tqboz_z;5A(K3>8I%<5>c#2tgV}8@D?|4vR_Al1Vm%g;}M4UCh4bL|F1BSib*kCT6cIjs#r02ySc-JbJ zvY{kKi8YqU1+GoqQS&Wd6`MN4A>uw5w(Na?+wV2f^}0%L~3XMcsWC)de$> zm`B2~wPmc@7a4ZvUtF#5#zjIi8VWw%VceA5kNkYiuTeMSNz@f^?=+#1tOwG$1Y%81gKGXdHq{#g^%VE;247q&x z-sdotx56+icMVG7nE zGN2?B;)oEfMriOLQT~ZIR!BO9yElNtZL#DAkL1_T)`pAyD<2ZgYpmIe zK&%j+mlg~Ig5rE~5LZ{WcA_@;%;!ayg=>Iv zYXzex>!J73rtBqRdh~57alB@mLjUcEfENb*eY9fVBiFZFXObs|KY)Do%F4E*Lgk!G z|Agz#0tasD^|c<=IWLE&im{!Z-cu z)^U&4=lwbR8ln`dcFFs%o3#gF8Lz1VM`bs_$M9V)MA>oln@^bdm25$gb8>x%aD=#A>iV8fnXi;jGH9RN6*we5orb>9A+MJg%() zUZl>3ywJpmcvZH_WH+R($W^=A#~gk@S1qF|xdqEe`nV>e9MOyFnOg5wuTfAPn=BeL z*J5gwxiP;d;=b)gIvPsSpLTI9lhnEmM^D7cZ1z8Z2%Z5izug#oL3B;YuF^@LqrI@9 z|IF&4t8YzXy`wyU;oGu2BPqQ>vBjr6(;8(BY#;!IsCrOHBrDce7DPfU#7?;!73Ob# z^zcCwsnYSY5o7UN*ai{!stY+61R+v_@;?!Rh;M25%t75Ic}hJtkni{lE6&QV)>(mT z%G}!Itd}fLHVw(bZB6A=ysrdsEruEeS1WJvuJNlsEEa>Fg!gTLPR95t$ffyZ`Q%a( zEQUt4aMUy52l^>aQQe&W*9>~KAsJ|yd1XH7Mi9)wq5EN~4hO5cCiAYuubY#twm+~m z?ht;=>E4GD$Ul5!vyGQaZJ=HvH@G?>*Sh2?!)ys;Y1{@E(3mL5X=?17sc4)b%$Yj} zpcYlH{sHjsC>fNu<&3w4o|7mja{5_r75E%0yTsQc8Xa1f+<~iO44qlGYy_ENTD#m4 z4hW;>6&oEXOG!_<135ZP@wx&wKSdv_HM{3Y_|IPX1e)BMT+B@hphFT;G;T1Yg1?-v zNEYPnO=RB$OO5o9)i2SwOaEkyIx)D8IRZ)pmq!EmVS7c9^G~lM3vwL@ZN!=IoyoeK zuKFt6GChYHSp-HB7nG`1V1@iq;HurGg5Q%38Zq7{A+b7tp5=<{6~4A#8%gjo;fj#& zFC;_l?O)1Ko2|*oD#0Z5fgDn+l9(HqYXFcf+bK%T!&0X@I-mN)&kyZJ79)O~DC3_N zD_BK)n7JzkfrLOG3vba8Nfe`9NF>~nl>@!*KyQRPqrQL`5WfcrigIMBAHviwv+cfaUswe?Hi75oa^f*CA~t+`yViqe}PZ_ z(fkE#-De}tz5kHBXadxSV>Fmx{yL|&kd)|xT!*Sx3SX*F1hkX)vo-fqW5!odGHios z-!H#!NCuivCrTT$V<%zTmspI^VY!#&jSSZNzY~u$l$TbplDe=~`W6xbWiFS*{ra~G zTmRWG|IZH8e_82&oNd0np`MWMKf~l8YzO`5IHZ+U2Ov!QI2>6RL( z3ju$kWWT2xokmShg_pQNf$M7T`;B!MnW=?{#~T6sW{E$5Dqfil(cR3~6TYNPZ$tq$ zxI42BhemHhyNDM$qE}8AlmdIAn?o-y7ifZ@kxNEr#E9U_qB~3XE4r5%%IS>nfy3+I z4$-5Uz_ZOck@PM!TkYBIg5mY=zN>GIgP*@VPZO;a!A>6h_ZaxohP~&&_dA=~FMs!I zdOU`9FZWO=(4_PsZ|aFA*82c@%)01m_vA_Z11M9t80v0&`n%()e?De0mPEm=!WSrX z0Hs`R1^PTXGyMT*6>KF0XINlPDoxK;Qs*;^sFKhPpgEdbv6;iD6POV~A3T=qIkipL za^}i-u=g#B-^dIvFNrk2G=md@u-4`50EPX+?FS5X)P#na)cm`}<`k=0HO*z(J^g-Y ziK`W|^rP_Q3`n_QWjUg{eCMPhKwYkD=k1%EYN?4Fp5}cVk^{sdRJ$hT zpLY2MpWV0i6tvgFq^4C+U6uIqeHyVa_iyhl`H&4$`A9TU4R}g+5tFmIe%xUm0g9p~ zA_r6~RpKe@t?Y3(cCZi~PmAYSOD&>1*T?m|el~s#KTrI+&PH|x+M{m~CNJ*)KJOcv z+PqsXA50;usAwNzV2zm0DW>p_oDB9WFxr$&A$*4_)(#F-p&vn7J5`e5)PLfP{O9j(&-`Nv#G&+8JE z+hVf}(}b<|%t*S9<)~Vz&Wa5w7C+Mql^(p%u;j(x3t&RGp@E23;`9&lgEJ)EzVPIn zc-4M-@YA0}Ho?-P8;71;?kiqo)2Rbwoz6P@YC{cEu>uAvKUjD@$Fl}x)DXy97Gziy z9ad=6HobA8Z7LUR%h5JIqsXb6CZ4DyeM|;e+lZX!SD(pi?5@cOoIULqD12Cv@BCsG znjI;=+85!m$`7(<_Cs~yFtuEC3z9d}$GilZF{8Pfm@o;>RoSa)=5CtzaGj+G$(nOC~6pX|dMK%%*LJXuItG_Vu z6?&YF?`cSzx2W3r4BY+zI#d%vJhBy6`+9jZTT0T>$9kvnUe0{sgX-UU{Ogv7RX8sO zc%vcZ1Bez|2dpag(o6S;&R>R-cRDdwnqvjDkM&)YOm`Ft;0{sd&f_Y*T#6a;m6&_9 zYfm;xA`cjG<~3*4Hw?)b6X}+er05>-a9Q)0ct@33gj!VTGhRG*@ENIk6+l_>HfMer z=_w~AjSu{Nj}A|3J4{{~S%aEG-O~vYB{jz!$oE_i2d#_lNL{VSUT)U48Ors40MZ#A zZC@U}BB-4i(BxO>Yv;^oC-`8tT7DoXXN~2Y<2%v$0i>7f6`~+ z|Jxt)|H)JE|Bvneldsj&-`hr}69>vO41u0$>!PQ&{@*(T{$D$Tc&O2g1p!&Js08Yv zjlD-!=WATpW)q4s#xO-ym5=G*lVi;y5eW?_Y~f?y$GTLGxl^7e&Zm#bT(yKbHFxd~ zx93a-TD$&Gk(s|#_SM$a*4;Xmo9WGLY@Ff)2AS)>3yYDEVTny%(kPkIoJw`p(b6bQ9TIlKGc<;Vt z_X0z8oyBlO6NDM#j2Ce{ly2)E182eDp!B0@NE-QeD0j%Ecodxl?HZZK-3<-4M;ls@ zd$sAHb*$c610K%IZ?+hT>Ox^?s*{h^@M*^r2t7rdA=k|@O-58691&!+;{IcHI)Yg7U|WoJXn5ps<60Z7{c;gc4ai@v-iZ+!r+fXdk> zCO9r-_HuvjF{hSU{J}ZIN#veswI0sSq8kF)EyK7zuZG>dd7;8@rIVR zk%Dp4O0rMkWo8d+hdtfTwD9o@UeBwgvvLIL%F=^;Q53H**m{0Mp}uDb?Qv8CxQD@torXDd`ot-%hdY~8aB&+HT+2wt~Sift69V8tjw{rRgSRrlQ(mcx&( zKMG3x3(l%9Ip2J(e=mZ^SGT!jWveYn4aDJP8bMnkBiD!K{m+zzogkb4+=M57P##V; zGD^mD7{c>7GtmrOPOGJN_`E(N-E<(aCL+}gwDYVamcHz3VtiIk|ES7Z6Kqs~=2p>Y zYG>g{=&hFa&Ts6dkiGqeC+Gl?j?fBLaS&CmMI18GX#E)5uZ0*BL;#Qtrj#3Tx`mbU zP4V@7TJ|_)*V^V?X7I*`Xnmx^6O~W*(J-DVz0doC;yaqz-0#2_9GC$sH!eoEIQ{%1 z@Fvw;FM|qsMh2$&GCjX;#Cs7U{&q^Su5d*dW}Qn4R*d9p?7KabWonPL7IuEWMRcJ% z^&oD-oc8n8tfbOIK77#k&xREj0SX;m&XF&|Vv$if^`|z=?rw;MQQanvi19+!y%9mH z>I;*fKIbYrk_pScaNt#+@(~CtOrsO`F|Dkn@(HWXtl@KeIZuOf84#D|pv0`Tm5A{xY8<#c;U}z){4KDntAeujo`X6Q~L2J9#g2(GI)aG)MKK&!-$RXbXk9>D=K>$ z>%PENvUxr2mvDLk*hHLNe!hF4Tq31gG<7(;`=R1Q+|rR|_J-zkh*DJEDs+NyQ?!b`SD&drH@DXbS*fyyw)8PVaC`Qm0#XDwCn0Ln-rHQ-my84CDbMlw8>hP- zl-!W!7}Ae>m3b-Ds=B7EKE;+b#xzP@C>bln8L7;Jeqo3$RF^o-mc_7(*##KVFb5c3 zvZfbQe%Y5A&PtMieiZCVCXEbBopP|FW|#vw1DFP3}MzNRH6 zboN!Lsgg;zqcy%x#~l$-+-uZKmjn+R$~Ym20CSX@ENf#9lxjxUt&Y@~@>)vH%%49v z%rH3Jao$Gfat)E=kud6~kyliX(AO5&v=&Ivf=0E!Z6~FxhRdtK;Q*cFmzBit>b}VY z3g*RQ7SkSTYZ(_npYb{%TXxO910<^BI}ACqYbqvb{ykDo~c{A5s=?(q^==RpB#hpw2yWMK{z!(!h zDI0TenQu6br3*@&`~L=RMeQi#DJB&o&mrOHtsXb=w1h z_N|EbA^qN_%_RNyEg6(iFfDLd?)mG#n%aLgUuU{rI97vR`^R2{mq+pB)C(G85c2X; zkkPNtp*g;SHUX61@r80KoW3%cXK+{AkqsoQ6mUZd8+rM$wn+kM<39T!gypY(0Fa)p z6}}C|gSeJZ`Ku)DH#l6>gyCO8LebC1uW}n*=&{=L*nH_XJ8DHg=I9u*A+cJ%nL}k7 z?J!)pAV;+9@0BQNDrh;$|c@?e}|x@ftCF&Uei&Qx3xoFjN%R$ zSd|NAHYpOOt+WJD$H!;$%s1lTq6pgmXsooDMPIC^-lcrrwxlP1DyO|z#D~A6d1V%5 zKT5|f!Kzx$Rnk?-b0UP&MJib=Jmp(fdG;4FD3Si&iSFI-@SIgm$9QOwyn=>!OvG0&B$zw)W5pO9 zxpQ)wB4DC3SHY0s$*jOep`vD-D)u$W1b+Cmr+B4_U`@acNc}7M1$>*@m8j%xRPrpo z6{G=^x9?XkoIhAGPK6w~HRN^^yt;CTo@lbZs-1~yNlAmfOeA%Xo##ATE()7w_d;)( z+lvC#1f2Dl{?zl5+};(>`Z~o-*6!bCmInrfD}rz#V$}N?rW?-RCx}?XXx#0@Xg1<% zCJtz=@YmD@o607UGjFu>OoEn9p!uljGVt{2+kXIvI(b1mtK*`vw8a8%Mig?(J;dT- zE2Id0MFQ3CXn9im)Prou`XSUmHcwoTcvufUyxE>@p5mPPL5E(zs?3vD6Y6-^4zoBh zS<9zb!Bv9$*+Uk-O|ztMYC4XpakB1nVo^5hMcARR`Aa$M=R24uZ%@TU*zJbOH=F~v znXA!n(tgms$?F+ep6J|A{=PEk27f>)?SVGmB5#TtrFeu=B57Z|M(QiWO1OVr5Al~0 zx0vBz4nRndZ45Acqxjj4Lc&&*ORy0VM7*`Z>O~WLT=x?9QQ=<3yjf$;l#s=tfhMCq$CNHBd41Bwoc7fHZKri2?F zw^KJ=MsE~ULN(08&*l(Dr#V@-Q!R(Zf9b6iH%seAs}7;NMXifgMY-yCU9m07nzSv# z-1;{4@g4hN1v^D$_`@eRzQEk?T9Nh}|05gcKN76|8aAz;|Xb3EW`%9y@p_O@@mqFflP&&6o~W(P^0{XQ$ziymS+{$j${sz36AP_yP`2p$z*~SuuL$w3 zN%>uX;vvQMbhP^W4*+V+X_$?)F*I(apeFp|pqAms0Xt{0hFBJA)r2Gp0JQktyO{C! zH;QD`5>9;Nr-`p?dLGlfLo$K%ulY!?o#ARXg2oqYT97)v_7eR$JnIphRe$=eYXEPW`C?y2Y{m0YIe;F0lmCb-#2WP>Z0-NXd&`Xo?C)>C;U2eq%{Zo)cNp zAX2S#wdy%EVH9tKh)J@cHYPHQ1k_ja=Tq{C`m&h^t@PM?Kd3G;yhv*&=f55}U^!Sn za;aZ{y${zlepj$tBZ=n|G;}h%kA=u&*|V^xV5r4Y0@0$?L%%N`c!Z8lpD2-pV2?OT zKqN^znRk1av%0ZhMyj=L@gA|1FNq}kYrT;^0^kHkxtF!cmhWOFt;Dw+rwE3hbn&n0 zI`g8k^CO!(=kU1IoH<)h?s~$Z^;~g4CpldL$z_zqSv1x46s5JA78O-4c~^Bin#)@T zOHEcs60Ny%&Qg|E6yF}X&BXHZ0!-Fu_WVb~F8Rukc7K)3WMy~z2tTx!w@N*jmS!?U ze1Zyx!T##iI5#7Ub!lCE(Z*R8Di!%1$MMl5<$X5~!q!~;?nK~quz8O?Zmp(UVV?4A<;{PcqhGsK3NvZXN$0W;Bgv++AlAyZHs42+Sv0t z$85tVJ6}%@&`(#hkZW2t3h`K-dh!Ijiclr>DLYU4z4Gkl6}QS(bu2A0t%T@vbib}- z8KQ5OD$N7(oIoye*E<6z;G}^@2^}yToO@BO_^`dchru*QM|?&WQbL2iT%ljdac03` z%Y6gW`f3QN6+kLTu0oA!$GSUiKjmgxfGea+kwb-@#d54aB`A_UCTEiyQ6Nu;lFa$G zUGhewM%fSNgyY0CYA7uiX%R{4KWHB+C%Y*Ln*$iKj!u+#-+p3;dFsG>MCxps9+WC+ zP>Xi1qLET5ru%JfbmPyD8?>~!jGPUECE!_hRCcqV%TZWbnA%p#GwcQvZa|RlI0)Fa z%#QG|$IY5I*@}OuW@>{~^}|(H>}{5E^*x0Qe{@sYw)#+m>Wj8;(<~rT>~cD}FN4e) zX^W6*GKF8R8j!t;W+koUg|o%Ecp?cUGSnGEkBX^8+haYt*|I`nM=_G9fmcdtQWUv%_LXntt`O!A_H8T#v{X*W2f|0 z#S_9sXbr=}I#{kO>?x(>6QgSHri$}lWrS%Avk)X8FsGg8D-39u>>@@g_JQLn1>k^( zLe*tE+#8^Yf)04@yJc+ZjGQnFhWQQBo?0kj<8zbI3wRPbNDmEfDZIJR!`>N%jYPg- z=nL=%X_=v}Qu=eqs}~;dmOA5wSDA;eA~HcYofMQBM!o7Vu+I)Z?RboH#}`6$nS)h$ zUO~9rkI{E{H#a~~awDl&&q6d%cw4W&+@z2?$o?k}lx0draM7vDVJ7EKry=FpIM#LGKkKCCZXw*>Birdm+9_e`_|=A=);6}_;}KjoKB`jjOf z&Cs&5EzO8&m1{*#Dst;hPOo>Q>EgOijqG&OVpt7JL)Pj|Pj2{ZLwnWBIxmL3DOZAh z`P-2}`&QH@rqx>%yA$bDD{zX**8H z|A+5l>kHZt;mP*2zO<#sj-WgwGxh}u~lJI%=unu_Q9nR zTb;YUs9z^J*w!JUKH$B|5H;SVuLUkW{gw{H&fd*5Y}1}|Zq0=Lt)xxd!V^TZ%Q~z9M{P}4oKl*hQu4d>yZk&~ zo_+E?O3%hseCPy%l#l1=uiyeUS${hi%nwN=l^R>vado_k!lqj=P+~j6vb?)KpP6pR z9AO>){Cit-B&_lccDn;67B7f@&Q35unJeO_um7e7$9SH5i`{1>-q3}06X!r$ zLs2Ztmls!WH9YVx9v^ihy`Stlgz{{u_jaeR1ScKucZc#1;DOeHo`;n?K7)QNo-cBy zFFf(QFXE&--4H!BNK;gbT=5%sNTRN*fdbrnF*23S$%B663if&$XJJ7MHk^W=Vc}mg z?e)!t{l1#kB?ME+i_t{h0`oa-fe3jv2DVC2@w~Lnn%{AyETC8KKX5YeCB8#*|+CU}rGV*VRpFE#Sf}vcPqCbGb zDD_@tFd}2DR#}8?N|mcL8d~C}Dabcgx1}*dxWL*r6}r?JbCsX15oady41_-JD?CH}JQEfsA}tT9VEF1E9XI31Xp zqa*KP`_!>~#{5<8K`y5gU&mYuq=Lm*(NPkRq7RG2HX=6@q!P?|gJe|h3v>>1ibjqa4V$BmTfV_ztzk^VS5|>MX;_zl zO3(0}k?8*Z3ZPS0;?K2DSlsL}XIqZTvp0b}RUz{#((O9e=Rrw=(&qqVhY4m=qDhSh z7|K^GAI!L&EnSi>0t`buI|b=0yv+u>aErXI6e`(1w$gJK%!4d|Y7ssN`$3fM)MQZy zVxXF4oh;&)z2k_Wt$x?ysXwNo~%~S{|9`UtJc!$xj@e zPf~an@2-bz{sG$Q;v84E)~M<9Vb^4p+hBkY-cDpdMVS5SRzrynJ@hR?+({R|05e(` z(R;Uts0+#>Or@lesZjjg{WC;tZwtGg`0+^IsEnH-AR>16VG0V>6qvYmpkV=irLh{Mn&U(BS8Ix8>Z> zd}3}}>0y1$r0Kikj#k=j`eipDtU`uFe~2uR_hTtPfVCB=XWA>MT@K)=kX@B^CknLqw%lJGQ49zxi|x`tcy9F-kH?zvI#58!9k0~FVM@pqhGRjJ@^eB@Tu z%eJr|?N3+5?^w{VkdVkH=BdU=WU;6f={(D634DzC187k8jO$}}tIVp<-Hf|IGL6fM z&F5e%CdOhL4N~#ls9yu2Z^;dK#Yq%NdFCA(YS5aDyby4jJnuEfx~Vf(f6mN0 z8|LSv_!NB@v>Ps3FMR*wp#g6*?FYyBnq>Yx6{SbHjH=q8q+sj>yZ0L$U5npu^gJ-d z(nU>P+CyEG@Euk@_u_xhfH8gdNw@><8~i41gL>Rcm=lVYCcI5OD2^Pu^v=Ny$4Zk|_*|MsBzx%uI76YO8MnE!q+Ny6sI% zV!Ud2Dq{`fk+-wz8K2tb$*dC8;6${KdyI(w0hHI)cAfZ3S;4VWu#i|>RDws$aW7CA z;S8EIE|2g&+-n(HZHof3Gu~uJn~A#`*n)>2h=WJjA!*q=Bjob{9)POTrCSa z!K)^dH*_dawc*!J?*vKhb94bV0qC&G(`6vwtnU4t;z8;KiX8@1ce`zynXCfF27JV| z^x<34HE0%Jf7?@>-?tJq$Z7tWWq27!yN(Tr4ABKgNnW|xxwyW_B)x^AAevBt=E6g8 zI*v(!nMsB`vvWZ0dDz49%~@O*UAl_{%^97#rLrG$)O7LBU1xEkv6@o=Q!yF6Xl-97 z&uLi-MzGFJfEZ(k^qz2BG(XVGa0I2ngkso~c$=pYv*{H4G>i8j9+87P3Z|awYOvP4 z(k$GuQM8#K-c6$t>hDO)VThMeCGW&`Vo<)7j}*NAkoB35 zJ5t1(Mq@+vURwS4;8;UTNyW*^e3Db55$;iwRejH3Lb+xP>$hQ!q+0?t6SKcZ3Kt4> zfxWE+ULo@0VrDrsiz^ZH*W0?!DRxyso1A%c=oj+r)Wcb);atfV(KrS;68Sc`<<@W# zC4Ij)87HQO6nMHw{r%5u*WqNRqa6TdVlZ}lBx?uni7ue*=e#tl*L_6Oy!Jz`%uO6} zW^p__*ZdzJ!UE2x;`%Zf(-CbFgBw4m)|kC+LzB_@annsjk)(h&g<0Mj$<|saxKAbx z&PDe9S$QFx9p#=PuH-iBc1$PcD4>dhuwkQED~{;f=r4)KAtOqiBEd4h3PYi?1| zUzilQHRd#sV15}P@1%9+<3{n+bGtMin(0vM+Q);{-*qu9r4iV9Y)oC`Tw40>25%O+ z)Hbm%a+Zua)RB9NZm;5w#RESV2=ADnW=9ERaOhp|G6Y0vC3CCTx9 zUX~)}nx%KO4^6#`1klrymul>|KiGeMZo9Qmbvdk|mJe;Mn_USAG(5+qb>gqqV2~27 zr*@#p&9I$uK~gBlD@a?1llmyn$-WN97iNppKsm=pgSvwkyU2@wMU0!=q@5Vnk>wLw zJwg$|VOt15Ym&e#3hv<<0$74db-Hq*N)FsjJM=wD%b_yb3(f2vPzMd}hvZBQ*X7_D z{7+*sn*IYM^L|`&9Z1h+9xS%d$&bE;W8ZN4JhS^iGev8M>Xy>gW{U*E^!Jv^L+P}8 zE0J;{L;F+sV~&mZrw-cvZwAdV&>di8tXqrV=n&(;0%h>p4nFZ4cGaV4(mB zT;8wmgNUxIRT;dJ$)f2LWA0*ep8f%ifa)^__qXo}MrJ2CQhZIhz`9s;2H~deT0{56 zHs(LA)-5e>mCQsjMEDil-ILi}xEGN1)pw&Z53EfQ*3|Es_>~*EaijBML>9>0p@{;> z`tyQ+g>KbEetl9(*^!9j75dPfpHmPXcOfz##N0=dE-{a9rAi}Q>W0=3K@_b5v3bDP zm}i!P9l5NOKehGC%39}i?BDTq{`v<%Km96=GF}4;=^5DghlfV-JJk3^j5Q5Yfl^4mLS0KYY-$&|<--)c#lyDa>+O=-(%?eqcV{3G3i^GuS7Tf&ru2Ke zGz@B<7SH2}6Y0KvMP-mNhG{BqbYC@?e3 z3wZ_+G7e8))#X#e-N37G#bKy_kVnb?ta*@NbF~b{p$}-;h2DN;uVkD}8i-vmIuwD^ zcpFZlUurju*aIzRXC}p~Y_?X+kmV&>o8!emQ+lHuM{{`)Q515MN;z#vtIctHb_uOS!`c&o0DoMmcx~2kZV>}Y!!Ojyz#FXn z^V^i|ohPQVnOkg^fzv)mTSK(evJ||)tIDfV!guOr^=*MEZsi?#xi0#!%bNfKLyJ^k zSoH-nQ@fd)hI8C85e*OMT1ov%jk!icYO|!5@ugtK3%;jQx29p$mo81)lA==o^nbAta*7 zp%VvN>uJ+-m5(Bn+F7Aa2kQxCNl3qTZcQq?LWRc40X&DPY*kJJ$YI{*cDESK>de58-_ z`;}H-!RAEaas%QEc1+#VEeX3z28Gr2f78GDI?TW$Zxrtm=8 z(F%tnQ503KBTJVuJOY%#-7di}IbKY*8k>r-yhK)G6ch6Ad)7>x`=TG#Tr?bRBY$vz z`azZ%hIrOz#TWXkHffk`CV;uaP;*|H+$N@n-V@vZH6=`GE-E-J2dYuP<+bn9uv z@HDt_2yyJu1yDU13(^=M!ppGe(V=?89?p3uMAJ%xpiK7u9-WJ#yAhtDYp|s&KUu2KPHsv7)WZ9^f993O+xWlQ`^u;|x^_!65Ii`+ zJwOA&-QC?SxHs+)2n4rajT7A6yP+Xy2X}XO4-g>9JN@1H-tW%3GqcvrTKC8OasTwG zs&%SPRac!;r}p#gy=&A1iGUgNMOjl{?y^_*Gf zp`Pm>qOIDl(j9^}6T9a)r%(1#Cn*yh&&*g<;2K(Oh4@|~?~pDVN%%Ki5N=tIOHh#K zD>n?fST}>;M7V@9k#Z1OD@bV&hMB-$=gemhC!EZw4@RH8&&k8|iav2i>Wu<)(8H6t ziPXZwO%2NrkrpYs&-d)2K&6N|%p=5SCp@@S_`AGHTGnUPX@8e6vq^@KJLj!bUjHV)5`ryju#{?aVNpdZ<31N z9etVrkr^^rN7Z?ma!_z~HJ$=mITp8zzI~bEyEr)02_RpM-dV8lIxTIZRQX*tDXcRu zxQx9jN82chTd&cbTN=ns(`E?Fl3XC;c;?= zrB8m8<5UGKlbjsi9g^$b7fpQ%c|oP!+Bf_e%$ zg5#td1`lz(2TeF52-vU4f}W+!PfK0A@Gr(AGbQ3s3q5|el9jZZ zPE)quU!0`pz|6j%@zUS0@MkHQ4Kp6jKy@WnW_)eE`(-1*ruOmf5&jNu z=YliPLJta};eaQ14JbMrkDhnG_Ci)R+lNOuWqtmN@;imoaBF++bsQ54^rWTM=!KszEfKOv0@|>IlK9A@P|}C?)y;DNJU8tkZ%1@-lKRG(Q{f=U1lI!dJ- z*%-9Qpe>Ifm}W=!Z5bipxn3`_|d?>VD)x z$q22hYtIIv7d_)v+E!WdE71nx0*ebm^{xz8)~hG`>_HTZD-$%~=v&?}owOp9OimAS z_P8<)-XV2QC9xO&S&gYN?t`tZN`r@iqs($(G=AQKcNKL@gVFNG}S>jjD=u8)g*g|;E(JT^$-=Z z=mzziipUx_z8VI2lHQf-vAA|)1pjLj74?bv%_VaAKh|uk!%2s6j&Jmsk^7|!M^uY=S5oGD=WrXM(3RMabI>DD<5$qY{kfP9W;T{9Q*(Y7tBV!}R+ zq#fY5OLw{3s~dhHl-S}V@;{RFJNYJPTEmQ`{tYFIX`T(4GyKI7_Z8bZ=j3yLu_pFY zdz4s$GXxXd@7goo`zFLol|MBFdPVNxV90^uVypR~cY8oC+F5VRRtPZE!~z}#DXC!Q z=NO%SA`m{jY}F9jpgr-4Hf}Q^(QXyZ`vCVcdjd}FaF0t5?Q*?Ocie#aoNg(oTpD!o zP#x3??e(6<(D96a8|a$^`gI2&mprLpUw--rx}7g^Yz$Gbb2ohdY*@vz1`^D*3^9c} z2|s@IKEhWLbC&cxX!#i_&nMcbxiCRygCNf8SekGUTNw86K3ocgi4A8bDuKBE4}*=- zkf^?&2@!u0nY5BwS+R%8;w<iv{a zvK67b;_j2_GK=wrx?!=!04YG&@V?33nekW?Ye;y*+iYO3qtSZJWW|{7!fM3i^C(kWky&)m>Kd2?3SMl zE)snbda`G155YvNuN?aPMQcHWI&g6PdTxx3gPMJ7n8% zhCVpi(Rq0X89C>$OTQCO3e6|u9PqY5M-AI9Bqma|20cA36?)%gR>8D8P&|4IT|xqvo|C zdx8mzyt0LkY(pg37x6tjTCKJ-dB%O?BK@rh&lVCL)kUpc*~{`%rCyRPO|9F)e`dI! z)K^iz+;U8Q+yzrRwObJQggC>;9-;c$N-xt<C)2a(WIqJs<~1$L8+lVir1{o%8lF<|f>t|Lm@woqvVwBE9b5+!2D2h@MT zAXtZ`=e|sW)eH;DDs!ON2c8Q@4C49MYGjHdJ2hiem3A$ind}(Ds2~zddyeC5@=yY&fT0S++2d77cN{oiVsohFSz#jS)%g?SurL$fFFxck2EXeP zrwZ$=-yT8dTcX+u!IK`bJ9WKQnprrfhd!P@zRe5Xy<<()&|qi&81L4S@*sdl zbU#0DCqr7G8o2|G4<-?QV6gC0UPt~y`WM2zz+VVs0xt{I4*WrHD?mbpg@aZZ(LCm> z!e0(^-?#@rv15(U;QjA-IP{=eqRW^<)ROd1YOdR2;IM}Yk#VUxE{SrUpO4zm##sZ} zjJ4mbMWgGtHO<9&NJ$SCP^je1{^3AmWZv19K#?Wo0(Ia(D2vt)E8Xto#S6?E!(4N& zH!2fjUwbUGQ|z#WfJco8UdF364c_HMdU`}?K{^^*DR)PBG7LkRF1{RCj-%K~e{~a>CC&UV|qTCi4A>6yJ+MjeGBu%fV5_@T14ich>AO)i7AQ#ej% zc&;Y8Wme72ea@tZvb{s9GbsNduDCtiu-f#5Qh_EhwKMfd_TkXME2*AcDDs)Rj&tIP%lFBbMd2FabV5r!(NR* z6nk_}jh*V7aGNwNJNd-RpbySDGmECvqBR9V?87AkO@Yc)t+B~ojDFoVwZXQ->u*gd z;2I;k=e6pt*yL2ROYJ%Erwg^LRCZb>#|MS{SikVVB=xmzj`BJHc@qE0@wGGHZci9Z zc%n%dlnQWj-NsxVB?!u(so!xGEAO>yap4oNK#c|Mvw@AxFdo&ficc3qvLE1WbcEz6Ifny9f`%LFSguQV9DsGF~&6B{ykAmpH_`z|@)tnq}_ zq%OY7nEXpb*RI{cn%L(t4@?pZg4faoO)U#ONtpww(3Olw4$B4}g9SWUR~t>X-u zM2xPr&KN3@=?t+XN{WsegFQeE1+D2bJ~}OzpdS{m<WsvVSl}v1Amv|ln+#?0Qd@MktvQfR60QSsbUMm*%4HgNm0Q2Wu z_9LrjFg?Rs+wYnN^;9>{hAl3QScS7HlkGZ|^{I%3*)C#|*rzFRC(fHrys{Po0=|JX zx>-0NP0dWwoLlQWHYU62|jg4j+cg+d7g_VuhrM+l9}4WdV~SYm*~#W?K!qt^7~s z2XAxl_AgdlC`QRZWX&0O6WXe&g01gU1>J~eY#Y8HD6OMTeXsyr@K5NEaMhq{YgO?V zZ(f{tK=_o_Pmgu==(|&_*YY%SqH`Rt59XR8hQ-a$@|_=r3|wE)*yqo}Q_1ahHus!=;4qK()GQ|?fhKL@^yz|fIg+tPfhaQR{@K>i2Hl16`bi0Fo$aU?0i+-+zsHgX<;X4JogUef)#oU zSiAWDl2iVJI(6&MF5FV(GW6%Zr-|1e4TGPdTLk9CbT24R+i_da?@?Pm{}cb#1Cqoo zXdhlVWp7WotdBP&^EJ4vphN3}&yczMMfF~5t1q=f6L};6L$!?l3r-I``Be?E3(%R* zL4U*I@&?MkiyJB};iGG{Lt={p;1(J+_{JB!$WKE}*H%L&Zvh};R@VqJdBOilMmB6s z;i{+2)m99G*8NhN_u-ad@RB{^HY|V#xYY7sjqqu%C^`+%{I7J+Hig(BLLyHE6?5*! zW`$SHMT?EW9KvR>b+?|gdTr^NanDi1Wn*K$zWQWBEs$NCyG}QsMqDs;gve%n4oi*^ zz+-d(n#$MUc;WmBRXPqtN=k<1G1v!A;i`2wca}u-V4`j(trJ0Ux8iGh@9=gsTSoGf ztd<0_(K>VlRN`V?YP@o;wr#o~Yct(?Fz>~_ceCh(4>@h#{!ap-2HnR!#sQiY1CEEK zr5R~f+Zdx-$Nyig&a2jm8K2+oh{M7d*Oc9GLC(!Q5ekGSBAtKrI?3(qk z>Dg?=x-QBTYv#}g?Q=n1Eq2(*UMUEaKS-C;=ekYUC?Fj*XeDF1S(e#(+9gHDV$ zi1sRG72yZVL<06VoIYDFKoyvuX0bsLDKQ;idTcPcEt;T{)6JjC`2i<`F5NU6my z!YN%!d{JAdWzrPLE^tBITu?gS%QA6k48s>z2g#DDt2g7sO#IJ??en^!{L9MI7ke*|WzF%)1Y-FTeLO-qZv z=R4K?f{Q&N5@8tJPV*dI5i5#u_ugE!OvM@LF$184cW`<(l$pBU$h4tcWo=_!;@@RH zyMzPk#8b#>U_ASt0+6-?)qm#6i+$PiDsevsFjn|s6N6Xt_&UU#U0r{3@>y^~^Xsyq zZxfPkkF1lA0OS;<93%*r)0Dr3>$Phsh3kCs6UnO6)4?Si`_Zm)s&wJ?8as_00Jng} zYT`?QJsyN6^6zAA*L6*nX{AZU@XSO2fdY*;kUiK99%gnq1eb4z3*fnQa5BG`ZOxz` zwm9t}3$8ODtNTPO3Q`qgY;HFNjrp2}97a$^tOs51T=ElJ4m`rC)xzw0JztV=1nzK# z%*g9r{yeis@I~rK$7-+MpA#u*9ey`x?#`gOq1_qSpkBDp#>Eeg^NPk5PNM;LAVLv& zFrzLf{cuS-$~1Sm?-rP^y>~a7MTW(tEDu-@j0D5;FZbL~eDeE@mN)G%yM_h4lJSq6 zw2)#1@~fk0cbny>SdLv3M92^P(VEH(Z&=sJj)bG`k{nLhCoB&<5Y6B39i(%vk-?tleOf}tZe6*F|7q91BoRS>5E|3oIC8_zzu^khi#$WXBgs)dR zBlUE2)$co3S~}hxPmY0}`rI#QT@hMkxrOR+9BC(LC+PjX)cPp>Fg;w_0js0FqwIP9 z+`K`ViO=4YdzB4F%YY5_w7!Wm%uzAN8}o{)(W5N=(i#r@nTJeoS@WcSvdbh}y;1Sr z;Gtrb6uv7)_>3ZpG)kr*sU?djJy0Zvhe=0=1Yf;-7Zwxt4o{d+3(he|L8ruc7lUp~ ziO8K4Rvg12^X?eFjufReO{j$kKMZ3ue0LHQ8uWkLCOZ1=pL@c2Yj~r=XxZFJpAO*_ zXb_Gu80csa;4KjU+X3-}@erqrV~`^MvH#zdWl>}iB|rURGhR#>!r$~ZJmaejfTXx$ zmDJ1f5%tYF;9KATFchw~@OF?~1@rLZVIu0iS909UqVk;H0%wj9V?fuwhZlrzTNq(u z-}KeS;b{`3<%eIVIX#sXHy;NAQY}qS0~Gp2MM6^<=;&_t>fuoW!k>xnas=f46LF=s z^?R!<6Nf4kc)tY4+W<^l-wEix_vY8A+A_!vviSb6@N0_n_H?#Q`0~0JRor6es;LgP zqbFP5+2D}?9yQ7929FKo^;9YLl}V00yb@zdtE;6_Q?6PwRe{e8EUyoy?|C)?9s`!3 zDfR-2{odoIcOT=I1K&163kR|8g#QsQ|5@VqH8dmmEFGRWvdZ2vXywE<+dpNlu6bt# zbu~RM!DUvG^G;XyoMvHx&6xIw5SZm>(5e92K@7+*!MfjBA1$(_gp z?4wMmcObULR@ScsHP3rf{>G)@)(x%S_6eZz&(cCJ#QFR$gy-g8_}8LAFKD@em^YjR z#>FcZ`SfWjX^U9@oCRXI*aOpbFq1{<;J+50 zm*A?b_qIP7w_jpTEoh?YxBG@+p6Zoku|B1b-GH4k&t!``f*& zt%@s&uyT~popUoL9H{U*P%|}=Y-6y0?IB!@1G*J}zR{RDN8U|_LPA6D*jncxX}&ET zyn!D_4)|_=LA*U)vj{2OXvn7?pYx}?>i?2?Yt4WscaheKznojs9AWk7ZjC51Wq0qm z`YYhZwycceKo!Cp1j6AK-`w~1&|2;$hr-PgUxUi61MGb3J;=k39l!`Uk>|X-9fV&i zr$>!f2&x;KxF(F49QInaFqIDL`LO-Sf^eeM2*;(HKX6QcUq@^yoy8E$;V{2OpLz!@ z1(G)mF3JjxfP1|NWE2 zZN4tP+q>W@Rncde@-oA2D^rP!-T77C&cJcpI3(P_SCuja1^JDE6*_>`OYs z1I8Ug-mAY542*A&I8oNjS&MNAf;O3lS&JZ;-l(j^9wPJoy6=E-bFuN*`NS)THb#k zvsorIDwUxUT8=D0InjDuPXtaA=UBkvwn9V`PsfBi-N44fwiVF7pb$j>8Hmx#I{Jx#W3#Dc`o-5x@Kqfc`k!H)b!L zpbz^tS>l_XmJqN}$G&WLuxw!7ZSBhGw;V4`$C+o+1wM|UqYIb*Ukq#@=bP`JSw1I% zEn94pp2eVMIOKi5%Z%rVzB-Sg<|zo7gCcs7 zUC!+^AGa3#R*$Jq0(;8CP&0K0MXr-2aO~?EVEHB-nRtyU1c8Az?vJo((T*m%xEm}W zcRfdIjh`c{U@ zb9QqUc%^D?0u7|tNl#`%5g0u%;V8e`I#9tDHrUwu1WHj!>dyN4K-2$L()tG@a^doAgZu5J7UPOM6(y*yRw8Jf=2HYUATr=y$yKi@h$B7M9N2>tZ= zKwA&qk4WX3_tHW?8#=oM4*cmC+sV|grdZtEZ&P}0XOiQ3Q}UrCm)xe@;j_Z_&h%mP z*JviV(mnkB0}*mlwN*gd7)mwWpWR@~v@N9z*9+mm(P!WbELRMDX3Re!;ilT$6n8h5 zFM7Wvey^Cfv>+AEOSQ+ZYnFvs5KkG8acxJD^|m>Uz7PPr74LT@ zwRuR$-FIV=iXh>EAu4l5Wsr2FY#S6BG-j(CA%3wqG``1WPHo_cq=|F%X4vDRUNQpi zI;--d(M&!s^GI2Ej_KaZik?-fY4TFcZ#a%omW`&IVSLT*i5%OA5}(p5HKf(!`=fdW zt1fs{=Scs_38q{EYEp~gXx8(oVyZJH*L*_YO1Ka{VrFCa6v#i^3)>}0(G2{w2b+aE zkNK+dF5w@arnVljbm~;H^&HE;F0J-Cat5mEy*ij08)~@ea+_^u1ae`~WD4&Gfsl?Y ziYGP>np^c19*qeIa*m68TuQMf>7KmaKsFGyjN|fL#+Cz{E7;+@R3C31{u^*Tg=dP# zy!>^LE*nckhHQ7PPywMf-X)4zJtY-^kN)W|a^muJ**dD$dF&sT>qlsA`#P@a6{l!uj<|cf1rxdKll7Hxd~7k* zqAAcO!M&G6Kx&bFS|5gS%GkxXJfY7|n7dW}VlcQo!IG^Ud&=oK&bPnmp#rLq(*VRp z727g0Lq?O@)IE}{m}BliYKV^=d#jbFO!}(Y;3jX9{E6o&NzH>Ie%7i2sUw{F#le?7 zD6H;vPemwxw@%Nw9afvdr%J(h8q88bRSu4L(!j=CQEP|)_tbZLhVZ~_jJ z(9s=ZsRGeW_AM0FZ9#Ttc9dX=myZ-Aa1S=rQ>xes^kjN?*kVY*av`7PDkrjfd zkk_^JsU4baxrHvlBe1OT@2xf)i8nU=i4;HiX!!$`%Ja(n)#`(7bTG}Y@hwZSzv~-= zMr@w@Vb6pwWlz!5gaKnve{$!)oBI5(`c5W{Y5#p{|NXE1_p|n2s~be3xq>JpzA`tn zd~9b|jiVmLk(jQ4+nc|CMv4~lYe2TucfDs*XoCTwBfnXH)M7~HhH;s-*MN3K8+l)* z;M7j`wJu3aGEL)J;F6tS2IQy{EM>9=Tea01b^meS_Tux$d|*CRXb=ofBoyHA;P4P* z$X7B~HX{*W5fXu_rRt-{RKc;4|2Zk4ISfY^4hJYGvKhMalRDaag$#5HPVE*@79O|9 zwYZuSZE3EQtkGYWoSnEnFO~hua&?;y$VoIZPK2`)c1UJ8b@t}<(CnNgISaQsQCl9Y zv9An~HMS^slx~u7nGOFK5wqdZK{Z=7R!B#8O}G3XhyTB&nh@SK4dTK1FH*wWwZ#iQ6Xa~lNe8@;L z-O$kwwZ_ZJrU^KpXe20UUVVBN>gIkceMsYLsShvkgsb&Z4T98qoU2&sDa@LAkDmct}Aa>)(kT+{VetTP3#Sks$QU9ql)q-rw zx94Q=8GlG#CuZ*p@6{270AEhxpBH!ilbca+VljK<*Eo*95ZI>Xk=k`;KGh_Koe1L! zXEVJc-_}u>6iG@ zm)D{QyMdsJwT}jl4m>il`Pk%E2}UJc$n#L`okAyt&pynx)r6_ru^l{w0}r;{8!_twMrMuc zj7```BeWHWO8G_A(R4e`A@7^ZD$7uuh}QXZlwhre??Vc|83)tMd>o4J;c!`wY;&T8 zF0!?f$_;&!EVbgmrVlUwlJyo#n&0Q5eNxrVhV!`oP|Kd6I4oAgaQG zKLgN|>uqEtB|Jg1J8jbz4$*BLyOBc5WmJn>afAzZ{4Q4s)l1K*k1aFTy;ad0=5UzX z+~)5DY&gjKcNhJyvlwU{Lz9S36EQ7cSbK(Dhu=R3lUbHeqVoAv(=)NK?~!onTe63E zpR9fHKrZ-H&hvfZDZ~3bQ|A7f7raO?roClq*-%q4IH8(}=)bqGn=)C!FL$Yc9~5}Q zj51z$#DYT6jbFT52K|nnS;(qVfK-uMn2&_icDJH(G@6Ema;4WeIMX``LW^15o3F^_ z4RKPF^CBNUoiZ|f;(d#1$h4c$F-?t@ti-xvKT?9`oQ%o`XH)3J@;6R1jw<_C?ZzCw zocBDfM*Y(4{yxGeAkh2>NEv?Z@zx3Gb3tDOPfxClo;5C5rn7WNdN% zf=G`KRnNw|j`BhSu(^6`9MDdJX!oh-o7-;9Mh8AtX17dTj`Wdt=gB^K^cR4=+rvWy zO3d9X*BmH~lGiu*mWtR7Or5ZcbmU?HatSOID>e?)yx>%Ojf?O@+@J?mi_jRr7~Cvu zWd6jEGBlN{KmxrKSw9lofVCNA*iM`3K4sgjd45f_N{b~EsoY6iio@{pT^_#`Yg-hl z%dCkTcD@OG{<^2`Y!-NF9?#q2OxuX@eGON>W zpKD?qEo^-pxJ%qo;dgE!6(EEIB#$0e*gQVT?%I?d{;hmLmAWBAmy*f0kiNuAv=2%= zJs3qt9MV+3R=zjV2|=oGkwZMG$B;ti(%DPaSuTb4P#5XG=0Mca8>Rx(Fj!@zV5lmP z_V@L~6F2mC9JhByrZ5^OHQ7T;p0v+MbP61 z6$@*K7#dr{LE}xP^2|eFOnd=9?SI8S_jg?94Ffqf$1@p ziX(dG=r;{oyP~H-%!ZR>rdIp{01+5opfr@fD2c=ottB+w-Tb8`S5AgHI&r^5n{_sR zW-I3~yZ?~P`&if4+)d^u(XJ2GPyI(F*L|D~BGIhRG8?8pcnMC{JF@bou%is>w7D)E z{k-0v>^SMZaJe;+DCn|iEomA z1y9v}XZFX5E@MuH4b{YLcf+-sGKooQ#^_2`7dxjkjT{#9CFClUt-11Dq5zI1%NA9c zB6aSF4d88iyR#bk1wC2%{D97Fs^gg}=eFIes&z5A6-~vKBAO%eVw-nc#-0xEXKa5e z%DCdMWYu$P1vq;vn^!M`jU>td=gxkpIIg0L`{O5$$ z#G`K=Jzqe>xak@46E&69XxXt%?|;?@#c!<|kMUBKWU;dTj$ybI5$9jDrP?y7r z9uW&q$aX4(MH`%`yOY7wwPph{^Ri{Q^E+{IZFRjx&2ZTq`~I2}q3xR~Vw&=PMlg^t!wSc1}abJrt<8~olD@lJO_Q?(Vq)d zL;eWt;zu355zUY6yhdU^^y78P=8n4h6|4t3#ZK1?+QSb38Jb&zLP7u(?{mg75lOI~ zj!xp81{VGA{Y3jS&Y~lOu z17tX@y9$};?ny_hGP7l%61U}RBB9jn(tK3 zPDo%7{u?e`6$h9el?YMz$!hD-7kQV25~%Rg%;yC&w9FEy{m7%09~znI^q6%=OF|oX z^-9FV@M^})s)QD%&TsJ6nCR+JPi?7J4ou80!h!6j z!g2G_p@4mNbLRBi;J9)?{Xiy8%Y0Tqp>_Suw@9DB+-t5lWi1FOo(J+(i*1CO?p>zYz&m$Sz6}Y3$qRW# zYY#YIL4rFKYv6!{O;3<$Ahs^|zPgK5aI_9h?nAdfws{UAQjDZa!O>fDFUputADu8_ zgI+sZ{#o#u;N_h0Qt%96Q>Qgx*t=~JZ55ASCq@TauXxbo9)75fp9coit{L#?<;!i%i z$|)0C=O5IG^G;jYU)zGJx9326=S74hvjBmHeOBte+F-T@#%mBu*Qn!exS`Rf2+B6! z!1(erJ%TEjzt`#d`(=IeKyRB4gbh{kT{YS6!-@)PeOV7WYhnQPs62~sYb6JZvc}>$ d6lT=Ynv+oN)qDw8ACZ+iL{o)l2mZD4KLE9bk&6HT literal 0 HcmV?d00001 diff --git a/apps/client/public/placeholder-user.jpg b/apps/client/public/placeholder-user.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6fa7543d38ed8fdb38f03b5c0f40ad2d66827d4a GIT binary patch literal 1635 zcmex=cRarq{jAqGJXh7$}Ym>C5bm;@P_1sVSzVUPwol9>?*7~p`Fjh%&&i5Vyo`r#xP0%qgXfnHy zn7E>$Lug{-LIb0a!ifhj3W%7RB^MNLx}>0_tP&7BY4IaqjBo(siP4_n_ky5FEmL(` zmhdc@Jb`OxUUPQK!#sq(C`ZJd3YCA-U zh)gnS;tOzhJ@#Yf$SRGl2DVF#R;SL@d2ijhdh5m?{S3~XPpnp*$)2k2D4JJuYTMD;n0K36=Y8OJ z-mS1ZZC1 z49BdqoLoM_v$9v)Hm?5W<`Stp{n4{)u7wjb{~fvi z!T;47&))dGMoGtVj(5+GENxwrz4z{INB>V}1-4JUxp@DgJ8LKAUAQWhoR~X5%Wp!~ z=~v%IB`XWv>j>XTei(%h-3q0fm1bY5udCHKmu^f&G@&$==-St!-gGk?J$~inXs)aj#q07WR4- zM=rxkFUy8C!QJtD_bgKux*|B+dhW6{-z2Xe?@~0Ks(ijMro-3a&Mj#N$xpGBRnmWt zTsUxz-_bhtPjF={K-%Z^57b<}UkWR&Lo)qWhnrV2yD?(SL?Q-l9d; zHS6^j9!_Ejaqqemoyn}=@ptvvS-S7I7N7FZ5}(WNv3l;#-@XTLOmcJGRz1a7FhcBC z-nPY(UsETGE4&Rdme=pC+jj2j;!j+6o-!m}7oD?jz2dGcAvK4%qSmfE=U+z7Z+`#j z$Mx4a@1yJ$R+zt@y0z(yW_ISH^4k|<^!Al@?-M=r`gz3ehXgqVyM1>}k-Q}GF<-;) z*LLGyVd)Qk|Ji$(J?dTY-07-((_=n_`3T&d5FiH|guzja;wny>q}tw+C34*a{8 zfJ9i0DbumfeTVp1E#|(wudjdSJE%AnL@H&$nSBB{^D;34Gp|fN9u>e68m!_b0O__- AD*ylh literal 0 HcmV?d00001 diff --git a/apps/client/public/placeholder.jpg b/apps/client/public/placeholder.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6bfe96336dbe567f5f1e9129f5bccdc78b114bba GIT binary patch literal 1064 zcmb7@Nla5w6o$`zL;Ko7c&|)~7+MC)5J;K9giwZ-mWToZDl29|7tA;;v?z!g5*b9% zRSP(-1ZOwO;J6Z;05{Ybq6y%HZtA^{7Ghj^Zu0K`Ud}o9eCM5OpR~^apJ^}|03iS) zUSPLDyMAv~1wd97gaQBuEK&lE6~YUU53r&J$VBT_bS?^Z_)q|CRlqoW3h_=1XC~2( zowlIWj23Fe8(HX8O~UM7AR)W5x}mzhvbshU9ifGUR8tm1vSSl)WSJzz{QQ zmi2yKNVU))a_#4eg7^#He zB=v{_T40oFHqzanm!#xGc@)^&2;D-M({g?EZs?j~+jH z`uxSqSCdoIGw \ No newline at end of file diff --git a/apps/client/src/@types/extension/browser.ts b/apps/client/src/@types/extension/browser.ts new file mode 100644 index 0000000..64241b5 --- /dev/null +++ b/apps/client/src/@types/extension/browser.ts @@ -0,0 +1,7 @@ +export const browsers = [ + "chrome", + "firefox", + "microsoft edge", + "safari", +] as const; +export type Browser = (typeof browsers)[number]; diff --git a/apps/client/src/@types/extension/category.ts b/apps/client/src/@types/extension/category.ts new file mode 100644 index 0000000..a96f748 --- /dev/null +++ b/apps/client/src/@types/extension/category.ts @@ -0,0 +1,10 @@ +export const category = [ + "productivity", + "security", + "developer", + "social", + "entertainment", + "utility", + "all", +] as const; +export type Category = (typeof category)[number]; diff --git a/apps/client/src/@types/extension/developer.ts b/apps/client/src/@types/extension/developer.ts new file mode 100644 index 0000000..cbae9b9 --- /dev/null +++ b/apps/client/src/@types/extension/developer.ts @@ -0,0 +1,5 @@ +export type Developer = { + name: string; + avatar: string; + verified: boolean; +}; diff --git a/apps/client/src/@types/extension/filter.ts b/apps/client/src/@types/extension/filter.ts new file mode 100644 index 0000000..4589948 --- /dev/null +++ b/apps/client/src/@types/extension/filter.ts @@ -0,0 +1,2 @@ +import { sortsBy } from "@/constants"; +export type SortBy = (typeof sortsBy)[number]; diff --git a/apps/client/src/@types/extension/media.ts b/apps/client/src/@types/extension/media.ts new file mode 100644 index 0000000..ee5e39e --- /dev/null +++ b/apps/client/src/@types/extension/media.ts @@ -0,0 +1,5 @@ +export type Media = { + type: "video" | "image"; + url: string; + thumbnail?: string; +}; diff --git a/apps/client/src/@types/extension/stats.ts b/apps/client/src/@types/extension/stats.ts new file mode 100644 index 0000000..c130864 --- /dev/null +++ b/apps/client/src/@types/extension/stats.ts @@ -0,0 +1,5 @@ +export type Stats = { + downloads: number; + likes: number; + views: number; +}; diff --git a/apps/client/src/@types/index.ts b/apps/client/src/@types/index.ts new file mode 100644 index 0000000..d1cafbe --- /dev/null +++ b/apps/client/src/@types/index.ts @@ -0,0 +1,8 @@ +export type LooseAutocomplete = T | Omit; +export * from "./extension/browser"; +export * from "./extension/category"; +export * from "./extension/developer"; +export * from "./extension/extension"; +export * from "./extension/filter"; +export * from "./extension/media"; +export * from "./extension/stats"; diff --git a/apps/client/src/app/(admin)/admin/extensions/loading.tsx b/apps/client/src/app/(admin)/admin/extensions/loading.tsx new file mode 100644 index 0000000..8565bd3 --- /dev/null +++ b/apps/client/src/app/(admin)/admin/extensions/loading.tsx @@ -0,0 +1,3 @@ +export default function Loading() { + return

loading...

; +} diff --git a/apps/client/src/app/(admin)/admin/extensions/page.tsx b/apps/client/src/app/(admin)/admin/extensions/page.tsx new file mode 100644 index 0000000..4a1c602 --- /dev/null +++ b/apps/client/src/app/(admin)/admin/extensions/page.tsx @@ -0,0 +1,265 @@ +"use client"; + +import { useState } from "react"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Badge } from "@/components/ui/badge"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { + Search, + MoreHorizontal, + Edit, + Trash2, + Eye, + Download, +} from "lucide-react"; + +const extensions = [ + { + id: 1, + name: "AdBlock Pro", + category: "Security", + status: "Published", + downloads: 1234, + revenue: 234.5, + version: "2.1.0", + uploadDate: "2024-01-15", + }, + { + id: 2, + name: "Password Manager", + category: "Security", + status: "Pending Review", + downloads: 567, + revenue: 89.25, + version: "1.5.2", + uploadDate: "2024-01-20", + }, + { + id: 3, + name: "Dark Mode Plus", + category: "Utilities", + status: "Published", + downloads: 890, + revenue: 156.75, + version: "3.0.1", + uploadDate: "2024-01-18", + }, + { + id: 4, + name: "Code Formatter", + category: "Developer Tools", + status: "Draft", + downloads: 0, + revenue: 0, + version: "1.0.0", + uploadDate: "2024-01-22", + }, + { + id: 5, + name: "Social Media Blocker", + category: "Productivity", + status: "Published", + downloads: 2341, + revenue: 445.2, + version: "1.8.3", + uploadDate: "2024-01-10", + }, +]; + +const statusColors = { + Published: + "bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300", + "Pending Review": + "bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300", + Draft: "bg-gray-100 text-gray-800 dark:bg-gray-900 dark:text-gray-300", + Rejected: "bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300", +}; + +export default function ManageExtensions() { + const [searchTerm, setSearchTerm] = useState(""); + const [statusFilter, setStatusFilter] = useState("all"); + const [categoryFilter, setCategoryFilter] = useState("all"); + + const filteredExtensions = extensions.filter((extension) => { + const matchesSearch = extension.name + .toLowerCase() + .includes(searchTerm.toLowerCase()); + const matchesStatus = + statusFilter === "all" || extension.status === statusFilter; + const matchesCategory = + categoryFilter === "all" || extension.category === categoryFilter; + return matchesSearch && matchesStatus && matchesCategory; + }); + + return ( +
+
+
+

+ Manage Extensions +

+

+ View and manage all extensions in the marketplace. +

+
+ +
+ + {/* Filters */} + + + Filters + + Filter extensions by search, status, and category + + + +
+
+
+ + setSearchTerm(e.target.value)} + className="pl-10" + /> +
+
+ + +
+
+
+ + {/* Extensions Table */} + + + Extensions ({filteredExtensions.length}) + + + + + + Name + Category + Status + Version + Downloads + Revenue + Upload Date + Actions + + + + {filteredExtensions.map((extension) => ( + + + {extension.name} + + {extension.category} + + + {extension.status} + + + {extension.version} + {extension.downloads.toLocaleString()} + ${extension.revenue.toFixed(2)} + + {new Date(extension.uploadDate).toLocaleDateString()} + + + + + + + + + + View Details + + + + Edit + + + + Download + + + + Delete + + + + + + ))} + +
+
+
+
+ ); +} diff --git a/apps/client/src/app/(admin)/admin/page.tsx b/apps/client/src/app/(admin)/admin/page.tsx new file mode 100644 index 0000000..d7cbb06 --- /dev/null +++ b/apps/client/src/app/(admin)/admin/page.tsx @@ -0,0 +1,156 @@ +"use client"; + +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Package, Upload, Users, TrendingUp, Download } from "lucide-react"; +import Link from "next/link"; + +const stats = [ + { + title: "Total Extensions", + value: "24", + description: "Active extensions in marketplace", + icon: Package, + trend: "+12%", + }, + { + title: "Total Users", + value: "1,234", + description: "Registered users", + icon: Users, + trend: "+8%", + }, + { + title: "Total Downloads", + value: "5,678", + description: "Extension downloads this month", + icon: Download, + trend: "+23%", + }, + { + title: "Revenue", + value: "$12,345", + description: "Total revenue this month", + icon: TrendingUp, + trend: "+15%", + }, +]; + +const recentExtensions = [ + { + id: 1, + name: "AdBlock Pro", + status: "Published", + downloads: 1234, + revenue: "$234", + }, + { + id: 2, + name: "Password Manager", + status: "Pending Review", + downloads: 567, + revenue: "$89", + }, + { + id: 3, + name: "Dark Mode Plus", + status: "Published", + downloads: 890, + revenue: "$156", + }, +]; + +export default function AdminDashboard() { + return ( +
+
+
+

Admin Dashboard

+

+ Manage your extension marketplace from here. +

+
+ +
+ + {/* Stats Grid */} +
+ {stats.map((stat) => ( + + + + {stat.title} + + + + +
{stat.value}
+

+ {stat.trend}{" "} + {stat.description} +

+
+
+ ))} +
+ + {/* Recent Extensions */} + + + Recent Extensions + + Latest extensions uploaded to the marketplace + + + +
+ {recentExtensions.map((extension) => ( +
+
+
+ +
+
+

{extension.name}

+

+ {extension.downloads} downloads • {extension.revenue}{" "} + revenue +

+
+
+
+ + {extension.status} + + +
+
+ ))} +
+
+
+
+ ); +} diff --git a/apps/client/src/app/(admin)/admin/upload/page.tsx b/apps/client/src/app/(admin)/admin/upload/page.tsx new file mode 100644 index 0000000..d4e9161 --- /dev/null +++ b/apps/client/src/app/(admin)/admin/upload/page.tsx @@ -0,0 +1,431 @@ +"use client"; + +import type React from "react"; + +import { useState } from "react"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Textarea } from "@/components/ui/textarea"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { Badge } from "@/components/ui/badge"; +import { Upload, X, ImageIcon, Video, FileText } from "lucide-react"; +import { toast } from "sonner"; + +const categories = [ + "Productivity", + "Security", + "Developer Tools", + "Social Media", + "Shopping", + "Entertainment", + "Utilities", + "Communication", +]; + +const browsers = ["Chrome", "Firefox", "Safari", "Edge", "Opera"]; + +export default function UploadExtension() { + const [formData, setFormData] = useState({ + name: "", + description: "", + shortDescription: "", + category: "", + price: "", + version: "", + browsers: [] as string[], + tags: [] as string[], + }); + const [files, setFiles] = useState({ + extensionFile: null as File | null, + icon: null as File | null, + screenshots: [] as File[], + video: null as File | null, + }); + const [currentTag, setCurrentTag] = useState(""); + const [isUploading, setIsUploading] = useState(false); + + const handleInputChange = (field: string, value: string) => { + setFormData((prev) => ({ ...prev, [field]: value })); + }; + + const handleBrowserToggle = (browser: string) => { + setFormData((prev) => ({ + ...prev, + browsers: prev.browsers.includes(browser) + ? prev.browsers.filter((b) => b !== browser) + : [...prev.browsers, browser], + })); + }; + + const handleAddTag = () => { + if (currentTag.trim() && !formData.tags.includes(currentTag.trim())) { + setFormData((prev) => ({ + ...prev, + tags: [...prev.tags, currentTag.trim()], + })); + setCurrentTag(""); + } + }; + + const handleRemoveTag = (tag: string) => { + setFormData((prev) => ({ + ...prev, + tags: prev.tags.filter((t) => t !== tag), + })); + }; + + const handleFileChange = (field: string, file: File | File[] | null) => { + setFiles((prev) => ({ ...prev, [field]: file })); + }; + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setIsUploading(true); + + // Simulate upload process + await new Promise((resolve) => setTimeout(resolve, 2000)); + + toast.success("Extension uploaded successfully!"); + + // Reset form + setFormData({ + name: "", + description: "", + shortDescription: "", + category: "", + price: "", + version: "", + browsers: [], + tags: [], + }); + setFiles({ + extensionFile: null, + icon: null, + screenshots: [], + video: null, + }); + setIsUploading(false); + }; + + return ( +
+
+

Upload Extension

+

+ Add a new extension to the BrowserPlugins marketplace. +

+
+ +
+ {/* Basic Information */} + + + Basic Information + + Provide basic details about your extension + + + +
+
+ + handleInputChange("name", e.target.value)} + placeholder="Enter extension name" + required + /> +
+
+ + handleInputChange("version", e.target.value)} + placeholder="1.0.0" + required + /> +
+
+ +
+ + + handleInputChange("shortDescription", e.target.value) + } + placeholder="Brief description (max 100 characters)" + maxLength={100} + required + /> +
+ +
+ +