diff --git a/docs/WEB-DESIGN-SYSTEM.md b/docs/WEB-DESIGN-SYSTEM.md new file mode 100644 index 000000000..481c49c96 --- /dev/null +++ b/docs/WEB-DESIGN-SYSTEM.md @@ -0,0 +1,926 @@ +# Hammer Editor Web Design System + +This document describes the design system used for Hammer Editor's server-side web interface. The design follows a " +Writer's Desk" aesthetic with a unified component library using BEM naming conventions. + +## Table of Contents + +- [Design Philosophy](#design-philosophy) +- [CSS Architecture](#css-architecture) +- [Design Tokens](#design-tokens) +- [Typography](#typography) +- [Shared Animations](#shared-animations) +- [Layout Components](#layout-components) +- [UI Components](#ui-components) +- [Form Components](#form-components) +- [Utility Classes](#utility-classes) +- [Responsive Design](#responsive-design) +- [Accessibility](#accessibility) + +--- + +## Design Philosophy + +The Hammer web interface uses a **"Writer's Desk"** aesthetic that evokes: + +- **Notebook paper** with lined backgrounds and red margin lines +- **Typewriter typography** for headings and labels +- **Warm, paper-like colors** with amber/gold accents +- **Sticky note aesthetics** for feature cards +- **Subtle shadows and textures** that feel tactile + +The goal is to create an interface that feels familiar and comfortable to writers, while remaining modern and +functional. + +--- + +## CSS Architecture + +### File Structure + +``` +server/src/main/resources/assets/css/ +├── base.css # Design tokens, typography, shared components +├── home.css # Landing/marketing page +├── dashboard.css # User dashboard +├── admin.css # Admin pages +├── login.css # Login page +├── author.css # Public author pages +├── story.css # Story viewing/editing pages +└── error.css # Error pages (404, 500, etc.) +``` + +### Naming Convention + +We use **BEM (Block Element Modifier)** naming: + +```css +.block { +} + +/* Component block */ +.block__element { +} + +/* Child element */ +.block--modifier { +} + +/* Variant/state */ +``` + +Examples: + +- `.card` - Block (the component) +- `.card__title` - Element (part of the card) +- `.card--interactive` - Modifier (makes it clickable) + +--- + +## Design Tokens + +### Color Palette + +```css +/* Primary Colors */ +--primary: #2563eb + +; /* Blue - links, primary actions */ +--primary-dark: #1e40af + +; +--primary-light: #3b82f6 + +; + +/* Accent Colors (Amber/Gold) */ +--accent: #d97706 + +; /* Main accent - borders, highlights */ +--accent-light: #f59e0b + +; +--accent-dark: #b45309 + +; + +/* Neutral Scale (Stone) */ +--neutral-50: #fafaf9 + +; +--neutral-100: #f5f5f4 + +; +--neutral-200: #e7e5e4 + +; +--neutral-300: #d6d3d1 + +; +--neutral-400: #a8a29e + +; +--neutral-500: #78716c + +; +--neutral-600: #57534e + +; +--neutral-700: #44403c + +; +--neutral-800: #292524 + +; +--neutral-900: #1c1917 + +; + +/* Writer's Desk Colors */ +--sticky-yellow: #fef08a + +; /* Yellow sticky notes */ +--sticky-blue: #bfdbfe + +; /* Blue sticky notes */ +--sticky-green: #bbf7d0 + +; /* Green sticky notes */ +--sticky-pink: #fbcfe8 + +; /* Pink sticky notes */ +--paper-white: #fffef9 + +; /* Warm paper color */ +--ink: #1c1917 + +; /* Dark ink color */ + +/* Semantic Colors */ +--success: #10b981 + +; /* Green - success states */ +--warning: #f59e0b + +; /* Amber - warnings */ +--error: #ef4444 + +; /* Red - errors */ +``` + +### Shadows + +```css +--shadow-sm: + +0 +1 +px + +2 +px + +0 +rgba +( +0 +, +0 +, +0 +, +0.05 +) +; +--shadow-md: + +0 +4 +px + +6 +px + +- +1 +px + +rgba +( +0 +, +0 +, +0 +, +0.1 +) +, +0 +2 +px + +4 +px + +- +1 +px + +rgba +( +0 +, +0 +, +0 +, +0.06 +) +; +--shadow-lg: + +0 +10 +px + +15 +px + +- +3 +px + +rgba +( +0 +, +0 +, +0 +, +0.1 +) +, +0 +4 +px + +6 +px + +- +2 +px + +rgba +( +0 +, +0 +, +0 +, +0.05 +) +; +--shadow-xl: + +0 +20 +px + +25 +px + +- +5 +px + +rgba +( +0 +, +0 +, +0 +, +0.1 +) +, +0 +10 +px + +10 +px + +- +5 +px + +rgba +( +0 +, +0 +, +0 +, +0.04 +) +; +--shadow-sticky: + +0 +1 +px + +3 +px + +rgba +( +0 +, +0 +, +0 +, +0.12 +) +, +0 +1 +px + +2 +px + +rgba +( +0 +, +0 +, +0 +, +0.24 +) +; +--shadow-sticky-hover: + +0 +10 +px + +20 +px + +rgba +( +0 +, +0 +, +0 +, +0.15 +) +, +0 +3 +px + +6 +px + +rgba +( +0 +, +0 +, +0 +, +0.10 +) +; +``` + +### Animation Timing + +```css +--transition-fast: + +150 +ms + +cubic-bezier +( +0.4 +, +0 +, +0.2 +, +1 +) +; +--transition-base: + +250 +ms + +cubic-bezier +( +0.4 +, +0 +, +0.2 +, +1 +) +; +--transition-slow: + +350 +ms + +cubic-bezier +( +0.4 +, +0 +, +0.2 +, +1 +) +; +``` + +--- + +## Typography + +### Font Families + +1. **Kingthings Typewriter** - Headings, labels, buttons + - Evokes vintage typewriter aesthetic + - Used for all `h1-h6`, form labels, button text + +2. **Lora** - Body text, paragraphs + - Elegant serif font for readability + - Used for body copy, descriptions, input values + +### Usage + +```css +/* Headings and UI elements */ +font-family: + +'Kingthings Typewriter' +, +monospace + +; + +/* Body text */ +font-family: + +'Lora' +, +Georgia, serif + +; +``` + +### Responsive Font Sizes + +```css +h1 { + font-size: clamp(2.5rem, 5vw, 4.5rem); +} + +h2 { + font-size: clamp(2rem, 4vw, 3.5rem); +} + +h3 { + font-size: clamp(1.5rem, 3vw, 2.25rem); +} +``` + +--- + +## Shared Animations + +These animations are defined in `base.css` and can be used across all pages: + +```css +/* Fade effects */ +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes fadeOut { + from { + opacity: 1; + } + to { + opacity: 0; + } +} + +/* Slide effects */ +@keyframes slideInUp { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slideInDown { + from { + opacity: 0; + transform: translateY(-20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} +``` + +Usage: + +```css +.my-element { + animation: slideInUp 0.5s ease-out; +} +``` + +--- + +## Layout Components + +### Page Container + +The base wrapper for page content. + +```html + +
+
+ +
+
+``` + +**Modifiers:** + +- `.page--centered` - Centers content vertically and horizontally +- `.page__container--narrow` - Max-width 480px (forms, login) +- `.page__container--wide` - Max-width 1200px (admin, dashboards) + +**Page-specific modifiers:** + +- `.page__container--author` - Max-width 900px +- `.page__container--error` - Max-width 600px + +### Page Header + +Dark header bar with title, subtitle, and optional actions. + +```html + + +``` + +### Paper Section + +Notebook-style content sections with lined background and red margin. + +```html + +
+
+

Your Projects

+
+ +
+
+

Manage your writing projects.

+ +
+``` + +**Modifiers:** + +- `.paper-section--compact` - Reduced padding +- `.paper-section--centered` - Center-aligned text + +--- + +## UI Components + +### Cards + +Interactive card components for lists of items. + +```html + +
+ +
+

My Novel

+ Last synced: 2 hours ago +
+ +
+
+``` + +**Modifiers:** + +- `.card--interactive` - Adds hover effects (translateX, border change) +- `.card--gradient` - Gradient background + +### Dialog/Modal + +Modal dialogs with header, body, and actions. + +```html + +
+
+
+

Dialog Title

+ +
+
+ +
+
+ + +
+
+
+``` + +**Modifiers:** + +- `.dialog--warning` - Warning variant with amber tint + +**JavaScript:** +Add `.closing` class to `.dialog-overlay` to trigger fade-out animation. + +### Buttons + +```html + + + + + + + + + + + + + + + + + +``` + +### Pagination + +```html + + +``` + +### Empty State + +For displaying when lists have no content. + +```html + +
+
📝
+

No projects yet. Start writing!

+
+``` + +### Toast Notifications + +```html + +
+
+ + Changes saved successfully + +
+
+``` + +**Variants:** `.toast-success`, `.toast-warning`, `.toast-error`, `.toast-info` + +--- + +## Form Components + +### Form Field + +```html + +
+ + +
+``` + +### Input Types + +```html + + + + + + + + +``` + +### Form Field Label Variants + +```html + + +``` + +--- + +## Utility Classes + +```css +.hidden { + display: none !important; +} +``` + +--- + +## Responsive Design + +The design system includes responsive breakpoints: + +| Breakpoint | Width | Usage | +|------------|----------------|-----------------------| +| Large | > 1024px | Full desktop layout | +| Medium | 769px - 1024px | Tablet/narrow desktop | +| Small | 601px - 768px | Large mobile | +| X-Small | ≤ 600px | Mobile phones | +| XX-Small | ≤ 480px | Small phones | + +### Behavior Changes + +**768px and below:** + +- Page headers stack vertically +- Paper sections reduce padding +- Cards don't transform on hover +- Dialogs use 95% width + +**480px and below:** + +- Smaller font sizes for titles +- Reduced spacing throughout + +--- + +## Accessibility + +### Reduced Motion + +All animations respect `prefers-reduced-motion`: + +```css +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { + animation-duration: 0.01ms !important; + transition-duration: 0.01ms !important; + } +} +``` + +### Focus States + +All interactive elements have visible focus states: + +```css +*:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 3px; +} +``` + +### Color Contrast + +- Text colors meet WCAG AA contrast requirements +- Interactive elements have clear hover/focus states +- Error states use both color and icons for accessibility + +--- + +## Page-Specific Extensions + +While the shared components cover most use cases, some pages have additional specific styles: + +- **home.css** - Marketing page sticky notes, feature grid, download cards +- **dashboard.css** - Pen name section, danger zone, account info +- **admin.css** - Sidebar navigation, whitelist management +- **login.css** - Login header styling, error shake animation, whitelist notices +- **author.css** - Author header with avatar, story count +- **story.css** - Story content formatting, publish toggle, access list +- **error.css** - Colored sticky-note error cards with animations + +--- + +## Example: Complete Page Structure + +```html +{{> header}} + +
+
+ + + + +
+
+

Section Title

+
+ + + + + +
+

No items yet.

+
+
+
+
+ +{{> footer}} +``` diff --git a/server/src/main/resources/assets/css/admin.css b/server/src/main/resources/assets/css/admin.css index 5ba7da0a2..1a038e12d 100644 --- a/server/src/main/resources/assets/css/admin.css +++ b/server/src/main/resources/assets/css/admin.css @@ -1,519 +1,4 @@ -/* Admin Page Styles */ - -.admin-page { - min-height: calc(100vh - 200px); - padding: 2rem; - background: linear-gradient(135deg, var(--neutral-100) 0%, var(--neutral-50) 100%); -} - -.admin-container { - max-width: 1000px; - margin: 0 auto; - animation: fadeIn 0.5s ease-out; -} - -@keyframes fadeIn { - from { - opacity: 0; - } - to { - opacity: 1; - } -} - -/* Admin Header */ -.admin-header { - background: var(--neutral-900); - color: white; - padding: 2.5rem 3rem; - border-radius: 0.75rem; - margin-bottom: 2rem; - display: flex; - justify-content: space-between; - align-items: center; - box-shadow: var(--shadow-lg); - border-bottom: 3px solid var(--accent); - animation: slideInDown 0.5s ease-out; -} - -@keyframes slideInDown { - from { - opacity: 0; - transform: translateY(-20px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -.admin-header-content h1 { - font-family: 'Kingthings Typewriter', monospace; - font-size: 2.5rem; - color: white; - margin-bottom: 0.5rem; -} - -.admin-subtitle { - color: var(--neutral-700); - font-size: 1.0625rem; - font-style: italic; - margin: 0; -} - -.logout-form { - margin: 0; -} - - -/* Section Cards */ -.admin-section { - background: var(--surface); - background-image: repeating-linear-gradient( - transparent, - transparent 31px, - rgba(0, 0, 0, 0.03) 31px, - rgba(0, 0, 0, 0.03) 32px - ); - padding: 2.5rem 3rem 2.5rem 4rem; - margin-bottom: 2rem; - border-radius: 0.75rem; - box-shadow: var(--shadow-lg), - inset 0 0 0 1px rgba(0, 0, 0, 0.05); - border-left: 4px solid var(--accent); - position: relative; - animation: slideInUp 0.5s ease-out; - animation-fill-mode: both; -} - -.admin-section:nth-child(2) { - animation-delay: 0.1s; -} - -.admin-section:nth-child(3) { - animation-delay: 0.2s; -} - -@keyframes slideInUp { - from { - opacity: 0; - transform: translateY(20px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -/* Red margin line like notebook paper */ -.admin-section::before { - content: ''; - position: absolute; - left: 2.5rem; - top: 0; - bottom: 0; - width: 2px; - background: rgba(239, 68, 68, 0.2); - pointer-events: none; -} - -/* Section Headers */ -.section-header { - display: flex; - justify-content: space-between; - align-items: flex-start; - gap: 1rem; - margin-bottom: 1rem; -} - -.section-title-group { - display: flex; - flex-direction: column; - gap: 0.25rem; -} - -.section-header h2 { - font-family: 'Kingthings Typewriter', monospace; - font-size: 2rem; - color: var(--text-primary); - margin: 0; -} - -.section-header-actions { - display: flex; - align-items: center; - gap: 1rem; -} - -.toggle-button { - font-family: 'Kingthings Typewriter', monospace; - font-size: 1rem; - padding: 0.75rem 1.5rem; - background: var(--accent); - color: white; - border: none; - border-radius: 0.5rem; - cursor: pointer; - transition: all var(--transition-base); - box-shadow: var(--shadow-sm); - white-space: nowrap; -} - -.toggle-button:hover { - background: var(--accent-dark); - transform: translateY(-2px); - box-shadow: var(--shadow-md); -} - -.toggle-button.active { - background: rgba(239, 68, 68, 0.9); -} - -.toggle-button.active:hover { - background: #dc2626; -} - -.section-badge { - font-family: 'Kingthings Typewriter', monospace; - font-size: 0.875rem; - padding: 0.375rem 0.875rem; - background: var(--neutral-200); - color: var(--neutral-700); - border-radius: 0.375rem; - font-weight: normal; -} - -.section-badge.accent { - background: var(--accent-light); - color: var(--accent-dark); -} - -.section-description { - color: var(--text-secondary); - font-size: 1rem; - margin-bottom: 1.5rem; - line-height: 1.6; -} - -/* Message Display */ -.message-display { - background: var(--neutral-100); - border: 2px solid var(--neutral-300); - border-radius: 0.5rem; - padding: 1.5rem; - margin-top: 1rem; -} - -.message-display pre { - font-family: 'Courier New', monospace; - font-size: 0.9375rem; - color: var(--text-primary); - white-space: pre-wrap; - line-height: 1.6; - margin: 0; -} - -/* Whitelist Form */ -.whitelist-form { - margin: 1.5rem 0; - padding: 1.5rem; - background: rgba(217, 119, 6, 0.05); - border: 2px solid rgba(217, 119, 6, 0.2); - border-radius: 0.5rem; -} - -.form-group { - display: flex; - flex-direction: column; - gap: 0.75rem; -} - -.form-group label { - font-family: 'Kingthings Typewriter', monospace; - font-size: 1.125rem; - color: var(--text-primary); -} - -.form-input-group { - display: flex; - gap: 0.75rem; -} - -.form-input-group input { - flex: 1; - font-family: 'Lora', Georgia, serif; - font-size: 1rem; - padding: 0.875rem 1rem; - border: 2px solid var(--neutral-300); - border-radius: 0.5rem; - background: white; - color: var(--text-primary); - transition: all var(--transition-base); - box-shadow: var(--shadow-sm); -} - -.form-input-group input::placeholder { - color: var(--neutral-400); - font-style: italic; -} - -.form-input-group input:hover { - border-color: var(--neutral-400); -} - -.form-input-group input:focus { - outline: none; - border-color: var(--accent); - box-shadow: var(--shadow-md), - 0 0 0 3px rgba(217, 119, 6, 0.1); -} - -.add-button, -.save-button { - font-family: 'Kingthings Typewriter', monospace; - font-size: 1rem; - padding: 0.875rem 2rem; - background: var(--accent); - color: white; - border: none; - border-radius: 0.5rem; - cursor: pointer; - transition: all var(--transition-base); - box-shadow: var(--shadow-sm); - white-space: nowrap; -} - -.add-button:hover, -.save-button:hover { - background: var(--accent-dark); - transform: translateY(-2px); - box-shadow: var(--shadow-md); -} - -.add-button:active, -.save-button:active { - transform: translateY(0); -} - -.settings-form { - display: flex; - flex-direction: column; - gap: 1.5rem; -} - -.settings-select { - width: 100%; - font-family: 'Lora', Georgia, serif; - font-size: 1rem; - padding: 0.875rem 1rem; - border: 2px solid var(--neutral-300); - border-radius: 0.5rem; - background: white; - color: var(--text-primary); - transition: all var(--transition-base); - box-shadow: var(--shadow-sm); - cursor: pointer; -} - -.settings-select:focus { - outline: none; - border-color: var(--accent); - box-shadow: var(--shadow-md), - 0 0 0 3px rgba(217, 119, 6, 0.1); -} - -.settings-textarea { - width: 100%; - font-family: 'Lora', Georgia, serif; - font-size: 1rem; - padding: 0.875rem 1rem; - border: 2px solid var(--neutral-300); - border-radius: 0.5rem; - background: white; - color: var(--text-primary); - transition: all var(--transition-base); - box-shadow: var(--shadow-sm); - resize: vertical; - min-height: 100px; -} - -.settings-textarea:focus { - outline: none; - border-color: var(--accent); - box-shadow: var(--shadow-md), - 0 0 0 3px rgba(217, 119, 6, 0.1); -} - -.form-actions { - display: flex; - justify-content: flex-end; -} - -/* Whitelist Container */ -.whitelist-container { - margin-top: 2rem; -} - -/* Whitelist User Items (for HTMX loaded content) */ -#whitelist { - display: flex; - flex-direction: column; - gap: 0.75rem; -} - -.whitelist-user { - display: flex; - justify-content: space-between; - align-items: center; - padding: 1rem 1.25rem; - background: white; - border: 2px solid var(--neutral-200); - border-radius: 0.5rem; - transition: all var(--transition-base); - box-shadow: var(--shadow-sm); -} - -.whitelist-user:hover { - border-color: var(--neutral-300); - box-shadow: var(--shadow-md); - transform: translateX(4px); -} - -.whitelist-user-email { - font-family: 'Lora', Georgia, serif; - font-size: 1rem; - color: var(--text-primary); - font-weight: 500; -} - -.whitelist-user-actions { - display: flex; - gap: 0.5rem; -} - -.remove-button { - font-family: 'Kingthings Typewriter', monospace; - font-size: 0.875rem; - padding: 0.5rem 1rem; - background: transparent; - color: #dc2626; - border: 2px solid #dc2626; - border-radius: 0.375rem; - cursor: pointer; - transition: all var(--transition-base); -} - -.remove-button:hover { - background: #dc2626; - color: white; - transform: translateY(-1px); - box-shadow: var(--shadow-sm); -} - -.remove-button:active { - transform: translateY(0); -} - -/* Empty State */ -.whitelist-empty { - text-align: center; - padding: 3rem 2rem; - color: var(--text-secondary); - font-style: italic; -} - -.whitelist-empty::before { - content: '📝'; - display: block; - font-size: 3rem; - margin-bottom: 1rem; - opacity: 0.5; -} - -/* Responsive Design */ -@media only screen and (max-width: 768px) { - .admin-page { - padding: 1.5rem; - } - - .admin-header { - flex-direction: column; - gap: 1.5rem; - padding: 2rem 1.75rem; - text-align: center; - } - - .admin-header-content h1 { - font-size: 2rem; - } - - .admin-section { - padding: 2rem 1.75rem 2rem 3rem; - } - - .admin-section::before { - left: 1.5rem; - } - - .section-header { - flex-direction: column; - align-items: flex-start; - gap: 0.5rem; - } - - .section-header h2 { - font-size: 1.75rem; - } - - .form-input-group { - flex-direction: column; - } - - .add-button { - width: 100%; - } - - .whitelist-user { - flex-direction: column; - align-items: flex-start; - gap: 1rem; - } - - .whitelist-user-actions { - width: 100%; - } - - .remove-button { - flex: 1; - } -} - -@media only screen and (max-width: 480px) { - .admin-header-content h1 { - font-size: 1.75rem; - } - - .admin-subtitle { - font-size: 0.9375rem; - } - - .section-header h2 { - font-size: 1.5rem; - } -} - -/* Accessibility */ -@media (prefers-reduced-motion: reduce) { - .admin-container, - .admin-header, - .admin-section { - animation: none; - } - - .whitelist-user:hover { - transform: none; - } -} +/* Admin Page Styles - Page-specific overrides */ /* ======================================== Admin Layout with Sidebar @@ -588,32 +73,187 @@ min-width: 0; } -/* Header actions for whitelist page */ -.admin-header-actions { +/* ======================================== + Admin-specific Buttons + ======================================== */ + +.toggle-button { + font-family: 'Kingthings Typewriter', monospace; + font-size: 1rem; + padding: 0.75rem 1.5rem; + background: var(--accent); + color: white; + border: none; + border-radius: 0.5rem; + cursor: pointer; + transition: all var(--transition-base); + box-shadow: var(--shadow-sm); + white-space: nowrap; +} + +.toggle-button:hover { + background: var(--accent-dark); + transform: translateY(-2px); + box-shadow: var(--shadow-md); +} + +.toggle-button.active { + background: rgba(239, 68, 68, 0.9); +} + +.toggle-button.active:hover { + background: #dc2626; +} + +.section-badge { + font-family: 'Kingthings Typewriter', monospace; + font-size: 0.875rem; + padding: 0.375rem 0.875rem; + background: var(--neutral-200); + color: var(--neutral-700); + border-radius: 0.375rem; + font-weight: normal; +} + +.section-badge.accent { + background: var(--accent-light); + color: var(--accent-dark); +} + +/* ======================================== + Form Styling + ======================================== */ + +.logout-form { + margin: 0; +} + +.whitelist-form { + margin: 1.5rem 0; + padding: 1.5rem; + background: rgba(217, 119, 6, 0.05); + border: 2px solid rgba(217, 119, 6, 0.2); + border-radius: 0.5rem; +} + +.form-group { display: flex; + flex-direction: column; + gap: 0.75rem; +} + +.form-input-group { + display: flex; + gap: 0.75rem; +} + +.form-input-group .form-input { + flex: 1; +} + +.add-button, +.save-button { + font-family: 'Kingthings Typewriter', monospace; + font-size: 1rem; + padding: 0.875rem 2rem; + background: var(--accent); + color: white; + border: none; + border-radius: 0.5rem; + cursor: pointer; + transition: all var(--transition-base); + box-shadow: var(--shadow-sm); + white-space: nowrap; +} + +.add-button:hover, +.save-button:hover { + background: var(--accent-dark); + transform: translateY(-2px); + box-shadow: var(--shadow-md); +} + +.add-button:active, +.save-button:active { + transform: translateY(0); +} + +.settings-form { + display: flex; + flex-direction: column; + gap: 1.5rem; +} + +.form-actions { + display: flex; + justify-content: flex-end; +} + +/* ======================================== + Whitelist Items + ======================================== */ + +.whitelist-container { + margin-top: 2rem; +} + +#whitelist { + display: flex; + flex-direction: column; + gap: 0.75rem; +} + +.whitelist-user { + display: flex; + justify-content: space-between; align-items: center; - gap: 1rem; + padding: 1rem 1.25rem; + background: white; + border: 2px solid var(--neutral-200); + border-radius: 0.5rem; + transition: all var(--transition-base); + box-shadow: var(--shadow-sm); } -/* Placeholder styling for User Management */ -.placeholder-content { - text-align: center; - padding: 4rem 2rem; - color: var(--text-tertiary); +.whitelist-user:hover { + border-color: var(--neutral-300); + box-shadow: var(--shadow-md); + transform: translateX(4px); } -.placeholder-icon { - font-size: 4rem; - margin-bottom: 1.5rem; - opacity: 0.3; -} - -.placeholder-content p { +.whitelist-user-email { font-family: 'Lora', Georgia, serif; - font-size: 1.125rem; - font-style: italic; - max-width: 400px; - margin: 0 auto; + font-size: 1rem; + color: var(--text-primary); + font-weight: 500; +} + +.whitelist-user-actions { + display: flex; + gap: 0.5rem; +} + +.remove-button { + font-family: 'Kingthings Typewriter', monospace; + font-size: 0.875rem; + padding: 0.5rem 1rem; + background: transparent; + color: #dc2626; + border: 2px solid #dc2626; + border-radius: 0.375rem; + cursor: pointer; + transition: all var(--transition-base); +} + +.remove-button:hover { + background: #dc2626; + color: white; + transform: translateY(-1px); + box-shadow: var(--shadow-sm); +} + +.remove-button:active { + transform: translateY(0); } /* ======================================== @@ -702,61 +342,10 @@ font-size: 0.75rem; } -.users-empty { - text-align: center; - padding: 3rem 2rem; - color: var(--text-secondary); - font-style: italic; -} +/* ======================================== + Responsive Design + ======================================== */ -.users-empty::before { - content: '\f0c0'; - font-family: 'Font Awesome 6 Free'; - font-weight: 900; - display: block; - font-size: 3rem; - margin-bottom: 1rem; - opacity: 0.3; -} - -/* Pagination Styles */ -.pagination { - display: flex; - justify-content: center; - align-items: center; - gap: 1rem; - margin-top: 2rem; - padding-top: 1.5rem; - border-top: 2px solid var(--neutral-200); -} - -.pagination-button { - font-family: 'Kingthings Typewriter', monospace; - font-size: 0.875rem; - padding: 0.5rem 1rem; - background: var(--neutral-100); - color: var(--text-primary); - border: 2px solid var(--neutral-300); - border-radius: 0.375rem; - cursor: pointer; - transition: all var(--transition-base); -} - -.pagination-button:hover { - background: var(--accent); - color: white; - border-color: var(--accent); - transform: translateY(-1px); - box-shadow: var(--shadow-sm); -} - -.pagination-info { - font-family: 'Lora', Georgia, serif; - font-size: 0.875rem; - color: var(--text-secondary); -} - -/* Responsive: Stack on mobile */ @media only screen and (max-width: 900px) { .admin-layout { flex-direction: column; @@ -801,10 +390,29 @@ .admin-nav-link span { font-size: 0.875rem; } +} - .admin-header-actions { +@media only screen and (max-width: 768px) { + .form-input-group { flex-direction: column; - gap: 0.75rem; + } + + .add-button { + width: 100%; + } + + .whitelist-user { + flex-direction: column; + align-items: flex-start; + gap: 1rem; + } + + .whitelist-user-actions { + width: 100%; + } + + .remove-button { + flex: 1; } .user-item { @@ -821,10 +429,12 @@ flex-direction: column; gap: 0.5rem; } - - .pagination { - flex-direction: column; - gap: 0.75rem; - } } +/* Accessibility */ +@media (prefers-reduced-motion: reduce) { + .whitelist-user:hover, + .user-item:hover { + transform: none; + } +} diff --git a/server/src/main/resources/assets/css/author.css b/server/src/main/resources/assets/css/author.css index 505aa5555..f6cf8499d 100644 --- a/server/src/main/resources/assets/css/author.css +++ b/server/src/main/resources/assets/css/author.css @@ -1,17 +1,9 @@ /* Author Page Styles */ /* A clean, simple literary portfolio */ -.author-page { - min-height: calc(100vh - 200px); - padding: 2rem 1rem; - background: linear-gradient(135deg, var(--neutral-100) 0%, var(--neutral-50) 100%); - display: flex; - justify-content: center; -} - -.author-container { +/* Author-specific container width */ +.page__container--author { max-width: 900px; - width: 100%; } /* ======================================== @@ -26,11 +18,6 @@ animation: fadeIn 0.5s ease-out; } -@keyframes fadeIn { - from { opacity: 0; } - to { opacity: 1; } -} - /* ======================================== Author Header (inside the card) ======================================== */ @@ -85,75 +72,6 @@ font-style: italic; } -/* ======================================== - Stories List - ======================================== */ - -.stories-list { - display: flex; - flex-direction: column; - gap: 0.75rem; -} - -/* ======================================== - Story Card - ======================================== */ - -.story-card { - display: flex; - align-items: center; - text-decoration: none; - background: linear-gradient(135deg, #fdfcfb 0%, #f5f4f0 100%); - border: 1px solid var(--neutral-200); - border-radius: 0.5rem; - box-shadow: var(--shadow-sm); - transition: all 0.2s ease; - padding: 1rem 1.25rem; -} - -.story-card:hover { - background: white; - border-color: var(--accent); - box-shadow: var(--shadow-md); -} - -.story-info { - flex: 1; - min-width: 0; -} - -.story-name { - font-family: 'Kingthings Typewriter', monospace; - font-size: 1.125rem; - color: var(--text-primary); - margin: 0 0 0.25rem; - line-height: 1.3; - transition: color 0.2s ease; -} - -.story-card:hover .story-name { - color: var(--accent-dark); -} - -.story-date { - font-family: 'Lora', Georgia, serif; - font-size: 0.8125rem; - color: var(--text-secondary); - font-style: italic; -} - -.story-arrow { - color: var(--neutral-400); - font-size: 0.875rem; - transition: all 0.2s ease; - margin-left: 1rem; -} - -.story-card:hover .story-arrow { - color: var(--accent); - transform: translateX(3px); -} - /* ======================================== Story Count ======================================== */ @@ -239,10 +157,6 @@ ======================================== */ @media only screen and (max-width: 768px) { - .author-page { - padding: 1.5rem 1rem; - } - .stories-section { padding: 1.5rem; border-radius: 0.5rem; @@ -273,14 +187,6 @@ .author-name { font-size: 1.5rem; } - - .story-card { - padding: 0.875rem 1rem; - } - - .story-name { - font-size: 1rem; - } } /* ======================================== @@ -288,16 +194,7 @@ ======================================== */ @media (prefers-reduced-motion: reduce) { - .stories-section, - .story-card, - .read-link i { + .stories-section { animation: none; - transition: none; } } - -/* Focus styles for keyboard navigation */ -.story-card:focus-visible { - outline: 3px solid var(--accent); - outline-offset: 2px; -} diff --git a/server/src/main/resources/assets/css/base.css b/server/src/main/resources/assets/css/base.css index f96cf7c7f..f61ae774d 100644 --- a/server/src/main/resources/assets/css/base.css +++ b/server/src/main/resources/assets/css/base.css @@ -549,3 +549,672 @@ a:focus-visible { color: var(--text-secondary); font-weight: 500; } + + +/* ======================================== + Shared Component System + BEM naming: .block__element--modifier + ======================================== */ + +/* ---------------------------------------- + Shared Animations + ---------------------------------------- */ + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes fadeOut { + from { + opacity: 1; + } + to { + opacity: 0; + } +} + +@keyframes slideInUp { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slideInDown { + from { + opacity: 0; + transform: translateY(-20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* ---------------------------------------- + Page Layout System + ---------------------------------------- */ + +.page { + min-height: calc(100vh - 200px); + padding: 2rem; + background: linear-gradient(135deg, var(--neutral-100) 0%, var(--neutral-50) 100%); +} + +.page--centered { + display: flex; + align-items: center; + justify-content: center; +} + +.page__container { + max-width: 1000px; + margin: 0 auto; + width: 100%; + animation: fadeIn 0.5s ease-out; +} + +.page__container--narrow { + max-width: 480px; +} + +.page__container--wide { + max-width: 1200px; +} + +/* ---------------------------------------- + Page Header (dark header bar) + ---------------------------------------- */ + +.page-header { + background: var(--neutral-900); + color: white; + padding: 2.5rem 3rem; + border-radius: 0.75rem; + margin-bottom: 2rem; + display: flex; + justify-content: space-between; + align-items: center; + box-shadow: var(--shadow-lg); + border-bottom: 3px solid var(--accent); + animation: slideInDown 0.5s ease-out; +} + +.page-header__content { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.page-header__title { + font-family: 'Kingthings Typewriter', monospace; + font-size: 2.5rem; + color: white; + margin: 0; +} + +.page-header__subtitle { + color: var(--neutral-400); + font-size: 1.0625rem; + font-style: italic; + margin: 0; +} + +.page-header__actions { + display: flex; + align-items: center; + gap: 1rem; +} + +/* ---------------------------------------- + Paper Section (notebook aesthetic) + ---------------------------------------- */ + +.paper-section { + background: var(--surface); + background-image: repeating-linear-gradient( + transparent, + transparent 31px, + rgba(0, 0, 0, 0.03) 31px, + rgba(0, 0, 0, 0.03) 32px + ); + padding: 2.5rem 3rem 2.5rem 4rem; + margin-bottom: 2rem; + border-radius: 0.75rem; + box-shadow: var(--shadow-lg), + inset 0 0 0 1px rgba(0, 0, 0, 0.05); + border-left: 4px solid var(--accent); + position: relative; + animation: slideInUp 0.5s ease-out; + animation-fill-mode: both; +} + +/* Red margin line like notebook paper */ +.paper-section::before { + content: ''; + position: absolute; + left: 2.5rem; + top: 0; + bottom: 0; + width: 2px; + background: rgba(239, 68, 68, 0.2); + pointer-events: none; +} + +.paper-section--compact { + padding: 3rem 2.5rem 3rem 4rem; + box-shadow: var(--shadow-xl), + inset 0 0 0 1px rgba(0, 0, 0, 0.05); +} + +.paper-section--centered { + text-align: center; +} + +/* Section Header */ +.section-header { + display: flex; + justify-content: space-between; + align-items: flex-start; + gap: 1rem; + margin-bottom: 1rem; +} + +.section-header__title { + font-family: 'Kingthings Typewriter', monospace; + font-size: 2rem; + color: var(--text-primary); + margin: 0; +} + +.section-header__actions { + display: flex; + align-items: center; + gap: 1rem; +} + +.section-description { + color: var(--text-secondary); + font-size: 1rem; + margin-bottom: 1.5rem; + line-height: 1.6; +} + +/* ---------------------------------------- + Card System + ---------------------------------------- */ + +.card { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1.25rem 1.5rem; + background: white; + border: 2px solid var(--neutral-200); + border-radius: 0.5rem; + transition: all var(--transition-base); + box-shadow: var(--shadow-sm); + text-decoration: none; + color: inherit; +} + +.card--interactive { + cursor: pointer; +} + +.card--interactive:hover { + border-color: var(--accent); + box-shadow: var(--shadow-md); + transform: translateX(4px); +} + +.card--gradient { + background: linear-gradient(135deg, #fdfcfb 0%, #f5f4f0 100%); + border: 1px solid var(--neutral-200); +} + +.card--gradient:hover { + background: white; + border-color: var(--accent); +} + +.card-list { + display: flex; + flex-direction: column; + gap: 0.75rem; +} + +.card__info { + display: flex; + flex-direction: column; + gap: 0.375rem; + flex: 1; + min-width: 0; +} + +.card__title { + font-family: 'Kingthings Typewriter', monospace; + font-size: 1.25rem; + color: var(--text-primary); + font-weight: normal; + margin: 0; + transition: color 0.2s ease; +} + +.card--interactive:hover .card__title { + color: var(--accent-dark); +} + +.card__subtitle { + font-family: 'Lora', Georgia, serif; + font-size: 0.875rem; + color: var(--text-secondary); + display: flex; + align-items: center; + gap: 0.5rem; +} + +.card__arrow { + color: var(--neutral-400); + font-size: 0.875rem; + transition: all 0.2s ease; + margin-left: 1rem; +} + +.card--interactive:hover .card__arrow { + color: var(--accent); + transform: translateX(3px); +} + +/* ---------------------------------------- + Dialog/Modal System + ---------------------------------------- */ + +.dialog-overlay { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; + animation: fadeIn 0.2s ease-out; + backdrop-filter: blur(2px); +} + +.dialog-overlay.closing { + animation: fadeOut 0.2s ease-out forwards; +} + +.dialog { + background: linear-gradient(135deg, rgba(255, 253, 250, 0.98) 0%, rgba(255, 250, 245, 1) 100%); + border: 2px solid var(--neutral-200); + border-radius: 0.75rem; + box-shadow: var(--shadow-xl), + 0 0 0 1px rgba(0, 0, 0, 0.05); + max-width: 420px; + width: 90%; + animation: slideInUp 0.3s ease-out; +} + +.dialog--warning { + background: linear-gradient(135deg, rgba(255, 253, 250, 0.99) 0%, rgba(255, 251, 235, 1) 100%); + border-color: var(--neutral-300); + max-width: 480px; +} + +.dialog__header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 1.25rem 1.5rem; + border-bottom: 1px dashed var(--neutral-200); +} + +.dialog__header h3 { + font-family: 'Kingthings Typewriter', monospace; + font-size: 1.25rem; + color: var(--text-primary); + margin: 0; +} + +.dialog__close { + display: flex; + align-items: center; + justify-content: center; + width: 2rem; + height: 2rem; + background: transparent; + border: none; + border-radius: 50%; + color: var(--text-secondary); + cursor: pointer; + transition: all var(--transition-base); +} + +.dialog__close:hover { + background: var(--neutral-100); + color: var(--text-primary); +} + +.dialog__body { + padding: 1.5rem; +} + +.dialog__actions { + display: flex; + gap: 0.75rem; + justify-content: flex-end; + padding: 1rem 1.5rem; + background: rgba(255, 255, 255, 0.5); + border-top: 1px dashed var(--neutral-200); +} + +/* ---------------------------------------- + Button Variants + ---------------------------------------- */ + +.btn--primary { + background: var(--neutral-900); + color: white; + border-color: var(--neutral-900); +} + +.btn--primary:hover { + background: var(--accent); + border-color: var(--accent); + color: white; +} + +.btn--accent { + background: var(--accent); + color: white; + border-color: var(--accent); +} + +.btn--accent:hover { + background: var(--accent-dark); + border-color: var(--accent-dark); + color: white; +} + +.btn--danger { + background: transparent; + color: #dc2626; + border-color: #dc2626; +} + +.btn--danger:hover { + background: #dc2626; + color: white; +} + +.btn--ghost { + background: transparent; + color: var(--text-secondary); + border-color: var(--neutral-300); +} + +.btn--ghost:hover { + background: var(--neutral-100); + border-color: var(--neutral-400); + color: var(--text-primary); +} + +.btn--block { + width: 100%; + justify-content: center; +} + +/* ---------------------------------------- + Form System + ---------------------------------------- */ + +.form-field { + display: flex; + flex-direction: column; + gap: 0.5rem; + margin-bottom: 1.25rem; +} + +.form-field:last-child { + margin-bottom: 0; +} + +.form-field__label { + font-family: 'Kingthings Typewriter', monospace; + font-size: 1.125rem; + color: var(--text-primary); + letter-spacing: 0.01em; +} + +.form-field__label--small { + font-size: 0.875rem; + color: var(--text-secondary); +} + +.form-input { + font-family: 'Lora', Georgia, serif; + font-size: 1rem; + padding: 0.875rem 1rem; + border: 2px solid var(--neutral-300); + border-radius: 0.5rem; + background: white; + color: var(--text-primary); + transition: all var(--transition-base); + box-shadow: var(--shadow-sm); +} + +.form-input::placeholder { + color: var(--neutral-400); + font-style: italic; +} + +.form-input:hover { + border-color: var(--neutral-400); +} + +.form-input:focus { + outline: none; + border-color: var(--accent); + box-shadow: var(--shadow-md), + 0 0 0 3px rgba(217, 119, 6, 0.1); +} + +.form-select { + font-family: 'Lora', Georgia, serif; + font-size: 1rem; + padding: 0.875rem 1rem; + border: 2px solid var(--neutral-300); + border-radius: 0.5rem; + background: white; + color: var(--text-primary); + transition: all var(--transition-base); + box-shadow: var(--shadow-sm); + cursor: pointer; +} + +.form-select:hover { + border-color: var(--neutral-400); +} + +.form-select:focus { + outline: none; + border-color: var(--accent); + box-shadow: var(--shadow-md), + 0 0 0 3px rgba(217, 119, 6, 0.1); +} + +.form-textarea { + font-family: 'Lora', Georgia, serif; + font-size: 1rem; + padding: 0.875rem 1rem; + border: 2px solid var(--neutral-300); + border-radius: 0.5rem; + background: white; + color: var(--text-primary); + transition: all var(--transition-base); + box-shadow: var(--shadow-sm); + resize: vertical; + min-height: 100px; +} + +.form-textarea:hover { + border-color: var(--neutral-400); +} + +.form-textarea:focus { + outline: none; + border-color: var(--accent); + box-shadow: var(--shadow-md), + 0 0 0 3px rgba(217, 119, 6, 0.1); +} + +/* ---------------------------------------- + Utility Components + ---------------------------------------- */ + +.empty-state { + text-align: center; + padding: 3rem 2rem; + color: var(--text-secondary); + font-style: italic; +} + +.empty-state__icon { + font-size: 3rem; + margin-bottom: 1rem; + opacity: 0.5; +} + +.info-panel { + background: linear-gradient(135deg, rgba(255, 253, 250, 0.95) 0%, rgba(255, 250, 245, 0.98) 100%); + border: 2px solid var(--neutral-200); + border-radius: 0.5rem; + overflow: hidden; + box-shadow: var(--shadow-sm); + margin-bottom: 1rem; +} + +.info-panel__header { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 0.875rem 1.25rem; + background: rgba(255, 255, 255, 0.6); + border-bottom: 1px dashed var(--neutral-200); +} + +.info-panel__content { + padding: 1rem 1.25rem; +} + +.info-panel--collapsible .info-panel__header { + cursor: pointer; + transition: all var(--transition-base); +} + +.info-panel--collapsible .info-panel__header:hover { + background: rgba(217, 119, 6, 0.05); +} + +/* Hidden utility class */ +.hidden { + display: none !important; +} + +/* ---------------------------------------- + Responsive Design for Shared Components + ---------------------------------------- */ + +@media only screen and (max-width: 768px) { + .page { + padding: 1.5rem; + } + + .page-header { + flex-direction: column; + gap: 1.5rem; + padding: 2rem 1.75rem; + text-align: center; + } + + .page-header__title { + font-size: 2rem; + } + + .page-header__actions { + flex-direction: column; + gap: 0.75rem; + width: 100%; + } + + .paper-section { + padding: 2rem 1.75rem 2rem 3rem; + } + + .paper-section::before { + left: 1.5rem; + } + + .paper-section--compact { + padding: 2rem 1.75rem 2rem 3rem; + } + + .paper-section--compact::before { + left: 1.5rem; + } + + .section-header { + flex-direction: column; + align-items: flex-start; + gap: 0.5rem; + } + + .section-header__title { + font-size: 1.75rem; + } + + .card--interactive:hover { + transform: none; + } + + .dialog { + width: 95%; + margin: 1rem; + } +} + +@media only screen and (max-width: 600px) { + .page--centered { + padding: 1.5rem; + min-height: calc(100vh - 150px); + } + + .paper-section--compact { + padding: 2rem 1.75rem 2rem 3rem; + } +} + +@media only screen and (max-width: 480px) { + .page-header__title { + font-size: 1.75rem; + } + + .page-header__subtitle { + font-size: 0.9375rem; + } + + .section-header__title { + font-size: 1.5rem; + } +} diff --git a/server/src/main/resources/assets/css/dashboard.css b/server/src/main/resources/assets/css/dashboard.css index 88fb280c8..b650729cc 100644 --- a/server/src/main/resources/assets/css/dashboard.css +++ b/server/src/main/resources/assets/css/dashboard.css @@ -1,66 +1,6 @@ -/* Dashboard Page Styles */ - -.dashboard-page { - min-height: calc(100vh - 200px); - padding: 2rem; - background: linear-gradient(135deg, var(--neutral-100) 0%, var(--neutral-50) 100%); -} - -.dashboard-container { - max-width: 1000px; - margin: 0 auto; - animation: fadeIn 0.5s ease-out; -} - -@keyframes fadeIn { - from { - opacity: 0; - } - to { - opacity: 1; - } -} - -/* Dashboard Header */ -.dashboard-header { - background: var(--neutral-900); - color: white; - padding: 2.5rem 3rem; - border-radius: 0.75rem; - margin-bottom: 2rem; - display: flex; - justify-content: space-between; - align-items: center; - box-shadow: var(--shadow-lg); - border-bottom: 3px solid var(--accent); - animation: slideInDown 0.5s ease-out; -} - -@keyframes slideInDown { - from { - opacity: 0; - transform: translateY(-20px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -.dashboard-header-content h1 { - font-family: 'Kingthings Typewriter', monospace; - font-size: 2.5rem; - color: white; - margin-bottom: 0.5rem; -} - -.dashboard-subtitle { - color: var(--neutral-700); - font-size: 1.0625rem; - font-style: italic; - margin: 0; -} +/* Dashboard Page Styles - Page-specific overrides */ +/* Dashboard-specific header buttons */ .logout-form { margin: 0; } @@ -89,85 +29,6 @@ transform: translateY(0); } -/* Section Cards */ -.dashboard-section { - background: var(--surface); - background-image: repeating-linear-gradient( - transparent, - transparent 31px, - rgba(0, 0, 0, 0.03) 31px, - rgba(0, 0, 0, 0.03) 32px - ); - padding: 2.5rem 3rem 2.5rem 4rem; - margin-bottom: 2rem; - border-radius: 0.75rem; - box-shadow: var(--shadow-lg), - inset 0 0 0 1px rgba(0, 0, 0, 0.05); - border-left: 4px solid var(--accent); - position: relative; - animation: slideInUp 0.5s ease-out; - animation-fill-mode: both; -} - -@keyframes slideInUp { - from { - opacity: 0; - transform: translateY(20px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -/* Red margin line like notebook paper */ -.dashboard-section::before { - content: ''; - position: absolute; - left: 2.5rem; - top: 0; - bottom: 0; - width: 2px; - background: rgba(239, 68, 68, 0.2); - pointer-events: none; -} - -/* Section Headers */ -.section-header { - display: flex; - justify-content: space-between; - align-items: flex-start; - gap: 1rem; - margin-bottom: 1rem; -} - -.section-title-group { - display: flex; - flex-direction: column; - gap: 0.25rem; -} - -.section-header h2 { - font-family: 'Kingthings Typewriter', monospace; - font-size: 2rem; - color: var(--text-primary); - margin: 0; -} - -.section-description { - color: var(--text-secondary); - font-size: 1rem; - margin-bottom: 1.5rem; - line-height: 1.6; -} - -/* Dashboard Header Actions */ -.dashboard-header-actions { - display: flex; - align-items: center; - gap: 1rem; -} - .manage-server-button { font-family: 'Kingthings Typewriter', monospace; font-size: 1rem; @@ -189,14 +50,6 @@ box-shadow: var(--shadow-md); } -.account-info p { - margin-bottom: 0.5rem; -} - -.hidden { - display: none !important; -} - /* ======================================== Pen Name Section - Author Identity Claim ======================================== */ @@ -760,81 +613,11 @@ box-shadow: none; } -/* Projects List */ +/* Projects and Account containers */ .projects-container { margin-top: 1.5rem; } -.projects-list { - display: flex; - flex-direction: column; - gap: 0.75rem; -} - -.project-card { - display: flex; - justify-content: space-between; - align-items: center; - padding: 1.25rem 1.5rem; - background: white; - border: 2px solid var(--neutral-200); - border-radius: 0.5rem; - transition: all var(--transition-base); - box-shadow: var(--shadow-sm); - text-decoration: none; - color: inherit; - cursor: pointer; -} - -.project-card:hover { - border-color: var(--accent); - box-shadow: var(--shadow-md); - transform: translateX(4px); -} - -.project-info { - display: flex; - flex-direction: column; - gap: 0.375rem; -} - -.project-name { - font-family: 'Kingthings Typewriter', monospace; - font-size: 1.25rem; - color: var(--text-primary); - font-weight: normal; -} - -.project-sync-date { - font-family: 'Lora', Georgia, serif; - font-size: 0.875rem; - color: var(--text-secondary); - display: flex; - align-items: center; - gap: 0.5rem; -} - -.project-arrow { - color: var(--neutral-400); - font-size: 0.875rem; - transition: all 0.2s ease; - margin-left: 1rem; -} - -.project-card:hover .project-arrow { - color: var(--accent); - transform: translateX(3px); -} - -/* Projects Empty State */ -.projects-empty { - text-align: center; - padding: 3rem 2rem; - color: var(--text-secondary); - font-style: italic; -} - -/* Account Info */ .account-container { margin-top: 1.5rem; } @@ -862,56 +645,11 @@ /* Responsive Design */ @media only screen and (max-width: 768px) { - .dashboard-page { - padding: 1.5rem; - } - - .dashboard-header { - flex-direction: column; - gap: 1.5rem; - padding: 2rem 1.75rem; - text-align: center; - } - - .dashboard-header-content h1 { - font-size: 2rem; - } - - .dashboard-header-actions { - flex-direction: column; - gap: 0.75rem; - width: 100%; - } - .manage-server-button { width: 100%; text-align: center; } - .dashboard-section { - padding: 2rem 1.75rem 2rem 3rem; - } - - .dashboard-section::before { - left: 1.5rem; - } - - .section-header { - flex-direction: column; - align-items: flex-start; - gap: 0.5rem; - } - - .section-header h2 { - font-size: 1.75rem; - } - - .project-card { - flex-direction: column; - align-items: flex-start; - gap: 0.75rem; - } - /* Pen Name Responsive */ .pen-name-section { padding: 1rem; @@ -975,30 +713,12 @@ } } -@media only screen and (max-width: 480px) { - .dashboard-header-content h1 { - font-size: 1.75rem; - } - - .dashboard-subtitle { - font-size: 0.9375rem; - } - - .section-header h2 { - font-size: 1.5rem; - } -} - /* Accessibility */ @media (prefers-reduced-motion: reduce) { - .dashboard-container, - .dashboard-header, - .dashboard-section, .pen-name-edit { animation: none; } - .project-card:hover, .claim-pen-name-btn:hover, .set-pen-name-btn:hover:not(:disabled) { transform: none; diff --git a/server/src/main/resources/assets/css/error.css b/server/src/main/resources/assets/css/error.css index 6b5add6a0..1cccbb18d 100644 --- a/server/src/main/resources/assets/css/error.css +++ b/server/src/main/resources/assets/css/error.css @@ -1,16 +1,7 @@ /* Error Page Styles */ -.error-page { - min-height: calc(100vh - 200px); - display: flex; - align-items: center; - justify-content: center; - padding: 2rem; - background: linear-gradient(135deg, var(--neutral-100) 0%, var(--neutral-50) 100%); -} - -.error-container { - width: 100%; +/* Error-specific container width */ +.page__container--error { max-width: 600px; } @@ -181,10 +172,6 @@ /* Responsive Design */ @media only screen and (max-width: 600px) { - .error-page { - padding: 1.5rem; - } - .error-card { padding: 2.5rem 2rem; transform: rotate(0deg); @@ -234,15 +221,6 @@ animation: fadeIn 0.3s ease-out; } - @keyframes fadeIn { - from { - opacity: 0; - } - to { - opacity: 1; - } - } - .error-card::before { animation: none; } diff --git a/server/src/main/resources/assets/css/home.css b/server/src/main/resources/assets/css/home.css index a975e8cea..13475a7ff 100644 --- a/server/src/main/resources/assets/css/home.css +++ b/server/src/main/resources/assets/css/home.css @@ -118,17 +118,6 @@ animation: slideInDown 0.4s ease-out; } -@keyframes slideInDown { - from { - opacity: 0; - transform: translateY(-20px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - .server-message h3 { color: #92400e; margin-bottom: 0.75rem; diff --git a/server/src/main/resources/assets/css/login.css b/server/src/main/resources/assets/css/login.css index aa35d8eab..d0613be6d 100644 --- a/server/src/main/resources/assets/css/login.css +++ b/server/src/main/resources/assets/css/login.css @@ -1,59 +1,6 @@ -/* Login Page Styles */ - -.login-page { - min-height: calc(100vh - 200px); - display: flex; - align-items: center; - justify-content: center; - padding: 2rem; - background: linear-gradient(135deg, var(--neutral-100) 0%, var(--neutral-50) 100%); -} - -.login-container { - width: 100%; - max-width: 480px; -} - -.login-card { - background: var(--surface); - background-image: repeating-linear-gradient( - transparent, - transparent 31px, - rgba(0, 0, 0, 0.03) 31px, - rgba(0, 0, 0, 0.03) 32px - ); - padding: 3rem 2.5rem 3rem 4rem; - border-radius: 0.75rem; - box-shadow: var(--shadow-xl), - inset 0 0 0 1px rgba(0, 0, 0, 0.05); - border-left: 4px solid var(--accent); - position: relative; - animation: slideInUp 0.5s ease-out; -} - -@keyframes slideInUp { - from { - opacity: 0; - transform: translateY(30px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -/* Red margin line like notebook paper */ -.login-card::before { - content: ''; - position: absolute; - left: 2.5rem; - top: 0; - bottom: 0; - width: 2px; - background: rgba(239, 68, 68, 0.2); - pointer-events: none; -} +/* Login Page Styles - Page-specific overrides */ +/* Login Header (centered within card) */ .login-header { text-align: center; margin-bottom: 2.5rem; @@ -73,58 +20,13 @@ margin: 0; } -/* Form Styles */ +/* Form Layout */ .login-form { display: flex; flex-direction: column; gap: 1.75rem; } -.form-field { - display: flex; - flex-direction: column; - gap: 0.5rem; -} - -.form-field label { - font-family: 'Kingthings Typewriter', monospace; - font-size: 1.125rem; - color: var(--text-primary); - letter-spacing: 0.01em; -} - -.form-field input { - font-family: 'Lora', Georgia, serif; - font-size: 1rem; - padding: 0.875rem 1rem; - border: 2px solid var(--neutral-300); - border-radius: 0.5rem; - background: white; - color: var(--text-primary); - transition: all var(--transition-base); - box-shadow: var(--shadow-sm); -} - -.form-field input::placeholder { - color: var(--neutral-400); - font-style: italic; -} - -.form-field input:hover { - border-color: var(--neutral-400); -} - -.form-field input:focus { - outline: none; - border-color: var(--accent); - box-shadow: var(--shadow-md), - 0 0 0 3px rgba(217, 119, 6, 0.1); -} - -.form-field input:focus::placeholder { - color: var(--neutral-500); -} - /* Error/Message Styling */ .login-message { background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%); @@ -153,7 +55,7 @@ font-size: 0.9375rem; } -/* Button Styles */ +/* Login Button (special styling with shimmer effect) */ .form-actions { margin-top: 1rem; } @@ -205,40 +107,6 @@ outline-offset: 4px; } -/* Responsive Design */ -@media only screen and (max-width: 600px) { - .login-page { - padding: 1.5rem; - min-height: calc(100vh - 150px); - } - - .login-card { - padding: 2rem 1.75rem 2rem 3rem; - } - - .login-card::before { - left: 1.5rem; - } - - .login-header h1 { - font-size: 2rem; - } - - .login-header p { - font-size: 0.9375rem; - } - - .form-field input { - font-size: 1rem; - padding: 0.75rem 0.875rem; - } - - .login-button { - font-size: 1rem; - padding: 0.875rem 1.75rem; - } -} - /* Login Info Section */ .login-info { margin-top: 2rem; @@ -283,12 +151,24 @@ color: #78350f; } -/* Accessibility */ -@media (prefers-reduced-motion: reduce) { - .login-card { - animation: none; +/* Responsive Design */ +@media only screen and (max-width: 600px) { + .login-header h1 { + font-size: 2rem; } + .login-header p { + font-size: 0.9375rem; + } + + .login-button { + font-size: 1rem; + padding: 0.875rem 1.75rem; + } +} + +/* Accessibility */ +@media (prefers-reduced-motion: reduce) { .login-message { animation: none; } diff --git a/server/src/main/resources/assets/css/story.css b/server/src/main/resources/assets/css/story.css index 3b41c8db5..efd3a9d62 100644 --- a/server/src/main/resources/assets/css/story.css +++ b/server/src/main/resources/assets/css/story.css @@ -167,15 +167,6 @@ } } -@keyframes fadeIn { - from { - opacity: 0; - } - to { - opacity: 1; - } -} - /* ======================================== Story Info Panel Displays story metadata at a glance @@ -703,175 +694,112 @@ } /* ======================================== - Share Dialog (Modal) + Dialog Customizations for Story Page + Additional styling for story-specific dialogs ======================================== */ -.share-dialog-overlay { - position: fixed; - inset: 0; - background: rgba(0, 0, 0, 0.5); - display: flex; - align-items: center; - justify-content: center; - z-index: 1000; - animation: fadeIn 0.2s ease-out; - backdrop-filter: blur(2px); -} - -.share-dialog-overlay.closing { - animation: fadeOut 0.2s ease-out forwards; -} - -@keyframes fadeOut { - from { opacity: 1; } - to { opacity: 0; } -} - -.share-dialog { - background: linear-gradient(135deg, rgba(255, 253, 250, 0.98) 0%, rgba(255, 250, 245, 1) 100%); - border: 2px solid var(--neutral-200); - border-radius: 0.75rem; - box-shadow: var(--shadow-xl), 0 0 0 1px rgba(0, 0, 0, 0.05); - max-width: 420px; - width: 90%; - animation: slideInUp 0.3s ease-out; -} - -@keyframes slideInUp { - from { - opacity: 0; - transform: translateY(20px) scale(0.95); - } - to { - opacity: 1; - transform: translateY(0) scale(1); - } -} - -.share-dialog-header { - display: flex; - align-items: center; - justify-content: space-between; - padding: 1.25rem 1.5rem; - border-bottom: 1px dashed var(--neutral-200); -} - -.share-dialog-header h3 { - font-family: 'Kingthings Typewriter', monospace; - font-size: 1.25rem; - color: var(--text-primary); - margin: 0; -} - -.dialog-close-btn { - display: flex; - align-items: center; - justify-content: center; - width: 2rem; - height: 2rem; - background: transparent; - border: none; - border-radius: 50%; - color: var(--text-secondary); - cursor: pointer; - transition: all var(--transition-base); -} - -.dialog-close-btn:hover { - background: var(--neutral-100); - color: var(--text-primary); -} - -.share-dialog-body { - padding: 1.5rem; -} - -.share-dialog .form-field { - margin-bottom: 1.25rem; -} - -.share-dialog .form-field:last-child { - margin-bottom: 0; -} - -.share-dialog .form-field label { - display: block; - font-family: 'Kingthings Typewriter', monospace; - font-size: 0.875rem; - color: var(--text-secondary); - margin-bottom: 0.5rem; -} - -.share-dialog .form-field .optional-label { +/* Optional label styling */ +.optional-label { font-style: italic; color: var(--neutral-400); } -.share-dialog .form-field input { - width: 100%; - padding: 0.75rem 1rem; - font-family: 'Lora', Georgia, serif; - font-size: 1rem; - color: var(--text-primary); - background: white; - border: 2px solid var(--neutral-200); - border-radius: 0.375rem; - box-sizing: border-box; - transition: border-color var(--transition-base); +/* Warning dialog header with icon */ +.dialog__header--warning { + background: linear-gradient(135deg, rgba(251, 191, 36, 0.08) 0%, rgba(245, 158, 11, 0.05) 100%); + border-bottom: 1px dashed rgba(217, 119, 6, 0.25); + position: relative; } -.share-dialog .form-field input:focus { - outline: none; - border-color: var(--accent); +.dialog__header--warning::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 3px; + background: linear-gradient(90deg, + transparent 0%, + rgba(245, 158, 11, 0.6) 20%, + rgba(217, 119, 6, 0.8) 50%, + rgba(245, 158, 11, 0.6) 80%, + transparent 100% + ); } -.share-dialog .form-field input::placeholder { - color: var(--neutral-400); -} - -.share-dialog-actions { +.warning-icon-wrapper { display: flex; - gap: 0.75rem; - justify-content: flex-end; - padding: 1rem 1.5rem; - background: rgba(255, 255, 255, 0.5); - border-top: 1px dashed var(--neutral-200); + align-items: center; + justify-content: center; + width: 2.5rem; + height: 2.5rem; + background: linear-gradient(135deg, rgba(251, 191, 36, 0.2) 0%, rgba(245, 158, 11, 0.15) 100%); + border: 1.5px solid rgba(217, 119, 6, 0.3); + border-radius: 50%; + flex-shrink: 0; + animation: warningPulse 2s ease-in-out infinite; } -.share-dialog .cancel-btn { - padding: 0.625rem 1.25rem; - background: transparent; - color: var(--text-secondary); - border: 2px solid var(--neutral-300); - border-radius: 0.375rem; - font-family: 'Kingthings Typewriter', monospace; +@keyframes warningPulse { + 0%, 100% { + box-shadow: 0 0 0 0 rgba(245, 158, 11, 0.3); + } + 50% { + box-shadow: 0 0 0 6px rgba(245, 158, 11, 0); + } +} + +.warning-icon-wrapper i { + font-size: 1.125rem; + color: #b45309; +} + +/* Warning Body Content */ +.warning-text { + font-family: 'Lora', Georgia, serif; font-size: 0.9375rem; - cursor: pointer; - transition: all var(--transition-base); -} - -.share-dialog .cancel-btn:hover { - background: var(--neutral-100); - border-color: var(--neutral-400); + line-height: 1.7; color: var(--text-primary); + margin: 0 0 1.25rem 0; + text-align: justify; + hyphens: auto; } -.share-dialog .create-access-btn { - padding: 0.625rem 1.25rem; - background: linear-gradient(135deg, var(--accent) 0%, var(--accent-dark) 100%); - color: white; - border: 2px solid var(--accent-dark); - border-radius: 0.375rem; +/* Recommendation Callout */ +.warning-recommendation { + display: flex; + align-items: flex-start; + gap: 0.75rem; + padding: 1rem 1.125rem; + background: linear-gradient(135deg, rgba(16, 185, 129, 0.06) 0%, rgba(5, 150, 105, 0.04) 100%); + border: 1.5px solid rgba(16, 185, 129, 0.2); + border-radius: 0.5rem; + border-left: 3px solid var(--success); +} + +.warning-recommendation i { + font-size: 1rem; + color: var(--success); + margin-top: 0.125rem; + flex-shrink: 0; +} + +.warning-recommendation span { font-family: 'Kingthings Typewriter', monospace; - font-size: 0.9375rem; - font-weight: 500; - cursor: pointer; - transition: all var(--transition-base); + font-size: 0.8125rem; + line-height: 1.5; + color: var(--text-secondary); } -.share-dialog .create-access-btn:hover { - background: linear-gradient(135deg, var(--accent-light) 0%, var(--accent) 100%); - transform: translateY(-1px); +/* Publish confirm button with icon */ +.publish-confirm-btn { + display: inline-flex; + align-items: center; + gap: 0.5rem; +} + +.publish-confirm-btn i { + font-size: 0.875rem; } /* ======================================== @@ -1100,36 +1028,6 @@ text-align: left; } -.password-form .form-field { - margin-bottom: 1rem; -} - -.password-form .form-field label { - display: block; - font-family: 'Kingthings Typewriter', monospace; - font-size: 0.875rem; - color: var(--text-secondary); - margin-bottom: 0.5rem; -} - -.password-form .form-field input { - width: 100%; - padding: 0.875rem 1rem; - font-family: 'Lora', Georgia, serif; - font-size: 1rem; - color: var(--text-primary); - background: white; - border: 2px solid var(--neutral-200); - border-radius: 0.375rem; - box-sizing: border-box; - transition: border-color var(--transition-base); -} - -.password-form .form-field input:focus { - outline: none; - border-color: var(--accent); -} - .password-error { display: flex; align-items: center; @@ -1166,233 +1064,6 @@ transform: translateY(0); } -/* ======================================== - Publish Warning Dialog - A thoughtful caution before public publishing - ======================================== */ - -.publish-warning-overlay { - position: fixed; - inset: 0; - background: rgba(41, 37, 36, 0.6); - display: flex; - align-items: center; - justify-content: center; - z-index: 1000; - animation: fadeIn 0.2s ease-out; - backdrop-filter: blur(3px); -} - -.publish-warning-overlay.closing { - animation: fadeOut 0.2s ease-out forwards; -} - -.publish-warning-dialog { - background: linear-gradient(135deg, rgba(255, 253, 250, 0.99) 0%, rgba(255, 251, 235, 1) 100%); - border: 2px solid var(--neutral-300); - border-radius: 0.75rem; - box-shadow: - var(--shadow-xl), - 0 0 0 1px rgba(217, 119, 6, 0.1), - 0 0 40px rgba(217, 119, 6, 0.08); - max-width: 480px; - width: 90%; - animation: warningSlideIn 0.35s cubic-bezier(0.34, 1.56, 0.64, 1); - overflow: hidden; -} - -@keyframes warningSlideIn { - from { - opacity: 0; - transform: translateY(-20px) scale(0.95); - } - to { - opacity: 1; - transform: translateY(0) scale(1); - } -} - -/* Warning Header with Icon */ -.publish-warning-header { - display: flex; - align-items: center; - gap: 0.875rem; - padding: 1.25rem 1.5rem; - background: linear-gradient(135deg, rgba(251, 191, 36, 0.08) 0%, rgba(245, 158, 11, 0.05) 100%); - border-bottom: 1px dashed rgba(217, 119, 6, 0.25); - position: relative; -} - -.publish-warning-header::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 3px; - background: linear-gradient(90deg, - transparent 0%, - rgba(245, 158, 11, 0.6) 20%, - rgba(217, 119, 6, 0.8) 50%, - rgba(245, 158, 11, 0.6) 80%, - transparent 100% - ); -} - -.warning-icon-wrapper { - display: flex; - align-items: center; - justify-content: center; - width: 2.5rem; - height: 2.5rem; - background: linear-gradient(135deg, rgba(251, 191, 36, 0.2) 0%, rgba(245, 158, 11, 0.15) 100%); - border: 1.5px solid rgba(217, 119, 6, 0.3); - border-radius: 50%; - flex-shrink: 0; - animation: warningPulse 2s ease-in-out infinite; -} - -@keyframes warningPulse { - 0%, 100% { - box-shadow: 0 0 0 0 rgba(245, 158, 11, 0.3); - } - 50% { - box-shadow: 0 0 0 6px rgba(245, 158, 11, 0); - } -} - -.warning-icon-wrapper i { - font-size: 1.125rem; - color: #b45309; -} - -.publish-warning-header h3 { - flex: 1; - font-family: 'Kingthings Typewriter', monospace; - font-size: 1.25rem; - color: var(--text-primary); - margin: 0; - letter-spacing: 0.02em; -} - -.publish-warning-header .dialog-close-btn { - display: flex; - align-items: center; - justify-content: center; - width: 2rem; - height: 2rem; - background: transparent; - border: none; - border-radius: 50%; - color: var(--text-secondary); - cursor: pointer; - transition: all var(--transition-base); -} - -.publish-warning-header .dialog-close-btn:hover { - background: rgba(217, 119, 6, 0.1); - color: #b45309; -} - -/* Warning Body */ -.publish-warning-body { - padding: 1.5rem; -} - -.warning-text { - font-family: 'Lora', Georgia, serif; - font-size: 0.9375rem; - line-height: 1.7; - color: var(--text-primary); - margin: 0 0 1.25rem 0; - text-align: justify; - hyphens: auto; -} - -/* Recommendation Callout */ -.warning-recommendation { - display: flex; - align-items: flex-start; - gap: 0.75rem; - padding: 1rem 1.125rem; - background: linear-gradient(135deg, rgba(16, 185, 129, 0.06) 0%, rgba(5, 150, 105, 0.04) 100%); - border: 1.5px solid rgba(16, 185, 129, 0.2); - border-radius: 0.5rem; - border-left: 3px solid var(--success); -} - -.warning-recommendation i { - font-size: 1rem; - color: var(--success); - margin-top: 0.125rem; - flex-shrink: 0; -} - -.warning-recommendation span { - font-family: 'Kingthings Typewriter', monospace; - font-size: 0.8125rem; - line-height: 1.5; - color: var(--text-secondary); -} - -/* Warning Actions */ -.publish-warning-actions { - display: flex; - gap: 0.75rem; - justify-content: flex-end; - padding: 1rem 1.5rem; - background: rgba(255, 255, 255, 0.6); - border-top: 1px dashed var(--neutral-200); -} - -.publish-warning-actions .cancel-btn { - padding: 0.625rem 1.25rem; - background: transparent; - color: var(--text-secondary); - border: 2px solid var(--neutral-300); - border-radius: 0.375rem; - font-family: 'Kingthings Typewriter', monospace; - font-size: 0.9375rem; - cursor: pointer; - transition: all var(--transition-base); -} - -.publish-warning-actions .cancel-btn:hover { - background: var(--neutral-100); - border-color: var(--neutral-400); - color: var(--text-primary); -} - -.publish-confirm-btn { - display: inline-flex; - align-items: center; - gap: 0.5rem; - padding: 0.625rem 1.25rem; - background: linear-gradient(135deg, #d97706 0%, #b45309 100%); - color: white; - border: 2px solid #92400e; - border-radius: 0.375rem; - font-family: 'Kingthings Typewriter', monospace; - font-size: 0.9375rem; - font-weight: 500; - cursor: pointer; - transition: all var(--transition-base); -} - -.publish-confirm-btn:hover { - background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%); - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(217, 119, 6, 0.25); -} - -.publish-confirm-btn:active { - transform: translateY(0); -} - -.publish-confirm-btn i { - font-size: 0.875rem; -} - /* ======================================== Story Stats (Public Page) Word count and reading time display @@ -1452,50 +1123,6 @@ border-top: 1px dashed var(--neutral-300); } -.pagination-button { - display: inline-flex; - align-items: center; - gap: 0.5rem; - padding: 0.75rem 1.25rem; - background: linear-gradient(135deg, var(--neutral-100) 0%, var(--neutral-200) 100%); - color: var(--text-primary); - border: 2px solid var(--neutral-300); - border-radius: 0.375rem; - font-family: 'Kingthings Typewriter', monospace; - font-size: 0.9375rem; - font-weight: 500; - cursor: pointer; - transition: all var(--transition-base); - text-decoration: none; -} - -.pagination-button:hover:not(.disabled) { - background: linear-gradient(135deg, var(--accent) 0%, var(--accent-dark) 100%); - color: white; - border-color: var(--accent-dark); - transform: translateY(-1px); -} - -.pagination-button:active:not(.disabled) { - transform: translateY(0); -} - -.pagination-button.disabled { - opacity: 0.4; - cursor: not-allowed; -} - -.pagination-button i { - font-size: 0.75rem; -} - -.pagination-info { - font-family: 'Kingthings Typewriter', monospace; - font-size: 0.875rem; - color: var(--text-secondary); - padding: 0 1rem; -} - /* Responsive pagination */ @media only screen and (max-width: 480px) { .story-pagination { @@ -1503,12 +1130,12 @@ gap: 0.75rem; } - .pagination-button { + .story-pagination .pagination-button { padding: 0.625rem 1rem; font-size: 0.875rem; } - .pagination-info { + .story-pagination .pagination-info { width: 100%; text-align: center; order: -1; diff --git a/server/src/main/resources/templates/admin-settings.mustache b/server/src/main/resources/templates/admin-settings.mustache index 23af1c63b..519f386f9 100644 --- a/server/src/main/resources/templates/admin-settings.mustache +++ b/server/src/main/resources/templates/admin-settings.mustache @@ -1,24 +1,22 @@ {{> header}} -
+
{{> partials/admin-nav}}
-
-
-

{{msg.admin_dashboard_title}}

-

{{msg.admin_dashboard_subtitle}}

+ -
+
-
-

{{msg.admin_serversettings_title}}

-
+

{{msg.admin_serversettings_title}}

{{msg.admin_serversettings_description}}

@@ -26,17 +24,19 @@ hx-post="/admin/settings" hx-swap="none">
- +
-
- +
- {{#availableLocales}} {{/availableLocales}} @@ -45,10 +45,11 @@
- +
+ class="form-textarea">{{serverMessage}}
diff --git a/server/src/main/resources/templates/admin-users.mustache b/server/src/main/resources/templates/admin-users.mustache index 3a2d1cabd..b36b74cda 100644 --- a/server/src/main/resources/templates/admin-users.mustache +++ b/server/src/main/resources/templates/admin-users.mustache @@ -1,24 +1,22 @@ {{> header}} -
+
{{> partials/admin-nav}}
-
-
-

{{msg.admin_users_title}}

-

{{msg.admin_users_subtitle}}

+ -
+
-
-

{{msg.admin_users_list_title}}

-
+

{{msg.admin_users_list_title}}

{{msg.admin_users_description}}

diff --git a/server/src/main/resources/templates/admin-whitelist.mustache b/server/src/main/resources/templates/admin-whitelist.mustache index 6fb9b0f58..fc944e402 100644 --- a/server/src/main/resources/templates/admin-whitelist.mustache +++ b/server/src/main/resources/templates/admin-whitelist.mustache @@ -1,15 +1,15 @@ {{> header}} -
+
{{> partials/admin-nav}}
-
-
-

{{msg.admin_whitelist_management_title}}

-

+