@vpnsin/devkit 0.1.3
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 +318 -0
- package/bin/cli.js +431 -0
- package/commitlint/index.js +7 -0
- package/eslint/base.js +50 -0
- package/eslint/next.js +27 -0
- package/jest/index.js +20 -0
- package/lint-staged/index.js +8 -0
- package/package.json +80 -0
- package/prettier/index.js +11 -0
- package/templates/README.template.md +51 -0
- package/templates/app/backend/Dockerfile +24 -0
- package/templates/app/backend/dockerignore +7 -0
- package/templates/app/backend/env.example +2 -0
- package/templates/app/backend/src/app.ts +22 -0
- package/templates/app/backend/src/env.ts +8 -0
- package/templates/app/backend/src/routes/health.ts +7 -0
- package/templates/app/backend/src/server.ts +19 -0
- package/templates/app/frontend/app/globals.css +28 -0
- package/templates/app/frontend/app/layout.tsx +16 -0
- package/templates/app/frontend/app/page.tsx +10 -0
- package/templates/app/frontend/env.example +5 -0
- package/templates/app/frontend/next.config.mjs +6 -0
- package/templates/claude/skills/design-craft/SKILL.md +226 -0
- package/templates/cspell.json +30 -0
- package/templates/dependabot.yml +18 -0
- package/templates/editorconfig +15 -0
- package/templates/github/CODEOWNERS +12 -0
- package/templates/github/CONTRIBUTING.md +51 -0
- package/templates/github/ISSUE_TEMPLATE/bug_report.yml +34 -0
- package/templates/github/ISSUE_TEMPLATE/config.yml +5 -0
- package/templates/github/ISSUE_TEMPLATE/feature_request.yml +23 -0
- package/templates/github/PULL_REQUEST_TEMPLATE.md +27 -0
- package/templates/github/SECURITY.md +24 -0
- package/templates/github/workflows/ci.yml +55 -0
- package/templates/github/workflows/codeql.yml +35 -0
- package/templates/github/workflows/dependency-review.yml +23 -0
- package/templates/github/workflows/lighthouse.yml +39 -0
- package/templates/github/workflows/publish.yml +38 -0
- package/templates/github/workflows/release-please-publish.yml +54 -0
- package/templates/github/workflows/release-please.yml +22 -0
- package/templates/github/workflows/scorecard.yml +41 -0
- package/templates/github/workflows/sonarqube.yml +31 -0
- package/templates/github/workflows/trivy.yml +43 -0
- package/templates/husky/commit-msg +1 -0
- package/templates/husky/pre-commit +1 -0
- package/templates/lighthouserc.json +23 -0
- package/templates/markdownlint-cli2.jsonc +20 -0
- package/templates/npmrc +9 -0
- package/templates/nvmrc +1 -0
- package/templates/release-please-config.json +14 -0
- package/templates/sonar-project.properties +13 -0
- package/templates/vscode/extensions.json +53 -0
- package/templates/vscode/settings.json +70 -0
- package/tsconfig/base.json +17 -0
- package/tsconfig/next.json +16 -0
- package/tsconfig/node.json +14 -0
- package/vitest/index.js +22 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Project Name
|
|
2
|
+
|
|
3
|
+
> One-line description of what this project does.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- …
|
|
8
|
+
- …
|
|
9
|
+
|
|
10
|
+
## Getting started
|
|
11
|
+
|
|
12
|
+
### Prerequisites
|
|
13
|
+
|
|
14
|
+
- Node.js >= 18.18
|
|
15
|
+
- npm
|
|
16
|
+
|
|
17
|
+
### Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Develop
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm run dev
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Scripts
|
|
30
|
+
|
|
31
|
+
| Script | Description |
|
|
32
|
+
| -------------------- | ---------------------------- |
|
|
33
|
+
| `npm run lint` | Lint with ESLint |
|
|
34
|
+
| `npm run format` | Format with Prettier |
|
|
35
|
+
| `npm run type-check` | Type-check with `tsc` |
|
|
36
|
+
| `npm run lint:md` | Lint Markdown |
|
|
37
|
+
| `npm run build` | Production build (if present)|
|
|
38
|
+
|
|
39
|
+
## Contributing
|
|
40
|
+
|
|
41
|
+
See [CONTRIBUTING](.github/CONTRIBUTING.md). Commits follow
|
|
42
|
+
[Conventional Commits](https://www.conventionalcommits.org/); releases are
|
|
43
|
+
automated with release-please.
|
|
44
|
+
|
|
45
|
+
## Security
|
|
46
|
+
|
|
47
|
+
See [SECURITY](.github/SECURITY.md) for how to report vulnerabilities.
|
|
48
|
+
|
|
49
|
+
## License
|
|
50
|
+
|
|
51
|
+
<!-- e.g. MIT © Year Author -->
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# syntax=docker/dockerfile:1
|
|
2
|
+
|
|
3
|
+
# ---- build ----
|
|
4
|
+
FROM node:22-alpine AS build
|
|
5
|
+
WORKDIR /app
|
|
6
|
+
COPY package*.json ./
|
|
7
|
+
RUN npm ci
|
|
8
|
+
COPY . .
|
|
9
|
+
RUN npm run build
|
|
10
|
+
|
|
11
|
+
# ---- runtime ----
|
|
12
|
+
FROM node:22-alpine AS runtime
|
|
13
|
+
WORKDIR /app
|
|
14
|
+
ENV NODE_ENV=production
|
|
15
|
+
COPY package*.json ./
|
|
16
|
+
RUN npm ci --omit=dev
|
|
17
|
+
COPY --from=build /app/dist ./dist
|
|
18
|
+
EXPOSE 3000
|
|
19
|
+
USER node
|
|
20
|
+
|
|
21
|
+
# Probe the /health route using Node's built-in fetch (no curl/wget needed).
|
|
22
|
+
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 CMD node -e "fetch('http://localhost:'+(process.env.PORT||3000)+'/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
|
|
23
|
+
|
|
24
|
+
CMD ["node", "dist/server.js"]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import express, { type Express } from 'express';
|
|
2
|
+
import cors from 'cors';
|
|
3
|
+
import helmet from 'helmet';
|
|
4
|
+
import { healthRouter } from './routes/health.js';
|
|
5
|
+
|
|
6
|
+
// App factory — keep it pure (no listen()) so tests can import and exercise it.
|
|
7
|
+
export function createApp(): Express {
|
|
8
|
+
const app = express();
|
|
9
|
+
|
|
10
|
+
app.use(helmet());
|
|
11
|
+
app.use(cors());
|
|
12
|
+
app.use(express.json());
|
|
13
|
+
|
|
14
|
+
app.use('/health', healthRouter);
|
|
15
|
+
|
|
16
|
+
// Fallback 404.
|
|
17
|
+
app.use((_req, res) => {
|
|
18
|
+
res.status(404).json({ error: 'Not found' });
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
return app;
|
|
22
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import 'dotenv/config';
|
|
2
|
+
|
|
3
|
+
// Central, typed access to environment config. Extend with validation
|
|
4
|
+
// (e.g. zod) as the surface grows.
|
|
5
|
+
export const env = {
|
|
6
|
+
NODE_ENV: process.env.NODE_ENV ?? 'development',
|
|
7
|
+
PORT: Number(process.env.PORT ?? 3000),
|
|
8
|
+
} as const;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createApp } from './app.js';
|
|
2
|
+
import { env } from './env.js';
|
|
3
|
+
|
|
4
|
+
const app = createApp();
|
|
5
|
+
|
|
6
|
+
const server = app.listen(env.PORT, () => {
|
|
7
|
+
// eslint-disable-next-line no-console
|
|
8
|
+
console.log(`API listening on http://localhost:${env.PORT} (${env.NODE_ENV})`);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
// Graceful shutdown so in-flight requests drain before the process exits.
|
|
12
|
+
function shutdown(signal: string): void {
|
|
13
|
+
// eslint-disable-next-line no-console
|
|
14
|
+
console.log(`${signal} received, shutting down…`);
|
|
15
|
+
server.close(() => process.exit(0));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
19
|
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
color-scheme: light dark;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
* {
|
|
6
|
+
box-sizing: border-box;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
html,
|
|
10
|
+
body {
|
|
11
|
+
margin: 0;
|
|
12
|
+
padding: 0;
|
|
13
|
+
font-family: system-ui, -apple-system, 'Segoe UI', sans-serif;
|
|
14
|
+
line-height: 1.5;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
main {
|
|
18
|
+
max-width: 48rem;
|
|
19
|
+
margin: 0 auto;
|
|
20
|
+
padding: 4rem 1.5rem;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
code {
|
|
24
|
+
font-family: ui-monospace, 'SFMono-Regular', Menlo, monospace;
|
|
25
|
+
background: rgba(127, 127, 127, 0.15);
|
|
26
|
+
padding: 0.1rem 0.35rem;
|
|
27
|
+
border-radius: 0.25rem;
|
|
28
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Metadata } from 'next';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
import './globals.css';
|
|
4
|
+
|
|
5
|
+
export const metadata: Metadata = {
|
|
6
|
+
title: 'App',
|
|
7
|
+
description: 'Bootstrapped with devkit',
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default function RootLayout({ children }: { children: ReactNode }) {
|
|
11
|
+
return (
|
|
12
|
+
<html lang="en">
|
|
13
|
+
<body>{children}</body>
|
|
14
|
+
</html>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: design-craft
|
|
3
|
+
description: >-
|
|
4
|
+
Elevate the user experience and visual design of the site. Use when polishing
|
|
5
|
+
UI, redesigning a page or section, adding motion/micro-interactions, tightening
|
|
6
|
+
typography/spacing/color, or auditing design quality. Runs three activity sets —
|
|
7
|
+
Define (taste & design language), Design (layout/type/color/space), Polish
|
|
8
|
+
(motion & micro-interactions) — then a Review gate. Works on Next.js + Tailwind
|
|
9
|
+
sites. Synthesises three skills: emilkowalski/skill, pbakaus/impeccable, and
|
|
10
|
+
Leonxlnx/taste-skill.
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Design Craft
|
|
14
|
+
|
|
15
|
+
A three-phase protocol for making interfaces that feel **considered, premium, and
|
|
16
|
+
alive** — not generic AI "slop". It unifies three sources:
|
|
17
|
+
|
|
18
|
+
- **emilkowalski/skill** (`emil-design-eng`) — motion, micro-interaction, and the
|
|
19
|
+
invisible details that compound. _"All those unseen details combine to produce
|
|
20
|
+
something that's just stunning."_
|
|
21
|
+
- **pbakaus/impeccable** — design quality, consistency, and a concrete anti-pattern
|
|
22
|
+
catalogue. Plan (shape) before you build.
|
|
23
|
+
- **Leonxlnx/taste-skill** — anti-slop framework: infer the brief, tune taste dials,
|
|
24
|
+
map a coherent design system before coding.
|
|
25
|
+
|
|
26
|
+
**Taste is trained, not innate.** Study great work, reverse-engineer why it feels
|
|
27
|
+
right, and apply the concrete rules below rather than defaulting to the obvious.
|
|
28
|
+
|
|
29
|
+
## How to use this skill
|
|
30
|
+
|
|
31
|
+
- **Full redesign of a page/section** → run Activity Sets 1 → 2 → 3, then Review.
|
|
32
|
+
- **Visual tweak** (spacing/type/color) → Activity Set 2 + Review.
|
|
33
|
+
- **Add/refine motion** → Activity Set 3 + Review.
|
|
34
|
+
- **"Make this feel better" / audit** → Review gate first to find issues, then the
|
|
35
|
+
relevant set to fix them.
|
|
36
|
+
|
|
37
|
+
Always **read the component and match the surrounding conventions** before editing,
|
|
38
|
+
and always finish with the Review gate. On these sites: Tailwind utilities + theme
|
|
39
|
+
tokens, `next/image`, mobile-first; verify at the dev server and keep
|
|
40
|
+
`type-check` / `lint` / `build` green.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Activity Set 1 — Define (taste & design language)
|
|
45
|
+
|
|
46
|
+
_Establish intent before touching code (impeccable: context-first; taste: infer the brief)._
|
|
47
|
+
|
|
48
|
+
1. **State the context** in one or two lines: audience, brand-vs-product, voice,
|
|
49
|
+
the single feeling the page should evoke. If the repo has a `DESIGN.md` /
|
|
50
|
+
`CLAUDE.md`, read it; otherwise infer from the existing site and say what you
|
|
51
|
+
inferred.
|
|
52
|
+
2. **Tune three dials (1–10) and write them down** so choices are deliberate:
|
|
53
|
+
- **DESIGN_VARIANCE** — layout experimentation (low = centred/clean; high = asymmetric/editorial).
|
|
54
|
+
- **MOTION_INTENSITY** — animation depth (low = hover/press only; high = scroll-driven/magnetic).
|
|
55
|
+
- **VISUAL_DENSITY** — information per viewport (low = spacious; high = dense dashboard).
|
|
56
|
+
- _Premium eco / marketing brand (e.g. Flora Dine) default:_ variance **4**, motion **4**, density **3** — calm, trustworthy, spacious.
|
|
57
|
+
3. **Map the design system** so everything is reused, not reinvented: type scale,
|
|
58
|
+
spacing rhythm (8px grid), colour tokens (already in the Tailwind theme),
|
|
59
|
+
radius, shadow, and the existing component inventory. New work must pull from
|
|
60
|
+
these tokens — no hard-coded hex or one-off spacing.
|
|
61
|
+
|
|
62
|
+
**Deliverable:** a 3–5 line direction (context + dials + the tokens you'll use).
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Activity Set 2 — Design (layout, type, colour, space)
|
|
67
|
+
|
|
68
|
+
_Shape the composition, then build it (impeccable + taste). Avoid generic patterns._
|
|
69
|
+
|
|
70
|
+
**Shape first.** Describe the layout and visual hierarchy in words before writing
|
|
71
|
+
JSX — what leads, what supports, where the eye goes.
|
|
72
|
+
|
|
73
|
+
**Typography**
|
|
74
|
+
|
|
75
|
+
- Clear scale with real hierarchy (don't size everything the same).
|
|
76
|
+
- Body line-height ≥ 1.5; tighten display headings.
|
|
77
|
+
- Avoid the obvious defaults for display type (Arial, system stack, and plain
|
|
78
|
+
**Inter** as the "AI default"). The brand font should do the talking.
|
|
79
|
+
|
|
80
|
+
**Colour**
|
|
81
|
+
|
|
82
|
+
- **Never pure black or pure gray** — always tint toward the brand (e.g. text is a
|
|
83
|
+
very dark brand-tinted neutral, not `#000`).
|
|
84
|
+
- **No gray text on coloured backgrounds** — it reads muddy; use a tint of the
|
|
85
|
+
background or an on-colour token.
|
|
86
|
+
- Maintain **4.5:1** contrast for text. Drive everything from theme tokens.
|
|
87
|
+
|
|
88
|
+
**Spacing & layout**
|
|
89
|
+
|
|
90
|
+
- 8px rhythm; treat white space as a design element, not leftover.
|
|
91
|
+
- Use the dials: raise variance with an asymmetric hero or offset grid when the
|
|
92
|
+
brand allows; keep density low for a premium feel.
|
|
93
|
+
|
|
94
|
+
**Avoid the "slop" tells** (taste + impeccable anti-patterns)
|
|
95
|
+
|
|
96
|
+
- Purple→blue "AI gradient"; bouncy/elastic easing; everything wrapped in cards;
|
|
97
|
+
**cards nested inside cards**; side-tab coloured borders; skipped heading levels;
|
|
98
|
+
undersized touch targets; centered-everything with no hierarchy.
|
|
99
|
+
- In UI microcopy, vary punctuation — don't lean on the em-dash as a verbal tic
|
|
100
|
+
(a common AI tell). Keep copy specific and human.
|
|
101
|
+
|
|
102
|
+
**Deliverable:** the built/edited section using tokens, with hierarchy that reads
|
|
103
|
+
at a glance and none of the anti-patterns above.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Activity Set 3 — Polish (motion & micro-interactions)
|
|
108
|
+
|
|
109
|
+
_The emil-design-eng layer — where "fine" becomes "loved". This is the most concrete set._
|
|
110
|
+
|
|
111
|
+
### Decide whether to animate at all
|
|
112
|
+
|
|
113
|
+
| Frequency | Decision |
|
|
114
|
+
| --- | --- |
|
|
115
|
+
| 100+×/day (keyboard, command palette) | **Never animate** |
|
|
116
|
+
| Tens×/day (hover, list nav) | Remove or drastically reduce |
|
|
117
|
+
| Occasional (modals, drawers, toasts) | Standard animation |
|
|
118
|
+
| Rare / first-time (onboarding, celebration) | Can add delight |
|
|
119
|
+
|
|
120
|
+
Every animation must answer **"why does this animate?"** — spatial consistency,
|
|
121
|
+
state indication, feedback, or preventing a jarring change. "Looks cool" + seen
|
|
122
|
+
often = don't.
|
|
123
|
+
|
|
124
|
+
### Easing — use custom curves, never `ease-in` on UI
|
|
125
|
+
|
|
126
|
+
```css
|
|
127
|
+
--ease-out: cubic-bezier(0.23, 1, 0.32, 1); /* enter/exit */
|
|
128
|
+
--ease-in-out: cubic-bezier(0.77, 0, 0.175, 1); /* move/morph on screen */
|
|
129
|
+
--ease-drawer: cubic-bezier(0.32, 0.72, 0, 1); /* drawers/sheets */
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
- Entering/exiting → `ease-out`. Moving/morphing → `ease-in-out`. Hover/colour →
|
|
133
|
+
`ease`. Constant motion → `linear`.
|
|
134
|
+
- **Never `ease-in`** on UI (delays the first frame users watch most). Built-in CSS
|
|
135
|
+
easings are too weak — use the curves above.
|
|
136
|
+
|
|
137
|
+
### Duration — keep UI under 300ms
|
|
138
|
+
|
|
139
|
+
| Element | Duration |
|
|
140
|
+
| --- | --- |
|
|
141
|
+
| Button press feedback | 100–160ms |
|
|
142
|
+
| Tooltip / small popover | 125–200ms |
|
|
143
|
+
| Dropdown / select | 150–250ms |
|
|
144
|
+
| Modal / drawer | 200–500ms |
|
|
145
|
+
|
|
146
|
+
### Core rules
|
|
147
|
+
|
|
148
|
+
- **Animate only `transform` and `opacity`** (GPU; skips layout/paint). Never
|
|
149
|
+
animate `width`/`height`/`margin`/`padding`/`top`/`left`.
|
|
150
|
+
- **Press feedback:** `:active { transform: scale(0.97) }` on pressable elements
|
|
151
|
+
(subtle, 0.95–0.98).
|
|
152
|
+
- **Never enter from `scale(0)`** — start `scale(0.95)` + `opacity: 0` (nothing in
|
|
153
|
+
reality appears from nothing).
|
|
154
|
+
- **Origin-aware popovers** scale from their trigger (`transform-origin`), not
|
|
155
|
+
center. **Modals stay centered.**
|
|
156
|
+
- **Asymmetric timing:** slow where the user is deciding (e.g. hold-to-delete 2s
|
|
157
|
+
linear), snappy where the system responds (200ms ease-out). Make exits a touch
|
|
158
|
+
faster than enters.
|
|
159
|
+
- **Stagger** list entries 30–80ms; never block interaction during a stagger.
|
|
160
|
+
- **Springs** for drag/gesture & "alive" elements (they keep velocity when
|
|
161
|
+
interrupted): Apple-style `{ type: 'spring', duration: 0.5, bounce: 0.2 }`; keep
|
|
162
|
+
bounce 0.1–0.3.
|
|
163
|
+
- Prefer **CSS transitions** over keyframes for interruptible UI; use `@starting-style`
|
|
164
|
+
for enter animations; reach for `clip-path` for reveals/wipes/comparison sliders.
|
|
165
|
+
- **Tailwind note:** these sites have `tailwindcss-animate`; for bespoke motion add a
|
|
166
|
+
token-based transition (`transition-transform duration-200 ease-[cubic-bezier(...)]`)
|
|
167
|
+
rather than `transition-all`.
|
|
168
|
+
|
|
169
|
+
### Accessibility (non-negotiable)
|
|
170
|
+
|
|
171
|
+
- `@media (prefers-reduced-motion: reduce)` → keep opacity/colour, drop movement
|
|
172
|
+
(reduce, don't remove).
|
|
173
|
+
- Gate hover effects behind `@media (hover: hover) and (pointer: fine)` so touch
|
|
174
|
+
taps don't trigger them.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Review gate (run before shipping)
|
|
179
|
+
|
|
180
|
+
Combine all three skills' checks. Produce findings as a **Before → After → Why**
|
|
181
|
+
markdown table (emil's required format), not prose bullets.
|
|
182
|
+
|
|
183
|
+
**Technical audit** (impeccable `audit`)
|
|
184
|
+
|
|
185
|
+
- A11y: 4.5:1 contrast, keyboard reachable + visible focus, real `<label>`s,
|
|
186
|
+
44×44px targets, `prefers-reduced-motion` respected.
|
|
187
|
+
- Performance: only `transform`/`opacity` animated; no `transition: all`; images via
|
|
188
|
+
`next/image` with correct `sizes`.
|
|
189
|
+
- Responsive: no horizontal overflow and correct reflow at 480 / 768 / 1024 / 1440.
|
|
190
|
+
|
|
191
|
+
**Creative critique** (impeccable `critique` + taste pre-flight)
|
|
192
|
+
|
|
193
|
+
- Hierarchy reads at a glance; one clear focal point per view.
|
|
194
|
+
- Clarity of copy and CTAs; emotional resonance matches the brand feeling.
|
|
195
|
+
- **Cohesion:** easing, duration, and vibe are unified — motion matches mood
|
|
196
|
+
(playful can bounce; a premium brand stays crisp/calm).
|
|
197
|
+
- No "slop" tells from Activity Set 2 remain.
|
|
198
|
+
|
|
199
|
+
**Emil's code checklist** (fix on sight)
|
|
200
|
+
|
|
201
|
+
| Issue | Fix |
|
|
202
|
+
| --- | --- |
|
|
203
|
+
| `transition: all` | name the property: `transition: transform 200ms var(--ease-out)` |
|
|
204
|
+
| `scale(0)` entry | `scale(0.95)` + `opacity: 0` |
|
|
205
|
+
| `ease-in` on UI | `ease-out` / custom curve |
|
|
206
|
+
| `transform-origin: center` on popover | set to trigger (modals exempt) |
|
|
207
|
+
| Animation on a keyboard action | remove |
|
|
208
|
+
| Duration > 300ms on UI | reduce to 150–250ms |
|
|
209
|
+
| Hover without `@media (hover)` | add the media query |
|
|
210
|
+
| Same enter/exit speed | make the exit faster |
|
|
211
|
+
| Everything appears at once | add 30–80ms stagger |
|
|
212
|
+
|
|
213
|
+
**Then verify the build:** `npm run type-check`, `npm run lint`, `npm run build`,
|
|
214
|
+
and look at it on the dev server (responsive widths above).
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Set your project's defaults
|
|
219
|
+
|
|
220
|
+
Record the design direction once — in `CLAUDE.md` or a `DESIGN.md` — so every run
|
|
221
|
+
is consistent: the brand's one-line feeling, the three dial values, and the token
|
|
222
|
+
set to reuse. Then Activity Set 1 reads it instead of re-inferring each time.
|
|
223
|
+
|
|
224
|
+
> Example (premium / calm brand): dials variance **4** / motion **4** / density
|
|
225
|
+
> **3**; `ease-out` motion under ~250ms; lean on the existing theme tokens and the
|
|
226
|
+
> 8px grid.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json",
|
|
3
|
+
"version": "0.2",
|
|
4
|
+
"language": "en",
|
|
5
|
+
"words": [
|
|
6
|
+
"commitlint",
|
|
7
|
+
"devkit",
|
|
8
|
+
"dotenv",
|
|
9
|
+
"esbenp",
|
|
10
|
+
"lintstagedrc",
|
|
11
|
+
"markdownlint",
|
|
12
|
+
"npmrc",
|
|
13
|
+
"nvmrc",
|
|
14
|
+
"tsup",
|
|
15
|
+
"unconfigured",
|
|
16
|
+
"vitest"
|
|
17
|
+
],
|
|
18
|
+
"ignorePaths": [
|
|
19
|
+
"node_modules/**",
|
|
20
|
+
"dist/**",
|
|
21
|
+
"build/**",
|
|
22
|
+
"coverage/**",
|
|
23
|
+
".next/**",
|
|
24
|
+
"*.log",
|
|
25
|
+
"package-lock.json",
|
|
26
|
+
"pnpm-lock.yaml",
|
|
27
|
+
"yarn.lock",
|
|
28
|
+
"CHANGELOG.md"
|
|
29
|
+
]
|
|
30
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
# npm dependencies
|
|
4
|
+
- package-ecosystem: npm
|
|
5
|
+
directory: /
|
|
6
|
+
schedule:
|
|
7
|
+
interval: weekly
|
|
8
|
+
open-pull-requests-limit: 5
|
|
9
|
+
groups:
|
|
10
|
+
# Batch low-risk updates into a single PR to cut noise.
|
|
11
|
+
minor-and-patch:
|
|
12
|
+
update-types: [minor, patch]
|
|
13
|
+
|
|
14
|
+
# GitHub Actions used in workflows
|
|
15
|
+
- package-ecosystem: github-actions
|
|
16
|
+
directory: /
|
|
17
|
+
schedule:
|
|
18
|
+
interval: weekly
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
root = true
|
|
2
|
+
|
|
3
|
+
[*]
|
|
4
|
+
charset = utf-8
|
|
5
|
+
end_of_line = lf
|
|
6
|
+
insert_final_newline = true
|
|
7
|
+
trim_trailing_whitespace = true
|
|
8
|
+
indent_style = space
|
|
9
|
+
indent_size = 2
|
|
10
|
+
|
|
11
|
+
[*.md]
|
|
12
|
+
trim_trailing_whitespace = false
|
|
13
|
+
|
|
14
|
+
[*.{bat,cmd}]
|
|
15
|
+
end_of_line = crlf
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Code owners are automatically requested for review on matching paths.
|
|
2
|
+
# Docs: https://docs.github.com/articles/about-code-owners
|
|
3
|
+
#
|
|
4
|
+
# Replace @OWNER with your username or team (e.g. @your-org/maintainers).
|
|
5
|
+
|
|
6
|
+
# Default owner for everything in the repo
|
|
7
|
+
* @OWNER
|
|
8
|
+
|
|
9
|
+
# Examples — uncomment and adjust:
|
|
10
|
+
# /.github/ @your-org/devops
|
|
11
|
+
# /src/api/ @your-org/backend
|
|
12
|
+
# *.md @your-org/docs
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for contributing! This repository uses shared tooling from
|
|
4
|
+
[`devkit`](https://github.com/vpnsin/devkit) — ESLint, Prettier,
|
|
5
|
+
commitlint, markdownlint, Husky, and CI/release workflows.
|
|
6
|
+
|
|
7
|
+
## Getting started
|
|
8
|
+
|
|
9
|
+
- **Node.js** >= 18.18 and **npm**
|
|
10
|
+
- `npm install` (sets up Git hooks via Husky automatically)
|
|
11
|
+
|
|
12
|
+
## Development workflow
|
|
13
|
+
|
|
14
|
+
1. Branch off `main` (or `dev`):
|
|
15
|
+
`git checkout -b feat/short-description`
|
|
16
|
+
2. Make your changes. On commit, the pre-commit hook auto-formats and lints
|
|
17
|
+
staged files.
|
|
18
|
+
3. Before pushing, verify locally:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm run type-check
|
|
22
|
+
npm run lint
|
|
23
|
+
npm run lint:md
|
|
24
|
+
npm run format:check
|
|
25
|
+
npm run build # if the repo has a build step
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Commit messages — Conventional Commits (required)
|
|
29
|
+
|
|
30
|
+
The `commit-msg` hook enforces them, and release-please uses them to compute the
|
|
31
|
+
version bump and changelog.
|
|
32
|
+
|
|
33
|
+
| Type | Effect |
|
|
34
|
+
| -------------------------------------------------------------------- | ------------- |
|
|
35
|
+
| `feat:` | minor release |
|
|
36
|
+
| `fix:` | patch release |
|
|
37
|
+
| `docs:` `chore:` `refactor:` `test:` `ci:` `build:` `perf:` `style:` | no release |
|
|
38
|
+
| `feat!:` / `BREAKING CHANGE:` footer | major release |
|
|
39
|
+
|
|
40
|
+
Example: `feat(auth): add password reset flow`
|
|
41
|
+
|
|
42
|
+
## Pull requests
|
|
43
|
+
|
|
44
|
+
- Keep PRs focused and fill in the PR template.
|
|
45
|
+
- Make sure CI is green.
|
|
46
|
+
- A code owner (see `CODEOWNERS`) will review and merge.
|
|
47
|
+
|
|
48
|
+
## Releases
|
|
49
|
+
|
|
50
|
+
Merging to `main` opens or updates a **release-please** PR. Merging that PR
|
|
51
|
+
publishes the GitHub release, tag, and changelog.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Report a problem so we can fix it
|
|
3
|
+
labels: [bug]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: what-happened
|
|
7
|
+
attributes:
|
|
8
|
+
label: What happened?
|
|
9
|
+
description: A clear description of the bug and what you expected instead.
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: repro
|
|
14
|
+
attributes:
|
|
15
|
+
label: Steps to reproduce
|
|
16
|
+
placeholder: |
|
|
17
|
+
1. Go to '...'
|
|
18
|
+
2. Run '...'
|
|
19
|
+
3. See error
|
|
20
|
+
validations:
|
|
21
|
+
required: true
|
|
22
|
+
- type: input
|
|
23
|
+
id: version
|
|
24
|
+
attributes:
|
|
25
|
+
label: Version / environment
|
|
26
|
+
description: Package version, Node version, OS.
|
|
27
|
+
validations:
|
|
28
|
+
required: true
|
|
29
|
+
- type: textarea
|
|
30
|
+
id: logs
|
|
31
|
+
attributes:
|
|
32
|
+
label: Logs / screenshots
|
|
33
|
+
description: Relevant output (will be rendered as code).
|
|
34
|
+
render: shell
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Suggest an idea or improvement
|
|
3
|
+
labels: [enhancement]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: problem
|
|
7
|
+
attributes:
|
|
8
|
+
label: Problem
|
|
9
|
+
description: What problem does this solve? What's the use case?
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: proposal
|
|
14
|
+
attributes:
|
|
15
|
+
label: Proposed solution
|
|
16
|
+
description: What would you like to happen?
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
- type: textarea
|
|
20
|
+
id: alternatives
|
|
21
|
+
attributes:
|
|
22
|
+
label: Alternatives considered
|
|
23
|
+
description: Other approaches you've thought about.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<!-- PR title MUST be a Conventional Commit, e.g. "feat: add X" or "fix: handle Y"
|
|
2
|
+
— release-please reads it to compute the version bump and changelog. -->
|
|
3
|
+
|
|
4
|
+
## Summary
|
|
5
|
+
|
|
6
|
+
<!-- What does this PR change, and why? Link any issue: Closes #123 -->
|
|
7
|
+
|
|
8
|
+
## Type of change
|
|
9
|
+
|
|
10
|
+
- [ ] `feat` — new feature (minor bump)
|
|
11
|
+
- [ ] `fix` — bug fix (patch bump)
|
|
12
|
+
- [ ] `refactor` — no behaviour change
|
|
13
|
+
- [ ] `docs` — documentation only
|
|
14
|
+
- [ ] `chore` / `ci` / `build` — tooling, deps, config
|
|
15
|
+
- [ ] `perf` / `style` / `test`
|
|
16
|
+
|
|
17
|
+
## Checklist
|
|
18
|
+
|
|
19
|
+
- [ ] PR title is a Conventional Commit (`feat:`, `fix:`, `chore:` …)
|
|
20
|
+
- [ ] `npm run type-check` passes
|
|
21
|
+
- [ ] `npm run lint` passes (+ `npm run lint:md` if docs changed)
|
|
22
|
+
- [ ] `npm run build` succeeds (if applicable)
|
|
23
|
+
- [ ] No secrets committed (env values stay in the deploy platform / local `.env`)
|
|
24
|
+
|
|
25
|
+
## Screenshots / notes
|
|
26
|
+
|
|
27
|
+
<!-- Before/after for UI changes; migration notes; follow-ups -->
|