feat: introduce admin design tokens and redesign AdminLayout/AdminLogin
Create AdminApp.module.css with admin-specific design tokens (--admin-bg, --admin-surface, --admin-border, --admin-text, --admin-text-muted, --admin-primary, --admin-primary-hover, --admin-danger, --admin-radius, --admin-shadow, --admin-font, --admin-space-xs/sm/md/lg/xl) scoped to .adminRoot wrapper class to avoid collisions with public site tokens. Create adminShared.module.css with composable component classes (page, card, table, form, error, button, buttonSecondary, buttonDanger) that all later admin pages will build against. Wrap AdminApp Routes in div with adminRoot class to establish token scope. Redesign AdminLayout.module.css to use new admin tokens with improved sidebar styling (240px width, better spacing, hover states, active link highlighting). Redesign AdminLogin.module.css to use new admin tokens with improved form styling (better card styling, focus states, proper typography). No changes to AdminLayout.tsx or AdminLogin.tsx needed — existing JSX structure matches new CSS selectors. Claude-Session: https://claude.ai/code/session_01NhxA4npAXAxmCDEJt6kxSH
This commit is contained in:
24
src/pages/admin/AdminApp.module.css
Normal file
24
src/pages/admin/AdminApp.module.css
Normal file
@@ -0,0 +1,24 @@
|
||||
/* src/pages/admin/AdminApp.module.css */
|
||||
.adminRoot {
|
||||
--admin-bg: #F4F5F7;
|
||||
--admin-surface: #FFFFFF;
|
||||
--admin-border: #E1E4E9;
|
||||
--admin-text: #1F2430;
|
||||
--admin-text-muted: #6B7280;
|
||||
--admin-primary: #2A5C8A;
|
||||
--admin-primary-hover: #1E4566;
|
||||
--admin-danger: #B3261E;
|
||||
--admin-radius: 8px;
|
||||
--admin-shadow: 0 1px 2px rgba(16, 24, 40, 0.06);
|
||||
--admin-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
||||
--admin-space-xs: 0.25rem;
|
||||
--admin-space-sm: 0.5rem;
|
||||
--admin-space-md: 1rem;
|
||||
--admin-space-lg: 1.5rem;
|
||||
--admin-space-xl: 2.5rem;
|
||||
|
||||
min-height: 100vh;
|
||||
background: var(--admin-bg);
|
||||
color: var(--admin-text);
|
||||
font-family: var(--admin-font);
|
||||
}
|
||||
@@ -7,23 +7,26 @@ import AdminServices from './AdminServices'
|
||||
import AdminSchedule from './AdminSchedule'
|
||||
import AdminBookings from './AdminBookings'
|
||||
import AdminInquiries from './AdminInquiries'
|
||||
import styles from './AdminApp.module.css'
|
||||
|
||||
function AdminApp() {
|
||||
return (
|
||||
<Routes>
|
||||
<Route path="login" element={<AdminLogin />} />
|
||||
<Route element={<ProtectedRoute />}>
|
||||
<Route element={<AdminLayout />}>
|
||||
<Route index element={<Navigate to="/admin/products" replace />} />
|
||||
<Route path="products" element={<AdminProducts />} />
|
||||
<Route path="services" element={<AdminServices />} />
|
||||
<Route path="schedule" element={<AdminSchedule />} />
|
||||
<Route path="bookings" element={<AdminBookings />} />
|
||||
<Route path="inquiries" element={<AdminInquiries />} />
|
||||
<Route path="*" element={<Navigate to="/admin/products" replace />} />
|
||||
<div className={styles.adminRoot}>
|
||||
<Routes>
|
||||
<Route path="login" element={<AdminLogin />} />
|
||||
<Route element={<ProtectedRoute />}>
|
||||
<Route element={<AdminLayout />}>
|
||||
<Route index element={<Navigate to="/admin/products" replace />} />
|
||||
<Route path="products" element={<AdminProducts />} />
|
||||
<Route path="services" element={<AdminServices />} />
|
||||
<Route path="schedule" element={<AdminSchedule />} />
|
||||
<Route path="bookings" element={<AdminBookings />} />
|
||||
<Route path="inquiries" element={<AdminInquiries />} />
|
||||
<Route path="*" element={<Navigate to="/admin/products" replace />} />
|
||||
</Route>
|
||||
</Route>
|
||||
</Route>
|
||||
</Routes>
|
||||
</Routes>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,50 +4,71 @@
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 220px;
|
||||
width: 240px;
|
||||
flex-shrink: 0;
|
||||
background: var(--color-charcoal);
|
||||
color: var(--color-cream);
|
||||
padding: var(--space-lg) var(--space-md);
|
||||
background: var(--admin-surface);
|
||||
border-right: 1px solid var(--admin-border);
|
||||
padding: var(--admin-space-lg) var(--admin-space-md);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-lg);
|
||||
gap: var(--admin-space-xl);
|
||||
}
|
||||
|
||||
.brand {
|
||||
font-family: var(--font-script);
|
||||
font-size: 1.5rem;
|
||||
color: var(--color-gold);
|
||||
font-weight: 700;
|
||||
font-size: 1.125rem;
|
||||
color: var(--admin-text);
|
||||
padding: 0 var(--admin-space-sm);
|
||||
}
|
||||
|
||||
.sidebar nav {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-sm);
|
||||
gap: var(--admin-space-xs);
|
||||
}
|
||||
|
||||
.navLink {
|
||||
color: var(--color-cream);
|
||||
color: var(--admin-text-muted);
|
||||
text-decoration: none;
|
||||
padding: var(--space-sm);
|
||||
padding: var(--admin-space-sm);
|
||||
border-radius: var(--admin-radius);
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.navLink:hover {
|
||||
background: var(--admin-bg);
|
||||
color: var(--admin-text);
|
||||
}
|
||||
|
||||
.navLinkActive {
|
||||
color: var(--color-gold);
|
||||
font-weight: bold;
|
||||
background: var(--admin-primary);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.navLinkActive:hover {
|
||||
background: var(--admin-primary-hover);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.signOut {
|
||||
margin-top: auto;
|
||||
background: none;
|
||||
border: 1px solid var(--color-gold);
|
||||
color: var(--color-cream);
|
||||
padding: var(--space-sm);
|
||||
border: 1px solid var(--admin-border);
|
||||
border-radius: var(--admin-radius);
|
||||
color: var(--admin-text-muted);
|
||||
padding: var(--admin-space-sm);
|
||||
cursor: pointer;
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
.signOut:hover {
|
||||
border-color: var(--admin-danger);
|
||||
color: var(--admin-danger);
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
padding: var(--space-xl) var(--space-lg);
|
||||
background: var(--color-cream-alt);
|
||||
padding: var(--admin-space-xl) var(--admin-space-lg);
|
||||
max-width: 1100px;
|
||||
}
|
||||
|
||||
@@ -3,46 +3,76 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--color-cream);
|
||||
padding: var(--space-lg);
|
||||
background: var(--admin-bg);
|
||||
padding: var(--admin-space-lg);
|
||||
}
|
||||
|
||||
.form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-md);
|
||||
gap: var(--admin-space-md);
|
||||
width: 100%;
|
||||
max-width: 320px;
|
||||
max-width: 340px;
|
||||
background: var(--admin-surface);
|
||||
border: 1px solid var(--admin-border);
|
||||
border-radius: var(--admin-radius);
|
||||
box-shadow: var(--admin-shadow);
|
||||
padding: var(--admin-space-xl) var(--admin-space-lg);
|
||||
}
|
||||
|
||||
.form h1 {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
color: var(--admin-text);
|
||||
margin: 0 0 var(--admin-space-sm);
|
||||
}
|
||||
|
||||
.field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-sm);
|
||||
gap: var(--admin-space-xs);
|
||||
}
|
||||
|
||||
.field label {
|
||||
color: var(--color-charcoal);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
color: var(--admin-text);
|
||||
}
|
||||
|
||||
.field input {
|
||||
padding: var(--space-sm);
|
||||
border: 1px solid var(--color-gold);
|
||||
background: white;
|
||||
padding: var(--admin-space-sm);
|
||||
border: 1px solid var(--admin-border);
|
||||
border-radius: calc(var(--admin-radius) / 2);
|
||||
font: inherit;
|
||||
background: var(--admin-surface);
|
||||
color: var(--admin-text);
|
||||
}
|
||||
|
||||
.field input:focus {
|
||||
outline: 2px solid var(--admin-primary);
|
||||
outline-offset: 1px;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: #a33;
|
||||
color: var(--admin-danger);
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.form button {
|
||||
background: var(--color-charcoal);
|
||||
color: var(--color-cream);
|
||||
background: var(--admin-primary);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: var(--space-sm) var(--space-md);
|
||||
border-radius: calc(var(--admin-radius) / 2);
|
||||
padding: var(--admin-space-sm) var(--admin-space-md);
|
||||
font: inherit;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.form button:hover {
|
||||
background: var(--admin-primary-hover);
|
||||
}
|
||||
|
||||
.form button:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: default;
|
||||
|
||||
133
src/pages/admin/adminShared.module.css
Normal file
133
src/pages/admin/adminShared.module.css
Normal file
@@ -0,0 +1,133 @@
|
||||
/* src/pages/admin/adminShared.module.css */
|
||||
.page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--admin-space-lg);
|
||||
}
|
||||
|
||||
.card {
|
||||
background: var(--admin-surface);
|
||||
border: 1px solid var(--admin-border);
|
||||
border-radius: var(--admin-radius);
|
||||
box-shadow: var(--admin-shadow);
|
||||
}
|
||||
|
||||
.table {
|
||||
composes: card;
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.table th {
|
||||
text-align: left;
|
||||
padding: var(--admin-space-sm) var(--admin-space-md);
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
color: var(--admin-text-muted);
|
||||
border-bottom: 1px solid var(--admin-border);
|
||||
background: var(--admin-bg);
|
||||
}
|
||||
|
||||
.table td {
|
||||
padding: var(--admin-space-sm) var(--admin-space-md);
|
||||
border-bottom: 1px solid var(--admin-border);
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.table tbody tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.table tbody tr:hover {
|
||||
background: var(--admin-bg);
|
||||
}
|
||||
|
||||
.form {
|
||||
composes: card;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--admin-space-md);
|
||||
max-width: 480px;
|
||||
padding: var(--admin-space-lg);
|
||||
}
|
||||
|
||||
.form label {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--admin-space-xs);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
color: var(--admin-text);
|
||||
}
|
||||
|
||||
.form input,
|
||||
.form select,
|
||||
.form textarea {
|
||||
padding: var(--admin-space-sm);
|
||||
border: 1px solid var(--admin-border);
|
||||
border-radius: calc(var(--admin-radius) / 2);
|
||||
font: inherit;
|
||||
color: var(--admin-text);
|
||||
background: var(--admin-surface);
|
||||
}
|
||||
|
||||
.form input:focus,
|
||||
.form select:focus,
|
||||
.form textarea:focus {
|
||||
outline: 2px solid var(--admin-primary);
|
||||
outline-offset: 1px;
|
||||
}
|
||||
|
||||
.form textarea {
|
||||
min-height: 6rem;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.button {
|
||||
font: inherit;
|
||||
font-weight: 600;
|
||||
padding: var(--admin-space-sm) var(--admin-space-md);
|
||||
border-radius: calc(var(--admin-radius) / 2);
|
||||
border: 1px solid transparent;
|
||||
cursor: pointer;
|
||||
background: var(--admin-primary);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background: var(--admin-primary-hover);
|
||||
}
|
||||
|
||||
.button:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.buttonSecondary {
|
||||
composes: button;
|
||||
font-weight: 500;
|
||||
background: var(--admin-surface);
|
||||
color: var(--admin-text);
|
||||
border-color: var(--admin-border);
|
||||
}
|
||||
|
||||
.buttonSecondary:hover {
|
||||
background: var(--admin-bg);
|
||||
}
|
||||
|
||||
.buttonDanger {
|
||||
composes: buttonSecondary;
|
||||
color: var(--admin-danger);
|
||||
}
|
||||
|
||||
.buttonDanger:hover {
|
||||
background: #FEF2F2;
|
||||
border-color: var(--admin-danger);
|
||||
}
|
||||
|
||||
.error {
|
||||
color: var(--admin-danger);
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
Reference in New Issue
Block a user