memory-journal-mcp 7.3.0 → 7.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -63
- package/dist/{chunk-CHWIPVQN.js → chunk-5ZA77VUW.js} +592 -86
- package/dist/{chunk-ZJJD2F5T.js → chunk-P5V2VY6N.js} +239 -40
- package/dist/cli.js +8 -3
- package/dist/index.d.ts +17 -2
- package/dist/index.js +2 -2
- package/dist/{tools-MNMGDTQI.js → tools-WZUENKJ6.js} +1 -1
- package/package.json +1 -1
- package/skills/README.md +5 -1
- package/skills/docker/SKILL.md +262 -0
- package/skills/github-actions/SKILL.md +315 -0
- package/skills/package.json +5 -1
- package/skills/python/SKILL.md +257 -0
- package/skills/tailwind-css/SKILL.md +268 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: python
|
|
3
|
+
description: |
|
|
4
|
+
Master modern Python development with production-grade tooling and idioms.
|
|
5
|
+
Use when writing Python code, configuring project structure, managing
|
|
6
|
+
dependencies with uv, linting with ruff, adding type hints, writing pytest
|
|
7
|
+
tests, or building FastAPI/Django/Flask applications. Triggers on "Python",
|
|
8
|
+
"FastAPI", "Django", "Flask", "pytest", "uv", "ruff", "pyproject.toml".
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Python Engineering Standards
|
|
12
|
+
|
|
13
|
+
This skill codifies 2026 Python best practices — modern tooling (`uv`, `ruff`), strict typing, and idiomatic patterns that produce maintainable, performant code.
|
|
14
|
+
|
|
15
|
+
## 1. Project Setup & Structure
|
|
16
|
+
|
|
17
|
+
### Tooling: `uv` (Not pip/pipenv/poetry)
|
|
18
|
+
|
|
19
|
+
`uv` is the standard package manager for Python in 2026. It replaces pip, pipenv, and poetry with a single, fast Rust binary.
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
uv init <project-name> # Initialize a new project
|
|
23
|
+
uv add <package> # Add a dependency
|
|
24
|
+
uv add --dev <package> # Add a dev dependency
|
|
25
|
+
uv run <command> # Run a command in the project's venv
|
|
26
|
+
uv sync # Install all deps from uv.lock
|
|
27
|
+
uv python install 3.13 # Install a specific Python version
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
- **ALWAYS** commit both `pyproject.toml` AND `uv.lock` to version control.
|
|
31
|
+
- **NEVER** use `requirements.txt` for new projects — it is a legacy pattern.
|
|
32
|
+
- **NEVER** use `pip install` directly — use `uv add` to keep the lock file in sync.
|
|
33
|
+
|
|
34
|
+
### Directory Layout: `src/` Layout
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
my-project/
|
|
38
|
+
├── .python-version # Pin Python version (e.g., 3.13)
|
|
39
|
+
├── pyproject.toml # Single source of truth for config
|
|
40
|
+
├── uv.lock # Deterministic lock file
|
|
41
|
+
├── src/
|
|
42
|
+
│ └── my_package/
|
|
43
|
+
│ ├── __init__.py
|
|
44
|
+
│ ├── main.py
|
|
45
|
+
│ └── models.py
|
|
46
|
+
└── tests/
|
|
47
|
+
├── __init__.py
|
|
48
|
+
├── conftest.py # Shared fixtures
|
|
49
|
+
└── test_main.py
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
- **Use `src/` layout** for packages and production apps — it prevents tests from accidentally importing the local source instead of the installed package.
|
|
53
|
+
- **Group by domain**, not file type — prefer `users/`, `billing/`, `auth/` over `models/`, `utils/`, `services/`.
|
|
54
|
+
- **Use `kebab-case`** for directory names, `snake_case` for Python modules.
|
|
55
|
+
|
|
56
|
+
### `pyproject.toml` Configuration (PEP 621)
|
|
57
|
+
|
|
58
|
+
```toml
|
|
59
|
+
[project]
|
|
60
|
+
name = "my-package"
|
|
61
|
+
version = "0.1.0"
|
|
62
|
+
requires-python = ">=3.12"
|
|
63
|
+
dependencies = [
|
|
64
|
+
"httpx>=0.27",
|
|
65
|
+
"pydantic>=2.0",
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
[project.optional-dependencies]
|
|
69
|
+
dev = ["pytest>=8.0", "ruff>=0.8", "mypy>=1.13"]
|
|
70
|
+
|
|
71
|
+
[tool.ruff]
|
|
72
|
+
target-version = "py312"
|
|
73
|
+
line-length = 88
|
|
74
|
+
|
|
75
|
+
[tool.ruff.lint]
|
|
76
|
+
select = ["E", "F", "I", "UP", "B", "SIM", "RUF"]
|
|
77
|
+
|
|
78
|
+
[tool.pytest.ini_options]
|
|
79
|
+
testpaths = ["tests"]
|
|
80
|
+
pythonpath = ["src"]
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## 2. Type Hints (Mandatory)
|
|
84
|
+
|
|
85
|
+
Type hints are **not optional** — they are foundational design tools.
|
|
86
|
+
|
|
87
|
+
### Rules
|
|
88
|
+
|
|
89
|
+
- **Use built-in generics** (Python 3.9+): `list[str]`, `dict[str, int]`, `tuple[int, ...]`
|
|
90
|
+
- **Use union syntax** (Python 3.10+): `str | None` instead of `Optional[str]`
|
|
91
|
+
- **Avoid `Any`** — use `object`, `Unknown`, or narrow with type guards
|
|
92
|
+
- **Use `TypedDict`** for dict-shaped data with known keys
|
|
93
|
+
- **Use `Protocol`** for structural subtyping instead of ABCs
|
|
94
|
+
- **Run static analysis**: `mypy --strict` or `pyright`
|
|
95
|
+
|
|
96
|
+
### Examples
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
# ✅ Good
|
|
100
|
+
def get_user(user_id: int) -> User | None:
|
|
101
|
+
...
|
|
102
|
+
|
|
103
|
+
class Config(TypedDict):
|
|
104
|
+
host: str
|
|
105
|
+
port: int
|
|
106
|
+
debug: bool
|
|
107
|
+
|
|
108
|
+
# ❌ Bad
|
|
109
|
+
def get_user(user_id): # Missing type hints
|
|
110
|
+
...
|
|
111
|
+
|
|
112
|
+
def process(data: Any): # Untyped escape hatch
|
|
113
|
+
...
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## 3. Code Quality: `ruff`
|
|
117
|
+
|
|
118
|
+
Ruff is the **all-in-one** linter and formatter for Python. It replaces Flake8, Black, isort, pyupgrade, and more.
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
ruff check --fix . # Lint with auto-fix
|
|
122
|
+
ruff format . # Format (replaces Black)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Configuration in `pyproject.toml`
|
|
126
|
+
|
|
127
|
+
```toml
|
|
128
|
+
[tool.ruff]
|
|
129
|
+
target-version = "py312"
|
|
130
|
+
line-length = 88
|
|
131
|
+
src = ["src", "tests"]
|
|
132
|
+
|
|
133
|
+
[tool.ruff.lint]
|
|
134
|
+
select = [
|
|
135
|
+
"E", # pycodestyle errors
|
|
136
|
+
"F", # pyflakes
|
|
137
|
+
"I", # isort
|
|
138
|
+
"UP", # pyupgrade
|
|
139
|
+
"B", # bugbear
|
|
140
|
+
"SIM", # simplify
|
|
141
|
+
"RUF", # ruff-specific
|
|
142
|
+
]
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
- **NEVER** use `# noqa` to suppress linter errors unless the suppression is explicitly justified by a comment explaining _why_.
|
|
146
|
+
- **NEVER** use `# type: ignore` — fix the type error or use a proper type guard.
|
|
147
|
+
|
|
148
|
+
## 4. Error Handling
|
|
149
|
+
|
|
150
|
+
### Patterns
|
|
151
|
+
|
|
152
|
+
- **Use specific exception types** — never catch bare `except:` or `except Exception:`
|
|
153
|
+
- **Create custom exceptions** inheriting from a base project exception
|
|
154
|
+
- **Use `from` for exception chaining**: `raise ValueError("msg") from original_error`
|
|
155
|
+
- **Never swallow exceptions silently** — at minimum, log them
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
# ✅ Good
|
|
159
|
+
class AppError(Exception):
|
|
160
|
+
"""Base exception for the application."""
|
|
161
|
+
|
|
162
|
+
class NotFoundError(AppError):
|
|
163
|
+
"""Raised when a resource is not found."""
|
|
164
|
+
|
|
165
|
+
try:
|
|
166
|
+
user = get_user(user_id)
|
|
167
|
+
except DatabaseError as e:
|
|
168
|
+
raise NotFoundError(f"User {user_id} not found") from e
|
|
169
|
+
|
|
170
|
+
# ❌ Bad
|
|
171
|
+
try:
|
|
172
|
+
user = get_user(user_id)
|
|
173
|
+
except: # Bare except — catches SystemExit, KeyboardInterrupt
|
|
174
|
+
pass # Silently swallowed
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## 5. Testing with `pytest`
|
|
178
|
+
|
|
179
|
+
### Structure
|
|
180
|
+
|
|
181
|
+
- **AAA pattern**: Arrange, Act, Assert — one concern per test
|
|
182
|
+
- **Use fixtures** for setup/teardown, not classes with `setUp()`/`tearDown()`
|
|
183
|
+
- **Use `conftest.py`** for shared fixtures across test modules
|
|
184
|
+
- **Use `@pytest.mark.parametrize`** for data-driven tests
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
@pytest.fixture
|
|
188
|
+
def client(tmp_path: Path) -> TestClient:
|
|
189
|
+
"""Create a test client with a temporary database."""
|
|
190
|
+
app = create_app(db_path=tmp_path / "test.db")
|
|
191
|
+
return TestClient(app)
|
|
192
|
+
|
|
193
|
+
@pytest.mark.parametrize("status_code,expected", [
|
|
194
|
+
(200, True),
|
|
195
|
+
(404, False),
|
|
196
|
+
(500, False),
|
|
197
|
+
])
|
|
198
|
+
def test_is_success(status_code: int, expected: bool) -> None:
|
|
199
|
+
assert is_success(status_code) == expected
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Running Tests
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
uv run pytest # Run all tests
|
|
206
|
+
uv run pytest tests/test_main.py # Run specific file
|
|
207
|
+
uv run pytest -k "test_user" # Run by pattern
|
|
208
|
+
uv run pytest --cov=src --cov-report=term-missing # Coverage
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## 6. Async & Concurrency
|
|
212
|
+
|
|
213
|
+
- **Use `asyncio`** for I/O-bound concurrency (HTTP calls, DB queries)
|
|
214
|
+
- **Use `async def` / `await`** — never mix sync and async code paths
|
|
215
|
+
- **Use `asyncio.TaskGroup`** (Python 3.11+) for structured concurrency
|
|
216
|
+
- **Use `httpx`** (async-native) instead of `requests` for HTTP clients
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
async with asyncio.TaskGroup() as tg:
|
|
220
|
+
task1 = tg.create_task(fetch_user(user_id))
|
|
221
|
+
task2 = tg.create_task(fetch_orders(user_id))
|
|
222
|
+
# Both tasks complete here — exceptions propagate cleanly
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## 7. Data Validation: Pydantic v2
|
|
226
|
+
|
|
227
|
+
- **Use Pydantic models** at system boundaries (API requests, config files, DB results)
|
|
228
|
+
- **Never trust external input** — validate with `model_validate()`, not dict access
|
|
229
|
+
- **Use `Field()` validators** for constraints, not manual `if` checks
|
|
230
|
+
|
|
231
|
+
```python
|
|
232
|
+
from pydantic import BaseModel, Field
|
|
233
|
+
|
|
234
|
+
class CreateUserRequest(BaseModel):
|
|
235
|
+
name: str = Field(min_length=1, max_length=100)
|
|
236
|
+
email: str = Field(pattern=r"^[\w.-]+@[\w.-]+\.\w+$")
|
|
237
|
+
age: int = Field(ge=0, le=150)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## 8. Anti-Patterns (Never Do These)
|
|
241
|
+
|
|
242
|
+
| Anti-Pattern | Why It's Wrong | Do This Instead |
|
|
243
|
+
| ------------------------------------ | ---------------------------------- | ---------------------------- |
|
|
244
|
+
| `import *` | Pollutes namespace, breaks tooling | Explicit imports |
|
|
245
|
+
| Mutable default args (`def f(x=[])`) | Shared across calls | Use `None` + assign |
|
|
246
|
+
| Global mutable state | Thread-unsafe, untestable | Dependency injection |
|
|
247
|
+
| `os.path` for path manipulation | Platform-inconsistent | Use `pathlib.Path` |
|
|
248
|
+
| `print()` for logging | No levels, no rotation | Use `logging` or `structlog` |
|
|
249
|
+
| `== None` / `== True` | Wrong semantics | `is None` / `is True` |
|
|
250
|
+
|
|
251
|
+
## 9. Web Frameworks Quick Reference
|
|
252
|
+
|
|
253
|
+
| Framework | Best For | Key Pattern |
|
|
254
|
+
| ----------- | ---------------------------- | --------------------------------------------------------- |
|
|
255
|
+
| **FastAPI** | REST APIs, async, auto-docs | Pydantic models, dependency injection, `async def` routes |
|
|
256
|
+
| **Django** | Full-stack, admin, ORM | Models → Views → Templates, `manage.py`, migrations |
|
|
257
|
+
| **Flask** | Lightweight APIs, prototypes | Blueprints, application factory pattern |
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tailwind-css
|
|
3
|
+
description: |
|
|
4
|
+
Master Tailwind CSS v4 with its CSS-first configuration paradigm. Use when
|
|
5
|
+
writing utility classes, configuring design tokens via @theme, implementing
|
|
6
|
+
dark mode, migrating from v3, or integrating with React/Vue/Svelte. Triggers
|
|
7
|
+
on "Tailwind", "utility CSS", "Tailwind v4", "@theme", "dark mode classes",
|
|
8
|
+
"responsive design", "Tailwind migration".
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Tailwind CSS v4 Engineering Standards
|
|
12
|
+
|
|
13
|
+
This skill codifies Tailwind CSS v4's **CSS-first architecture** — the paradigm shift from JavaScript configuration to native CSS-based theming and customization.
|
|
14
|
+
|
|
15
|
+
## 1. Core Paradigm: CSS-First Configuration
|
|
16
|
+
|
|
17
|
+
### Entry Point
|
|
18
|
+
|
|
19
|
+
Replace all legacy directives with a single import:
|
|
20
|
+
|
|
21
|
+
```css
|
|
22
|
+
/* main.css */
|
|
23
|
+
@import 'tailwindcss';
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
- **NEVER** use `@tailwind base; @tailwind components; @tailwind utilities;` — this is v3 syntax
|
|
27
|
+
- **No `tailwind.config.js` needed** for most projects — CSS is the single source of truth
|
|
28
|
+
- Use `@config "./tailwind.config.js"` only for legacy migration or PostCSS plugin compatibility
|
|
29
|
+
|
|
30
|
+
### The `@theme` Directive
|
|
31
|
+
|
|
32
|
+
All design tokens are defined directly in CSS:
|
|
33
|
+
|
|
34
|
+
```css
|
|
35
|
+
@import 'tailwindcss';
|
|
36
|
+
|
|
37
|
+
@theme {
|
|
38
|
+
/* Colors */
|
|
39
|
+
--color-primary-50: #eff6ff;
|
|
40
|
+
--color-primary-500: #3b82f6;
|
|
41
|
+
--color-primary-900: #1e3a5a;
|
|
42
|
+
|
|
43
|
+
/* Typography */
|
|
44
|
+
--font-display: 'Inter', sans-serif;
|
|
45
|
+
--font-mono: 'JetBrains Mono', monospace;
|
|
46
|
+
|
|
47
|
+
/* Spacing */
|
|
48
|
+
--spacing-container: 1200px;
|
|
49
|
+
|
|
50
|
+
/* Border Radius */
|
|
51
|
+
--radius-card: 0.75rem;
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
- Tailwind **automatically generates utility classes** from `@theme` variables
|
|
56
|
+
- `--color-primary-500` → `bg-primary-500`, `text-primary-500`, `border-primary-500`
|
|
57
|
+
- `--font-display` → `font-display`
|
|
58
|
+
- Tokens are native CSS variables — inspectable in browser DevTools
|
|
59
|
+
|
|
60
|
+
## 2. Dark Mode
|
|
61
|
+
|
|
62
|
+
### Configuration (v4 Pattern)
|
|
63
|
+
|
|
64
|
+
```css
|
|
65
|
+
/* Class-based dark mode (most common) */
|
|
66
|
+
@custom-variant dark (&:where(.dark, .dark *));
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Usage in HTML
|
|
70
|
+
|
|
71
|
+
```html
|
|
72
|
+
<div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100">
|
|
73
|
+
<h1 class="text-primary-500 dark:text-primary-300">Title</h1>
|
|
74
|
+
</div>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### System Preference (Default)
|
|
78
|
+
|
|
79
|
+
By default, Tailwind v4 respects `prefers-color-scheme`. If you want manual class toggle control, use `@custom-variant dark` as shown above.
|
|
80
|
+
|
|
81
|
+
### Toggle Implementation
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
// Toggle dark mode via JavaScript
|
|
85
|
+
document.documentElement.classList.toggle('dark')
|
|
86
|
+
|
|
87
|
+
// Or persist to localStorage
|
|
88
|
+
const isDark = localStorage.getItem('theme') === 'dark'
|
|
89
|
+
document.documentElement.classList.toggle('dark', isDark)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## 3. Responsive Design
|
|
93
|
+
|
|
94
|
+
### Mobile-First Breakpoints
|
|
95
|
+
|
|
96
|
+
Tailwind uses a **mobile-first** approach — unprefixed utilities apply to all screens, prefixed utilities apply at that breakpoint and above.
|
|
97
|
+
|
|
98
|
+
```html
|
|
99
|
+
<!-- Full width on mobile, half on md, third on lg -->
|
|
100
|
+
<div class="w-full md:w-1/2 lg:w-1/3">...</div>
|
|
101
|
+
|
|
102
|
+
<!-- Stack on mobile, row on sm+ -->
|
|
103
|
+
<div class="flex flex-col sm:flex-row gap-4">...</div>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Default Breakpoints
|
|
107
|
+
|
|
108
|
+
| Prefix | Min Width | Target |
|
|
109
|
+
| ------ | --------- | ------------- |
|
|
110
|
+
| `sm` | 640px | Small tablets |
|
|
111
|
+
| `md` | 768px | Tablets |
|
|
112
|
+
| `lg` | 1024px | Laptops |
|
|
113
|
+
| `xl` | 1280px | Desktops |
|
|
114
|
+
| `2xl` | 1536px | Large screens |
|
|
115
|
+
|
|
116
|
+
### Custom Breakpoints
|
|
117
|
+
|
|
118
|
+
```css
|
|
119
|
+
@theme {
|
|
120
|
+
--breakpoint-xs: 475px;
|
|
121
|
+
--breakpoint-3xl: 1920px;
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## 4. Component Patterns
|
|
126
|
+
|
|
127
|
+
### Buttons
|
|
128
|
+
|
|
129
|
+
```html
|
|
130
|
+
<button
|
|
131
|
+
class="
|
|
132
|
+
inline-flex items-center justify-center
|
|
133
|
+
rounded-lg px-4 py-2
|
|
134
|
+
bg-primary-500 text-white font-medium
|
|
135
|
+
hover:bg-primary-600
|
|
136
|
+
focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-500
|
|
137
|
+
active:scale-[0.98]
|
|
138
|
+
disabled:opacity-50 disabled:cursor-not-allowed
|
|
139
|
+
transition-all duration-150
|
|
140
|
+
"
|
|
141
|
+
>
|
|
142
|
+
Click me
|
|
143
|
+
</button>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Cards
|
|
147
|
+
|
|
148
|
+
```html
|
|
149
|
+
<article
|
|
150
|
+
class="
|
|
151
|
+
rounded-xl border border-gray-200 dark:border-gray-700
|
|
152
|
+
bg-white dark:bg-gray-800
|
|
153
|
+
p-6 shadow-sm
|
|
154
|
+
hover:shadow-md transition-shadow
|
|
155
|
+
"
|
|
156
|
+
>
|
|
157
|
+
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">Title</h3>
|
|
158
|
+
<p class="mt-2 text-gray-600 dark:text-gray-400">Description text.</p>
|
|
159
|
+
</article>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Custom Component Classes
|
|
163
|
+
|
|
164
|
+
```css
|
|
165
|
+
@layer components {
|
|
166
|
+
.btn-primary {
|
|
167
|
+
@apply inline-flex items-center justify-center rounded-lg px-4 py-2
|
|
168
|
+
bg-primary-500 text-white font-medium
|
|
169
|
+
hover:bg-primary-600 transition-colors;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
- **Use `@layer components`** for reusable component styles
|
|
175
|
+
- **Prefer utility classes inline** for one-off styling
|
|
176
|
+
- **Use `@apply` sparingly** — only for highly-repeated patterns
|
|
177
|
+
|
|
178
|
+
## 5. Animations & Transitions
|
|
179
|
+
|
|
180
|
+
### Built-in Transitions
|
|
181
|
+
|
|
182
|
+
```html
|
|
183
|
+
<!-- Smooth hover effect -->
|
|
184
|
+
<div class="transition-all duration-300 ease-in-out hover:scale-105">
|
|
185
|
+
<!-- Color transitions only -->
|
|
186
|
+
<a class="transition-colors duration-150 text-gray-500 hover:text-primary-500"></a>
|
|
187
|
+
</div>
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Custom Animations
|
|
191
|
+
|
|
192
|
+
```css
|
|
193
|
+
@theme {
|
|
194
|
+
--animate-fade-in: fade-in 0.3s ease-out;
|
|
195
|
+
--animate-slide-up: slide-up 0.4s ease-out;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
@keyframes fade-in {
|
|
199
|
+
from {
|
|
200
|
+
opacity: 0;
|
|
201
|
+
}
|
|
202
|
+
to {
|
|
203
|
+
opacity: 1;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
@keyframes slide-up {
|
|
208
|
+
from {
|
|
209
|
+
opacity: 0;
|
|
210
|
+
transform: translateY(1rem);
|
|
211
|
+
}
|
|
212
|
+
to {
|
|
213
|
+
opacity: 1;
|
|
214
|
+
transform: translateY(0);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Usage: `class="animate-fade-in"` or `class="animate-slide-up"`
|
|
220
|
+
|
|
221
|
+
## 6. Migration from v3 to v4
|
|
222
|
+
|
|
223
|
+
### Step-by-Step
|
|
224
|
+
|
|
225
|
+
1. **Update package**: `pnpm add -D tailwindcss@latest`
|
|
226
|
+
2. **Replace CSS entry point**:
|
|
227
|
+
- Remove: `@tailwind base; @tailwind components; @tailwind utilities;`
|
|
228
|
+
- Add: `@import "tailwindcss";`
|
|
229
|
+
3. **Migrate `tailwind.config.js`** → `@theme` block in CSS
|
|
230
|
+
4. **Update dark mode**: Replace `darkMode: "class"` config with `@custom-variant dark`
|
|
231
|
+
5. **Check defaults**: Some defaults changed (e.g., border colors). Verify visually.
|
|
232
|
+
6. **Remove PostCSS plugins** if no longer needed (v4 has its own engine)
|
|
233
|
+
|
|
234
|
+
### Key Breaking Changes
|
|
235
|
+
|
|
236
|
+
| v3 | v4 |
|
|
237
|
+
| ------------------------------------- | ---------------------------- |
|
|
238
|
+
| `tailwind.config.js` | `@theme` in CSS |
|
|
239
|
+
| `darkMode: "class"` | `@custom-variant dark (...)` |
|
|
240
|
+
| `@tailwind base/components/utilities` | `@import "tailwindcss"` |
|
|
241
|
+
| `theme.extend.colors` | `--color-*` in `@theme` |
|
|
242
|
+
| `theme.extend.fontFamily` | `--font-*` in `@theme` |
|
|
243
|
+
|
|
244
|
+
## 7. Anti-Patterns (Never Do These)
|
|
245
|
+
|
|
246
|
+
| Anti-Pattern | Why It's Wrong | Do This Instead |
|
|
247
|
+
| -------------------------------------------- | ------------------------------------------------- | ---------------------------------------------------------------- |
|
|
248
|
+
| `@apply` everywhere | Defeats utility-first purpose, harder to maintain | Use inline utilities; `@apply` only for highly-repeated patterns |
|
|
249
|
+
| `!important` classes | Specificity wars, unpredictable cascade | Use proper specificity layers |
|
|
250
|
+
| Arbitrary values excessively (`text-[17px]`) | Breaks design system consistency | Define tokens in `@theme` |
|
|
251
|
+
| Inline `style=` alongside utilities | Mixed paradigms, inconsistent | All styling via Tailwind utilities |
|
|
252
|
+
| Using v3 `tailwind.config.js` in v4 | Unnecessary JS dependency | Migrate to `@theme` in CSS |
|
|
253
|
+
| Not using `dark:` variants | Inaccessible for dark-mode users | Always implement dark mode |
|
|
254
|
+
| Ignoring mobile-first | Desktop-only layouts break on phones | Design mobile-first, add breakpoints up |
|
|
255
|
+
|
|
256
|
+
## 8. Accessibility Essentials
|
|
257
|
+
|
|
258
|
+
- **Always use `focus-visible:`** for keyboard focus indicators — never remove focus outlines without replacement
|
|
259
|
+
- **Ensure color contrast** — text must meet WCAG AA (4.5:1 normal, 3:1 large)
|
|
260
|
+
- **Use `sr-only`** class for screen-reader-only text on icon buttons
|
|
261
|
+
- **Never use `hidden`** for content that should be accessible — use `sr-only` instead
|
|
262
|
+
|
|
263
|
+
```html
|
|
264
|
+
<button class="p-2 rounded-lg hover:bg-gray-100 focus-visible:ring-2">
|
|
265
|
+
<svg class="size-5" aria-hidden="true">...</svg>
|
|
266
|
+
<span class="sr-only">Close menu</span>
|
|
267
|
+
</button>
|
|
268
|
+
```
|