refactor(frontend): consolidate shared styles into centralized style system
- Create comprehensive shared.ts with design tokens and categorized styles: - layoutStyles: main, loader, content variants - cardStyles: card, tableCard, cardHeader - tableStyles: complete table styling - paginationStyles: pagination controls - formStyles: inputs, labels, errors - buttonStyles: primary, secondary, accent, danger variants - badgeStyles: status badges with color variants - bannerStyles: error/success banners - modalStyles: modal overlay and content - toastStyles: toast notifications - utilityStyles: divider, emptyState, etc. - Refactor all page components to use shared styles: - page.tsx (counter) - audit/page.tsx - booking/page.tsx - appointments/page.tsx - profile/page.tsx - invites/page.tsx - admin/invites/page.tsx - admin/availability/page.tsx - Reduce code duplication significantly (each page now has only truly page-specific styles) - Maintain backwards compatibility with sharedStyles export
This commit is contained in:
parent
4d9edd7fd4
commit
81cd34b0e7
9 changed files with 1148 additions and 1173 deletions
|
|
@ -3,7 +3,6 @@
|
|||
import { useEffect, useState, useCallback } from "react";
|
||||
import { Permission } from "../../auth-context";
|
||||
import { api } from "../../api";
|
||||
import { sharedStyles } from "../../styles/shared";
|
||||
import { Header } from "../../components/Header";
|
||||
import { useRequireAuth } from "../../hooks/useRequireAuth";
|
||||
import { components } from "../../generated/api";
|
||||
|
|
@ -15,6 +14,13 @@ import {
|
|||
formatTimeString,
|
||||
isWeekend,
|
||||
} from "../../utils/date";
|
||||
import {
|
||||
layoutStyles,
|
||||
typographyStyles,
|
||||
bannerStyles,
|
||||
buttonStyles,
|
||||
modalStyles,
|
||||
} from "../../styles/shared";
|
||||
|
||||
const { slotDurationMinutes, maxAdvanceDays, minAdvanceDays } = constants.booking;
|
||||
|
||||
|
|
@ -217,8 +223,8 @@ export default function AdminAvailabilityPage() {
|
|||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<main style={styles.main}>
|
||||
<div style={styles.loader}>Loading...</div>
|
||||
<main style={layoutStyles.main}>
|
||||
<div style={layoutStyles.loader}>Loading...</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
|
@ -228,15 +234,15 @@ export default function AdminAvailabilityPage() {
|
|||
}
|
||||
|
||||
return (
|
||||
<main style={styles.main}>
|
||||
<main style={layoutStyles.main}>
|
||||
<Header currentPage="admin-availability" />
|
||||
|
||||
<div style={styles.content}>
|
||||
<div style={layoutStyles.contentScrollable}>
|
||||
<div style={styles.pageContainer}>
|
||||
<div style={styles.headerRow}>
|
||||
<div>
|
||||
<h1 style={styles.pageTitle}>Availability</h1>
|
||||
<p style={styles.pageSubtitle}>
|
||||
<h1 style={typographyStyles.pageTitle}>Availability</h1>
|
||||
<p style={typographyStyles.pageSubtitle}>
|
||||
Configure your available time slots for the next {maxAdvanceDays} days
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -246,18 +252,18 @@ export default function AdminAvailabilityPage() {
|
|||
<button
|
||||
onClick={executeCopy}
|
||||
disabled={copyTargets.size === 0 || isCopying}
|
||||
style={styles.copyButton}
|
||||
style={buttonStyles.accentButton}
|
||||
>
|
||||
{isCopying ? "Copying..." : `Copy to ${copyTargets.size} day(s)`}
|
||||
</button>
|
||||
<button onClick={cancelCopyMode} style={styles.cancelButton}>
|
||||
<button onClick={cancelCopyMode} style={buttonStyles.secondaryButton}>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{error && !selectedDate && <div style={styles.errorBanner}>{error}</div>}
|
||||
{error && !selectedDate && <div style={bannerStyles.errorBanner}>{error}</div>}
|
||||
|
||||
<div style={styles.calendar}>
|
||||
{dates.map((date) => {
|
||||
|
|
@ -322,11 +328,13 @@ export default function AdminAvailabilityPage() {
|
|||
|
||||
{/* Edit Modal */}
|
||||
{selectedDate && (
|
||||
<div style={styles.modalOverlay} onClick={closeModal}>
|
||||
<div style={styles.modal} onClick={(e) => e.stopPropagation()}>
|
||||
<h2 style={styles.modalTitle}>Edit Availability - {formatDisplayDate(selectedDate)}</h2>
|
||||
<div style={modalStyles.modalOverlay} onClick={closeModal}>
|
||||
<div style={modalStyles.modal} onClick={(e) => e.stopPropagation()}>
|
||||
<h2 style={modalStyles.modalTitle}>
|
||||
Edit Availability - {formatDisplayDate(selectedDate)}
|
||||
</h2>
|
||||
|
||||
{error && <div style={styles.modalError}>{error}</div>}
|
||||
{error && <div style={modalStyles.modalError}>{error}</div>}
|
||||
|
||||
<div style={styles.slotsEditor}>
|
||||
{editSlots.map((slot, index) => (
|
||||
|
|
@ -368,15 +376,19 @@ export default function AdminAvailabilityPage() {
|
|||
</button>
|
||||
</div>
|
||||
|
||||
<div style={styles.modalActions}>
|
||||
<div style={modalStyles.modalActions}>
|
||||
<button onClick={clearAvailability} disabled={isSaving} style={styles.clearButton}>
|
||||
Clear All
|
||||
</button>
|
||||
<div style={styles.modalActionsRight}>
|
||||
<button onClick={closeModal} style={styles.cancelButton}>
|
||||
<div style={modalStyles.modalActionsRight}>
|
||||
<button onClick={closeModal} style={buttonStyles.secondaryButton}>
|
||||
Cancel
|
||||
</button>
|
||||
<button onClick={saveAvailability} disabled={isSaving} style={styles.saveButton}>
|
||||
<button
|
||||
onClick={saveAvailability}
|
||||
disabled={isSaving}
|
||||
style={buttonStyles.accentButton}
|
||||
>
|
||||
{isSaving ? "Saving..." : "Save"}
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -388,12 +400,8 @@ export default function AdminAvailabilityPage() {
|
|||
);
|
||||
}
|
||||
|
||||
const pageStyles: Record<string, React.CSSProperties> = {
|
||||
content: {
|
||||
flex: 1,
|
||||
padding: "2rem",
|
||||
overflowY: "auto",
|
||||
},
|
||||
// Page-specific styles
|
||||
const styles: Record<string, React.CSSProperties> = {
|
||||
pageContainer: {
|
||||
maxWidth: "1200px",
|
||||
margin: "0 auto",
|
||||
|
|
@ -406,19 +414,6 @@ const pageStyles: Record<string, React.CSSProperties> = {
|
|||
flexWrap: "wrap",
|
||||
gap: "1rem",
|
||||
},
|
||||
pageTitle: {
|
||||
fontFamily: "'Instrument Serif', Georgia, serif",
|
||||
fontSize: "2rem",
|
||||
fontWeight: 400,
|
||||
color: "#fff",
|
||||
margin: 0,
|
||||
},
|
||||
pageSubtitle: {
|
||||
fontFamily: "'DM Sans', system-ui, sans-serif",
|
||||
color: "rgba(255, 255, 255, 0.5)",
|
||||
marginTop: "0.5rem",
|
||||
fontSize: "0.95rem",
|
||||
},
|
||||
copyActions: {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
|
|
@ -429,16 +424,6 @@ const pageStyles: Record<string, React.CSSProperties> = {
|
|||
fontSize: "0.85rem",
|
||||
color: "rgba(255, 255, 255, 0.6)",
|
||||
},
|
||||
copyButton: {
|
||||
fontFamily: "'DM Sans', system-ui, sans-serif",
|
||||
fontSize: "0.85rem",
|
||||
padding: "0.5rem 1rem",
|
||||
background: "rgba(99, 102, 241, 0.3)",
|
||||
color: "#fff",
|
||||
border: "1px solid rgba(99, 102, 241, 0.5)",
|
||||
borderRadius: "8px",
|
||||
cursor: "pointer",
|
||||
},
|
||||
calendar: {
|
||||
display: "grid",
|
||||
gridTemplateColumns: "repeat(auto-fill, minmax(180px, 1fr))",
|
||||
|
|
@ -506,44 +491,6 @@ const pageStyles: Record<string, React.CSSProperties> = {
|
|||
borderRadius: "4px",
|
||||
color: "rgba(129, 140, 248, 0.9)",
|
||||
},
|
||||
modalOverlay: {
|
||||
position: "fixed",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
background: "rgba(0, 0, 0, 0.7)",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
zIndex: 1000,
|
||||
},
|
||||
modal: {
|
||||
background: "#1a1a3e",
|
||||
border: "1px solid rgba(255, 255, 255, 0.1)",
|
||||
borderRadius: "16px",
|
||||
padding: "2rem",
|
||||
width: "90%",
|
||||
maxWidth: "400px",
|
||||
boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.5)",
|
||||
},
|
||||
modalTitle: {
|
||||
fontFamily: "'Instrument Serif', Georgia, serif",
|
||||
fontSize: "1.5rem",
|
||||
fontWeight: 400,
|
||||
color: "#fff",
|
||||
margin: "0 0 1.5rem 0",
|
||||
},
|
||||
modalError: {
|
||||
fontFamily: "'DM Sans', system-ui, sans-serif",
|
||||
fontSize: "0.85rem",
|
||||
padding: "0.75rem",
|
||||
background: "rgba(239, 68, 68, 0.15)",
|
||||
border: "1px solid rgba(239, 68, 68, 0.3)",
|
||||
borderRadius: "8px",
|
||||
color: "#f87171",
|
||||
marginBottom: "1rem",
|
||||
},
|
||||
slotsEditor: {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
|
|
@ -593,16 +540,6 @@ const pageStyles: Record<string, React.CSSProperties> = {
|
|||
borderRadius: "6px",
|
||||
cursor: "pointer",
|
||||
},
|
||||
modalActions: {
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
gap: "1rem",
|
||||
},
|
||||
modalActionsRight: {
|
||||
display: "flex",
|
||||
gap: "0.75rem",
|
||||
},
|
||||
clearButton: {
|
||||
fontFamily: "'DM Sans', system-ui, sans-serif",
|
||||
fontSize: "0.85rem",
|
||||
|
|
@ -613,27 +550,4 @@ const pageStyles: Record<string, React.CSSProperties> = {
|
|||
borderRadius: "8px",
|
||||
cursor: "pointer",
|
||||
},
|
||||
cancelButton: {
|
||||
fontFamily: "'DM Sans', system-ui, sans-serif",
|
||||
fontSize: "0.85rem",
|
||||
padding: "0.6rem 1rem",
|
||||
background: "rgba(255, 255, 255, 0.05)",
|
||||
color: "rgba(255, 255, 255, 0.7)",
|
||||
border: "1px solid rgba(255, 255, 255, 0.1)",
|
||||
borderRadius: "8px",
|
||||
cursor: "pointer",
|
||||
},
|
||||
saveButton: {
|
||||
fontFamily: "'DM Sans', system-ui, sans-serif",
|
||||
fontSize: "0.85rem",
|
||||
fontWeight: 500,
|
||||
padding: "0.6rem 1.5rem",
|
||||
background: "rgba(99, 102, 241, 0.3)",
|
||||
color: "#fff",
|
||||
border: "1px solid rgba(99, 102, 241, 0.5)",
|
||||
borderRadius: "8px",
|
||||
cursor: "pointer",
|
||||
},
|
||||
};
|
||||
|
||||
const styles = { ...sharedStyles, ...pageStyles };
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue