@ai.all/ds7 0.0.0-stage → 2.0.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/01-architecture/ATOMIC-DESIGN.md +68 -0
- package/01-architecture/COMPONENT-ANATOMY.md +101 -0
- package/01-architecture/MODIFIER-SYSTEM.md +90 -0
- package/02-design-system/BRANDBOOK-SANDBOX.md +52 -0
- package/02-design-system/NAMING-CONVENTIONS.md +45 -0
- package/02-design-system/TOKENS-SPEC.md +102 -0
- package/03-performance-web-vitals/ASSETS-PIPELINE.md +62 -0
- package/03-performance-web-vitals/CRITICAL-CSS.md +39 -0
- package/03-performance-web-vitals/FONTS-ZERO-CLS.md +59 -0
- package/03-performance-web-vitals/HYDRATION-STRATEGY.md +68 -0
- package/04-seo-ai-optimization/AEO-GEO-AI-SEARCH.md +53 -0
- package/04-seo-ai-optimization/GOOGLE-LOCAL-EEAT.md +36 -0
- package/04-seo-ai-optimization/STRUCTURED-DATA.md +95 -0
- package/05-internationalization/I18N-ARCHITECTURE.md +59 -0
- package/05-internationalization/LOCALE-TEMPLATE.json +33 -0
- package/06-business-conversion/B2C-B2B-MODELS.md +37 -0
- package/06-business-conversion/CONTEXTUAL-LEADS.md +45 -0
- package/06-business-conversion/EV-SOLAR-ECOSYSTEM.md +38 -0
- package/07-testing/TESTING-STRATEGY.md +95 -0
- package/08-token-optimization/TOKEN-STRATEGY.md +100 -0
- package/ALL.md +232 -0
- package/CHANGELOG.md +27 -0
- package/LICENSE +21 -0
- package/README.md +118 -2
- package/SPEC.md +102 -0
- package/bin/ds7.js +224 -0
- package/package.json +61 -4
- package/templates/component.vue +116 -0
- package/templates/nuxt.config.ts +64 -0
- package/templates/theme.css +55 -0
package/bin/ds7.js
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
// DS7 CLI. Installs the DS7 standard into ds7/ and enables it as the `ds7`
|
|
5
|
+
// pack of AI-ALL (@ai.all/aiall). The agent entrypoints and the root ALL.md
|
|
6
|
+
// belong to AI-ALL; this CLI never writes them.
|
|
7
|
+
//
|
|
8
|
+
// Usage: npx @ai.all/ds7 [init|sync|update|--version|--help]
|
|
9
|
+
//
|
|
10
|
+
// Ownership:
|
|
11
|
+
// ds7/** the standard, vendored; overwritten by `update`
|
|
12
|
+
// ds7/aiall-pack.json pack manifest, generated from this version; overwritten by `update`
|
|
13
|
+
// ds7/VERSION installed version; written by `init` and `update`
|
|
14
|
+
// ALL.md (project root) AI-ALL routing file; its packs block is managed by AI-ALL,
|
|
15
|
+
// the text outside that block is the project's own
|
|
16
|
+
|
|
17
|
+
const fs = require('fs');
|
|
18
|
+
const path = require('path');
|
|
19
|
+
const { spawnSync } = require('child_process');
|
|
20
|
+
|
|
21
|
+
const C = {
|
|
22
|
+
reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m',
|
|
23
|
+
green: '\x1b[32m', yellow: '\x1b[33m', cyan: '\x1b[36m', red: '\x1b[31m',
|
|
24
|
+
};
|
|
25
|
+
const ok = (s) => console.log(` ${C.green}✓${C.reset} ${s}`);
|
|
26
|
+
const skip = (s) => console.log(` ${C.dim}· ${s} (exists, kept)${C.reset}`);
|
|
27
|
+
const info = (s) => console.log(` ${C.yellow}→${C.reset} ${s}`);
|
|
28
|
+
const err = (s) => console.log(` ${C.red}✗${C.reset} ${s}`);
|
|
29
|
+
|
|
30
|
+
const PKG = path.resolve(__dirname, '..');
|
|
31
|
+
const TARGET = process.cwd();
|
|
32
|
+
const DS7 = path.join(TARGET, 'ds7');
|
|
33
|
+
const PACK_REF = 'ds7/aiall-pack.json';
|
|
34
|
+
|
|
35
|
+
const { version } = require(path.join(PKG, 'package.json'));
|
|
36
|
+
|
|
37
|
+
// Folders that make up the standard (copied into ds7/).
|
|
38
|
+
const DS7_DIRS = [
|
|
39
|
+
'01-architecture', '02-design-system', '03-performance-web-vitals',
|
|
40
|
+
'04-seo-ai-optimization', '05-internationalization', '06-business-conversion',
|
|
41
|
+
'07-testing', '08-token-optimization', 'templates',
|
|
42
|
+
];
|
|
43
|
+
// Root-level documents of the standard (copied into ds7/).
|
|
44
|
+
const DS7_FILES = ['README.md', 'SPEC.md', 'ALL.md', 'CHANGELOG.md'];
|
|
45
|
+
|
|
46
|
+
// Collect every file under a folder of the package, as paths relative to PKG.
|
|
47
|
+
function listFiles(relDir) {
|
|
48
|
+
const out = [];
|
|
49
|
+
const walk = (abs, rel) => {
|
|
50
|
+
for (const e of fs.readdirSync(abs, { withFileTypes: true })) {
|
|
51
|
+
const a = path.join(abs, e.name);
|
|
52
|
+
const r = path.join(rel, e.name);
|
|
53
|
+
if (e.isDirectory()) walk(a, r);
|
|
54
|
+
else out.push(r);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
walk(path.join(PKG, relDir), relDir);
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Copy one file. `overwrite` decides whether an existing file is replaced.
|
|
62
|
+
function copyOne(relFromPkg, destAbs, overwrite) {
|
|
63
|
+
const label = path.relative(TARGET, destAbs);
|
|
64
|
+
if (fs.existsSync(destAbs) && !overwrite) { skip(label); return false; }
|
|
65
|
+
fs.mkdirSync(path.dirname(destAbs), { recursive: true });
|
|
66
|
+
fs.copyFileSync(path.join(PKG, relFromPkg), destAbs);
|
|
67
|
+
ok(label);
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Every file of the standard, as [relative path in package, destination].
|
|
72
|
+
function standardFiles() {
|
|
73
|
+
const pairs = [];
|
|
74
|
+
for (const dir of DS7_DIRS) {
|
|
75
|
+
if (!fs.existsSync(path.join(PKG, dir))) continue;
|
|
76
|
+
for (const rel of listFiles(dir)) pairs.push([rel, path.join(DS7, rel)]);
|
|
77
|
+
}
|
|
78
|
+
for (const f of DS7_FILES) pairs.push([f, path.join(DS7, f)]);
|
|
79
|
+
return pairs;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// The pack manifest that AI-ALL reads. Paths are project-relative, because the
|
|
83
|
+
// standard is vendored into ds7/ and AI-ALL links to them from the project's ALL.md.
|
|
84
|
+
function packManifest() {
|
|
85
|
+
const doc = (p) => `ds7/${p}`;
|
|
86
|
+
return {
|
|
87
|
+
name: '@ai.all/ds7',
|
|
88
|
+
version,
|
|
89
|
+
title: 'DS7 web architecture standard',
|
|
90
|
+
directives: [
|
|
91
|
+
{ id: 'ds7.rules', title: 'DS7 agent rules',
|
|
92
|
+
summary: 'Read before any change in a DS7 web project: ground rules, build order, components and the pre-finish checklist.',
|
|
93
|
+
doc: doc('ALL.md') },
|
|
94
|
+
{ id: 'ds7.spec', title: 'DS7 stack and quality gates',
|
|
95
|
+
summary: 'Read for the stack, directory layout, naming, performance targets and quality gates.',
|
|
96
|
+
doc: doc('SPEC.md') },
|
|
97
|
+
{ id: 'ds7.architecture', title: 'Atomic architecture',
|
|
98
|
+
summary: 'Read before creating or changing components, variants or modifiers.',
|
|
99
|
+
doc: doc('01-architecture/COMPONENT-ANATOMY.md') },
|
|
100
|
+
{ id: 'ds7.brand', title: 'Brand tokens and brandbook',
|
|
101
|
+
summary: 'Read before changing colours, type, spacing or the brandbook page.',
|
|
102
|
+
doc: doc('02-design-system/TOKENS-SPEC.md') },
|
|
103
|
+
{ id: 'ds7.i18n', title: 'Internationalisation',
|
|
104
|
+
summary: 'Read before adding a locale, a route or a translated string.',
|
|
105
|
+
doc: doc('05-internationalization/I18N-ARCHITECTURE.md') },
|
|
106
|
+
{ id: 'ds7.testing', title: 'Testing strategy',
|
|
107
|
+
summary: 'Read before adding or changing tests or quality checks.',
|
|
108
|
+
doc: doc('07-testing/TESTING-STRATEGY.md') },
|
|
109
|
+
],
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function writePackManifest(overwrite) {
|
|
114
|
+
const dest = path.join(DS7, 'aiall-pack.json');
|
|
115
|
+
if (fs.existsSync(dest) && !overwrite) { skip(path.relative(TARGET, dest)); return; }
|
|
116
|
+
fs.mkdirSync(DS7, { recursive: true });
|
|
117
|
+
fs.writeFileSync(dest, `${JSON.stringify(packManifest(), null, 2)}\n`);
|
|
118
|
+
ok(path.relative(TARGET, dest));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function writeVersion() {
|
|
122
|
+
fs.mkdirSync(DS7, { recursive: true });
|
|
123
|
+
fs.writeFileSync(path.join(DS7, 'VERSION'), `${version}\n`);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Run an AI-ALL command with the @ai.all/aiall version this package depends on.
|
|
127
|
+
// The dependency is pinned, so the tested version is the one that runs.
|
|
128
|
+
function runAiall(args) {
|
|
129
|
+
let bin;
|
|
130
|
+
try { bin = require.resolve('@ai.all/aiall/bin/cli.js'); }
|
|
131
|
+
catch { err('@ai.all/aiall is not installed. Reinstall with: npm i -D @ai.all/ds7'); return false; }
|
|
132
|
+
const r = spawnSync(process.execPath, [bin, ...args, '--path', TARGET], { stdio: 'inherit' });
|
|
133
|
+
return r.status === 0;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// True when .ai/aiall.json already lists the DS7 pack.
|
|
137
|
+
function packEnabled() {
|
|
138
|
+
try {
|
|
139
|
+
const cfg = JSON.parse(fs.readFileSync(path.join(TARGET, '.ai', 'aiall.json'), 'utf8'));
|
|
140
|
+
return Array.isArray(cfg.packs) && cfg.packs.includes(PACK_REF);
|
|
141
|
+
} catch { return false; }
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function enablePack() {
|
|
145
|
+
if (packEnabled()) { skip(`pack ${PACK_REF}`); return true; }
|
|
146
|
+
if (!runAiall(['packs', 'add', PACK_REF])) return false;
|
|
147
|
+
ok(`pack ${PACK_REF} enabled`);
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Warn about files left by DS7 1.x. Nothing is deleted or rewritten automatically.
|
|
152
|
+
function legacyWarnings() {
|
|
153
|
+
const rootAll = path.join(TARGET, 'ALL.md');
|
|
154
|
+
if (fs.existsSync(rootAll) && fs.readFileSync(rootAll, 'utf8').includes('Agent Rules for DS7 Projects')) {
|
|
155
|
+
info('Root ALL.md still holds the DS7 1.x rules. Those rules now live in ds7/ALL.md.');
|
|
156
|
+
info('Remove the copied rules from root ALL.md and keep the aiall packs block.');
|
|
157
|
+
}
|
|
158
|
+
if (fs.existsSync(path.join(TARGET, 'ALL.project.md'))) {
|
|
159
|
+
info('ALL.project.md is from DS7 1.x and is no longer used. Move its project values into');
|
|
160
|
+
info('root ALL.md (below the aiall packs block), then delete the file.');
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function cmdInit() {
|
|
165
|
+
console.log(`\n${C.bold}${C.cyan}DS7 v${version} — setup${C.reset}\n`);
|
|
166
|
+
|
|
167
|
+
for (const [rel, dest] of standardFiles()) copyOne(rel, dest, false);
|
|
168
|
+
writePackManifest(false);
|
|
169
|
+
writeVersion();
|
|
170
|
+
|
|
171
|
+
console.log(`\n${C.yellow}Configuring AI-ALL…${C.reset}\n`);
|
|
172
|
+
if (!runAiall(['init'])) { err('AI-ALL init failed. Run: npx @ai.all/aiall init'); process.exitCode = 1; return; }
|
|
173
|
+
if (!enablePack()) { err(`Could not enable the pack. Run: npx @ai.all/aiall packs add ${PACK_REF}`); process.exitCode = 1; return; }
|
|
174
|
+
legacyWarnings();
|
|
175
|
+
|
|
176
|
+
console.log(`\n${C.bold}${C.green}DS7 is installed.${C.reset}`);
|
|
177
|
+
console.log(` 1. Read ${C.cyan}ds7/README.md${C.reset} for the standard and the build order.`);
|
|
178
|
+
console.log(` 2. Add this project's values to the root ${C.cyan}ALL.md${C.reset}, below the aiall packs block.`);
|
|
179
|
+
console.log(` 3. Run ${C.cyan}npx @ai.all/ds7 update${C.reset} to get new versions of the standard.\n`);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function cmdSync() {
|
|
183
|
+
console.log(`\n${C.yellow}Syncing agent entrypoints…${C.reset}\n`);
|
|
184
|
+
if (runAiall(['sync'])) ok('Agent entrypoints are in sync.');
|
|
185
|
+
else { err('Sync failed. Run: npx @ai.all/aiall sync'); process.exitCode = 1; }
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function cmdUpdate() {
|
|
189
|
+
console.log(`\n${C.yellow}Updating the standard to v${version}…${C.reset}\n`);
|
|
190
|
+
if (!fs.existsSync(DS7)) {
|
|
191
|
+
err('ds7/ not found. Run `npx @ai.all/ds7` (init) first.');
|
|
192
|
+
process.exitCode = 1;
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
for (const [rel, dest] of standardFiles()) copyOne(rel, dest, true);
|
|
196
|
+
writePackManifest(true);
|
|
197
|
+
writeVersion();
|
|
198
|
+
|
|
199
|
+
if (!runAiall(['sync'])) { err('Sync failed. Run: npx @ai.all/aiall sync'); process.exitCode = 1; return; }
|
|
200
|
+
if (!enablePack()) { process.exitCode = 1; return; }
|
|
201
|
+
legacyWarnings();
|
|
202
|
+
|
|
203
|
+
console.log(`\n${C.green}Standard updated to v${version}. See ds7/CHANGELOG.md for what changed.${C.reset}`);
|
|
204
|
+
info('The root ALL.md outside the aiall packs block was not changed.\n');
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function cmdHelp() {
|
|
208
|
+
console.log(`
|
|
209
|
+
DS7 ${version}
|
|
210
|
+
|
|
211
|
+
npx @ai.all/ds7 install the standard and enable the ds7 pack (init)
|
|
212
|
+
npx @ai.all/ds7 sync sync agent entrypoints (AI-ALL sync)
|
|
213
|
+
npx @ai.all/ds7 update update ds7/ to this version and refresh the pack
|
|
214
|
+
npx @ai.all/ds7 --version print the version
|
|
215
|
+
`);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const cmd = process.argv[2];
|
|
219
|
+
if (cmd === '--version' || cmd === '-v') console.log(version);
|
|
220
|
+
else if (cmd === '--help' || cmd === '-h' || cmd === 'help') cmdHelp();
|
|
221
|
+
else if (cmd === 'sync') cmdSync();
|
|
222
|
+
else if (cmd === 'update') cmdUpdate();
|
|
223
|
+
else if (!cmd || cmd === 'init') cmdInit();
|
|
224
|
+
else { err(`Unknown command: ${cmd}`); cmdHelp(); process.exitCode = 1; }
|
package/package.json
CHANGED
|
@@ -1,6 +1,63 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai.all/ds7",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "AI-ready architecture standard for web projects: brand-first foundations, Atomic Design and agent rules in one place",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"architecture",
|
|
7
|
+
"design-system",
|
|
8
|
+
"design-tokens",
|
|
9
|
+
"brandbook",
|
|
10
|
+
"atomic-design",
|
|
11
|
+
"nuxt",
|
|
12
|
+
"vue",
|
|
13
|
+
"web-vitals",
|
|
14
|
+
"seo",
|
|
15
|
+
"ai",
|
|
16
|
+
"agents",
|
|
17
|
+
"i18n",
|
|
18
|
+
"accessibility"
|
|
19
|
+
],
|
|
20
|
+
"homepage": "https://github.com/ai-all-ai/ds7#readme",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/ai-all-ai/ds7.git"
|
|
24
|
+
},
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/ai-all-ai/ds7/issues"
|
|
27
|
+
},
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"author": "Igor Orlov",
|
|
30
|
+
"bin": {
|
|
31
|
+
"ds7": "bin/ds7.js"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"bin/",
|
|
35
|
+
"01-architecture/",
|
|
36
|
+
"02-design-system/",
|
|
37
|
+
"03-performance-web-vitals/",
|
|
38
|
+
"04-seo-ai-optimization/",
|
|
39
|
+
"05-internationalization/",
|
|
40
|
+
"06-business-conversion/",
|
|
41
|
+
"07-testing/",
|
|
42
|
+
"08-token-optimization/",
|
|
43
|
+
"templates/",
|
|
44
|
+
"ALL.md",
|
|
45
|
+
"CHANGELOG.md",
|
|
46
|
+
"README.md",
|
|
47
|
+
"SPEC.md"
|
|
48
|
+
],
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": ">=18"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@ai.all/aiall": "^0.3.0"
|
|
54
|
+
},
|
|
55
|
+
"publishConfig": {
|
|
56
|
+
"access": "public",
|
|
57
|
+
"registry": "https://registry.npmjs.org/"
|
|
58
|
+
},
|
|
59
|
+
"scripts": {
|
|
60
|
+
"test": "node bin/ds7.js --version && node bin/ds7.js --help > /dev/null && node --test test/integration.test.js",
|
|
61
|
+
"prepublishOnly": "npm test"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* DS7 component template: product card molecule (CARD-01).
|
|
4
|
+
* Atomic level: molecule. Modifiers: -top, -new, -compact, -dark.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
interface SpecItem {
|
|
8
|
+
label: string
|
|
9
|
+
value: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const props = withDefaults(defineProps<{
|
|
13
|
+
title: string
|
|
14
|
+
description?: string
|
|
15
|
+
price?: number | null
|
|
16
|
+
badge?: 'top' | 'new' | 'sale'
|
|
17
|
+
specs?: SpecItem[]
|
|
18
|
+
top?: boolean
|
|
19
|
+
compact?: boolean
|
|
20
|
+
dark?: boolean
|
|
21
|
+
}>(), {
|
|
22
|
+
description: '',
|
|
23
|
+
price: null,
|
|
24
|
+
specs: () => [],
|
|
25
|
+
top: false,
|
|
26
|
+
compact: false,
|
|
27
|
+
dark: false,
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
const classes = computed(() => [
|
|
31
|
+
'p-card',
|
|
32
|
+
props.top && '-top',
|
|
33
|
+
props.compact && '-compact',
|
|
34
|
+
props.dark && '-dark',
|
|
35
|
+
props.badge && `-${props.badge}`,
|
|
36
|
+
])
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<template>
|
|
40
|
+
<article :class="classes" data-ref="CARD-01">
|
|
41
|
+
<!-- Artwork or logo slot -->
|
|
42
|
+
<div class="p-card__art">
|
|
43
|
+
<slot name="art" />
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<!-- Text body -->
|
|
47
|
+
<div class="p-card__body">
|
|
48
|
+
<h3 class="p-card__title">{{ title }}</h3>
|
|
49
|
+
<p v-if="description" class="p-card__desc">{{ description }}</p>
|
|
50
|
+
|
|
51
|
+
<dl v-if="specs.length" class="p-card__specs">
|
|
52
|
+
<div v-for="s in specs" :key="s.label">
|
|
53
|
+
<dt>{{ s.label }}</dt>
|
|
54
|
+
<dd>{{ s.value }}</dd>
|
|
55
|
+
</div>
|
|
56
|
+
</dl>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
<!-- Footer: price and action. The price is formatted by the project's price atom. -->
|
|
60
|
+
<div class="p-card__footer">
|
|
61
|
+
<div v-if="price !== null" class="p-card__price">
|
|
62
|
+
<span class="p-card__price-val">{{ price }} €</span>
|
|
63
|
+
</div>
|
|
64
|
+
<slot name="action" />
|
|
65
|
+
</div>
|
|
66
|
+
</article>
|
|
67
|
+
</template>
|
|
68
|
+
|
|
69
|
+
<style>
|
|
70
|
+
/*
|
|
71
|
+
* Component styles. Not scoped: the prefix isolates them, and parents can
|
|
72
|
+
* override the custom properties. Values come from the tokens in theme.css.
|
|
73
|
+
*/
|
|
74
|
+
.p-card {
|
|
75
|
+
--card-bg: var(--color-white, #fff);
|
|
76
|
+
--card-ink: var(--color-ink, #1f1b16);
|
|
77
|
+
--card-border: var(--color-ink-100, rgba(31, 27, 22, 0.08));
|
|
78
|
+
|
|
79
|
+
container-type: inline-size;
|
|
80
|
+
display: flex;
|
|
81
|
+
flex-direction: column;
|
|
82
|
+
background: var(--card-bg);
|
|
83
|
+
color: var(--card-ink);
|
|
84
|
+
border: 1px solid var(--card-border);
|
|
85
|
+
border-radius: var(--radius-md, 12px);
|
|
86
|
+
padding: var(--space-4, 16px);
|
|
87
|
+
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.p-card.-top {
|
|
91
|
+
--card-border: var(--color-sun, #ffd84d);
|
|
92
|
+
box-shadow: var(--shadow-lift);
|
|
93
|
+
}
|
|
94
|
+
.p-card.-top .p-card__title {
|
|
95
|
+
font-weight: 700;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.p-card.-dark {
|
|
99
|
+
--card-bg: var(--color-ink-950, #12100d);
|
|
100
|
+
--card-ink: #ffffff;
|
|
101
|
+
--card-border: rgba(255, 255, 255, 0.12);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.p-card.-compact {
|
|
105
|
+
padding: var(--space-2, 8px);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
@container (max-width: 320px) {
|
|
109
|
+
.p-card {
|
|
110
|
+
padding: var(--space-2, 8px);
|
|
111
|
+
}
|
|
112
|
+
.p-card__title {
|
|
113
|
+
font-size: 0.95rem;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
</style>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import tailwindcss from '@tailwindcss/vite'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* DS7 reference Nuxt 4 configuration.
|
|
5
|
+
* Static generation, inlined critical CSS, one i18n hub.
|
|
6
|
+
* Replace the placeholders in [brackets] with project values.
|
|
7
|
+
*/
|
|
8
|
+
export default defineNuxtConfig({
|
|
9
|
+
compatibilityDate: '2025-07-15',
|
|
10
|
+
devtools: { enabled: false },
|
|
11
|
+
|
|
12
|
+
css: ['~/assets/css/main.css'],
|
|
13
|
+
|
|
14
|
+
modules: [
|
|
15
|
+
'@nuxtjs/i18n',
|
|
16
|
+
],
|
|
17
|
+
|
|
18
|
+
vite: {
|
|
19
|
+
plugins: [tailwindcss()],
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
experimental: {
|
|
23
|
+
inlineSSRStyles: true, // critical CSS per page, see 03-performance-web-vitals/CRITICAL-CSS.md
|
|
24
|
+
viewTransition: false,
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
i18n: {
|
|
28
|
+
strategy: 'prefix_except_default',
|
|
29
|
+
defaultLocale: 'es',
|
|
30
|
+
locales: [
|
|
31
|
+
{ code: 'es', language: 'es-ES', name: 'Español', file: 'es.ts' },
|
|
32
|
+
{ code: 'en', language: 'en-GB', name: 'English', file: 'en.ts' },
|
|
33
|
+
{ code: 'uk', language: 'uk-UA', name: 'Українська', file: 'uk.ts' },
|
|
34
|
+
],
|
|
35
|
+
langDir: '../i18n/locales',
|
|
36
|
+
detectBrowserLanguage: false,
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
app: {
|
|
40
|
+
head: {
|
|
41
|
+
htmlAttrs: { lang: 'es' },
|
|
42
|
+
meta: [
|
|
43
|
+
{ name: 'theme-color', content: '#f7f5ef' },
|
|
44
|
+
{ name: 'color-scheme', content: 'light' },
|
|
45
|
+
{ name: 'robots', content: 'index, follow, max-image-preview:large, max-snippet:-1' },
|
|
46
|
+
],
|
|
47
|
+
link: [
|
|
48
|
+
{ rel: 'icon', type: 'image/svg+xml', href: '/favicon.svg' },
|
|
49
|
+
// Preload the brand font used on the first screen (see 03-performance-web-vitals/FONTS-ZERO-CLS.md):
|
|
50
|
+
// { rel: 'preload', href: '/fonts/[brand-font].woff2', as: 'font', type: 'font/woff2', crossorigin: 'anonymous' },
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
nitro: {
|
|
56
|
+
prerender: {
|
|
57
|
+
crawlLinks: true,
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
typescript: {
|
|
62
|
+
strict: true,
|
|
63
|
+
},
|
|
64
|
+
})
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* DS7 foundations: design tokens.
|
|
3
|
+
* Components read these variables only. Add a value here before using it anywhere.
|
|
4
|
+
* See 02-design-system/TOKENS-SPEC.md.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
:root {
|
|
8
|
+
/* 1. Surfaces and text */
|
|
9
|
+
--color-paper: #f7f5ef;
|
|
10
|
+
--color-white: #ffffff;
|
|
11
|
+
--color-ink: #1f1b16;
|
|
12
|
+
--color-ink-500: #6b6459;
|
|
13
|
+
--color-ink-100: rgba(31, 27, 22, 0.08);
|
|
14
|
+
--color-ink-950: #12100d;
|
|
15
|
+
|
|
16
|
+
/* 2. Brand accent (fill only, never text) */
|
|
17
|
+
--color-sun: #ffd84d;
|
|
18
|
+
--color-sun-hover: #ffcf2e;
|
|
19
|
+
|
|
20
|
+
/* 3. Spacing scale */
|
|
21
|
+
--space-1: 0.25rem;
|
|
22
|
+
--space-2: 0.5rem;
|
|
23
|
+
--space-3: 0.75rem;
|
|
24
|
+
--space-4: 1rem;
|
|
25
|
+
--space-6: 1.5rem;
|
|
26
|
+
--space-8: 2rem;
|
|
27
|
+
--space-12: 3rem;
|
|
28
|
+
--space-16: 4rem;
|
|
29
|
+
|
|
30
|
+
/* Section rhythm */
|
|
31
|
+
--space-single: clamp(1.2rem, 3vw, 2.2rem);
|
|
32
|
+
--space-double: clamp(2.4rem, 6vw, 4.5rem);
|
|
33
|
+
--space-triple: clamp(3.6rem, 9vw, 6.5rem);
|
|
34
|
+
|
|
35
|
+
/* Page grid */
|
|
36
|
+
--content-width: 78rem;
|
|
37
|
+
--page-gutter: clamp(1rem, 3.5vw, 2rem);
|
|
38
|
+
|
|
39
|
+
/* 4. Elevation */
|
|
40
|
+
--shadow-lift: 0 4px 16px -2px rgba(31, 27, 22, 0.06);
|
|
41
|
+
--shadow-hover: 0 12px 32px -4px rgba(31, 27, 22, 0.12);
|
|
42
|
+
--shadow-modal: 0 24px 64px -8px rgba(18, 16, 13, 0.24);
|
|
43
|
+
|
|
44
|
+
/* 5. Radius */
|
|
45
|
+
--radius-sm: 0.375rem;
|
|
46
|
+
--radius-md: 0.75rem;
|
|
47
|
+
--radius-lg: 1.25rem;
|
|
48
|
+
--radius-full: 9999px;
|
|
49
|
+
|
|
50
|
+
/* 6. Breakpoints (for media queries; components use container queries) */
|
|
51
|
+
--bp-sm: 480px;
|
|
52
|
+
--bp-md: 800px;
|
|
53
|
+
--bp-lg: 900px;
|
|
54
|
+
--bp-xl: 1200px;
|
|
55
|
+
}
|