@deernova/style 0.1.0 → 0.2.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 +11 -8
- package/bin/cli.mjs +10 -7
- package/package.json +3 -4
- package/skill/SKILL.md +4 -2
- package/skill/manifest.json +2 -2
- package/skill/references/web.md +2 -2
- package/template/app.js +0 -7
- package/template/index.html +0 -1290
- package/template/manifest.json +0 -24
- package/template/project/README.md +0 -170
- package/template/project/components/Banner/README.md +0 -33
- package/template/project/components/Banner/preview.html +0 -26
- package/template/project/components/Button/README.md +0 -59
- package/template/project/components/Button/preview.html +0 -27
- package/template/project/components/Card/README.md +0 -31
- package/template/project/components/Card/preview.html +0 -24
- package/template/project/components/CodeBlock/README.md +0 -34
- package/template/project/components/CodeBlock/preview.html +0 -16
- package/template/project/components/Composer/README.md +0 -42
- package/template/project/components/Composer/preview.html +0 -28
- package/template/project/components/Cover/preview.html +0 -53
- package/template/project/components/EmptyState/README.md +0 -28
- package/template/project/components/EmptyState/preview.html +0 -16
- package/template/project/components/GlassControls/README.md +0 -43
- package/template/project/components/GlassControls/preview.html +0 -40
- package/template/project/components/ListGroup/README.md +0 -39
- package/template/project/components/ListGroup/preview.html +0 -22
- package/template/project/components/MacWindow/README.md +0 -27
- package/template/project/components/MacWindow/preview.html +0 -70
- package/template/project/components/Message/README.md +0 -31
- package/template/project/components/Message/preview.html +0 -21
- package/template/project/components/PhoneScreen/README.md +0 -25
- package/template/project/components/PhoneScreen/preview.html +0 -74
- package/template/project/components/Segmented/README.md +0 -21
- package/template/project/components/Segmented/preview.html +0 -21
- package/template/project/components/Sheet/README.md +0 -29
- package/template/project/components/Sheet/preview.html +0 -31
- package/template/project/components/Sidebar/README.md +0 -36
- package/template/project/components/Sidebar/preview.html +0 -20
- package/template/project/components/StepRow/README.md +0 -35
- package/template/project/components/StepRow/preview.html +0 -17
- package/template/project/components/Tag/README.md +0 -36
- package/template/project/components/Tag/preview.html +0 -22
- package/template/project/components/TextField/README.md +0 -29
- package/template/project/components/TextField/preview.html +0 -28
- package/template/project/components/bundle.css +0 -189
- package/template/project/design-system.json +0 -25
- package/template/project/images/Banner-dark.png +0 -0
- package/template/project/images/Banner-light.png +0 -0
- package/template/project/images/Button-dark.png +0 -0
- package/template/project/images/Button-light.png +0 -0
- package/template/project/images/Card-dark.png +0 -0
- package/template/project/images/Card-light.png +0 -0
- package/template/project/images/CodeBlock-dark.png +0 -0
- package/template/project/images/CodeBlock-light.png +0 -0
- package/template/project/images/Composer-dark.png +0 -0
- package/template/project/images/Composer-light.png +0 -0
- package/template/project/images/Cover-dark.png +0 -0
- package/template/project/images/Cover-light.png +0 -0
- package/template/project/images/EmptyState-dark.png +0 -0
- package/template/project/images/EmptyState-light.png +0 -0
- package/template/project/images/Example-iOSButtonsInPhone-dark.png +0 -0
- package/template/project/images/Example-iOSButtonsInPhone-light.png +0 -0
- package/template/project/images/GlassControls-dark.png +0 -0
- package/template/project/images/GlassControls-light.png +0 -0
- package/template/project/images/ListGroup-dark.png +0 -0
- package/template/project/images/ListGroup-light.png +0 -0
- package/template/project/images/MacWindow-dark.png +0 -0
- package/template/project/images/MacWindow-light.png +0 -0
- package/template/project/images/Message-dark.png +0 -0
- package/template/project/images/Message-light.png +0 -0
- package/template/project/images/PhoneScreen-dark.png +0 -0
- package/template/project/images/PhoneScreen-light.png +0 -0
- package/template/project/images/Segmented-dark.png +0 -0
- package/template/project/images/Segmented-light.png +0 -0
- package/template/project/images/Sheet-dark.png +0 -0
- package/template/project/images/Sheet-light.png +0 -0
- package/template/project/images/Sidebar-dark.png +0 -0
- package/template/project/images/Sidebar-light.png +0 -0
- package/template/project/images/StepRow-dark.png +0 -0
- package/template/project/images/StepRow-light.png +0 -0
- package/template/project/images/Tag-dark.png +0 -0
- package/template/project/images/Tag-light.png +0 -0
- package/template/project/images/TextField-dark.png +0 -0
- package/template/project/images/TextField-light.png +0 -0
- package/template/project/tokens.css +0 -187
- package/template/project/tokens.json +0 -142
- package/template/style.css +0 -1
package/README.md
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
# @deernova/style
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Install the Deernova design reference skill into an existing repository. Requires Node.js 22+. No runtime dependencies.
|
|
4
4
|
|
|
5
5
|
```sh
|
|
6
|
-
npx @deernova/style@latest install
|
|
7
|
-
npx @deernova/style@latest update
|
|
8
|
-
npx @deernova/style@latest doctor
|
|
9
|
-
npx @deernova/style@latest init ./my-site
|
|
6
|
+
npx @deernova/style@latest install --repo /path/to/project
|
|
7
|
+
npx @deernova/style@latest update --repo /path/to/project
|
|
8
|
+
npx @deernova/style@latest doctor --repo /path/to/project
|
|
10
9
|
```
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
Run without `--repo` inside your target project to use its current directory. The CLI writes only `.agents/skills/deernova-style/` by default. It does not add application code, CSS imports or package dependencies. The AI uses the installed skill to guide implementation through your project's existing framework and components.
|
|
13
12
|
|
|
14
|
-
The skill
|
|
13
|
+
The skill contains the complete Deernova foundations, writing, typography, semantic values, platform density, accessibility, review criteria, component/layout references, SwiftUI examples and visual assets. The documentation website and skill are generated from the same design source.
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
Use `--agent claude|codex|agents` to choose the skill directory, `--dir <skills-parent>` for a custom destination, or `--global` for a user installation. These three destination modes are mutually exclusive. Repeat the same options on update.
|
|
16
|
+
|
|
17
|
+
Updates are explicit. Modified skills are protected; `--force` backs up before replacing them. doctor returns nonzero if missing, modified or out of sync.
|
|
18
|
+
|
|
19
|
+
In 0.2.0, `init [existing-repository]` is an alias for skill installation, replacing the 0.1.0 website scaffold command. No separate tokens or UI package is needed.
|
package/bin/cli.mjs
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { cp, mkdir, readFile, readdir, rename, rm, lstat } from 'node:fs/promises';
|
|
3
|
-
import { resolve, join
|
|
3
|
+
import { resolve, join } from 'node:path';
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { createHash } from 'node:crypto';
|
|
7
7
|
const pkg = fileURLToPath(new URL('../',import.meta.url));
|
|
8
|
-
const args=process.argv.slice(2)
|
|
8
|
+
const args=process.argv.slice(2); let command=args.shift()||'help';
|
|
9
9
|
const options={};let positional;
|
|
10
|
-
for(let i=0;i<args.length;i++){const a=args[i];if(['--global','--force'].includes(a))options[a.slice(2)]=true;else if(['--dir','--agent'].includes(a)){if(!args[i+1]||args[i+1].startsWith('--'))throw Error(`${a} needs a value`);options[a.slice(2)]=args[++i];}else if(a.startsWith('-'))throw Error(`Unknown option: ${a}`);else if(positional)throw Error('Too many arguments');else positional=a;}
|
|
10
|
+
for(let i=0;i<args.length;i++){const a=args[i];if(['--global','--force'].includes(a))options[a.slice(2)]=true;else if(['--dir','--agent','--repo'].includes(a)){if(!args[i+1]||args[i+1].startsWith('--'))throw Error(`${a} needs a value`);options[a.slice(2)]=args[++i];}else if(a.startsWith('-'))throw Error(`Unknown option: ${a}`);else if(positional)throw Error('Too many arguments');else positional=a;}
|
|
11
11
|
async function exists(p){try{return await lstat(p);}catch(e){if(e.code==='ENOENT')return null;throw e;}}
|
|
12
12
|
async function main(){
|
|
13
|
-
if(['help','--help','-h'].includes(command)){console.log(`deernova-style install|update|doctor [--global] [--agent codex|claude|agents] [--dir <skills-parent>] [--force]\ndeernova-style init
|
|
13
|
+
if(['help','--help','-h'].includes(command)){console.log(`deernova-style install|update|doctor [--repo <existing-repository>] [--global] [--agent codex|claude|agents] [--dir <skills-parent>] [--force]\ndeernova-style init [existing-repository] (alias for install --repo)\ndeernova-style version\nInstalls design reference files only; does not add app code or package dependencies. Default: project .agents/skills/deernova-style. --global defaults to CODEX_HOME/skills.\nupdate installs the version bundled in this CLI; use npx @deernova/style@latest update to fetch latest.\n--force keeps a timestamped backup before replacing a locally modified skill.`);return;}
|
|
14
14
|
const manifest=JSON.parse(await readFile(join(pkg,'skill/manifest.json'),'utf8'));
|
|
15
15
|
if(command==='version'){console.log(manifest.version);return;}
|
|
16
|
-
if(command==='init'){if(
|
|
16
|
+
if(command==='init'){if(options.repo&&positional)throw Error('Specify the repository once');options.repo=positional||options.repo||process.cwd();positional=undefined;command='install';}
|
|
17
17
|
if(!['install','update','doctor'].includes(command))throw Error(`Unknown command: ${command}`);
|
|
18
|
-
if(positional)throw Error('Use --dir to specify a skills parent
|
|
18
|
+
if(positional)throw Error('Use --repo to specify a repository or --dir to specify a skills parent');
|
|
19
|
+
if([options.repo,options.global,options.dir].filter(Boolean).length>1)throw Error('--repo, --global and --dir are mutually exclusive');
|
|
20
|
+
const repo=resolve(options.repo||process.cwd());
|
|
21
|
+
if(!options.global&&!options.dir&&!(await exists(repo))?.isDirectory())throw Error('Repository must be an existing directory');
|
|
19
22
|
const agent=options.agent||(options.global?'codex':'agents');if(!['codex','claude','agents'].includes(agent))throw Error('Agent must be codex, claude or agents');
|
|
20
|
-
const base=options.dir?resolve(options.dir):options.global?(agent==='codex'?join(process.env.CODEX_HOME||join(homedir(),'.codex'),'skills'):join(homedir(),'.'+agent,'skills')):
|
|
23
|
+
const base=options.dir?resolve(options.dir):options.global?(agent==='codex'?join(process.env.CODEX_HOME||join(homedir(),'.codex'),'skills'):join(homedir(),'.'+agent,'skills')):join(repo,'.'+agent,'skills');
|
|
21
24
|
const dest=join(base,'deernova-style');const state=await exists(dest);
|
|
22
25
|
if(state?.isSymbolicLink()||(state&&!state.isDirectory()))throw Error('Destination is not a regular directory');
|
|
23
26
|
let installed=null;try{installed=JSON.parse(await readFile(join(dest,'manifest.json'),'utf8'));}catch{}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deernova/style",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22"
|
|
@@ -13,8 +13,7 @@
|
|
|
13
13
|
},
|
|
14
14
|
"files": [
|
|
15
15
|
"bin",
|
|
16
|
-
"skill"
|
|
17
|
-
"template"
|
|
16
|
+
"skill"
|
|
18
17
|
],
|
|
19
|
-
"description": "Deernova design skill
|
|
18
|
+
"description": "Install the Deernova design reference skill into an existing repository"
|
|
20
19
|
}
|
package/skill/SKILL.md
CHANGED
|
@@ -5,12 +5,14 @@ description: Apply Deernova's monochrome design language to Deernova apps, websi
|
|
|
5
5
|
|
|
6
6
|
# Deernova Style
|
|
7
7
|
|
|
8
|
+
Use this skill as the design reference for the repository in which it is installed. Read its guidelines when creating, modifying or reviewing that repository’s interface. Apply the principles through the project’s existing technology and components; do not install a component library or replace the architecture merely to follow this skill.
|
|
9
|
+
|
|
8
10
|
Build coherent Deernova interfaces using the versioned resources bundled with this skill. Preserve the user's product, platform, framework and requested scope. The HTML previews demonstrate appearance; they are not production SwiftUI components or proof of functional behavior.
|
|
9
11
|
|
|
10
12
|
## Start with the relevant source
|
|
11
13
|
|
|
12
14
|
- Read [foundations](references/foundations.md) for principles, writing, layout, platform behavior, motion and accessibility.
|
|
13
|
-
- Read [tokens](references/tokens.md) when choosing semantic values. Exact structured values and typography live in `assets/design/tokens.json`;
|
|
15
|
+
- Read [tokens](references/tokens.md) when choosing semantic values. Exact structured values and typography live in `assets/design/tokens.json`; the CSS in `assets/design/tokens.css` is a reference implementation, not a mandatory dependency.
|
|
14
16
|
- Search [components](references/components.md) for the component being implemented, then inspect `assets/design/components/<Name>/preview.html` for its anatomy and variants. Native implementation examples live in that component's README.
|
|
15
17
|
- For web implementation and validation, read [web](references/web.md). For native implementation, read [native](references/native.md).
|
|
16
18
|
- For design review, read [review](references/review.md). Report concrete mismatches and locations; do not redesign unrelated screens.
|
|
@@ -33,4 +35,4 @@ Cards use thin borders without floating shadows. System-native controls and glas
|
|
|
33
35
|
|
|
34
36
|
## Version and updates
|
|
35
37
|
|
|
36
|
-
`manifest.json` identifies the package version and source hash.
|
|
38
|
+
`manifest.json` identifies the package version and source hash. The documentation website and skill references are generated together from the repository's `design/` source. Update through `npx @deernova/style@latest update` in the same project; for global installations append `--global` and the same agent choice. This is an explicit update, not a background network service. Preserve local changes; the CLI refuses to overwrite them unless `--force` is requested, in which case it keeps a backup. Never edit generated references as the upstream source.
|
package/skill/manifest.json
CHANGED
package/skill/references/web.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Web implementation
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Read the repository’s existing framework, styles and components first. Translate Deernova’s semantic values and visual principles into that system. No npm style or UI package is required. The bundled HTML/CSS files are visual references; their `dn-` class names are not an interface that consuming projects must adopt.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Use `assets/design/tokens.json` and the relevant previews to make implementation decisions. Copy selected reference CSS only if it fits the user’s task and project conventions; do not add an entire stylesheet or scaffold application code just because the skill is installed. Ensure buttons submit only intentionally, fields have labels, dialogs manage focus and Escape, and segmented controls expose their selected state. Preview-only static elements must receive real product behavior before shipping.
|
|
6
6
|
|
|
7
7
|
`data-theme="light"` or `data-theme="dark"` on the root overrides system theme; removing it follows the system. Persist preferences only if appropriate. Honor prefers-reduced-motion and prefers-reduced-transparency with stable and opaque fallbacks. Do not layer glass over reading content.
|
|
8
8
|
|
package/template/app.js
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
const theme = document.querySelector('#theme');
|
|
2
|
-
try { theme.value = localStorage.getItem('deernova-theme') || 'system'; } catch {}
|
|
3
|
-
function applyTheme(){const value=theme.value; if(value==='system')document.documentElement.removeAttribute('data-theme');else document.documentElement.dataset.theme=value;document.querySelectorAll('iframe').forEach(f=>{f.src=f.src.split('#')[0]+(value==='system'?'':'#'+value);});try{localStorage.setItem('deernova-theme',value);}catch{}}
|
|
4
|
-
theme.addEventListener('change',applyTheme);applyTheme();
|
|
5
|
-
const search=document.querySelector('#search');search.addEventListener('input',()=>{const q=search.value.trim().toLowerCase();let n=0;document.querySelectorAll('.component').forEach(c=>{c.hidden=!c.dataset.search.toLowerCase().includes(q);if(!c.hidden)n++;});document.querySelector('#results').textContent=q?`找到 ${n} 个组件`:'';});search.addEventListener('keydown',e=>{if(e.key==='Enter')document.querySelector('#components').scrollIntoView();});
|
|
6
|
-
let timer;document.querySelectorAll('[data-copy]').forEach(b=>b.addEventListener('click',async()=>{const toast=document.querySelector('#toast');try{await navigator.clipboard.writeText(b.dataset.copy);toast.textContent='已复制 '+b.dataset.copy;}catch{toast.textContent='请手动复制:'+b.dataset.copy;}toast.classList.add('show');clearTimeout(timer);timer=setTimeout(()=>toast.classList.remove('show'),3000);}));
|
|
7
|
-
const observer=new IntersectionObserver(entries=>{for(const e of entries)if(e.isIntersecting){document.querySelectorAll('nav>a').forEach(a=>{const active=a.hash==='#'+e.target.id;a.classList.toggle('active',active);if(active)a.setAttribute('aria-current','location');else a.removeAttribute('aria-current');});}},{rootMargin:'-10% 0px -70% 0px'});document.querySelectorAll('main>section').forEach(s=>observer.observe(s));
|