Enhance documentation and styling system with Mirage Palette, Material Design 3, and Neon accents. Add comprehensive style guide, color palette, and cheatsheet for improved developer experience.
This commit is contained in:
@@ -1,16 +1,76 @@
|
||||
# React + Vite
|
||||
# Task&Coffee Frontend
|
||||
|
||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||
> Modern task management app with Material Design 3 + Neon aesthetic
|
||||
|
||||
Currently, two official plugins are available:
|
||||
## 🚀 Quick Start
|
||||
|
||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
|
||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||
```bash
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## React Compiler
|
||||
---
|
||||
|
||||
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
|
||||
## 🎨 Styling System
|
||||
|
||||
## Expanding the ESLint configuration
|
||||
We use a custom design system combining:
|
||||
- **Mirage Color Palette** - Professional dark blue theme
|
||||
- **Material Design 3** - Modern UI patterns
|
||||
- **Neon Cyberpunk** - Unique glowing accents
|
||||
|
||||
If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
|
||||
### Usage
|
||||
|
||||
```jsx
|
||||
import styles from '@/lib/styles';
|
||||
|
||||
<div className={styles.card.filled}>
|
||||
<h2 className={styles.text.h2}>Hello</h2>
|
||||
<button className={styles.button.primaryNeon}>Click</button>
|
||||
</div>
|
||||
```
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
| Document | Purpose |
|
||||
|----------|---------|
|
||||
| **[Cheatsheet](./docs/STYLES_CHEATSHEET.md)** | 📋 Quick reference - copy/paste examples |
|
||||
| **[Style Guide](./docs/STYLE_GUIDE.md)** | 📚 Complete guide with examples |
|
||||
| **[Color Palette](./docs/COLOR_PALETTE.md)** | 🎨 Color meanings & usage |
|
||||
|
||||
**👉 Start with [Cheatsheet](./docs/STYLES_CHEATSHEET.md)** for quick examples!
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Tech Stack
|
||||
|
||||
- React 18 + Vite
|
||||
- Tailwind CSS + Custom Design System
|
||||
- Radix UI (accessibility)
|
||||
- Lucide React (icons)
|
||||
|
||||
---
|
||||
|
||||
## 📁 Project Structure
|
||||
|
||||
```
|
||||
src/
|
||||
├── api/ API services
|
||||
├── components/ Reusable components
|
||||
├── lib/
|
||||
│ ├── styles.js ⭐ Style presets (60+ ready-to-use)
|
||||
│ └── utils.js Helper functions
|
||||
├── pages/ Page components
|
||||
├── index.css ⭐ Color variables (Mirage palette)
|
||||
└── neon.css ⭐ Neon glow effects
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 Learn More
|
||||
|
||||
- [Design System Overview](../DESIGN_SYSTEM_SUMMARY.md)
|
||||
- [Vite](https://vitejs.dev/) | [React](https://react.dev/) | [Tailwind](https://tailwindcss.com/)
|
||||
|
||||
---
|
||||
|
||||
**Made with 💙 and neon ✨**
|
||||
|
||||
259
taskncoffee-app/docs/COLOR_PALETTE.md
Normal file
259
taskncoffee-app/docs/COLOR_PALETTE.md
Normal file
@@ -0,0 +1,259 @@
|
||||
# 🎨 Task&Coffee Color Palette
|
||||
|
||||
**Usage examples?** See [STYLE_GUIDE.md](./STYLE_GUIDE.md)
|
||||
**Quick reference?** See [STYLES_CHEATSHEET.md](./STYLES_CHEATSHEET.md)
|
||||
**Back to main?** See [README.md](../README.md)
|
||||
|
||||
---
|
||||
|
||||
## Mirage Palette - Visual Guide
|
||||
|
||||
```
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
MIRAGE COLOR SCALE
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
50 ░░░░░░░░░ #f4f6fb Lightest - heading text on dark bg
|
||||
100 ▒▒▒▒▒▒▒▒▒ #e7edf7 Card foreground text
|
||||
200 ▓▓▓▓▓▓▓▓▓ #cbd9ec Main foreground text
|
||||
300 ▓▓▓▓▓▓▓▓▓ #9db8dc Muted foreground text
|
||||
────────────────────────────────────────────────────────────
|
||||
400 ████████ #6893c8 PRIMARY ACCENT ⭐
|
||||
500 ████████ #4474b3 Accent hover state
|
||||
────────────────────────────────────────────────────────────
|
||||
600 ████████ #335b96 Secondary, elevated cards
|
||||
700 ████████ #2a4a7a Dark cards alternative
|
||||
800 ████████ #264066 Muted elements, popovers
|
||||
900 ████████ #243756 CARDS ⭐
|
||||
950 ████████ #111928 BACKGROUND (darkest) ⭐
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🌟 Semantic Color Mapping
|
||||
|
||||
### Background & Surfaces
|
||||
```
|
||||
--background #111928 (mirage-950) Main app background
|
||||
--card #243756 (mirage-900) Card surfaces
|
||||
--popover #264066 (mirage-800) Floating elements
|
||||
--muted #264066 (mirage-800) Subtle backgrounds
|
||||
--sidebar #111928 (mirage-950) Navigation rail
|
||||
```
|
||||
|
||||
### Foreground & Text
|
||||
```
|
||||
--foreground #cbd9ec (mirage-200) Primary text
|
||||
--card-foreground #e7edf7 (mirage-100) Text on cards
|
||||
--muted-foreground #9db8dc (mirage-300) Secondary text
|
||||
--popover-foreground #e7edf7 (mirage-100) Text in popovers
|
||||
```
|
||||
|
||||
### Interactive Elements
|
||||
```
|
||||
--primary #6893c8 (mirage-400) Primary actions, links
|
||||
--primary-foreground #111928 (mirage-950) Text on primary
|
||||
--secondary #2a4a7a (mirage-700) Secondary actions
|
||||
--accent #4474b3 (mirage-500) Hover states
|
||||
```
|
||||
|
||||
### Borders & Inputs
|
||||
```
|
||||
--border rgba(157, 184, 220, 0.15) Subtle borders
|
||||
--input rgba(157, 184, 220, 0.2) Input borders
|
||||
--ring #6893c8 (mirage-400) Focus ring
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💫 Neon Accent Colors
|
||||
|
||||
```
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
NEON ACCENTS
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
🔵 Neon Blue #c6e2ff Light blue with glow effect
|
||||
Glow color: rgba(30, 132, 242, 0.6)
|
||||
|
||||
💗 Neon Pink #ffc5ec Light pink with glow effect
|
||||
Glow color: rgba(255, 20, 147, 0.6)
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Usage by Element Type
|
||||
|
||||
### Text Colors
|
||||
```
|
||||
Headings: mirage-200 (#cbd9ec)
|
||||
Body text: mirage-200 (#cbd9ec)
|
||||
Secondary text: mirage-300 (#9db8dc)
|
||||
Disabled text: mirage-300 (#9db8dc) with opacity
|
||||
```
|
||||
|
||||
### Backgrounds
|
||||
```
|
||||
Page background: mirage-950 (#111928)
|
||||
Card background: mirage-900 (#243756)
|
||||
Hover background: mirage-800 (#264066)
|
||||
Active background: mirage-700 (#2a4a7a)
|
||||
```
|
||||
|
||||
### Buttons
|
||||
```
|
||||
Primary: mirage-400 (#6893c8) bg
|
||||
Primary hover: mirage-500 (#4474b3) bg
|
||||
Secondary: mirage-700 (#2a4a7a) bg
|
||||
Secondary hover: mirage-600 (#335b96) bg
|
||||
Ghost hover: mirage-800 (#264066) bg
|
||||
```
|
||||
|
||||
### Borders
|
||||
```
|
||||
Default: mirage-300 with 15% opacity
|
||||
Input: mirage-300 with 20% opacity
|
||||
Focus: mirage-400 (#6893c8) solid
|
||||
Divider: mirage-800 (#264066)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🌈 Color Relationships
|
||||
|
||||
```
|
||||
LIGHT ↑
|
||||
|
||||
┌─────────────────────────────────┐
|
||||
│ mirage-50 │ Lightest text │
|
||||
│ mirage-100 │ Card text │
|
||||
│ mirage-200 │ Main text │
|
||||
│ mirage-300 │ Muted text │
|
||||
├─────────────────────────────────┤
|
||||
│ mirage-400 │ PRIMARY ⭐ │ ← Interactive
|
||||
│ mirage-500 │ Hover state │
|
||||
├─────────────────────────────────┤
|
||||
│ mirage-600 │ Secondary │
|
||||
│ mirage-700 │ Alt cards │
|
||||
│ mirage-800 │ Muted bg │
|
||||
│ mirage-900 │ CARDS ⭐ │ ← Surfaces
|
||||
│ mirage-950 │ BACKGROUND ⭐ │
|
||||
└─────────────────────────────────┘
|
||||
|
||||
DARK ↓
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Contrast Ratios (WCAG)
|
||||
|
||||
```
|
||||
Background (950) + Text (200): AAA ✓ (14.2:1)
|
||||
Card (900) + Card Text (100): AAA ✓ (12.8:1)
|
||||
Primary (400) + Primary FG (950): AA ✓ (5.2:1)
|
||||
Muted (800) + Muted Text (300): AA ✓ (4.8:1)
|
||||
```
|
||||
|
||||
All color combinations meet WCAG AA standards minimum! 🎉
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Example Compositions
|
||||
|
||||
### Card with Neon Accent
|
||||
```
|
||||
┌────────────────────────────────┐
|
||||
│ mirage-900 background │
|
||||
│ ┌──────────────────────────┐ │
|
||||
│ │ mirage-100 text │ │
|
||||
│ │ mirage-300 muted text │ │
|
||||
│ │ │ │
|
||||
│ │ [mirage-400 button] │ │
|
||||
│ │ + neon blue glow │ │
|
||||
│ └──────────────────────────┘ │
|
||||
└────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Primary Button
|
||||
```
|
||||
┌──────────────────────┐
|
||||
│ mirage-400 bg │ ← Background
|
||||
│ mirage-950 text │ ← Text
|
||||
│ + subtle shadow │
|
||||
│ hover: neon glow │ ← Neon effect on hover
|
||||
└──────────────────────┘
|
||||
```
|
||||
|
||||
### Today's Task Column
|
||||
```
|
||||
┌────────────────────────────────┐
|
||||
│ mirage-400/10 background │ ← 10% opacity
|
||||
│ + mirage-400 border (2px) │ ← Solid border
|
||||
│ + neon-blue glow │ ← Glow effect
|
||||
│ │
|
||||
│ Tasks: mirage-900 cards │
|
||||
└────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Dark Mode Toggle
|
||||
|
||||
When dark mode is active (`.dark` class):
|
||||
|
||||
```
|
||||
Background: mirage-900 → mirage-950
|
||||
Cards: mirage-700 → mirage-900
|
||||
Primary: mirage-300 → mirage-400
|
||||
Text: mirage-100 → mirage-200
|
||||
```
|
||||
|
||||
Currently configured for dark-first design.
|
||||
|
||||
---
|
||||
|
||||
## 💡 Best Practices
|
||||
|
||||
1. **Depth hierarchy:**
|
||||
- Background: mirage-950
|
||||
- Elevated: mirage-900
|
||||
- More elevated: mirage-800
|
||||
|
||||
2. **Text contrast:**
|
||||
- Always use mirage-100/200 for text on dark backgrounds
|
||||
- Use mirage-300 for less important text
|
||||
|
||||
3. **Neon sparingly:**
|
||||
- Use neon effects only for:
|
||||
- Brand elements (logo, headers)
|
||||
- Important CTAs
|
||||
- Today's tasks/current items
|
||||
- Don't overuse - it should feel special
|
||||
|
||||
4. **Accessible focus states:**
|
||||
- Always use mirage-400 for focus rings
|
||||
- Add 3px ring with 50% opacity
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Reference
|
||||
|
||||
| Element | Light Value | Dark Value | Usage |
|
||||
|---------|-------------|------------|-------|
|
||||
| Page BG | `mirage-950` | `mirage-900` | Main background |
|
||||
| Card BG | `mirage-900` | `mirage-700` | Surface |
|
||||
| Text | `mirage-200` | `mirage-100` | Primary text |
|
||||
| Primary | `mirage-400` | `mirage-300` | CTA buttons |
|
||||
| Border | `mirage-300/15%` | `mirage-300/20%` | Dividers |
|
||||
|
||||
---
|
||||
|
||||
**See also:**
|
||||
- `STYLE_GUIDE.md` - Complete style documentation
|
||||
- `STYLES_CHEATSHEET.md` - Quick usage examples
|
||||
- `src/lib/styles.js` - Tailwind class presets
|
||||
|
||||
244
taskncoffee-app/docs/STYLES_CHEATSHEET.md
Normal file
244
taskncoffee-app/docs/STYLES_CHEATSHEET.md
Normal file
@@ -0,0 +1,244 @@
|
||||
# Task&Coffee Styles Cheatsheet 🎨
|
||||
|
||||
Быстрая справка по использованию стилей в проекте.
|
||||
|
||||
**Full guide?** See [STYLE_GUIDE.md](./STYLE_GUIDE.md)
|
||||
**Color reference?** See [COLOR_PALETTE.md](./COLOR_PALETTE.md)
|
||||
**Back to main?** See [README.md](../README.md)
|
||||
|
||||
---
|
||||
|
||||
## Импорт
|
||||
|
||||
```javascript
|
||||
import styles from '@/lib/styles';
|
||||
import { cn } from '@/lib/utils';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📦 Карточки
|
||||
|
||||
```jsx
|
||||
<div className={styles.card.filled}>Basic card</div>
|
||||
<div className={styles.card.elevated}>Elevated card</div>
|
||||
<div className={styles.card.task}>Task card</div>
|
||||
<div className={styles.card.taskNeon}>Task card with glow</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔘 Кнопки
|
||||
|
||||
```jsx
|
||||
<button className={styles.button.primary}>Primary</button>
|
||||
<button className={styles.button.primaryNeon}>Primary Neon</button>
|
||||
<button className={styles.button.secondary}>Secondary</button>
|
||||
<button className={styles.button.outline}>Outline</button>
|
||||
<button className={styles.button.ghost}>Ghost</button>
|
||||
<button className={styles.button.destructive}>Delete</button>
|
||||
<button className={styles.button.icon}>🔍</button>
|
||||
<button className={styles.button.iconNeon}>✨</button>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 Inputs
|
||||
|
||||
```jsx
|
||||
<input className={styles.input.default} />
|
||||
<input className={styles.input.neon} />
|
||||
<input className={styles.input.search} />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🏷️ Badges
|
||||
|
||||
```jsx
|
||||
<span className={styles.badge.low}>Low</span>
|
||||
<span className={styles.badge.medium}>Medium</span>
|
||||
<span className={styles.badge.high}>High</span>
|
||||
<span className={styles.badge.critical}>Critical</span>
|
||||
<span className={styles.badge.success}>Success</span>
|
||||
<span className={styles.badge.warning}>Warning</span>
|
||||
<span className={styles.badge.error}>Error</span>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✨ Neon Effects (CSS Classes)
|
||||
|
||||
```jsx
|
||||
<div className="neon-glow-blue">Blue glow on hover</div>
|
||||
<div className="neon-glow-pink">Pink glow on hover</div>
|
||||
<div className="neon-glow-soft">Soft glow</div>
|
||||
<div className="neon-border-blue">Blue neon border</div>
|
||||
<div className="neon-border-pink">Pink neon border</div>
|
||||
<span className="neon-text-blue">Blue neon text</span>
|
||||
<span className="neon-text-pink">Pink neon text</span>
|
||||
<Icon className="neon-icon" />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎭 Neon Animated Text
|
||||
|
||||
```jsx
|
||||
<span className="sign-inline">Task&Coffee</span>
|
||||
<span className="sign-pink-inline">Task&Coffee</span>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📐 Layout
|
||||
|
||||
```jsx
|
||||
<div className={styles.layout.container}>
|
||||
<aside className={styles.layout.sidebar}>Sidebar</aside>
|
||||
<main className={styles.layout.main}>
|
||||
<div className={styles.layout.content}>Content</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div className={styles.layout.gridCards}>Cards grid</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔤 Typography
|
||||
|
||||
```jsx
|
||||
<h1 className={styles.text.h1}>Heading 1</h1>
|
||||
<h2 className={styles.text.h2}>Heading 2</h2>
|
||||
<p className={styles.text.body}>Body text</p>
|
||||
<p className={styles.text.bodyMuted}>Muted text</p>
|
||||
<small className={styles.text.small}>Small text</small>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Utilities
|
||||
|
||||
```jsx
|
||||
// Glow effects
|
||||
<div className={styles.utility.glowBlue}>Blue glow</div>
|
||||
<div className={styles.utility.glowPink}>Pink glow</div>
|
||||
<div className={styles.utility.glowSoft}>Soft glow</div>
|
||||
|
||||
// Glass effect
|
||||
<div className={styles.utility.glass}>Glassmorphism</div>
|
||||
|
||||
// Transitions
|
||||
<div className={styles.utility.transition}>Smooth</div>
|
||||
<div className={styles.utility.transitionSlow}>Slow</div>
|
||||
|
||||
// Focus ring
|
||||
<button className={styles.utility.focusRing}>Accessible</button>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Цветовые переменные
|
||||
|
||||
### В CSS
|
||||
```css
|
||||
background: var(--color-background);
|
||||
color: var(--color-foreground);
|
||||
background: var(--color-card);
|
||||
color: var(--color-primary);
|
||||
border: 1px solid var(--color-border);
|
||||
```
|
||||
|
||||
### В Tailwind
|
||||
```jsx
|
||||
<div className="bg-background text-foreground">
|
||||
<div className="bg-card text-card-foreground">
|
||||
<div className="bg-primary text-primary-foreground">
|
||||
<div className="border border-border">
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Комбинирование
|
||||
|
||||
```jsx
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
<div className={cn(
|
||||
styles.card.task,
|
||||
"neon-glow-soft",
|
||||
isActive && "neon-border-blue"
|
||||
)}>
|
||||
Combined styles
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📏 Радиусы
|
||||
|
||||
- `rounded-lg` = **0.5rem** ← используем для кнопок и карточек
|
||||
- `rounded-xl` = 0.75rem
|
||||
- `rounded-2xl` = 1rem
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Полный пример компонента
|
||||
|
||||
```jsx
|
||||
import styles from '@/lib/styles';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
function TaskCard({ task, isToday }) {
|
||||
return (
|
||||
<div className={cn(
|
||||
styles.card.task,
|
||||
"neon-glow-soft",
|
||||
isToday && "neon-border-blue"
|
||||
)}>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className={styles.badge[task.priority]}>
|
||||
{task.priority}
|
||||
</span>
|
||||
<h3 className={styles.text.small}>{task.title}</h3>
|
||||
</div>
|
||||
<p className={styles.text.smallMuted}>{task.description}</p>
|
||||
<button className={styles.button.primaryNeon}>
|
||||
Complete
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🌈 Mirage Colors
|
||||
|
||||
| Name | Hex | Usage |
|
||||
|------|-----|-------|
|
||||
| mirage-950 | `#111928` | Background (darkest) |
|
||||
| mirage-900 | `#243756` | Cards |
|
||||
| mirage-800 | `#264066` | Muted elements |
|
||||
| mirage-700 | `#2a4a7a` | Secondary |
|
||||
| mirage-600 | `#335b96` | Elevated cards |
|
||||
| mirage-500 | `#4474b3` | Accent hover |
|
||||
| mirage-400 | `#6893c8` | Primary accent |
|
||||
| mirage-300 | `#9db8dc` | Muted text |
|
||||
| mirage-200 | `#cbd9ec` | Main text |
|
||||
| mirage-100 | `#e7edf7` | Card text |
|
||||
| mirage-50 | `#f4f6fb` | Lightest text |
|
||||
|
||||
---
|
||||
|
||||
## 💡 Tips
|
||||
|
||||
1. Используйте готовые стили из `styles.js`
|
||||
2. Комбинируйте с `cn()` для кастомизации
|
||||
3. Неон - только для акцентов!
|
||||
4. Всегда используйте CSS переменные
|
||||
5. `rounded-lg` для консистентности
|
||||
|
||||
**Полная документация:** См. `STYLE_GUIDE.md`
|
||||
|
||||
371
taskncoffee-app/docs/STYLE_GUIDE.md
Normal file
371
taskncoffee-app/docs/STYLE_GUIDE.md
Normal file
@@ -0,0 +1,371 @@
|
||||
# Task&Coffee Style Guide
|
||||
|
||||
> Complete guide with examples and best practices
|
||||
|
||||
**Quick reference?** See [STYLES_CHEATSHEET.md](./STYLES_CHEATSHEET.md)
|
||||
**Color details?** See [COLOR_PALETTE.md](./COLOR_PALETTE.md)
|
||||
**Back to main?** See [README.md](../README.md)
|
||||
|
||||
---
|
||||
|
||||
## 📦 Using Styles
|
||||
|
||||
### Import
|
||||
```javascript
|
||||
import styles from '@/lib/styles';
|
||||
import { cn } from '@/lib/utils';
|
||||
```
|
||||
|
||||
### Примеры использования
|
||||
|
||||
#### 1. Карточки (Cards)
|
||||
|
||||
```jsx
|
||||
// Filled card - основной вариант
|
||||
<div className={cardStyles.filled}>
|
||||
<h3>Card Title</h3>
|
||||
<p>Card content...</p>
|
||||
</div>
|
||||
|
||||
// Elevated card с тенью
|
||||
<div className={cardStyles.elevated}>
|
||||
<h3>Important Card</h3>
|
||||
</div>
|
||||
|
||||
// Task card с неоновым эффектом
|
||||
<div className={cardStyles.taskNeon}>
|
||||
<p>Task description</p>
|
||||
</div>
|
||||
|
||||
// Или используя cn helper
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
<div className={cn(cardStyles.filled, "additional-class")}>
|
||||
Content
|
||||
</div>
|
||||
```
|
||||
|
||||
#### 2. Кнопки (Buttons)
|
||||
|
||||
```jsx
|
||||
// Primary button
|
||||
<button className={buttonStyles.primary}>
|
||||
Submit
|
||||
</button>
|
||||
|
||||
// Primary с неоновым эффектом
|
||||
<button className={buttonStyles.primaryNeon}>
|
||||
Create Task
|
||||
</button>
|
||||
|
||||
// Secondary button
|
||||
<button className={buttonStyles.secondary}>
|
||||
Cancel
|
||||
</button>
|
||||
|
||||
// Ghost button
|
||||
<button className={buttonStyles.ghost}>
|
||||
Learn More
|
||||
</button>
|
||||
|
||||
// Icon button с неоновым эффектом
|
||||
<button className={buttonStyles.iconNeon}>
|
||||
<Icon />
|
||||
</button>
|
||||
```
|
||||
|
||||
#### 3. Layouts
|
||||
|
||||
```jsx
|
||||
// Dashboard layout
|
||||
<div className={layoutStyles.container}>
|
||||
<aside className={layoutStyles.sidebar}>
|
||||
{/* Sidebar content */}
|
||||
</aside>
|
||||
<main className={layoutStyles.main}>
|
||||
<div className={layoutStyles.content}>
|
||||
{/* Main content */}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
// Grid для карточек
|
||||
<div className={layoutStyles.gridCards}>
|
||||
<Card />
|
||||
<Card />
|
||||
<Card />
|
||||
</div>
|
||||
```
|
||||
|
||||
#### 4. Inputs
|
||||
|
||||
```jsx
|
||||
// Стандартный input
|
||||
<input
|
||||
type="text"
|
||||
className={inputStyles.default}
|
||||
placeholder="Enter text..."
|
||||
/>
|
||||
|
||||
// Input с неоновым фокусом
|
||||
<input
|
||||
type="text"
|
||||
className={inputStyles.neon}
|
||||
placeholder="Task name..."
|
||||
/>
|
||||
|
||||
// Search input
|
||||
<div className="relative">
|
||||
<SearchIcon className="absolute left-3 top-1/2 -translate-y-1/2" />
|
||||
<input
|
||||
type="search"
|
||||
className={inputStyles.search}
|
||||
placeholder="Search tasks..."
|
||||
/>
|
||||
</div>
|
||||
```
|
||||
|
||||
#### 5. Typography
|
||||
|
||||
```jsx
|
||||
// Headings
|
||||
<h1 className={textStyles.h1}>Main Title</h1>
|
||||
<h2 className={textStyles.h2}>Section Title</h2>
|
||||
|
||||
// Body text
|
||||
<p className={textStyles.body}>Regular text</p>
|
||||
<p className={textStyles.bodyMuted}>Muted text</p>
|
||||
|
||||
// Неоновый текст (используется с neon.css)
|
||||
<span className={cn(textStyles.neonBlue, "sign-inline")}>
|
||||
Task&
|
||||
</span>
|
||||
<span className={cn(textStyles.neonPink, "sign-pink-inline")}>
|
||||
Coffee
|
||||
</span>
|
||||
```
|
||||
|
||||
#### 6. Badges
|
||||
|
||||
```jsx
|
||||
// Priority badges
|
||||
<span className={badgeStyles.low}>Low</span>
|
||||
<span className={badgeStyles.medium}>Medium</span>
|
||||
<span className={badgeStyles.high}>High</span>
|
||||
<span className={badgeStyles.critical}>Critical</span>
|
||||
|
||||
// Status badges
|
||||
<span className={badgeStyles.success}>Completed</span>
|
||||
<span className={badgeStyles.warning}>In Progress</span>
|
||||
<span className={badgeStyles.error}>Failed</span>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✨ Неоновые эффекты
|
||||
|
||||
### CSS классы из neon.css
|
||||
|
||||
```jsx
|
||||
// Неоновое свечение при hover - голубое
|
||||
<div className="neon-glow-blue bg-card p-4 rounded-lg">
|
||||
Card with blue glow on hover
|
||||
</div>
|
||||
|
||||
// Неоновое свечение - розовое
|
||||
<div className="neon-glow-pink bg-card p-4 rounded-lg">
|
||||
Card with pink glow on hover
|
||||
</div>
|
||||
|
||||
// Мягкое свечение
|
||||
<button className="neon-glow-soft bg-primary px-4 py-2 rounded-lg">
|
||||
Subtle glow
|
||||
</button>
|
||||
|
||||
// Неоновая граница
|
||||
<div className="neon-border-blue p-4 rounded-lg">
|
||||
Border with neon effect
|
||||
</div>
|
||||
|
||||
// Неоновый текст (без анимации)
|
||||
<span className="neon-text-blue">
|
||||
Static neon text
|
||||
</span>
|
||||
|
||||
// Иконка с неоновым эффектом
|
||||
<Icon className="neon-icon" />
|
||||
```
|
||||
|
||||
### Анимированный неоновый текст
|
||||
|
||||
```jsx
|
||||
// Для заголовков и брендинга
|
||||
<div className="sign-inline">Coffee</div>
|
||||
<div className="sign-pink-inline">Task&</div>
|
||||
|
||||
// Для больших заголовков (fullscreen)
|
||||
<div className="sign">
|
||||
<span>Task&Coffee</span>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎭 Комбинирование стилей
|
||||
|
||||
### Пример: Карточка задачи с неоновым эффектом
|
||||
|
||||
```jsx
|
||||
import { cn } from '@/lib/utils';
|
||||
import { cardStyles, badgeStyles, textStyles } from '@/lib/styles';
|
||||
|
||||
function TaskCard({ task }) {
|
||||
return (
|
||||
<div className={cn(
|
||||
cardStyles.task,
|
||||
"neon-glow-soft",
|
||||
task.isToday && "neon-border-blue"
|
||||
)}>
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<span className={badgeStyles[task.priority]}>
|
||||
{task.priority}
|
||||
</span>
|
||||
<h3 className={textStyles.small}>
|
||||
{task.title}
|
||||
</h3>
|
||||
</div>
|
||||
<p className={textStyles.smallMuted}>
|
||||
{task.description}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Пример: Кнопка с неоновым эффектом и иконкой
|
||||
|
||||
```jsx
|
||||
import { PlusIcon } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { buttonStyles } from '@/lib/styles';
|
||||
|
||||
function CreateButton() {
|
||||
return (
|
||||
<button className={cn(
|
||||
buttonStyles.primaryNeon,
|
||||
"gap-2"
|
||||
)}>
|
||||
<PlusIcon className="w-4 h-4" />
|
||||
Create Task
|
||||
</button>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Миграция с dashboard.css на Tailwind
|
||||
|
||||
### До (dashboard.css):
|
||||
```css
|
||||
.dashboard-task-card {
|
||||
background: var(--color-card);
|
||||
padding: 0.75rem;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
||||
}
|
||||
```
|
||||
|
||||
### После (с использованием стилей):
|
||||
```jsx
|
||||
<div className={cardStyles.task}>
|
||||
{/* content */}
|
||||
</div>
|
||||
|
||||
// Или чистый Tailwind:
|
||||
<div className="bg-card p-3 rounded-lg shadow-sm">
|
||||
{/* content */}
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📐 Радиусы округления
|
||||
|
||||
Теперь все радиусы синхронизированы:
|
||||
- `rounded-sm` = `0.25rem` (4px)
|
||||
- `rounded-md` = `0.375rem` (6px)
|
||||
- `rounded-lg` = `0.5rem` (8px) ✅ **Используем для карточек и кнопок**
|
||||
- `rounded-xl` = `0.75rem` (12px)
|
||||
- `rounded-2xl` = `1rem` (16px)
|
||||
|
||||
Базовый радиус установлен в `--radius: 0.5rem` для консистентности с Material Design 3.
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Утилиты
|
||||
|
||||
### Neon Glow Utilities
|
||||
```javascript
|
||||
import { utilityStyles } from '@/lib/styles';
|
||||
|
||||
<div className={cn(cardStyles.filled, utilityStyles.glowBlue)}>
|
||||
Card with blue glow
|
||||
</div>
|
||||
```
|
||||
|
||||
### Glassmorphism
|
||||
```jsx
|
||||
<div className={cn(utilityStyles.glass, "p-6 rounded-lg")}>
|
||||
Glass effect card
|
||||
</div>
|
||||
```
|
||||
|
||||
### Focus Ring
|
||||
```jsx
|
||||
<button className={cn(
|
||||
buttonStyles.primary,
|
||||
utilityStyles.focusRing
|
||||
)}>
|
||||
Accessible button
|
||||
</button>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 Best Practices
|
||||
|
||||
1. **Используйте готовые стили** из `styles.js` для консистентности
|
||||
2. **Комбинируйте с cn()** для добавления кастомных классов
|
||||
3. **Неоновые эффекты** используйте умеренно - только для акцентов
|
||||
4. **Радиусы** - используйте `rounded-lg` для основных элементов
|
||||
5. **Цвета** - всегда используйте CSS переменные, не хардкодьте цвета
|
||||
6. **Accessibility** - не забывайте про `focusRing` для интерактивных элементов
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Быстрый старт
|
||||
|
||||
```jsx
|
||||
// 1. Импортируйте стили
|
||||
import styles from '@/lib/styles';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
// 2. Используйте в компонентах
|
||||
function MyComponent() {
|
||||
return (
|
||||
<div className={styles.layout.container}>
|
||||
<div className={styles.card.filled}>
|
||||
<h2 className={styles.text.h2}>Title</h2>
|
||||
<p className={styles.text.bodyMuted}>Description</p>
|
||||
<button className={styles.button.primaryNeon}>
|
||||
Action
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
Теперь у вас есть полная система стилей, объединяющая Mirage palette, Material Design 3 и неоновую эстетику! 🎉
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { getUserTasks } from '@/api/users.service';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { cn } from '@/lib/utils';
|
||||
import styles from '@/lib/styles';
|
||||
import { Plus } from 'lucide-react';
|
||||
|
||||
export default function Calendar() {
|
||||
const [tasksFromBackend, setTasksFromBackend] = useState([]);
|
||||
@@ -77,53 +80,108 @@ export default function Calendar() {
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="dashboard-surface-container">
|
||||
<div className={cn(styles.card.elevated, "flex-[3]")}>
|
||||
<div className="flex items-center justify-center p-8">
|
||||
<p className="text-lg">Loading tasks...</p>
|
||||
<p className={styles.text.body}>Loading tasks...</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="dashboard-surface-container">
|
||||
<div className="dashboard-week-grid">
|
||||
{daysOfWeek.map((day, index) => {
|
||||
<div className={cn(
|
||||
"bg-card/30 backdrop-blur-md p-6 rounded-2xl flex-[3]",
|
||||
styles.utility.transitionSlow
|
||||
)}>
|
||||
<div className="flex gap-4 h-full overflow-x-auto px-2">
|
||||
{daysOfWeek.map((day) => {
|
||||
const isToday = day.fullDate.toDateString() === today.toDateString();
|
||||
|
||||
return (
|
||||
<div
|
||||
key={day.name}
|
||||
className={`dashboard-day-column ${isToday ? 'today' : ''} dashboard-card-filled`}
|
||||
className={cn(
|
||||
"flex-1 min-w-[180px] flex flex-col rounded-lg p-4 transition-all duration-300",
|
||||
isToday
|
||||
? "bg-primary/10 border-2 border-primary neon-glow-soft"
|
||||
: "bg-background border border-border"
|
||||
)}
|
||||
>
|
||||
<div className="dashboard-day-header">
|
||||
<h3 className="dashboard-day-title">{day.name}</h3>
|
||||
<p className="dashboard-day-date">{day.month} {day.date}</p>
|
||||
{/* Header */}
|
||||
<div className="text-center pb-3 border-b border-border mb-3">
|
||||
<h3 className={cn(
|
||||
styles.text.small,
|
||||
"font-semibold mb-1",
|
||||
isToday && "text-primary font-bold"
|
||||
)}>
|
||||
{day.name}
|
||||
</h3>
|
||||
<p className={cn(
|
||||
styles.text.smallMuted,
|
||||
isToday && "text-primary font-semibold"
|
||||
)}>
|
||||
{day.month} {day.date}
|
||||
</p>
|
||||
</div>
|
||||
<div className="dashboard-tasks-container">
|
||||
{
|
||||
day.tasks.map((task) => (
|
||||
<div
|
||||
key={task.id}
|
||||
className={`dashboard-task-card ${task.completed ? 'completed' : ''} priority-${task.priority}`}
|
||||
>
|
||||
<div className="dashboard-task-header">
|
||||
<span className={`dashboard-task-priority ${task.priority}`}></span>
|
||||
<p className="dashboard-task-title">{task.title}</p>
|
||||
</div>
|
||||
|
||||
{/* Tasks */}
|
||||
<div className="flex-1 flex flex-col gap-2 overflow-y-auto pt-1">
|
||||
{day.tasks.map((task) => (
|
||||
<div
|
||||
key={task.id}
|
||||
className={cn(
|
||||
styles.card.task,
|
||||
"neon-glow-soft",
|
||||
task.completed && "opacity-60 line-through"
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
{/* Priority indicator */}
|
||||
<span
|
||||
className={cn(
|
||||
"w-1 h-1 rounded-full flex-shrink-0",
|
||||
task.priority === 'low' && "bg-green-500",
|
||||
task.priority === 'medium' && "bg-yellow-500",
|
||||
task.priority === 'high' && "bg-orange-500",
|
||||
task.priority === 'critical' && "bg-red-500"
|
||||
)}
|
||||
/>
|
||||
<p className={cn(styles.text.small, "flex-1")}>
|
||||
{task.title}
|
||||
</p>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
<Button variant="elevated" onClick={() => {
|
||||
console.log('Add task clicked');
|
||||
}}>
|
||||
+
|
||||
</Button>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* Empty state */}
|
||||
{day.tasks.length === 0 && (
|
||||
<p className={cn(
|
||||
styles.text.smallMuted,
|
||||
"text-center py-8 italic"
|
||||
)}>
|
||||
No tasks
|
||||
</p>
|
||||
)}
|
||||
|
||||
{/* Add button */}
|
||||
<button
|
||||
className={cn(
|
||||
styles.button.icon,
|
||||
"mt-2 w-full flex items-center justify-center gap-2",
|
||||
styles.utility.glowSoft
|
||||
)}
|
||||
onClick={() => {
|
||||
console.log('Add task clicked for', day.name);
|
||||
}}
|
||||
>
|
||||
<Plus className="w-4 h-4" />
|
||||
<span className="text-sm">Add Task</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -8,46 +8,80 @@
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
|
||||
color-scheme: light dark;
|
||||
color-scheme: dark;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background-color: #242424;
|
||||
background-color: #111928;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
--radius: 0.625rem;
|
||||
--background: #111928;
|
||||
--foreground: #bcbebc;
|
||||
--card: #243756;
|
||||
--card-foreground: oklch(0.13 0.028 261.692);
|
||||
--popover: oklch(1 0 0);
|
||||
--popover-foreground: oklch(0.13 0.028 261.692);
|
||||
--primary: oklch(0.21 0.034 264.665);
|
||||
--primary-foreground: oklch(0.985 0.002 247.839);
|
||||
--secondary: oklch(0.967 0.003 264.542);
|
||||
--secondary-foreground: oklch(0.21 0.034 264.665);
|
||||
--muted: oklch(0.967 0.003 264.542);
|
||||
--muted-foreground: oklch(0.551 0.027 264.364);
|
||||
--accent: oklch(0.967 0.003 264.542);
|
||||
--accent-foreground: oklch(0.21 0.034 264.665);
|
||||
--destructive: oklch(0.577 0.245 27.325);
|
||||
--border: oklch(0.928 0.006 264.531);
|
||||
--input: oklch(0.928 0.006 264.531);
|
||||
--ring: oklch(0.707 0.022 261.325);
|
||||
--chart-1: oklch(0.646 0.222 41.116);
|
||||
--chart-2: oklch(0.6 0.118 184.704);
|
||||
--chart-3: oklch(0.398 0.07 227.392);
|
||||
--chart-4: oklch(0.828 0.189 84.429);
|
||||
--chart-5: oklch(0.769 0.188 70.08);
|
||||
--sidebar: oklch(0.985 0.002 247.839);
|
||||
--sidebar-foreground: oklch(0.13 0.028 261.692);
|
||||
--sidebar-primary: oklch(0.21 0.034 264.665);
|
||||
--sidebar-primary-foreground: oklch(0.985 0.002 247.839);
|
||||
--sidebar-accent: oklch(0.967 0.003 264.542);
|
||||
--sidebar-accent-foreground: oklch(0.21 0.034 264.665);
|
||||
--sidebar-border: oklch(0.928 0.006 264.531);
|
||||
--sidebar-ring: oklch(0.707 0.022 261.325);
|
||||
|
||||
/* Mirage Palette Colors */
|
||||
--mirage-50: #f4f6fb;
|
||||
--mirage-100: #e7edf7;
|
||||
--mirage-200: #cbd9ec;
|
||||
--mirage-300: #9db8dc;
|
||||
--mirage-400: #6893c8;
|
||||
--mirage-500: #4474b3;
|
||||
--mirage-600: #335b96;
|
||||
--mirage-700: #2a4a7a;
|
||||
--mirage-800: #264066;
|
||||
--mirage-900: #243756;
|
||||
--mirage-950: #111928;
|
||||
|
||||
/* Neon Accent Colors */
|
||||
--neon-blue: #c6e2ff;
|
||||
--neon-blue-glow: rgba(30, 132, 242, 0.6);
|
||||
--neon-pink: #ffc5ec;
|
||||
--neon-pink-glow: rgba(255, 20, 147, 0.6);
|
||||
|
||||
/* Material Design 3 Semantic Colors with Mirage Palette */
|
||||
--radius: 0.5rem;
|
||||
--background: #111928; /* mirage-950 - самый темный для фона */
|
||||
--foreground: #cbd9ec; /* mirage-200 - светлый текст */
|
||||
|
||||
--card: #243756; /* mirage-900 - карточки темнее фона */
|
||||
--card-foreground: #e7edf7; /* mirage-100 - текст на карточках */
|
||||
|
||||
--popover: #264066; /* mirage-800 - всплывающие элементы */
|
||||
--popover-foreground: #e7edf7; /* mirage-100 */
|
||||
|
||||
--primary: #6893c8; /* mirage-400 - основной акцент (средний синий) */
|
||||
--primary-foreground: #111928; /* mirage-950 - темный текст на акценте */
|
||||
|
||||
--secondary: #2a4a7a; /* mirage-700 - вторичный цвет */
|
||||
--secondary-foreground: #e7edf7; /* mirage-100 */
|
||||
|
||||
--muted: #264066; /* mirage-800 - приглушенные элементы */
|
||||
--muted-foreground: #9db8dc; /* mirage-300 - приглушенный текст */
|
||||
|
||||
--accent: #4474b3; /* mirage-500 - акцент при наведении */
|
||||
--accent-foreground: #f4f6fb; /* mirage-50 */
|
||||
|
||||
--destructive: #ef4444; /* красный для удаления */
|
||||
--destructive-foreground: #f4f6fb;
|
||||
|
||||
--border: rgba(157, 184, 220, 0.15); /* mirage-300 с прозрачностью */
|
||||
--input: rgba(157, 184, 220, 0.2); /* чуть плотнее для полей ввода */
|
||||
--ring: #6893c8; /* mirage-400 - фокус как primary */
|
||||
|
||||
/* Sidebar */
|
||||
--sidebar: #111928; /* mirage-950 - как фон */
|
||||
--sidebar-foreground: #cbd9ec; /* mirage-200 */
|
||||
--sidebar-primary: #6893c8; /* mirage-400 */
|
||||
--sidebar-primary-foreground: #111928;
|
||||
--sidebar-accent: #335b96; /* mirage-600 */
|
||||
--sidebar-accent-foreground: #e7edf7;
|
||||
--sidebar-border: rgba(157, 184, 220, 0.1);
|
||||
--sidebar-ring: #6893c8;
|
||||
|
||||
/* Chart Colors - используем палитру */
|
||||
--chart-1: #6893c8; /* mirage-400 */
|
||||
--chart-2: #4474b3; /* mirage-500 */
|
||||
--chart-3: #335b96; /* mirage-600 */
|
||||
--chart-4: #9db8dc; /* mirage-300 */
|
||||
--chart-5: #2a4a7a; /* mirage-700 */
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
@@ -89,37 +123,39 @@
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: oklch(0.13 0.028 261.692);
|
||||
--foreground: oklch(0.985 0.002 247.839);
|
||||
--card: oklch(0.21 0.034 264.665);
|
||||
--card-foreground: oklch(0.985 0.002 247.839);
|
||||
--popover: oklch(0.21 0.034 264.665);
|
||||
--popover-foreground: oklch(0.985 0.002 247.839);
|
||||
--primary: oklch(0.928 0.006 264.531);
|
||||
--primary-foreground: oklch(0.21 0.034 264.665);
|
||||
--secondary: oklch(0.278 0.033 256.848);
|
||||
--secondary-foreground: oklch(0.985 0.002 247.839);
|
||||
--muted: oklch(0.278 0.033 256.848);
|
||||
--muted-foreground: oklch(0.707 0.022 261.325);
|
||||
--accent: oklch(0.278 0.033 256.848);
|
||||
--accent-foreground: oklch(0.985 0.002 247.839);
|
||||
--destructive: oklch(0.704 0.191 22.216);
|
||||
--border: oklch(1 0 0 / 10%);
|
||||
--input: oklch(1 0 0 / 15%);
|
||||
--ring: oklch(0.551 0.027 264.364);
|
||||
--chart-1: oklch(0.488 0.243 264.376);
|
||||
--chart-2: oklch(0.696 0.17 162.48);
|
||||
--chart-3: oklch(0.769 0.188 70.08);
|
||||
--chart-4: oklch(0.627 0.265 303.9);
|
||||
--chart-5: oklch(0.645 0.246 16.439);
|
||||
--sidebar: oklch(0.21 0.034 264.665);
|
||||
--sidebar-foreground: oklch(0.985 0.002 247.839);
|
||||
--sidebar-primary: oklch(0.488 0.243 264.376);
|
||||
--sidebar-primary-foreground: oklch(0.985 0.002 247.839);
|
||||
--sidebar-accent: oklch(0.278 0.033 256.848);
|
||||
--sidebar-accent-foreground: oklch(0.985 0.002 247.839);
|
||||
--sidebar-border: oklch(1 0 0 / 10%);
|
||||
--sidebar-ring: oklch(0.551 0.027 264.364);
|
||||
/* Темная тема немного светлее основной (для toggle режима) */
|
||||
--background: #243756; /* mirage-900 */
|
||||
--foreground: #e7edf7; /* mirage-100 */
|
||||
--card: #2a4a7a; /* mirage-700 */
|
||||
--card-foreground: #f4f6fb; /* mirage-50 */
|
||||
--popover: #264066; /* mirage-800 */
|
||||
--popover-foreground: #e7edf7;
|
||||
--primary: #9db8dc; /* mirage-300 - светлее для контраста */
|
||||
--primary-foreground: #111928;
|
||||
--secondary: #335b96; /* mirage-600 */
|
||||
--secondary-foreground: #f4f6fb;
|
||||
--muted: #264066;
|
||||
--muted-foreground: #9db8dc;
|
||||
--accent: #6893c8; /* mirage-400 */
|
||||
--accent-foreground: #111928;
|
||||
--destructive: #ef4444;
|
||||
--destructive-foreground: #f4f6fb;
|
||||
--border: rgba(157, 184, 220, 0.2);
|
||||
--input: rgba(157, 184, 220, 0.25);
|
||||
--ring: #9db8dc;
|
||||
--chart-1: #9db8dc;
|
||||
--chart-2: #6893c8;
|
||||
--chart-3: #4474b3;
|
||||
--chart-4: #cbd9ec;
|
||||
--chart-5: #335b96;
|
||||
--sidebar: #243756;
|
||||
--sidebar-foreground: #e7edf7;
|
||||
--sidebar-primary: #9db8dc;
|
||||
--sidebar-primary-foreground: #111928;
|
||||
--sidebar-accent: #4474b3;
|
||||
--sidebar-accent-foreground: #f4f6fb;
|
||||
--sidebar-border: rgba(157, 184, 220, 0.15);
|
||||
--sidebar-ring: #9db8dc;
|
||||
}
|
||||
|
||||
@layer base {
|
||||
|
||||
168
taskncoffee-app/src/lib/styles.js
Normal file
168
taskncoffee-app/src/lib/styles.js
Normal file
@@ -0,0 +1,168 @@
|
||||
/**
|
||||
* Tailwind CSS Class Presets for Task&Coffee
|
||||
* Material Design 3 + Neon Aesthetic
|
||||
* Using Mirage Color Palette
|
||||
*/
|
||||
|
||||
// Card Styles - Material Design 3 Variants
|
||||
export const cardStyles = {
|
||||
// Filled card - основной вариант для большинства карточек
|
||||
filled: "bg-card text-card-foreground p-6 rounded-lg shadow-sm",
|
||||
|
||||
// Elevated card - карточки с эффектом поднятия
|
||||
elevated: "bg-card text-card-foreground p-6 rounded-lg shadow-lg hover:shadow-xl transition-all duration-300",
|
||||
|
||||
// Outlined card - карточки с границей
|
||||
outlined: "bg-background border-2 border-border text-foreground p-6 rounded-lg",
|
||||
|
||||
// Task card - компактные карточки для задач
|
||||
task: "bg-card text-card-foreground p-3 rounded-lg shadow-sm hover:shadow-md hover:-translate-y-0.5 transition-all duration-200",
|
||||
|
||||
// Task card with neon accent
|
||||
taskNeon: "bg-card text-card-foreground p-3 rounded-lg shadow-sm hover:shadow-[0_0_15px_rgba(104,147,200,0.3)] hover:-translate-y-0.5 transition-all duration-200",
|
||||
};
|
||||
|
||||
// Button Styles
|
||||
export const buttonStyles = {
|
||||
// Primary button - основные действия
|
||||
primary: "bg-primary text-primary-foreground hover:bg-primary/90 px-4 py-2 rounded-lg font-medium transition-all duration-200 shadow-sm hover:shadow-md",
|
||||
|
||||
// Primary with neon glow
|
||||
primaryNeon: "bg-primary text-primary-foreground hover:bg-primary/90 px-4 py-2 rounded-lg font-medium transition-all duration-200 hover:shadow-[0_0_20px_rgba(104,147,200,0.5)]",
|
||||
|
||||
// Secondary button - вторичные действия
|
||||
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 px-4 py-2 rounded-lg font-medium transition-all duration-200",
|
||||
|
||||
// Outline button - менее важные действия
|
||||
outline: "border-2 border-input bg-background text-foreground hover:bg-accent hover:text-accent-foreground px-4 py-2 rounded-lg font-medium transition-all duration-200",
|
||||
|
||||
// Ghost button - минималистичные кнопки
|
||||
ghost: "text-foreground hover:bg-accent hover:text-accent-foreground px-4 py-2 rounded-lg font-medium transition-all duration-200",
|
||||
|
||||
// Destructive button - опасные действия
|
||||
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90 px-4 py-2 rounded-lg font-medium transition-all duration-200 shadow-sm hover:shadow-md",
|
||||
|
||||
// Icon button
|
||||
icon: "p-2 rounded-lg hover:bg-accent transition-all duration-200",
|
||||
|
||||
// Icon button with neon effect
|
||||
iconNeon: "p-2 rounded-lg hover:bg-accent transition-all duration-200 hover:shadow-[0_0_15px_rgba(104,147,200,0.4)]",
|
||||
};
|
||||
|
||||
// Layout Styles
|
||||
export const layoutStyles = {
|
||||
// Main container
|
||||
container: "flex min-h-screen bg-background text-foreground",
|
||||
|
||||
// Sidebar/Navigation rail
|
||||
sidebar: "w-20 bg-sidebar border-r border-sidebar-border flex flex-col items-center py-4 gap-4",
|
||||
|
||||
// Main content area
|
||||
main: "flex-1 p-6 bg-background flex flex-col",
|
||||
|
||||
// Content wrapper with max width
|
||||
content: "max-w-7xl mx-auto w-full flex flex-1 flex-col gap-6",
|
||||
|
||||
// Grid layouts
|
||||
gridCards: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",
|
||||
gridTasks: "grid grid-cols-1 gap-3",
|
||||
};
|
||||
|
||||
// Input Styles
|
||||
export const inputStyles = {
|
||||
// Standard input
|
||||
default: "w-full px-4 py-2 bg-background border border-input rounded-lg text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring transition-all duration-200",
|
||||
|
||||
// Input with neon focus effect
|
||||
neon: "w-full px-4 py-2 bg-background border border-input rounded-lg text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:shadow-[0_0_15px_rgba(104,147,200,0.3)] transition-all duration-200",
|
||||
|
||||
// Search input
|
||||
search: "w-full px-4 py-2 pl-10 bg-background border border-input rounded-lg text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring transition-all duration-200",
|
||||
};
|
||||
|
||||
// Text Styles
|
||||
export const textStyles = {
|
||||
// Headings
|
||||
h1: "text-4xl font-bold text-foreground",
|
||||
h2: "text-3xl font-semibold text-foreground",
|
||||
h3: "text-2xl font-semibold text-foreground",
|
||||
h4: "text-xl font-semibold text-foreground",
|
||||
|
||||
// Body text
|
||||
body: "text-base text-foreground",
|
||||
bodyMuted: "text-base text-muted-foreground",
|
||||
|
||||
// Small text
|
||||
small: "text-sm text-foreground",
|
||||
smallMuted: "text-sm text-muted-foreground",
|
||||
|
||||
// Neon text (to be combined with neon.css animations)
|
||||
neonBlue: "text-[#c6e2ff]",
|
||||
neonPink: "text-[#ffc5ec]",
|
||||
};
|
||||
|
||||
// Badge/Chip Styles
|
||||
export const badgeStyles = {
|
||||
// Default badge
|
||||
default: "inline-flex items-center px-2.5 py-0.5 rounded-md text-xs font-medium bg-primary/20 text-primary border border-primary/30",
|
||||
|
||||
// Priority badges
|
||||
low: "inline-flex items-center px-2.5 py-0.5 rounded-md text-xs font-medium bg-green-500/20 text-green-400 border border-green-500/30",
|
||||
medium: "inline-flex items-center px-2.5 py-0.5 rounded-md text-xs font-medium bg-yellow-500/20 text-yellow-400 border border-yellow-500/30",
|
||||
high: "inline-flex items-center px-2.5 py-0.5 rounded-md text-xs font-medium bg-orange-500/20 text-orange-400 border border-orange-500/30",
|
||||
critical: "inline-flex items-center px-2.5 py-0.5 rounded-md text-xs font-medium bg-red-500/20 text-red-400 border border-red-500/30",
|
||||
|
||||
// Status badges
|
||||
success: "inline-flex items-center px-2.5 py-0.5 rounded-md text-xs font-medium bg-green-500/20 text-green-400 border border-green-500/30",
|
||||
warning: "inline-flex items-center px-2.5 py-0.5 rounded-md text-xs font-medium bg-yellow-500/20 text-yellow-400 border border-yellow-500/30",
|
||||
error: "inline-flex items-center px-2.5 py-0.5 rounded-md text-xs font-medium bg-red-500/20 text-red-400 border border-red-500/30",
|
||||
info: "inline-flex items-center px-2.5 py-0.5 rounded-md text-xs font-medium bg-blue-500/20 text-blue-400 border border-blue-500/30",
|
||||
};
|
||||
|
||||
// Utility Styles
|
||||
export const utilityStyles = {
|
||||
// Neon glow effects (for hover states)
|
||||
glowBlue: "hover:shadow-[0_0_20px_rgba(104,147,200,0.6)]",
|
||||
glowPink: "hover:shadow-[0_0_20px_rgba(255,20,147,0.6)]",
|
||||
glowSoft: "hover:shadow-[0_0_15px_rgba(104,147,200,0.3)]",
|
||||
|
||||
// Glassmorphism effect
|
||||
glass: "bg-card/50 backdrop-blur-md border border-border/50",
|
||||
|
||||
// Smooth transitions
|
||||
transition: "transition-all duration-200 ease-in-out",
|
||||
transitionSlow: "transition-all duration-300 ease-in-out",
|
||||
|
||||
// Focus visible states
|
||||
focusRing: "focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:ring-offset-background",
|
||||
};
|
||||
|
||||
// Complete component compositions
|
||||
export const componentStyles = {
|
||||
// Day column in calendar
|
||||
dayColumn: "flex-1 min-w-[180px] flex flex-col bg-background rounded-lg p-4 transition-all duration-300",
|
||||
dayColumnToday: "flex-1 min-w-[180px] flex flex-col bg-primary/10 border-2 border-primary rounded-lg p-4 transition-all duration-300",
|
||||
|
||||
// Avatar
|
||||
avatar: "w-14 h-14 rounded-lg overflow-hidden",
|
||||
avatarLarge: "w-20 h-20 rounded-xl overflow-hidden",
|
||||
|
||||
// Divider
|
||||
divider: "h-px bg-border w-full",
|
||||
dividerVertical: "w-px bg-border h-full",
|
||||
};
|
||||
|
||||
// Export all styles as a single object for convenience
|
||||
export const styles = {
|
||||
card: cardStyles,
|
||||
button: buttonStyles,
|
||||
layout: layoutStyles,
|
||||
input: inputStyles,
|
||||
text: textStyles,
|
||||
badge: badgeStyles,
|
||||
utility: utilityStyles,
|
||||
component: componentStyles,
|
||||
};
|
||||
|
||||
export default styles;
|
||||
|
||||
@@ -135,4 +135,87 @@
|
||||
0 0 11px rgba(30,132,242,0.78),
|
||||
0 0 16px rgba(30,132,242,0.92);
|
||||
}
|
||||
}
|
||||
|
||||
/*-- Utility Neon Classes for Cards and Buttons --*/
|
||||
|
||||
/* Neon glow on hover - blue */
|
||||
.neon-glow-blue {
|
||||
transition: box-shadow 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.neon-glow-blue:hover {
|
||||
box-shadow: 0 0 20px rgba(104, 147, 200, 0.6),
|
||||
0 0 30px rgba(104, 147, 200, 0.4),
|
||||
0 0 40px rgba(104, 147, 200, 0.2);
|
||||
}
|
||||
|
||||
/* Neon glow on hover - pink */
|
||||
.neon-glow-pink {
|
||||
transition: box-shadow 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.neon-glow-pink:hover {
|
||||
box-shadow: 0 0 20px rgba(255, 20, 147, 0.6),
|
||||
0 0 30px rgba(255, 20, 147, 0.4),
|
||||
0 0 40px rgba(255, 20, 147, 0.2);
|
||||
}
|
||||
|
||||
/* Soft neon glow - for subtle effects */
|
||||
.neon-glow-soft {
|
||||
transition: box-shadow 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.neon-glow-soft:hover {
|
||||
box-shadow: 0 0 15px rgba(104, 147, 200, 0.3),
|
||||
0 0 25px rgba(104, 147, 200, 0.2);
|
||||
}
|
||||
|
||||
/* Neon border - blue */
|
||||
.neon-border-blue {
|
||||
border: 1px solid rgba(104, 147, 200, 0.4);
|
||||
box-shadow: 0 0 10px rgba(104, 147, 200, 0.2);
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.neon-border-blue:hover {
|
||||
border-color: rgba(104, 147, 200, 0.8);
|
||||
box-shadow: 0 0 15px rgba(104, 147, 200, 0.4),
|
||||
0 0 25px rgba(104, 147, 200, 0.2);
|
||||
}
|
||||
|
||||
/* Neon border - pink */
|
||||
.neon-border-pink {
|
||||
border: 1px solid rgba(255, 20, 147, 0.4);
|
||||
box-shadow: 0 0 10px rgba(255, 20, 147, 0.2);
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.neon-border-pink:hover {
|
||||
border-color: rgba(255, 20, 147, 0.8);
|
||||
box-shadow: 0 0 15px rgba(255, 20, 147, 0.4),
|
||||
0 0 25px rgba(255, 20, 147, 0.2);
|
||||
}
|
||||
|
||||
/* Text with subtle neon effect (non-animated) */
|
||||
.neon-text-blue {
|
||||
color: #c6e2ff;
|
||||
text-shadow: 0 0 10px rgba(30, 132, 242, 0.5),
|
||||
0 0 20px rgba(30, 132, 242, 0.3);
|
||||
}
|
||||
|
||||
.neon-text-pink {
|
||||
color: #ffc5ec;
|
||||
text-shadow: 0 0 10px rgba(255, 20, 147, 0.5),
|
||||
0 0 20px rgba(255, 20, 147, 0.3);
|
||||
}
|
||||
|
||||
/* Icon with neon glow on hover */
|
||||
.neon-icon {
|
||||
transition: filter 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.neon-icon:hover {
|
||||
filter: drop-shadow(0 0 8px rgba(104, 147, 200, 0.8))
|
||||
drop-shadow(0 0 15px rgba(104, 147, 200, 0.5));
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
'use client';
|
||||
import { useState, useEffect } from 'react';
|
||||
import '../neon.css';
|
||||
import './dashboard.css';
|
||||
import { MenuDock } from '@/components/ui/shadcn-io/menu-dock';
|
||||
import { Home, Settings, Bell } from 'lucide-react';
|
||||
import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar';
|
||||
import { jwtexp } from '@/lib/utils';
|
||||
import { jwtexp, cn } from '@/lib/utils';
|
||||
import Calendar from '@/components/Calendar';
|
||||
import { useNavigate } from "react-router";
|
||||
import styles from '@/lib/styles';
|
||||
|
||||
const menuItems = [
|
||||
{ label: 'home', icon: Home, onClick: () => console.log('Home clicked') },
|
||||
@@ -66,9 +66,9 @@ export default function Dashboard() {
|
||||
|
||||
if (loading || authError) {
|
||||
return (
|
||||
<div className="dashboard-container">
|
||||
<div className={styles.layout.container}>
|
||||
<div className="flex items-center justify-center min-h-screen">
|
||||
<p className="text-xl">
|
||||
<p className={styles.text.h3}>
|
||||
{loading ? 'Loading dashboard...' : 'Redirecting...'}
|
||||
</p>
|
||||
</div>
|
||||
@@ -77,14 +77,14 @@ export default function Dashboard() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="dashboard-container">
|
||||
<div className={styles.layout.container}>
|
||||
{/* Navigation Rail - Material Design 3 */}
|
||||
<aside className="dashboard-sidebar">
|
||||
{/* Avatar with large M3 container */}
|
||||
<div className="dashboard-avatar-container">
|
||||
<Avatar className="dashboard-avatar">
|
||||
<aside className={styles.layout.sidebar}>
|
||||
{/* Avatar */}
|
||||
<div className="mb-2">
|
||||
<Avatar className={styles.component.avatar}>
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
||||
<AvatarFallback className="dashboard-avatar-fallback">CN</AvatarFallback>
|
||||
<AvatarFallback className="rounded-lg">CN</AvatarFallback>
|
||||
</Avatar>
|
||||
</div>
|
||||
|
||||
@@ -99,15 +99,19 @@ export default function Dashboard() {
|
||||
</aside>
|
||||
|
||||
{/* Main Content Area */}
|
||||
<main className="dashboard-main">
|
||||
<div className="dashboard-content">
|
||||
<h1 className="dashboard-header">
|
||||
<main className={styles.layout.main}>
|
||||
<div className={styles.layout.content}>
|
||||
{/* Header with neon text */}
|
||||
<h1 className={cn(styles.text.h1, "mb-6")}>
|
||||
<span className="sign-pink-inline">Task&</span>
|
||||
<span className="sign-inline">Coffee</span>
|
||||
</h1>
|
||||
|
||||
{/* Calendar component */}
|
||||
<Calendar />
|
||||
|
||||
<div className="dashboard-spacer"></div>
|
||||
{/* Spacer */}
|
||||
<div className="flex-[0.5]"></div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
@@ -1,265 +0,0 @@
|
||||
/* Dashboard Layout */
|
||||
.dashboard-container {
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
background: var(--color-background);
|
||||
}
|
||||
|
||||
/* Navigation Rail - Material Design 3 */
|
||||
.dashboard-sidebar {
|
||||
width: 80px;
|
||||
background: color-mix(in srgb, var(--color-card) 50%, transparent);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.dashboard-avatar-container {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.dashboard-avatar {
|
||||
width: 3.5rem;
|
||||
height: 3.5rem;
|
||||
border-radius: 1rem;
|
||||
}
|
||||
|
||||
.dashboard-avatar-fallback {
|
||||
border-radius: 1rem;
|
||||
}
|
||||
|
||||
/* Main Content Area */
|
||||
.dashboard-main {
|
||||
flex: 1;
|
||||
padding: 1.5rem;
|
||||
background: var(--color-background);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.dashboard-content {
|
||||
max-width: 90rem;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
.dashboard-header {
|
||||
font-size: 1.875rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Material Design 3 Cards Grid */
|
||||
.dashboard-cards-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.dashboard-cards-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.dashboard-cards-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
/* M3 Card Variants */
|
||||
.dashboard-card-filled {
|
||||
background: var(--color-card);
|
||||
padding: 1.5rem;
|
||||
border-radius: 1.5rem;
|
||||
box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
||||
}
|
||||
|
||||
.dashboard-card-elevated {
|
||||
background: var(--color-card);
|
||||
padding: 1.5rem;
|
||||
border-radius: 1.5rem;
|
||||
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1);
|
||||
transition: box-shadow 0.3s;
|
||||
}
|
||||
|
||||
.dashboard-card-elevated:hover {
|
||||
box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1);
|
||||
}
|
||||
|
||||
.dashboard-card-outlined {
|
||||
background: var(--color-background);
|
||||
border: 2px solid var(--color-border);
|
||||
padding: 1.5rem;
|
||||
border-radius: 1.5rem;
|
||||
}
|
||||
|
||||
.dashboard-card-title {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.dashboard-card-text {
|
||||
color: var(--color-muted-foreground);
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
/* Surface Container */
|
||||
.dashboard-surface-container {
|
||||
background: color-mix(in srgb, var(--color-card) 30%, transparent);
|
||||
padding: 1.5rem;
|
||||
border-radius: 1.5rem;
|
||||
flex: 3;
|
||||
}
|
||||
|
||||
.dashboard-surface-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.dashboard-surface-text {
|
||||
color: var(--color-muted-foreground);
|
||||
}
|
||||
|
||||
/* Spacer */
|
||||
.dashboard-spacer {
|
||||
flex: 0.5;
|
||||
}
|
||||
|
||||
/* Weekly View */
|
||||
.dashboard-week-grid {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
height: 100%;
|
||||
overflow-x: auto;
|
||||
padding: 0.6rem;
|
||||
}
|
||||
|
||||
.dashboard-day-column {
|
||||
flex: 1;
|
||||
min-width: 180px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--color-background);
|
||||
border-radius: 1rem;
|
||||
padding: 1rem;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
}
|
||||
|
||||
.dashboard-day-column.today {
|
||||
background: color-mix(in srgb, var(--color-primary) 10%, transparent);
|
||||
border: 2px solid var(--color-primary);
|
||||
}
|
||||
|
||||
.dashboard-day-header {
|
||||
text-align: center;
|
||||
padding-bottom: 0.75rem;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.dashboard-day-title {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
margin: 0 0 0.25rem 0;
|
||||
}
|
||||
|
||||
.dashboard-day-date {
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-muted-foreground);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.dashboard-day-column.today .dashboard-day-title {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.dashboard-day-column.today .dashboard-day-date {
|
||||
color: var(--color-primary);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.dashboard-tasks-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
overflow-y: auto;
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.dashboard-task-card {
|
||||
background: var(--color-card);
|
||||
padding: 0.75rem;
|
||||
border-radius: 0.625rem;
|
||||
box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
||||
font-size: 0.875rem;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.dashboard-task-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1);
|
||||
}
|
||||
|
||||
.dashboard-task-card.completed {
|
||||
opacity: 0.6;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.dashboard-task-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.dashboard-task-priority {
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.dashboard-task-priority.low {
|
||||
background: #10b981; /* green */
|
||||
}
|
||||
|
||||
.dashboard-task-priority.medium {
|
||||
background: #f59e0b; /* orange */
|
||||
}
|
||||
|
||||
.dashboard-task-priority.high {
|
||||
background: #ef4444; /* red */
|
||||
}
|
||||
|
||||
.dashboard-task-priority.critical {
|
||||
background: #a90404; /* red */
|
||||
}
|
||||
|
||||
.dashboard-task-title {
|
||||
margin: 0;
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-foreground);
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.dashboard-no-tasks {
|
||||
color: var(--color-muted-foreground);
|
||||
font-size: 0.875rem;
|
||||
text-align: center;
|
||||
padding: 2rem 0;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user