mirror of
https://github.com/Darkrock-Studios/hammer-editor.git
synced 2026-08-04 23:29:46 +00:00
CSS Refactor
- Commonized a lot of core components - Moved to a bit more of a design system - Moved to BEM style naming
This commit is contained in:
parent
07387a9db7
commit
f82f3561bb
23 changed files with 2011 additions and 1720 deletions
926
docs/WEB-DESIGN-SYSTEM.md
Normal file
926
docs/WEB-DESIGN-SYSTEM.md
Normal file
|
|
@ -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
|
||||
|
||||
<main class="page">
|
||||
<div class="page__container">
|
||||
<!-- Page content -->
|
||||
</div>
|
||||
</main>
|
||||
```
|
||||
|
||||
**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
|
||||
|
||||
<div class="page-header">
|
||||
<div class="page-header__content">
|
||||
<h1 class="page-header__title">Dashboard</h1>
|
||||
<p class="page-header__subtitle">Welcome back, username</p>
|
||||
</div>
|
||||
<div class="page-header__actions">
|
||||
<button class="btn btn--ghost">Settings</button>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Paper Section
|
||||
|
||||
Notebook-style content sections with lined background and red margin.
|
||||
|
||||
```html
|
||||
|
||||
<div class="paper-section">
|
||||
<div class="section-header">
|
||||
<h2 class="section-header__title">Your Projects</h2>
|
||||
<div class="section-header__actions">
|
||||
<button class="btn">New Project</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="section-description">Manage your writing projects.</p>
|
||||
<!-- Section content -->
|
||||
</div>
|
||||
```
|
||||
|
||||
**Modifiers:**
|
||||
|
||||
- `.paper-section--compact` - Reduced padding
|
||||
- `.paper-section--centered` - Center-aligned text
|
||||
|
||||
---
|
||||
|
||||
## UI Components
|
||||
|
||||
### Cards
|
||||
|
||||
Interactive card components for lists of items.
|
||||
|
||||
```html
|
||||
|
||||
<div class="card-list">
|
||||
<a href="/project/1" class="card card--interactive">
|
||||
<div class="card__info">
|
||||
<h3 class="card__title">My Novel</h3>
|
||||
<span class="card__subtitle">Last synced: 2 hours ago</span>
|
||||
</div>
|
||||
<i class="fa-solid fa-chevron-right card__arrow"></i>
|
||||
</a>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Modifiers:**
|
||||
|
||||
- `.card--interactive` - Adds hover effects (translateX, border change)
|
||||
- `.card--gradient` - Gradient background
|
||||
|
||||
### Dialog/Modal
|
||||
|
||||
Modal dialogs with header, body, and actions.
|
||||
|
||||
```html
|
||||
|
||||
<div class="dialog-overlay" id="my-dialog">
|
||||
<div class="dialog">
|
||||
<div class="dialog__header">
|
||||
<h3>Dialog Title</h3>
|
||||
<button class="dialog__close">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="dialog__body">
|
||||
<!-- Dialog content -->
|
||||
</div>
|
||||
<div class="dialog__actions">
|
||||
<button class="btn btn--ghost">Cancel</button>
|
||||
<button class="btn btn--accent">Confirm</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Modifiers:**
|
||||
|
||||
- `.dialog--warning` - Warning variant with amber tint
|
||||
|
||||
**JavaScript:**
|
||||
Add `.closing` class to `.dialog-overlay` to trigger fade-out animation.
|
||||
|
||||
### Buttons
|
||||
|
||||
```html
|
||||
<!-- Default (outlined) -->
|
||||
<button class="btn">Default</button>
|
||||
|
||||
<!-- Primary (filled dark, hover to accent) -->
|
||||
<button class="btn btn--primary">Primary</button>
|
||||
|
||||
<!-- Accent (filled amber) -->
|
||||
<button class="btn btn--accent">Accent</button>
|
||||
|
||||
<!-- Danger (red outlined/filled) -->
|
||||
<button class="btn btn--danger">Delete</button>
|
||||
|
||||
<!-- Ghost (subtle) -->
|
||||
<button class="btn btn--ghost">Cancel</button>
|
||||
|
||||
<!-- Full width -->
|
||||
<button class="btn btn--primary btn--block">Submit</button>
|
||||
```
|
||||
|
||||
### Pagination
|
||||
|
||||
```html
|
||||
|
||||
<div class="pagination">
|
||||
<button class="pagination-button">« Previous</button>
|
||||
<span class="pagination-info">Page 1 of 5</span>
|
||||
<button class="pagination-button">Next »</button>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Empty State
|
||||
|
||||
For displaying when lists have no content.
|
||||
|
||||
```html
|
||||
|
||||
<div class="empty-state">
|
||||
<div class="empty-state__icon">📝</div>
|
||||
<p>No projects yet. Start writing!</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Toast Notifications
|
||||
|
||||
```html
|
||||
|
||||
<div id="toast-container">
|
||||
<div class="toast toast-success">
|
||||
<span class="toast-icon">✓</span>
|
||||
<span class="toast-message">Changes saved successfully</span>
|
||||
<button class="toast-dismiss">×</button>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Variants:** `.toast-success`, `.toast-warning`, `.toast-error`, `.toast-info`
|
||||
|
||||
---
|
||||
|
||||
## Form Components
|
||||
|
||||
### Form Field
|
||||
|
||||
```html
|
||||
|
||||
<div class="form-field">
|
||||
<label for="email" class="form-field__label">Email Address</label>
|
||||
<input type="email" id="email" class="form-input" placeholder="you@example.com">
|
||||
</div>
|
||||
```
|
||||
|
||||
### Input Types
|
||||
|
||||
```html
|
||||
<!-- Text Input -->
|
||||
<input type="text" class="form-input">
|
||||
|
||||
<!-- Select Dropdown -->
|
||||
<select class="form-select">
|
||||
<option>Option 1</option>
|
||||
<option>Option 2</option>
|
||||
</select>
|
||||
|
||||
<!-- Textarea -->
|
||||
<textarea class="form-textarea"></textarea>
|
||||
```
|
||||
|
||||
### Form Field Label Variants
|
||||
|
||||
```html
|
||||
<label class="form-field__label">Regular Label</label>
|
||||
<label class="form-field__label form-field__label--small">Small Label</label>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 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}}
|
||||
|
||||
<main class="page">
|
||||
<div class="page__container">
|
||||
<!-- Dark header bar -->
|
||||
<div class="page-header">
|
||||
<div class="page-header__content">
|
||||
<h1 class="page-header__title">My Page</h1>
|
||||
<p class="page-header__subtitle">Subtitle text</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Content section -->
|
||||
<div class="paper-section">
|
||||
<div class="section-header">
|
||||
<h2 class="section-header__title">Section Title</h2>
|
||||
</div>
|
||||
|
||||
<!-- Card list -->
|
||||
<div class="card-list">
|
||||
<a href="#" class="card card--interactive">
|
||||
<div class="card__info">
|
||||
<h3 class="card__title">Item Title</h3>
|
||||
<span class="card__subtitle">Subtitle</span>
|
||||
</div>
|
||||
<i class="fa-solid fa-chevron-right card__arrow"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Or empty state -->
|
||||
<div class="empty-state">
|
||||
<p>No items yet.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{{> footer}}
|
||||
```
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1,24 +1,22 @@
|
|||
{{> header}}
|
||||
|
||||
<main class="admin-page">
|
||||
<main class="page">
|
||||
<div class="admin-layout">
|
||||
{{> partials/admin-nav}}
|
||||
|
||||
<div class="admin-content">
|
||||
<!-- Admin Header -->
|
||||
<div class="admin-header">
|
||||
<div class="admin-header-content">
|
||||
<h1>{{msg.admin_dashboard_title}}</h1>
|
||||
<p class="admin-subtitle">{{msg.admin_dashboard_subtitle}}</p>
|
||||
<div class="page-header">
|
||||
<div class="page-header__content">
|
||||
<h1 class="page-header__title">{{msg.admin_dashboard_title}}</h1>
|
||||
<p class="page-header__subtitle">{{msg.admin_dashboard_subtitle}}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Server Settings Section -->
|
||||
<section class="admin-section">
|
||||
<section class="paper-section">
|
||||
<div class="section-header">
|
||||
<div class="section-title-group">
|
||||
<h2>{{msg.admin_serversettings_title}}</h2>
|
||||
</div>
|
||||
<h2 class="section-header__title">{{msg.admin_serversettings_title}}</h2>
|
||||
</div>
|
||||
<p class="section-description">{{msg.admin_serversettings_description}}</p>
|
||||
|
||||
|
|
@ -26,17 +24,19 @@
|
|||
hx-post="/admin/settings"
|
||||
hx-swap="none">
|
||||
<div class="form-group">
|
||||
<label for="contact">{{msg.admin_serversettings_contact_label}}</label>
|
||||
<label for="contact"
|
||||
class="form-field__label">{{msg.admin_serversettings_contact_label}}</label>
|
||||
<div class="form-input-group">
|
||||
<input id="contact" name="contact" type="email" value="{{contactEmail}}"
|
||||
<input id="contact" name="contact" type="email" value="{{contactEmail}}" class="form-input"
|
||||
placeholder="{{msg.admin_serversettings_contact_placeholder}}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="defaultLocale">{{msg.admin_serversettings_default_locale_label}}</label>
|
||||
<label for="defaultLocale"
|
||||
class="form-field__label">{{msg.admin_serversettings_default_locale_label}}</label>
|
||||
<div class="form-input-group">
|
||||
<select id="defaultLocale" name="defaultLocale" class="settings-select">
|
||||
<select id="defaultLocale" name="defaultLocale" class="form-select">
|
||||
{{#availableLocales}}
|
||||
<option value="{{tag}}" {{#selected}}selected{{/selected}}>{{label}}</option>
|
||||
{{/availableLocales}}
|
||||
|
|
@ -45,10 +45,11 @@
|
|||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="message">{{msg.admin_serversettings_message_label}}</label>
|
||||
<label for="message"
|
||||
class="form-field__label">{{msg.admin_serversettings_message_label}}</label>
|
||||
<div class="form-input-group">
|
||||
<textarea id="message" name="message" rows="4"
|
||||
class="settings-textarea">{{serverMessage}}</textarea>
|
||||
class="form-textarea">{{serverMessage}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,24 +1,22 @@
|
|||
{{> header}}
|
||||
|
||||
<main class="admin-page">
|
||||
<main class="page">
|
||||
<div class="admin-layout">
|
||||
{{> partials/admin-nav}}
|
||||
|
||||
<div class="admin-content">
|
||||
<!-- Admin Header -->
|
||||
<div class="admin-header">
|
||||
<div class="admin-header-content">
|
||||
<h1>{{msg.admin_users_title}}</h1>
|
||||
<p class="admin-subtitle">{{msg.admin_users_subtitle}}</p>
|
||||
<div class="page-header">
|
||||
<div class="page-header__content">
|
||||
<h1 class="page-header__title">{{msg.admin_users_title}}</h1>
|
||||
<p class="page-header__subtitle">{{msg.admin_users_subtitle}}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- User Management Section -->
|
||||
<section class="admin-section">
|
||||
<section class="paper-section">
|
||||
<div class="section-header">
|
||||
<div class="section-title-group">
|
||||
<h2>{{msg.admin_users_list_title}}</h2>
|
||||
</div>
|
||||
<h2 class="section-header__title">{{msg.admin_users_list_title}}</h2>
|
||||
</div>
|
||||
<p class="section-description">{{msg.admin_users_description}}</p>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
{{> header}}
|
||||
|
||||
<main class="admin-page">
|
||||
<main class="page">
|
||||
<div class="admin-layout">
|
||||
{{> partials/admin-nav}}
|
||||
|
||||
<div class="admin-content">
|
||||
<!-- Admin Header -->
|
||||
<div class="admin-header">
|
||||
<div class="admin-header-content">
|
||||
<h1>{{msg.admin_whitelist_management_title}}</h1>
|
||||
<p class="admin-subtitle">
|
||||
<div class="page-header">
|
||||
<div class="page-header__content">
|
||||
<h1 class="page-header__title">{{msg.admin_whitelist_management_title}}</h1>
|
||||
<p class="page-header__subtitle">
|
||||
{{#whitelist.enabled}}
|
||||
{{msg.admin_whitelist_enabled_subtitle}}
|
||||
{{/whitelist.enabled}}
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
{{/whitelist.enabled}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="admin-header-actions">
|
||||
<div class="page-header__actions">
|
||||
<form action="/admin/whitelist/toggle" method="post" class="logout-form"
|
||||
hx-post="/admin/whitelist/toggle"
|
||||
hx-swap="none">
|
||||
|
|
@ -34,11 +34,9 @@
|
|||
</div>
|
||||
|
||||
<!-- Whitelist Management Section -->
|
||||
<section class="admin-section">
|
||||
<section class="paper-section">
|
||||
<div class="section-header">
|
||||
<div class="section-title-group">
|
||||
<h2>{{msg.admin_whitelist_add_title}}</h2>
|
||||
</div>
|
||||
<h2 class="section-header__title">{{msg.admin_whitelist_add_title}}</h2>
|
||||
</div>
|
||||
<p class="section-description">{{msg.admin_whitelist_description}}</p>
|
||||
|
||||
|
|
@ -48,9 +46,9 @@
|
|||
hx-swap="innerHTML"
|
||||
hx-on::after-request="this.reset()">
|
||||
<div class="form-group">
|
||||
<label for="email">{{msg.admin_whitelist_email_label}}</label>
|
||||
<label for="email" class="form-field__label">{{msg.admin_whitelist_email_label}}</label>
|
||||
<div class="form-input-group">
|
||||
<input id="email" name="email" type="email"
|
||||
<input id="email" name="email" type="email" class="form-input"
|
||||
placeholder="{{msg.admin_whitelist_email_placeholder}}" required/>
|
||||
<button type="submit" class="add-button">{{msg.admin_whitelist_add_button}}</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{{> header}}
|
||||
|
||||
<main class="author-page">
|
||||
<div class="author-container">
|
||||
<main class="page">
|
||||
<div class="page__container page__container--author">
|
||||
<!-- Stories Section -->
|
||||
<section class="stories-section">
|
||||
<!-- Author Info inside the card -->
|
||||
|
|
@ -16,14 +16,14 @@
|
|||
</header>
|
||||
|
||||
{{#hasStories}}
|
||||
<div class="stories-list">
|
||||
<div class="card-list">
|
||||
{{#stories}}
|
||||
<a href="/a/{{urlPenName}}/{{urlName}}" class="story-card">
|
||||
<div class="story-info">
|
||||
<h2 class="story-name">{{name}}</h2>
|
||||
<span class="story-date">{{msg.author_story_published_on}} {{publishedAt}}</span>
|
||||
<a href="/a/{{urlPenName}}/{{urlName}}" class="card card--gradient card--interactive">
|
||||
<div class="card__info">
|
||||
<h2 class="card__title">{{name}}</h2>
|
||||
<span class="card__subtitle">{{msg.author_story_published_on}} {{publishedAt}}</span>
|
||||
</div>
|
||||
<i class="fa-solid fa-chevron-right story-arrow"></i>
|
||||
<i class="fa-solid fa-chevron-right card__arrow"></i>
|
||||
</a>
|
||||
{{/stories}}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
{{> header}}
|
||||
|
||||
<main class="dashboard-page">
|
||||
<div class="dashboard-container">
|
||||
<main class="page">
|
||||
<div class="page__container">
|
||||
<!-- Dashboard Header -->
|
||||
<div class="dashboard-header">
|
||||
<div class="dashboard-header-content">
|
||||
<h1>{{msg.dashboard_title}}</h1>
|
||||
<p class="dashboard-subtitle">{{msg.dashboard_subtitle}} {{username}}</p>
|
||||
<div class="page-header">
|
||||
<div class="page-header__content">
|
||||
<h1 class="page-header__title">{{msg.dashboard_title}}</h1>
|
||||
<p class="page-header__subtitle">{{msg.dashboard_subtitle}} {{username}}</p>
|
||||
</div>
|
||||
<div class="dashboard-header-actions">
|
||||
<div class="page-header__actions">
|
||||
{{#isAdmin}}
|
||||
<a href="/admin" class="manage-server-button">{{msg.dashboard_manage_server}}</a>
|
||||
{{/isAdmin}}
|
||||
|
|
@ -19,11 +19,9 @@
|
|||
</div>
|
||||
|
||||
<!-- Projects Section -->
|
||||
<section class="dashboard-section">
|
||||
<section class="paper-section">
|
||||
<div class="section-header">
|
||||
<div class="section-title-group">
|
||||
<h2>{{msg.dashboard_projects_title}}</h2>
|
||||
</div>
|
||||
<h2 class="section-header__title">{{msg.dashboard_projects_title}}</h2>
|
||||
</div>
|
||||
<p class="section-description">{{msg.dashboard_projects_description}}</p>
|
||||
|
||||
|
|
@ -35,11 +33,9 @@
|
|||
</section>
|
||||
|
||||
<!-- Account Section -->
|
||||
<section class="dashboard-section">
|
||||
<section class="paper-section">
|
||||
<div class="section-header">
|
||||
<div class="section-title-group">
|
||||
<h2>{{msg.dashboard_account_title}}</h2>
|
||||
</div>
|
||||
<h2 class="section-header__title">{{msg.dashboard_account_title}}</h2>
|
||||
</div>
|
||||
<div class="account-container">
|
||||
<div class="account-info">
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
{{> header}}
|
||||
|
||||
<main class="login-page">
|
||||
<div class="login-container">
|
||||
<div class="login-card">
|
||||
<main class="page page--centered">
|
||||
<div class="page__container page__container--narrow">
|
||||
<div class="paper-section paper-section--compact">
|
||||
<div class="login-header">
|
||||
<h1>{{msg.login_title}}</h1>
|
||||
<p>{{msg.login_subtitle}}</p>
|
||||
|
|
@ -10,14 +10,14 @@
|
|||
|
||||
<form action="/login" method="post" class="login-form">
|
||||
<div class="form-field">
|
||||
<label for="email">{{msg.login_email_label}}</label>
|
||||
<input type="email" id="email" name="email" required autofocus
|
||||
<label for="email" class="form-field__label">{{msg.login_email_label}}</label>
|
||||
<input type="email" id="email" name="email" class="form-input" required autofocus
|
||||
placeholder="{{msg.login_email_placeholder}}">
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="password">{{msg.login_password_label}}</label>
|
||||
<input type="password" id="password" name="password" required
|
||||
<label for="password" class="form-field__label">{{msg.login_password_label}}</label>
|
||||
<input type="password" id="password" name="password" class="form-input" required
|
||||
placeholder="{{msg.login_password_placeholder}}">
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{{> header}}
|
||||
|
||||
<main class="error-page">
|
||||
<div class="error-container">
|
||||
<main class="page page--centered">
|
||||
<div class="page__container page__container--error">
|
||||
<div class="error-card notfound">
|
||||
<div class="error-icon">📄</div>
|
||||
<h1 class="error-title">{{msg.error_notfound_title}}</h1>
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
{{#projects}}
|
||||
{{#hasProjects}}
|
||||
<div class="projects-list">
|
||||
<div class="card-list">
|
||||
{{#items}}
|
||||
<a href="/story/{{uuid}}" class="project-card">
|
||||
<div class="project-info">
|
||||
<span class="project-name">{{name}}</span>
|
||||
<span class="project-sync-date">
|
||||
<a href="/story/{{uuid}}" class="card card--interactive">
|
||||
<div class="card__info">
|
||||
<span class="card__title">{{name}}</span>
|
||||
<span class="card__subtitle">
|
||||
{{msg.dashboard_last_sync}}: {{lastSync}}
|
||||
</span>
|
||||
</div>
|
||||
<i class="fa-solid fa-chevron-right project-arrow"></i>
|
||||
<i class="fa-solid fa-chevron-right card__arrow"></i>
|
||||
</a>
|
||||
{{/items}}
|
||||
</div>
|
||||
{{/hasProjects}}
|
||||
{{^hasProjects}}
|
||||
<div class="projects-empty">
|
||||
<div class="empty-state">
|
||||
<p>{{msg.dashboard_no_projects}}</p>
|
||||
</div>
|
||||
{{/hasProjects}}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,26 @@
|
|||
<div class="publish-warning-overlay" id="publish-warning-overlay" onclick="closePublishWarning(event)">
|
||||
<div class="publish-warning-dialog" onclick="event.stopPropagation()">
|
||||
<div class="publish-warning-header">
|
||||
<div class="dialog-overlay" id="publish-warning-overlay" onclick="closePublishWarning(event)">
|
||||
<div class="dialog dialog--warning" onclick="event.stopPropagation()">
|
||||
<div class="dialog__header dialog__header--warning">
|
||||
<div class="warning-icon-wrapper">
|
||||
<i class="fas fa-exclamation-triangle"></i>
|
||||
</div>
|
||||
<h3>{{msg.story_publish_warning_title}}</h3>
|
||||
<button type="button" class="dialog-close-btn" onclick="closePublishWarning()">
|
||||
<button type="button" class="dialog__close" onclick="closePublishWarning()">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="publish-warning-body">
|
||||
<div class="dialog__body">
|
||||
<p class="warning-text">{{msg.story_publish_warning_content}}</p>
|
||||
<div class="warning-recommendation">
|
||||
<i class="fas fa-lightbulb"></i>
|
||||
<span>{{msg.story_publish_warning_recommendation}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="publish-warning-actions">
|
||||
<button type="button" class="cancel-btn" onclick="closePublishWarning()">
|
||||
<div class="dialog__actions">
|
||||
<button type="button" class="btn btn--ghost" onclick="closePublishWarning()">
|
||||
{{msg.story_cancel}}
|
||||
</button>
|
||||
<button type="button" class="publish-confirm-btn" onclick="confirmPublish()">
|
||||
<button type="button" class="btn btn--accent publish-confirm-btn" onclick="confirmPublish()">
|
||||
<i class="fas fa-globe"></i> {{msg.story_publish_publicly}}
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<div class="share-dialog-overlay" id="share-dialog-overlay" onclick="closeShareDialog(event)">
|
||||
<div class="share-dialog" onclick="event.stopPropagation()">
|
||||
<div class="share-dialog-header">
|
||||
<div class="dialog-overlay" id="share-dialog-overlay" onclick="closeShareDialog(event)">
|
||||
<div class="dialog" onclick="event.stopPropagation()">
|
||||
<div class="dialog__header">
|
||||
<h3>{{msg.story_share_private_title}}</h3>
|
||||
<button type="button" class="dialog-close-btn" onclick="closeShareDialog()">
|
||||
<button type="button" class="dialog__close" onclick="closeShareDialog()">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -10,33 +10,35 @@
|
|||
hx-target="#publish-section"
|
||||
hx-swap="outerHTML"
|
||||
hx-on::after-request="closeShareDialog()">
|
||||
<div class="share-dialog-body">
|
||||
<div class="dialog__body">
|
||||
<div class="form-field">
|
||||
<label for="access-password">{{msg.story_access_password}}</label>
|
||||
<label for="access-password" class="form-field__label">{{msg.story_access_password}}</label>
|
||||
<input type="text"
|
||||
id="access-password"
|
||||
name="password"
|
||||
class="form-input"
|
||||
required
|
||||
minlength="1"
|
||||
autocomplete="off"
|
||||
placeholder="{{msg.story_access_password_placeholder}}">
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="access-expires">
|
||||
<label for="access-expires" class="form-field__label">
|
||||
{{msg.story_access_expires}}
|
||||
<span class="optional-label">({{msg.story_access_optional}})</span>
|
||||
</label>
|
||||
<input type="date"
|
||||
id="access-expires"
|
||||
name="expiresAt"
|
||||
class="form-input"
|
||||
min="{{minDate}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="share-dialog-actions">
|
||||
<button type="button" class="cancel-btn" onclick="closeShareDialog()">
|
||||
<div class="dialog__actions">
|
||||
<button type="button" class="btn btn--ghost" onclick="closeShareDialog()">
|
||||
{{msg.story_cancel}}
|
||||
</button>
|
||||
<button type="submit" class="create-access-btn">
|
||||
<button type="submit" class="btn btn--accent">
|
||||
{{msg.story_create_access}}
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
{{/.}}
|
||||
{{/items}}
|
||||
{{^items}}
|
||||
<div class="users-empty">
|
||||
<div class="empty-state">
|
||||
<p>{{msg.admin_users_empty}}</p>
|
||||
</div>
|
||||
{{/items}}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
{{/.}}
|
||||
{{/items}}
|
||||
{{^items}}
|
||||
<div class="whitelist-empty">
|
||||
<div class="empty-state">
|
||||
<p>{{msg.admin_whitelist_empty}}</p>
|
||||
</div>
|
||||
{{/items}}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{{> header}}
|
||||
|
||||
<main class="error-page">
|
||||
<div class="error-container">
|
||||
<main class="page page--centered">
|
||||
<div class="page__container page__container--error">
|
||||
<div class="error-card servererror">
|
||||
<div class="error-icon">⚙️</div>
|
||||
<h1 class="error-title">{{msg.error_servererror_title}}</h1>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{{> header}}
|
||||
|
||||
<main class="error-page">
|
||||
<div class="error-container">
|
||||
<main class="page page--centered">
|
||||
<div class="page__container page__container--error">
|
||||
<div class="error-card">
|
||||
<div class="error-icon">🔒</div>
|
||||
<h1 class="error-title">{{msg.error_unauthorized_title}}</h1>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue