theme-provider #17
32
src/App.css
32
src/App.css
@@ -1,32 +0,0 @@
|
|||||||
* {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-family: 'Nunito Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', sans-serif;
|
|
||||||
background-color: #FFFFFF;
|
|
||||||
color: #422268;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
|
||||||
font-family: 'Inter', sans-serif;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inter {
|
|
||||||
font-family: 'Inter', sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nunito-sans {
|
|
||||||
font-family: 'Nunito Sans', sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg-purple-gradient {
|
|
||||||
background: linear-gradient(135deg, rgba(100, 76, 159, 0.2) 0%, rgba(72, 40, 110, 0.2) 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg-soft-mesh {
|
|
||||||
background: radial-gradient(ellipse at top right, rgba(221, 216, 235, 0.4) 0%, #FFFFFF 50%, #FFFFFF 100%);
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
@layer components {
|
|
||||||
.btn {
|
|
||||||
@apply inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors
|
|
||||||
focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring
|
|
||||||
disabled:pointer-events-none disabled:opacity-50
|
|
||||||
[&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-primary {
|
|
||||||
@apply bg-primary text-primary-foreground shadow hover:bg-primary/90;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-secondary {
|
|
||||||
@apply bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-ghost {
|
|
||||||
@apply hover:bg-accent hover:text-accent-foreground;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-outline {
|
|
||||||
@apply border border-input shadow-sm hover:bg-accent hover:text-accent-foreground;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-accent {
|
|
||||||
@apply bg-accent text-accent-foreground shadow hover:bg-accent/90;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-destructive {
|
|
||||||
@apply bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-link {
|
|
||||||
@apply text-primary underline-offset-4 hover:underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-sm {
|
|
||||||
@apply h-8 rounded-md px-3 text-xs;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-md {
|
|
||||||
@apply h-9 px-4 py-2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-lg {
|
|
||||||
@apply h-10 rounded-md px-8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-icon {
|
|
||||||
@apply h-9 w-9;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -283,7 +283,7 @@ const AdminSidebar = ({ isOpen, onToggle, isMobile }) => {
|
|||||||
/>
|
/>
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
<h2 className="text-xl font-semibold text-primary" style={{ fontFamily: "'Inter', sans-serif" }}>
|
<h2 className="text-xl font-semibold text-primary dark:text-brand-light-lavender " style={{ fontFamily: "'Inter', sans-serif" }}>
|
||||||
Admin
|
Admin
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-xs text-muted-foreground group-hover:text-accent transition-colors" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
<p className="text-xs text-muted-foreground group-hover:text-accent transition-colors" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||||
@@ -384,7 +384,7 @@ const AdminSidebar = ({ isOpen, onToggle, isMobile }) => {
|
|||||||
{user.first_name?.[0]}{user.last_name?.[0]}
|
{user.first_name?.[0]}{user.last_name?.[0]}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
<p className="text-sm font-medium text-primary truncate" style={{ fontFamily: "'Inter', sans-serif" }}>
|
<p className="text-sm font-medium text-primary dark:text-brand-light-lavender truncate" style={{ fontFamily: "'Inter', sans-serif" }}>
|
||||||
{user.first_name} {user.last_name}
|
{user.first_name} {user.last_name}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-xs text-muted-foreground capitalize truncate" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
<p className="text-xs text-muted-foreground capitalize truncate" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||||
@@ -392,7 +392,7 @@ const AdminSidebar = ({ isOpen, onToggle, isMobile }) => {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Link to='/profile'><Settings size={16} />
|
<Link className='dark:text-brand-lavender ' to='/profile'><Settings size={16} />
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -406,16 +406,16 @@ const AdminSidebar = ({ isOpen, onToggle, isMobile }) => {
|
|||||||
aria-label={isDark ? 'Switch to light mode' : 'Switch to dark mode'}
|
aria-label={isDark ? 'Switch to light mode' : 'Switch to dark mode'}
|
||||||
className={`
|
className={`
|
||||||
flex items-center gap-3 px-4 py-3 rounded-lg w-full
|
flex items-center gap-3 px-4 py-3 rounded-lg w-full
|
||||||
text-primary hover:bg-muted/20 transition-colors
|
text-primary dark:text-brand-lavender hover:bg-muted/20 transition-colors
|
||||||
${!isOpen && 'justify-center'}
|
${!isOpen && 'justify-center'}
|
||||||
`}
|
`}
|
||||||
>
|
>
|
||||||
{isDark ? (
|
{isDark ? (
|
||||||
<Sun className="h-5 w-5 flex-shrink-0" />
|
<Sun className="h-5 w-5 flex-shrink-0 " />
|
||||||
) : (
|
) : (
|
||||||
<Moon className="h-5 w-5 flex-shrink-0" />
|
<Moon className="h-5 w-5 flex-shrink-0" />
|
||||||
)}
|
)}
|
||||||
{isOpen && <span>{isDark ? 'Light mode' : 'Dark mode'}</span>}
|
{isOpen && <span >{isDark ? 'Light mode' : 'Dark mode'}</span>}
|
||||||
</button>
|
</button>
|
||||||
{!isOpen && (
|
{!isOpen && (
|
||||||
<div className="absolute left-full ml-2 top-1/2 -translate-y-1/2 px-3 py-2 bg-primary foreground text-sm rounded-lg opacity-0 group-hover:opacity-100 pointer-events-none transition-opacity whitespace-nowrap z-50">
|
<div className="absolute left-full ml-2 top-1/2 -translate-y-1/2 px-3 py-2 bg-primary foreground text-sm rounded-lg opacity-0 group-hover:opacity-100 pointer-events-none transition-opacity whitespace-nowrap z-50">
|
||||||
@@ -429,7 +429,7 @@ const AdminSidebar = ({ isOpen, onToggle, isMobile }) => {
|
|||||||
{isOpen ? (
|
{isOpen ? (
|
||||||
<div className="px-4 py-3 bg-[var(--lavender-500)] rounded-lg">
|
<div className="px-4 py-3 bg-[var(--lavender-500)] rounded-lg">
|
||||||
<div className="flex items-center justify-between mb-2">
|
<div className="flex items-center justify-between mb-2">
|
||||||
<span className="text-sm font-medium text-primary">Storage Usage</span>
|
<span className="text-sm font-medium text-primary dark:text-brand-light-lavender ">Storage Usage</span>
|
||||||
<span className="text-xs text-muted-foreground">{storagePercentage}%</span>
|
<span className="text-xs text-muted-foreground">{storagePercentage}%</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full bg-[var(--neutral-800)] rounded-full h-2">
|
<div className="w-full bg-[var(--neutral-800)] rounded-full h-2">
|
||||||
|
|||||||
@@ -127,16 +127,15 @@ const ChangePasswordDialog = ({ open, onOpenChange }) => {
|
|||||||
<DialogFooter className="mt-6">
|
<DialogFooter className="mt-6">
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant="outline"
|
|
||||||
onClick={() => onOpenChange(false)}
|
onClick={() => onOpenChange(false)}
|
||||||
className="rounded-full px-6"
|
className="btn-outline mr-33"
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
className="bg-[var(--neutral-800)] text-[var(--purple-ink)] hover:bg-background rounded-full px-6 disabled:opacity-50"
|
className=" btn-primary"
|
||||||
>
|
>
|
||||||
{loading ? 'Changing...' : 'Change Password'}
|
{loading ? 'Changing...' : 'Change Password'}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import { cva } from "class-variance-authority";
|
import { cva } from "class-variance-authority";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const badgeVariants = cva(
|
const badgeVariants = cva(
|
||||||
"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
||||||
@@ -15,20 +15,31 @@ const badgeVariants = cva(
|
|||||||
destructive:
|
destructive:
|
||||||
"border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
|
"border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
|
||||||
outline: "text-foreground",
|
outline: "text-foreground",
|
||||||
|
green:
|
||||||
|
"border-transparent bg-[var(--green-light)] text-white hover:bg-[var(--green-forest)]",
|
||||||
|
orange:
|
||||||
|
"border-transparent bg-orange-500 text-white hover:bg-orange-500/80",
|
||||||
|
orange2:
|
||||||
|
"border-transparent bg-orange-100 text-orange-700 hover:bg-orange-100/80",
|
||||||
|
pink: "border-transparent bg-[var(--pink-500)] text-white hover:bg-[var(--pink-500)]/80",
|
||||||
|
red: "border-transparent bg-red-100 text-red-700 hover:bg-red-100/80",
|
||||||
|
red2: "border-transparent bg-red-500 text-white hover:bg-red-500/80",
|
||||||
|
gray: "border-transparent bg-gray-200 text-gray-700 hover:bg-gray-200/80",
|
||||||
|
gray2: "border-transparent bg-gray-400 text-white hover:bg-gray-400/80",
|
||||||
|
gray3:
|
||||||
|
"border-transparent bg-gray-300 text-gray-600 hover:bg-gray-300/80",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
variant: "default",
|
variant: "default",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
|
|
||||||
function Badge({
|
function Badge({ className, variant, ...props }) {
|
||||||
className,
|
return (
|
||||||
variant,
|
<div className={cn(badgeVariants({ variant }), className)} {...props} />
|
||||||
...props
|
);
|
||||||
}) {
|
|
||||||
return (<div className={cn(badgeVariants({ variant }), className)} {...props} />);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Badge, badgeVariants }
|
export { Badge, badgeVariants };
|
||||||
|
|||||||
@@ -1,28 +1,8 @@
|
|||||||
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap");
|
@import "./styles/App.css";
|
||||||
|
@import "./styles/theme.css";
|
||||||
@import url("https://fonts.googleapis.com/css2?family=Nunito+Sans:ital,opsz,wght@0,6..12,200..1000;1,6..12,200..1000&display=swap");
|
@import "./styles/components.css";
|
||||||
|
@import "./styles/base.css";
|
||||||
@tailwind base;
|
@import "./styles/utilities.css";
|
||||||
@tailwind components;
|
|
||||||
@tailwind utilities;
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
|
|
||||||
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
|
||||||
sans-serif;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
|
||||||
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
|
|
||||||
monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=========================
|
=========================
|
||||||
End of File
|
End of File
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ const AdminDashboard = () => {
|
|||||||
</div>
|
</div>
|
||||||
<Link to={'/'}>
|
<Link to={'/'}>
|
||||||
<Button
|
<Button
|
||||||
className="bg-[var(--purple-lavender)] text-white hover:bg-[var(--purple-muted)] rounded-full flex items-center gap-2"
|
className="btn-lavender"
|
||||||
>
|
>
|
||||||
<Globe />
|
<Globe />
|
||||||
View Public Site
|
View Public Site
|
||||||
|
|||||||
@@ -201,20 +201,20 @@ const AdminMembers = () => {
|
|||||||
|
|
||||||
const getStatusBadge = (status) => {
|
const getStatusBadge = (status) => {
|
||||||
const config = {
|
const config = {
|
||||||
pending_email: { label: 'Pending Email', className: 'bg-orange-100 text-orange-700' },
|
pending_email: { label: 'Pending Email', variant: 'orange2' },
|
||||||
pending_validation: { label: 'Pending Validation', className: 'bg-gray-200 text-gray-700' },
|
pending_validation: { label: 'Pending Validation', variant: 'gray' },
|
||||||
pre_validated: { label: 'Pre-Validated', className: 'bg-[var(--green-light)] text-white' },
|
pre_validated: { label: 'Pre-Validated', variant: 'green' },
|
||||||
payment_pending: { label: 'Payment Pending', className: 'bg-orange-500 text-white' },
|
payment_pending: { label: 'Payment Pending', variant: 'orange' },
|
||||||
active: { label: 'Active', className: 'bg-[var(--green-light)] text-white' },
|
active: { label: 'Active', variant: 'green' },
|
||||||
inactive: { label: 'Inactive', className: 'bg-gray-400 text-white' },
|
inactive: { label: 'Inactive', variant: 'gray2' },
|
||||||
canceled: { label: 'Canceled', className: 'bg-red-100 text-red-700' },
|
canceled: { label: 'Canceled', variant: 'red' },
|
||||||
expired: { label: 'Expired', className: 'bg-red-500 text-white' },
|
expired: { label: 'Expired', variant: 'red2' },
|
||||||
abandoned: { label: 'Abandoned', className: 'bg-gray-300 text-gray-600' }
|
abandoned: { label: 'Abandoned', variant: 'gray3' }
|
||||||
};
|
};
|
||||||
|
|
||||||
const statusConfig = config[status] || config.inactive;
|
const statusConfig = config[status] || config.inactive;
|
||||||
return (
|
return (
|
||||||
<Badge className={`${statusConfig.className} px-3 py-1 rounded-full text-sm`}>
|
<Badge variant={statusConfig.variant} className={` px-3 py-1 rounded-full text-sm`}>
|
||||||
{statusConfig.label}
|
{statusConfig.label}
|
||||||
</Badge>
|
</Badge>
|
||||||
);
|
);
|
||||||
@@ -248,7 +248,7 @@ const AdminMembers = () => {
|
|||||||
<h1 className="text-4xl md:text-5xl font-semibold text-[var(--purple-ink)] mb-4" style={{ fontFamily: "'Inter', sans-serif" }}>
|
<h1 className="text-4xl md:text-5xl font-semibold text-[var(--purple-ink)] mb-4" style={{ fontFamily: "'Inter', sans-serif" }}>
|
||||||
Members Management
|
Members Management
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-lg text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
<p className="text-lg text-brand-purple dark:text-brand-lavender" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||||
Manage paying members and their subscriptions.
|
Manage paying members and their subscriptions.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -257,7 +257,7 @@ const AdminMembers = () => {
|
|||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
className="bg-brand-purple hover:bg-[var(--purple-ink)] text-white rounded-xl h-12 px-6"
|
className="btn-util-purple "
|
||||||
disabled={exporting}
|
disabled={exporting}
|
||||||
>
|
>
|
||||||
{exporting ? (
|
{exporting ? (
|
||||||
@@ -288,7 +288,7 @@ const AdminMembers = () => {
|
|||||||
{hasPermission('users.import') && (
|
{hasPermission('users.import') && (
|
||||||
<Button
|
<Button
|
||||||
onClick={() => setImportDialogOpen(true)}
|
onClick={() => setImportDialogOpen(true)}
|
||||||
className="bg-[var(--green-light)] hover:bg-[var(--green-fern)] text-white rounded-xl h-12 px-6"
|
className="btn-util-green "
|
||||||
>
|
>
|
||||||
<Upload className="h-5 w-5 mr-2" />
|
<Upload className="h-5 w-5 mr-2" />
|
||||||
Import
|
Import
|
||||||
@@ -298,7 +298,7 @@ const AdminMembers = () => {
|
|||||||
{hasPermission('users.invite') && (
|
{hasPermission('users.invite') && (
|
||||||
<Button
|
<Button
|
||||||
onClick={() => setInviteDialogOpen(true)}
|
onClick={() => setInviteDialogOpen(true)}
|
||||||
className="bg-brand-purple hover:bg-[var(--purple-ink)] text-white rounded-xl h-12 px-6"
|
className="btn-util-purple "
|
||||||
>
|
>
|
||||||
<Mail className="h-5 w-5 mr-2" />
|
<Mail className="h-5 w-5 mr-2" />
|
||||||
Invite Member
|
Invite Member
|
||||||
@@ -308,7 +308,7 @@ const AdminMembers = () => {
|
|||||||
{hasPermission('users.create') && (
|
{hasPermission('users.create') && (
|
||||||
<Button
|
<Button
|
||||||
onClick={() => setCreateDialogOpen(true)}
|
onClick={() => setCreateDialogOpen(true)}
|
||||||
className="bg-[var(--green-light)] hover:bg-[var(--green-fern)] text-white rounded-xl h-12 px-6"
|
className="btn-util-green "
|
||||||
>
|
>
|
||||||
<UserPlus className="h-5 w-5 mr-2" />
|
<UserPlus className="h-5 w-5 mr-2" />
|
||||||
Create Member
|
Create Member
|
||||||
@@ -321,26 +321,26 @@ const AdminMembers = () => {
|
|||||||
{/* Stats */}
|
{/* Stats */}
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-4 mb-8">
|
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-4 mb-8">
|
||||||
<Card className="p-6 bg-background rounded-2xl border border-[var(--neutral-800)]">
|
<Card className="p-6 bg-background rounded-2xl border border-[var(--neutral-800)]">
|
||||||
<p className="text-sm text-brand-purple mb-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Total Members</p>
|
<p className="text-sm text-brand-purple dark:text-brand-lavender mb-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Total Members</p>
|
||||||
<p className="text-3xl font-semibold text-[var(--purple-ink)]" style={{ fontFamily: "'Inter', sans-serif" }}>
|
<p className="text-4xl font-semibold text-[var(--purple-ink)]" style={{ fontFamily: "'Inter', sans-serif" }}>
|
||||||
{users.length}
|
{users.length}
|
||||||
</p>
|
</p>
|
||||||
</Card>
|
</Card>
|
||||||
<Card className="p-6 bg-background rounded-2xl border border-[var(--neutral-800)]">
|
<Card className="p-6 bg-background rounded-2xl border border-[var(--neutral-800)]">
|
||||||
<p className="text-sm text-brand-purple mb-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Active</p>
|
<p className="text-sm text-brand-purple dark:text-brand-lavender mb-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Active</p>
|
||||||
<p className="text-3xl font-semibold text-[var(--purple-ink)]" style={{ fontFamily: "'Inter', sans-serif" }}>
|
<p className="text-4xl font-semibold text-[var(--purple-ink)]" style={{ fontFamily: "'Inter', sans-serif" }}>
|
||||||
{users.filter(u => u.status === 'active').length}
|
{users.filter(u => u.status === 'active').length}
|
||||||
</p>
|
</p>
|
||||||
</Card>
|
</Card>
|
||||||
<Card className="p-6 bg-background rounded-2xl border border-[var(--neutral-800)]">
|
<Card className="p-6 bg-background rounded-2xl border border-[var(--neutral-800)]">
|
||||||
<p className="text-sm text-brand-purple mb-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Payment Pending</p>
|
<p className="text-sm text-brand-purple dark:text-brand-lavender mb-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Payment Pending</p>
|
||||||
<p className="text-3xl font-semibold text-[var(--purple-ink)]" style={{ fontFamily: "'Inter', sans-serif" }}>
|
<p className="text-4xl font-semibold text-[var(--purple-ink)]" style={{ fontFamily: "'Inter', sans-serif" }}>
|
||||||
{users.filter(u => u.status === 'payment_pending').length}
|
{users.filter(u => u.status === 'payment_pending').length}
|
||||||
</p>
|
</p>
|
||||||
</Card>
|
</Card>
|
||||||
<Card className="p-6 bg-background rounded-2xl border border-[var(--neutral-800)]">
|
<Card className="p-6 bg-background rounded-2xl border border-[var(--neutral-800)]">
|
||||||
<p className="text-sm text-brand-purple mb-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Inactive</p>
|
<p className="text-sm text-brand-purple dark:text-brand-lavender mb-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Inactive</p>
|
||||||
<p className="text-3xl font-semibold text-[var(--purple-ink)]" style={{ fontFamily: "'Inter', sans-serif" }}>
|
<p className="text-4xl font-semibold text-[var(--purple-ink)]" style={{ fontFamily: "'Inter', sans-serif" }}>
|
||||||
{users.filter(u => u.status === 'inactive').length}
|
{users.filter(u => u.status === 'inactive').length}
|
||||||
</p>
|
</p>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -381,7 +381,7 @@ const AdminMembers = () => {
|
|||||||
{/* Members List */}
|
{/* Members List */}
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div className="text-center py-20">
|
<div className="text-center py-20">
|
||||||
<p className="text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Loading members...</p>
|
<p className="text-brand-purple dark:text-brand-lavender " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Loading members...</p>
|
||||||
</div>
|
</div>
|
||||||
) : filteredUsers.length > 0 ? (
|
) : filteredUsers.length > 0 ? (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
@@ -401,12 +401,12 @@ const AdminMembers = () => {
|
|||||||
{/* Info */}
|
{/* Info */}
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
<div className="flex items-center gap-3 mb-2 flex-wrap">
|
<div className="flex items-center gap-3 mb-2 flex-wrap">
|
||||||
<h3 className="text-xl font-semibold text-[var(--purple-ink)]" style={{ fontFamily: "'Inter', sans-serif" }}>
|
<h3 className="text-xl font-semibold text-[var(--purple-ink)] " style={{ fontFamily: "'Inter', sans-serif" }}>
|
||||||
{user.first_name} {user.last_name}
|
{user.first_name} {user.last_name}
|
||||||
</h3>
|
</h3>
|
||||||
{getStatusBadge(user.status)}
|
{getStatusBadge(user.status)}
|
||||||
</div>
|
</div>
|
||||||
<div className="grid md:grid-cols-2 gap-2 text-sm text-brand-purple " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
<div className="grid md:grid-cols-2 gap-2 text-sm text-brand-purple dark:text-brand-lavender " style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||||
<p>Email: {user.email}</p>
|
<p>Email: {user.email}</p>
|
||||||
<p>Phone: {user.phone}</p>
|
<p>Phone: {user.phone}</p>
|
||||||
<p>Joined: {new Date(user.created_at).toLocaleDateString()}</p>
|
<p>Joined: {new Date(user.created_at).toLocaleDateString()}</p>
|
||||||
@@ -478,7 +478,7 @@ const AdminMembers = () => {
|
|||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
className="border-brand-purple text-brand-purple hover:bg-brand-purple hover:text-white"
|
className="border-brand-purple text-brand-purple dark:bg-background dark:border-brand-lavender dark:text-brand-light-lavender hover:bg-brand-light-lavender "
|
||||||
>
|
>
|
||||||
<Eye className="h-4 w-4 mr-1" />
|
<Eye className="h-4 w-4 mr-1" />
|
||||||
View Profile
|
View Profile
|
||||||
@@ -500,7 +500,7 @@ const AdminMembers = () => {
|
|||||||
|
|
||||||
{/* Status Management */}
|
{/* Status Management */}
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span className="text-sm text-brand-purple whitespace-nowrap" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
<span className="text-sm text-brand-purple dark:text-brand-lavender whitespace-nowrap" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
||||||
Change Status:
|
Change Status:
|
||||||
</span>
|
</span>
|
||||||
<Select
|
<Select
|
||||||
|
|||||||
56
src/styles/App.css
Normal file
56
src/styles/App.css
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap");
|
||||||
|
|
||||||
|
@import url("https://fonts.googleapis.com/css2?family=Nunito+Sans:ital,opsz,wght@0,6..12,200..1000;1,6..12,200..1000&display=swap");
|
||||||
|
|
||||||
|
code {
|
||||||
|
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
|
||||||
|
monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: "Nunito Sans", -apple-system, BlinkMacSystemFont, "Segoe UI",
|
||||||
|
"Roboto", "Oxygen", sans-serif;
|
||||||
|
background-color: #ffffff;
|
||||||
|
color: #422268;
|
||||||
|
margin: 0;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
|
||||||
|
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||||
|
sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
|
font-family: "Poppins", sans-serif;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inter {
|
||||||
|
font-family: "Poppins", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nunito-sans {
|
||||||
|
font-family: "Nunito Sans", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-purple-gradient {
|
||||||
|
background: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
rgba(100, 76, 159, 0.2) 0%,
|
||||||
|
rgba(72, 40, 110, 0.2) 100%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-soft-mesh {
|
||||||
|
background: radial-gradient(
|
||||||
|
ellipse at top right,
|
||||||
|
rgba(221, 216, 235, 0.4) 0%,
|
||||||
|
#ffffff 50%,
|
||||||
|
#ffffff 100%
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
@tailwind base;
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
* {
|
* {
|
||||||
77
src/styles/components.css
Normal file
77
src/styles/components.css
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
@tailwind components;
|
||||||
|
|
||||||
|
@layer components {
|
||||||
|
.btn {
|
||||||
|
@apply inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors
|
||||||
|
focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring
|
||||||
|
disabled:pointer-events-none disabled:opacity-50
|
||||||
|
[&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
@apply bg-primary text-primary-foreground shadow hover:bg-primary/90 rounded-full px-6 disabled:opacity-50 px-6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
@apply bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80 rounded-full disabled:opacity-50 px-6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-ghost {
|
||||||
|
@apply hover:bg-accent hover:text-accent-foreground rounded-full disabled:opacity-50 px-6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-outline {
|
||||||
|
@apply border border-primary border-2 bg-white text-primary shadow-sm hover:bg-primary/10 rounded-full disabled:opacity-50 px-6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-accent {
|
||||||
|
@apply bg-accent text-accent-foreground shadow hover:bg-accent/90 rounded-full disabled:opacity-50 px-6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-destructive {
|
||||||
|
@apply bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90 rounded-full disabled:opacity-50 px-6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-link {
|
||||||
|
@apply text-primary underline-offset-4 hover:underline disabled:opacity-50 px-6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-sm {
|
||||||
|
@apply h-8 rounded-full px-3 text-xs disabled:opacity-50 px-6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-md {
|
||||||
|
@apply h-9 px-4 py-2 rounded-full disabled:opacity-50 px-6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-lg {
|
||||||
|
@apply h-10 rounded-full px-8 disabled:opacity-50;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-icon {
|
||||||
|
@apply h-9 w-9 rounded-full disabled:opacity-50 px-6;
|
||||||
|
}
|
||||||
|
.btn-util-green {
|
||||||
|
@apply bg-[var(--green-light)] hover:bg-[var(--green-forest)] text-white rounded-xl h-12 px-6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-util-purple {
|
||||||
|
@apply bg-brand-purple hover:bg-[var(--purple-ink-2)] text-background dark:text-white dark:hover:text-white rounded-xl h-12 px-6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-light-orange {
|
||||||
|
@apply bg-brand-light-orange hover:bg-brand-orange text-background dark:hover:text-white rounded-xl h-12 px-6;
|
||||||
|
}
|
||||||
|
.btn-pink {
|
||||||
|
@apply bg-brand-pink hover:bg-brand-dark-rose dark:text-[var(--lavender-100)] text-background dark:hover:text-white rounded-xl h-12 px-6;
|
||||||
|
}
|
||||||
|
.btn-lavender {
|
||||||
|
@apply bg-[var(--purple-lavender)] text-white hover:bg-[var(--purple-muted)] rounded-full flex items-center gap-2 dark:hover:bg-brand-lavender dark:hover:text-brand-dark-lavender
|
||||||
|
}
|
||||||
|
.badge {
|
||||||
|
@apply px-3 py-1 rounded-full text-sm font-medium ;
|
||||||
|
}
|
||||||
|
.badge-green {
|
||||||
|
@apply bg-[var(--green-light)] text-white;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
@tailwind base;
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
:root {
|
:root {
|
||||||
--background: 0 0% 100%;
|
--background: 0 0% 100%;
|
||||||
@@ -53,6 +55,7 @@
|
|||||||
--blue-facebook: #1877f2;
|
--blue-facebook: #1877f2;
|
||||||
--blue-twitter: #1da1f2;
|
--blue-twitter: #1da1f2;
|
||||||
--purple-ink: #422268;
|
--purple-ink: #422268;
|
||||||
|
--purple-ink-2: #422268;
|
||||||
--purple-deep: #48286e;
|
--purple-deep: #48286e;
|
||||||
--purple-muted: #533a82;
|
--purple-muted: #533a82;
|
||||||
--purple-plum: #553d8a;
|
--purple-plum: #553d8a;
|
||||||
@@ -74,6 +77,7 @@
|
|||||||
--green-muted: #66927e;
|
--green-muted: #66927e;
|
||||||
--green-soft: #6a9680;
|
--green-soft: #6a9680;
|
||||||
--green-eucalyptus: #6a9a83;
|
--green-eucalyptus: #6a9a83;
|
||||||
|
--green-forest: #5e8374;
|
||||||
--green-fern: #6da085;
|
--green-fern: #6da085;
|
||||||
--green-mint: #6fa087;
|
--green-mint: #6fa087;
|
||||||
--green-pastel: #6fa188;
|
--green-pastel: #6fa188;
|
||||||
@@ -154,6 +158,7 @@
|
|||||||
/* -------- Purples (Primary UI) -------- */
|
/* -------- Purples (Primary UI) -------- */
|
||||||
--purple-ink: #422268; /* deepest background */
|
--purple-ink: #422268; /* deepest background */
|
||||||
--purple-ink: hsl(var(--brand-light-lavender)); /* deepest background */
|
--purple-ink: hsl(var(--brand-light-lavender)); /* deepest background */
|
||||||
|
--purple-ink-2: #422268;
|
||||||
--purple-deep: #24153a; /* app shell */
|
--purple-deep: #24153a; /* app shell */
|
||||||
--purple-muted: #34204f; /* panels */
|
--purple-muted: #34204f; /* panels */
|
||||||
--purple-plum: #3f2760;
|
--purple-plum: #3f2760;
|
||||||
@@ -175,10 +180,11 @@
|
|||||||
--green-muted: #5fb39a;
|
--green-muted: #5fb39a;
|
||||||
--green-soft: #6fc4aa;
|
--green-soft: #6fc4aa;
|
||||||
--green-eucalyptus: #7dd3b0;
|
--green-eucalyptus: #7dd3b0;
|
||||||
--green-fern: #8be0bc;
|
--green-fern: #315446;
|
||||||
--green-mint: #66a38b;
|
--green-mint: #8be0bc;
|
||||||
|
--green-forest: #5e8374;
|
||||||
--green-pastel: #a6ecd1;
|
--green-pastel: #a6ecd1;
|
||||||
--green-light: #5e8374;
|
--green-light: #66a38b;
|
||||||
--green-bg: #0f2a1e;
|
--green-bg: #0f2a1e;
|
||||||
|
|
||||||
/* -------- Oranges (Warnings / Energy) -------- */
|
/* -------- Oranges (Warnings / Energy) -------- */
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
@layer utilities {
|
@layer utilities {
|
||||||
@supports selector(::-webkit-scrollbar) {
|
@supports selector(::-webkit-scrollbar) {
|
||||||
.scrollbar-dashboard::-webkit-scrollbar {
|
.scrollbar-dashboard::-webkit-scrollbar {
|
||||||
Reference in New Issue
Block a user