- - New ThemeConfigContext provider that fetches theme on app load and applies it to the DOM (title, meta description, favicon, CSS variables,
theme-color)/- - Admin Theme settings page under Settings > Theme tab/- All logo references (5 components) now pull from the theme config with fallback to default
This commit is contained in:
@@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
|
||||
import { Link, useLocation, useNavigate } from 'react-router-dom';
|
||||
import { useTheme } from 'next-themes';
|
||||
import { useAuth } from '../context/AuthContext';
|
||||
import { useThemeConfig } from '../context/ThemeConfigContext';
|
||||
import api from '../utils/api';
|
||||
import { Badge } from './ui/badge';
|
||||
import {
|
||||
@@ -32,6 +33,7 @@ const AdminSidebar = ({ isOpen, onToggle, isMobile }) => {
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const { user, logout } = useAuth();
|
||||
const { getLogoUrl } = useThemeConfig();
|
||||
const { theme, setTheme } = useTheme();
|
||||
const [pendingCount, setPendingCount] = useState(0);
|
||||
const [storageUsed, setStorageUsed] = useState(0);
|
||||
@@ -281,7 +283,7 @@ const AdminSidebar = ({ isOpen, onToggle, isMobile }) => {
|
||||
<div className="flex items-center justify-between p-4 border-b border-[var(--neutral-800)]">
|
||||
<Link to="/" className="flex items-center gap-3 group flex-1 min-w-0">
|
||||
<img
|
||||
src={`${process.env.PUBLIC_URL}/loaf-logo.png`}
|
||||
src={getLogoUrl()}
|
||||
alt="LOAF Logo"
|
||||
className={`object-contain transition-all duration-200 ${isOpen ? 'h-10 w-10' : 'h-8 w-8'
|
||||
}`}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import { useAuth } from '../context/AuthContext';
|
||||
import { useThemeConfig } from '../context/ThemeConfigContext';
|
||||
import { Button } from './ui/button';
|
||||
import { ChevronDown, Menu, X } from 'lucide-react';
|
||||
import {
|
||||
@@ -12,11 +13,12 @@ import {
|
||||
|
||||
const Navbar = () => {
|
||||
const { user, logout } = useAuth();
|
||||
const { getLogoUrl } = useThemeConfig();
|
||||
const navigate = useNavigate();
|
||||
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
||||
|
||||
// LOAF logo (local)
|
||||
const loafLogo = `${process.env.PUBLIC_URL}/loaf-logo.png`;
|
||||
// Get logo URL from theme config (with fallback to default)
|
||||
const loafLogo = getLogoUrl();
|
||||
|
||||
const handleLogout = () => {
|
||||
logout();
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Button } from './ui/button';
|
||||
import { useThemeConfig } from '../context/ThemeConfigContext';
|
||||
|
||||
const PublicFooter = () => {
|
||||
const loafLogo = `${process.env.PUBLIC_URL}/loaf-logo.png`;
|
||||
const { getLogoUrl } = useThemeConfig();
|
||||
const loafLogo = getLogoUrl();
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { useState } from 'react';
|
||||
import { Link, useNavigate, useLocation } from 'react-router-dom';
|
||||
import { Button } from './ui/button';
|
||||
import { useAuth } from '../context/AuthContext';
|
||||
import { useThemeConfig } from '../context/ThemeConfigContext';
|
||||
import { ChevronDown, Menu, X } from 'lucide-react';
|
||||
import {
|
||||
DropdownMenu,
|
||||
@@ -12,6 +13,7 @@ import {
|
||||
|
||||
const PublicNavbar = () => {
|
||||
const { user, logout } = useAuth();
|
||||
const { getLogoUrl } = useThemeConfig();
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
||||
@@ -30,8 +32,8 @@ const PublicNavbar = () => {
|
||||
return location.pathname.startsWith('/about');
|
||||
};
|
||||
|
||||
// LOAF logo (local)
|
||||
const loafLogo = `${process.env.PUBLIC_URL}/loaf-logo.png`;
|
||||
// Get logo URL from theme config (with fallback to default)
|
||||
const loafLogo = getLogoUrl();
|
||||
|
||||
const handleAuthAction = () => {
|
||||
if (user) {
|
||||
|
||||
@@ -1,46 +1,45 @@
|
||||
import React from 'react';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
import { CreditCard, Shield, Settings, Star } from 'lucide-react';
|
||||
import { NavLink, useLocation } from 'react-router-dom';
|
||||
import { CreditCard, Shield, Star, Palette } from 'lucide-react';
|
||||
|
||||
const settingsItems = [
|
||||
{ label: 'Stripe Integration', path: '/admin/settings/stripe', icon: CreditCard },
|
||||
{ label: 'Stripe', path: '/admin/settings/stripe', icon: CreditCard },
|
||||
{ label: 'Permissions', path: '/admin/settings/permissions', icon: Shield },
|
||||
{ label: 'Member Tiers', path: '/admin/settings/member-tiers', icon: Star },
|
||||
{ label: 'Theme', path: '/admin/settings/theme', icon: Palette },
|
||||
];
|
||||
|
||||
const SettingsSidebar = () => {
|
||||
const SettingsTabs = () => {
|
||||
const location = useLocation();
|
||||
|
||||
return (
|
||||
<aside className="w-full lg:w-64 shrink-0 bg-background border border-[var(--neutral-800)] rounded-2xl p-4 lg:sticky lg:top-8 h-max">
|
||||
<div className="flex items-center gap-2 px-2 pb-3 border-b border-[var(--neutral-800)]">
|
||||
<Settings className="h-4 w-4 text-[var(--purple-ink)]" />
|
||||
<span className="text-sm font-semibold text-[var(--purple-ink)]" style={{ fontFamily: "'Inter', sans-serif" }}>
|
||||
Settings
|
||||
</span>
|
||||
</div>
|
||||
<nav className="mt-3 space-y-1">
|
||||
<div className="w-full border-b border-border">
|
||||
<nav className="flex gap-1 overflow-x-auto pb-px -mb-px" aria-label="Settings tabs">
|
||||
{settingsItems.map((item) => {
|
||||
const Icon = item.icon;
|
||||
const isActive = location.pathname === item.path;
|
||||
|
||||
return (
|
||||
<NavLink
|
||||
key={item.label}
|
||||
to={item.path}
|
||||
className={({ isActive }) =>
|
||||
[
|
||||
'flex items-center gap-3 px-3 py-2 rounded-lg text-sm font-medium transition-colors',
|
||||
isActive
|
||||
? 'bg-[var(--orange-light)]/10 text-[var(--purple-ink)]'
|
||||
: 'text-[var(--purple-ink)] hover:bg-[var(--neutral-800)]/10',
|
||||
].join(' ')
|
||||
}
|
||||
className={`
|
||||
flex items-center gap-2 px-4 py-3 text-sm font-medium whitespace-nowrap
|
||||
border-b-2 transition-all duration-200
|
||||
${isActive
|
||||
? 'border-primary text-primary bg-primary/5'
|
||||
: 'border-transparent text-muted-foreground hover:text-foreground hover:border-border'
|
||||
}
|
||||
`}
|
||||
>
|
||||
<Icon className="h-4 w-4" />
|
||||
<Icon className={`h-4 w-4 ${isActive ? 'text-primary' : ''}`} />
|
||||
<span>{item.label}</span>
|
||||
</NavLink>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
</aside>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SettingsSidebar;
|
||||
export default SettingsTabs;
|
||||
|
||||
Reference in New Issue
Block a user