sdtk-design-kit 0.1.0 → 0.1.2
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 +46 -9
- package/package.json +1 -1
- package/src/commands/handoff.js +83 -8
- package/src/commands/help.js +17 -6
- package/src/commands/prototype.js +503 -0
- package/src/commands/review.js +56 -4
- package/src/commands/start.js +97 -11
- package/src/commands/status.js +42 -2
- package/src/commands/system.js +49 -19
- package/src/index.js +4 -0
- package/src/lib/design-input-contract.js +423 -0
- package/src/lib/design-paths.js +9 -0
- package/src/lib/design-profiles.js +58 -0
- package/src/lib/domain-profile.js +108 -0
- package/src/lib/style-presets.js +150 -0
package/src/commands/start.js
CHANGED
|
@@ -8,13 +8,21 @@ const { runDesignSystem } = require("./system");
|
|
|
8
8
|
const { runDesignWireframe } = require("./wireframe");
|
|
9
9
|
const { parseFlags } = require("../lib/args");
|
|
10
10
|
const { describeDesignPaths, resolveProjectPath } = require("../lib/design-paths");
|
|
11
|
+
const { availableProfileNames } = require("../lib/design-profiles");
|
|
12
|
+
const { buildInputContractState, writeInputContractState } = require("../lib/design-input-contract");
|
|
11
13
|
const { ValidationError } = require("../lib/errors");
|
|
14
|
+
const { DEFAULT_STYLE, availableStyleNames, resolveStyleName } = require("../lib/style-presets");
|
|
12
15
|
|
|
13
16
|
const START_FLAG_DEFS = {
|
|
14
17
|
help: { type: "boolean" },
|
|
15
18
|
idea: { type: "string" },
|
|
16
19
|
"project-path": { type: "string" },
|
|
17
20
|
force: { type: "boolean" },
|
|
21
|
+
style: { type: "string" },
|
|
22
|
+
"from-spec": { type: "string" },
|
|
23
|
+
"design-brief": { type: "string" },
|
|
24
|
+
"reference-dir": { type: "string" },
|
|
25
|
+
profile: { type: "string" },
|
|
18
26
|
};
|
|
19
27
|
|
|
20
28
|
const REQUIRED_WIREFRAME_FILES = ["LANDING.md", "ONBOARDING.md", "DASHBOARD.md"];
|
|
@@ -23,25 +31,42 @@ function cmdStartHelp() {
|
|
|
23
31
|
console.log(`SDTK-DESIGN Start
|
|
24
32
|
|
|
25
33
|
Usage:
|
|
26
|
-
sdtk-design start --idea "<rough MVP idea>" [--project-path <path>] [--force]
|
|
34
|
+
sdtk-design start --idea "<rough MVP idea>" [--style <preset>] [--project-path <path>] [--force]
|
|
35
|
+
sdtk-design start --from-spec <projectPath> [--design-brief <file>] [--reference-dir <dir>] [--profile <name>] [--project-path <path>]
|
|
27
36
|
|
|
28
37
|
Example:
|
|
29
38
|
sdtk-design start --idea "I want to build a lightweight CRM for solo consultants to track leads."
|
|
39
|
+
sdtk-design start --idea "ClientPulse for consultants" --style premium-dashboard
|
|
40
|
+
sdtk-design start --from-spec . --reference-dir ./docs/ui/claude-design-export --profile b2b-commerce
|
|
41
|
+
|
|
42
|
+
Style presets:
|
|
43
|
+
${availableStyleNames().join(", ")}
|
|
44
|
+
Default: ${DEFAULT_STYLE}
|
|
45
|
+
|
|
46
|
+
Design profiles (optional in from-spec mode):
|
|
47
|
+
${availableProfileNames().join(", ")}
|
|
30
48
|
|
|
31
49
|
Runs:
|
|
32
|
-
|
|
50
|
+
idea mode:
|
|
51
|
+
brief -> screens -> wireframe --screen all -> system
|
|
52
|
+
from-spec mode:
|
|
53
|
+
explicit SPEC/design artifact intake -> contract state write
|
|
33
54
|
|
|
34
55
|
Creates:
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
56
|
+
idea mode:
|
|
57
|
+
docs/design/DESIGN_BRIEF.md
|
|
58
|
+
docs/design/SCREEN_MAP.md
|
|
59
|
+
docs/design/wireframes/LANDING.md
|
|
60
|
+
docs/design/wireframes/ONBOARDING.md
|
|
61
|
+
docs/design/wireframes/DASHBOARD.md
|
|
62
|
+
docs/design/DESIGN_SYSTEM.md
|
|
63
|
+
from-spec mode:
|
|
64
|
+
.sdtk/design/START_INPUT_STATE.json
|
|
41
65
|
|
|
42
66
|
Safety:
|
|
43
67
|
Local files only.
|
|
44
68
|
Existing managed core design outputs are not overwritten unless --force is explicit.
|
|
69
|
+
--from-spec consumes explicit artifacts; no raw requirement semantic parsing.
|
|
45
70
|
No review, handoff, URL, browser, screenshot, vision, or DOM work.
|
|
46
71
|
No .sdtk/atlas creation or mutation.
|
|
47
72
|
No SDTK-WIKI output mutation.
|
|
@@ -65,11 +90,12 @@ function coreOutputTargets(paths) {
|
|
|
65
90
|
];
|
|
66
91
|
}
|
|
67
92
|
|
|
68
|
-
function runDesignStart({ idea, projectPath, force = false }) {
|
|
93
|
+
function runDesignStart({ idea, projectPath, force = false, style = DEFAULT_STYLE }) {
|
|
69
94
|
const normalizedIdea = normalizeIdea(idea);
|
|
70
95
|
if (!normalizedIdea) {
|
|
71
96
|
throw new ValidationError('Missing required --idea "<rough MVP idea>". No project files were changed.');
|
|
72
97
|
}
|
|
98
|
+
const styleName = resolveStyleName(style);
|
|
73
99
|
|
|
74
100
|
const resolvedProjectPath = resolveProjectPath(projectPath || process.cwd());
|
|
75
101
|
if (!fs.existsSync(resolvedProjectPath) || !fs.statSync(resolvedProjectPath).isDirectory()) {
|
|
@@ -86,12 +112,35 @@ function runDesignStart({ idea, projectPath, force = false }) {
|
|
|
86
112
|
runDesignBrief({ idea: normalizedIdea, projectPath: resolvedProjectPath, force });
|
|
87
113
|
runDesignScreens({ projectPath: resolvedProjectPath, force });
|
|
88
114
|
runDesignWireframe({ screen: "all", projectPath: resolvedProjectPath, force });
|
|
89
|
-
runDesignSystem({ projectPath: resolvedProjectPath, force });
|
|
115
|
+
runDesignSystem({ projectPath: resolvedProjectPath, force, style: styleName });
|
|
90
116
|
|
|
91
117
|
return {
|
|
92
118
|
projectPath: resolvedProjectPath,
|
|
93
119
|
written: coreOutputTargets(paths).map((target) => target.relativePath),
|
|
94
120
|
forced: Boolean(force),
|
|
121
|
+
style: styleName,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function runDesignStartFromSpec({
|
|
126
|
+
fromSpecPath,
|
|
127
|
+
projectPath,
|
|
128
|
+
designBrief,
|
|
129
|
+
referenceDir,
|
|
130
|
+
profile,
|
|
131
|
+
}) {
|
|
132
|
+
const contractState = buildInputContractState({
|
|
133
|
+
fromSpecPath,
|
|
134
|
+
projectPath,
|
|
135
|
+
designBriefPath: designBrief,
|
|
136
|
+
referenceDir,
|
|
137
|
+
profile,
|
|
138
|
+
});
|
|
139
|
+
const statePath = writeInputContractState(contractState.projectPath, contractState);
|
|
140
|
+
return {
|
|
141
|
+
...contractState,
|
|
142
|
+
statePath,
|
|
143
|
+
stateRelativePath: ".sdtk/design/START_INPUT_STATE.json",
|
|
95
144
|
};
|
|
96
145
|
}
|
|
97
146
|
|
|
@@ -99,17 +148,53 @@ function cmdStart(args) {
|
|
|
99
148
|
const { flags } = parseFlags(args || [], START_FLAG_DEFS);
|
|
100
149
|
if (flags.help) return cmdStartHelp();
|
|
101
150
|
|
|
151
|
+
const contractMode = Boolean(flags["from-spec"] || flags["design-brief"] || flags["reference-dir"] || flags.profile);
|
|
152
|
+
if (contractMode) {
|
|
153
|
+
const contractResult = runDesignStartFromSpec({
|
|
154
|
+
fromSpecPath: flags["from-spec"],
|
|
155
|
+
projectPath: flags["project-path"],
|
|
156
|
+
designBrief: flags["design-brief"],
|
|
157
|
+
referenceDir: flags["reference-dir"],
|
|
158
|
+
profile: flags.profile,
|
|
159
|
+
});
|
|
160
|
+
if (contractResult.blockers.length > 0) {
|
|
161
|
+
throw new ValidationError(
|
|
162
|
+
`SDTK-DESIGN input contract blocked: ${contractResult.blockers.join(", ")}. Review ${contractResult.stateRelativePath}.`
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
console.log(`[design] Started SDTK-DESIGN package: ${contractResult.projectPath}`);
|
|
166
|
+
console.log(`[design] Mode: from-spec`);
|
|
167
|
+
console.log(`[design] Wrote ${contractResult.stateRelativePath}`);
|
|
168
|
+
console.log(`[design] Screen model: ${contractResult.screenModel.totalScreens} explicit screen(s), readiness=${contractResult.screenModel.readiness}`);
|
|
169
|
+
if (contractResult.referenceDirectory && contractResult.referenceDirectory.provided) {
|
|
170
|
+
console.log(
|
|
171
|
+
`[design] Reference map: ${contractResult.referenceMap.mappedCount}/${contractResult.referenceMap.totalFiles} mapped (${contractResult.referenceMap.unmappedCount} unmapped)`
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
console.log(
|
|
175
|
+
`[design] Inputs: ${Object.entries(contractResult.artifacts)
|
|
176
|
+
.filter(([, artifact]) => artifact.found)
|
|
177
|
+
.map(([name, artifact]) => `${name}=${artifact.relativeToSpecRoot}`)
|
|
178
|
+
.join(", ")}`
|
|
179
|
+
);
|
|
180
|
+
console.log("[design] No raw requirement semantic parsing, .sdtk/atlas, SDTK-WIKI output, or network activity was used.");
|
|
181
|
+
console.log("[design] Next: sdtk-design prototype");
|
|
182
|
+
return 0;
|
|
183
|
+
}
|
|
184
|
+
|
|
102
185
|
const result = runDesignStart({
|
|
103
186
|
idea: flags.idea,
|
|
104
187
|
projectPath: flags["project-path"],
|
|
105
188
|
force: Boolean(flags.force),
|
|
189
|
+
style: flags.style,
|
|
106
190
|
});
|
|
107
191
|
|
|
108
192
|
console.log(`[design] Started SDTK-DESIGN package: ${result.projectPath}`);
|
|
109
193
|
console.log(`[design] Wrote core artifacts: ${result.written.join(", ")}`);
|
|
194
|
+
console.log(`[design] Style: ${result.style}`);
|
|
110
195
|
console.log(`[design] Overwrite: ${result.forced ? "enabled by --force" : "not needed"}`);
|
|
111
196
|
console.log("[design] No review, handoff, URL, browser, screenshot, vision, network, .sdtk/atlas, or SDTK-WIKI output was used.");
|
|
112
|
-
console.log("[design] Next: sdtk-design
|
|
197
|
+
console.log("[design] Next: sdtk-design prototype");
|
|
113
198
|
return 0;
|
|
114
199
|
}
|
|
115
200
|
|
|
@@ -117,5 +202,6 @@ module.exports = {
|
|
|
117
202
|
cmdStart,
|
|
118
203
|
cmdStartHelp,
|
|
119
204
|
coreOutputTargets,
|
|
205
|
+
runDesignStartFromSpec,
|
|
120
206
|
runDesignStart,
|
|
121
207
|
};
|
package/src/commands/status.js
CHANGED
|
@@ -41,6 +41,7 @@ function artifactPlan(paths) {
|
|
|
41
41
|
{ label: "Onboarding wireframe", relativePath: "docs/design/wireframes/ONBOARDING.md", filePath: path.join(paths.wireframesPath, "ONBOARDING.md"), phase: "core" },
|
|
42
42
|
{ label: "Dashboard wireframe", relativePath: "docs/design/wireframes/DASHBOARD.md", filePath: path.join(paths.wireframesPath, "DASHBOARD.md"), phase: "core" },
|
|
43
43
|
{ label: "Design system", relativePath: "docs/design/DESIGN_SYSTEM.md", filePath: paths.designSystemPath, phase: "core" },
|
|
44
|
+
{ label: "Prototype preview", relativePath: "docs/design/prototype/index.html", filePath: paths.prototypeIndexPath, phase: "prototype" },
|
|
44
45
|
{ label: "Design handoff", relativePath: "docs/design/DESIGN_HANDOFF.md", filePath: paths.designHandoffPath, phase: "handoff" },
|
|
45
46
|
];
|
|
46
47
|
}
|
|
@@ -52,6 +53,17 @@ function hasReview(paths) {
|
|
|
52
53
|
return fs.readdirSync(paths.reviewsPath).some((name) => /^DESIGN_REVIEW_\d{8}\.md$/.test(name));
|
|
53
54
|
}
|
|
54
55
|
|
|
56
|
+
function readInputContractState(paths) {
|
|
57
|
+
if (!fs.existsSync(paths.designStartInputStatePath) || !fs.statSync(paths.designStartInputStatePath).isFile()) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
return JSON.parse(fs.readFileSync(paths.designStartInputStatePath, "utf-8"));
|
|
62
|
+
} catch (_err) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
55
67
|
function inspectDesignStatus(projectPath) {
|
|
56
68
|
const resolvedProjectPath = resolveProjectPath(projectPath || process.cwd());
|
|
57
69
|
if (!fs.existsSync(resolvedProjectPath) || !fs.statSync(resolvedProjectPath).isDirectory()) {
|
|
@@ -64,14 +76,24 @@ function inspectDesignStatus(projectPath) {
|
|
|
64
76
|
exists: fs.existsSync(artifact.filePath),
|
|
65
77
|
}));
|
|
66
78
|
const reviewExists = hasReview(paths);
|
|
79
|
+
const inputContractState = readInputContractState(paths);
|
|
67
80
|
const coreMissing = artifacts.filter((artifact) => artifact.phase === "core" && !artifact.exists);
|
|
81
|
+
const prototypeMissing = artifacts.find((artifact) => artifact.phase === "prototype" && !artifact.exists);
|
|
68
82
|
const handoffMissing = artifacts.find((artifact) => artifact.phase === "handoff" && !artifact.exists);
|
|
69
83
|
|
|
70
84
|
let nextCommand = "SDTK-CODE can consume docs/design/DESIGN_HANDOFF.md";
|
|
71
|
-
if (
|
|
85
|
+
if (inputContractState && inputContractState.mode === "from-spec") {
|
|
86
|
+
if (Array.isArray(inputContractState.blockers) && inputContractState.blockers.length > 0) {
|
|
87
|
+
nextCommand = "Provide missing explicit SPEC/design artifacts and re-run sdtk-design start --from-spec.";
|
|
88
|
+
} else {
|
|
89
|
+
nextCommand = "sdtk-design prototype";
|
|
90
|
+
}
|
|
91
|
+
} else if (coreMissing.length > 0) {
|
|
72
92
|
nextCommand = 'sdtk-design start --idea "<idea>"';
|
|
93
|
+
} else if (prototypeMissing) {
|
|
94
|
+
nextCommand = "sdtk-design prototype";
|
|
73
95
|
} else if (!reviewExists) {
|
|
74
|
-
nextCommand = "sdtk-design review --artifact docs/design/
|
|
96
|
+
nextCommand = "sdtk-design review --artifact docs/design/prototype/index.html";
|
|
75
97
|
} else if (handoffMissing) {
|
|
76
98
|
nextCommand = "sdtk-design handoff";
|
|
77
99
|
}
|
|
@@ -79,6 +101,7 @@ function inspectDesignStatus(projectPath) {
|
|
|
79
101
|
return {
|
|
80
102
|
projectPath: resolvedProjectPath,
|
|
81
103
|
artifacts,
|
|
104
|
+
inputContractState,
|
|
82
105
|
reviewExists,
|
|
83
106
|
nextCommand,
|
|
84
107
|
};
|
|
@@ -118,6 +141,23 @@ function cmdStatus(args) {
|
|
|
118
141
|
}
|
|
119
142
|
}
|
|
120
143
|
console.log("");
|
|
144
|
+
console.log("Input contract:");
|
|
145
|
+
if (!status.inputContractState) {
|
|
146
|
+
console.log(" - not found");
|
|
147
|
+
} else {
|
|
148
|
+
console.log(` - mode: ${status.inputContractState.mode}`);
|
|
149
|
+
console.log(` - status: ${status.inputContractState.analysisStatus}`);
|
|
150
|
+
if (status.inputContractState.screenModel && typeof status.inputContractState.screenModel.totalScreens === "number") {
|
|
151
|
+
console.log(` - explicit screens: ${status.inputContractState.screenModel.totalScreens}`);
|
|
152
|
+
console.log(` - readiness: ${status.inputContractState.screenModel.readiness}`);
|
|
153
|
+
}
|
|
154
|
+
if (status.inputContractState.profileSelection) {
|
|
155
|
+
console.log(` - profile: ${status.inputContractState.profileSelection}`);
|
|
156
|
+
}
|
|
157
|
+
const blockers = Array.isArray(status.inputContractState.blockers) ? status.inputContractState.blockers : [];
|
|
158
|
+
console.log(` - blockers: ${blockers.length > 0 ? blockers.join(", ") : "none"}`);
|
|
159
|
+
}
|
|
160
|
+
console.log("");
|
|
121
161
|
console.log(`Next recommended command: ${status.nextCommand}`);
|
|
122
162
|
console.log("No .sdtk/atlas, SDTK-WIKI output, network, or app code was modified.");
|
|
123
163
|
return 0;
|
package/src/commands/system.js
CHANGED
|
@@ -5,21 +5,28 @@ const path = require("path");
|
|
|
5
5
|
const { parseFlags } = require("../lib/args");
|
|
6
6
|
const { describeDesignPaths, resolveProjectPath } = require("../lib/design-paths");
|
|
7
7
|
const { ValidationError } = require("../lib/errors");
|
|
8
|
+
const { DEFAULT_STYLE, availableStyleNames, getStylePreset, resolveStyleName } = require("../lib/style-presets");
|
|
8
9
|
|
|
9
10
|
const SYSTEM_FLAG_DEFS = {
|
|
10
11
|
help: { type: "boolean" },
|
|
11
12
|
"project-path": { type: "string" },
|
|
12
13
|
force: { type: "boolean" },
|
|
14
|
+
style: { type: "string" },
|
|
13
15
|
};
|
|
14
16
|
|
|
15
17
|
function cmdSystemHelp() {
|
|
16
18
|
console.log(`SDTK-DESIGN System
|
|
17
19
|
|
|
18
20
|
Usage:
|
|
19
|
-
sdtk-design system [--project-path <path>] [--force]
|
|
21
|
+
sdtk-design system [--style <preset>] [--project-path <path>] [--force]
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
Examples:
|
|
22
24
|
sdtk-design system
|
|
25
|
+
sdtk-design system --style premium-dashboard
|
|
26
|
+
|
|
27
|
+
Style presets:
|
|
28
|
+
${availableStyleNames().join(", ")}
|
|
29
|
+
Default: ${DEFAULT_STYLE}
|
|
23
30
|
|
|
24
31
|
Reads:
|
|
25
32
|
docs/design/DESIGN_BRIEF.md
|
|
@@ -42,7 +49,12 @@ function includesAny(text, terms) {
|
|
|
42
49
|
return terms.some((term) => value.includes(term));
|
|
43
50
|
}
|
|
44
51
|
|
|
45
|
-
function
|
|
52
|
+
function linesForBullets(items) {
|
|
53
|
+
return items.map((item) => `- ${item}`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function systemContent(briefContent, screenMapContent, style = DEFAULT_STYLE) {
|
|
57
|
+
const preset = getStylePreset(style);
|
|
46
58
|
const source = `${briefContent}\n${screenMapContent}`;
|
|
47
59
|
const isCrm = includesAny(source, ["crm", "lead", "follow-up", "pipeline"]);
|
|
48
60
|
const primaryAction = isCrm ? "Add first lead" : "Start first workflow";
|
|
@@ -57,26 +69,24 @@ function systemContent(briefContent, screenMapContent) {
|
|
|
57
69
|
"- Favor clarity, scannability, and obvious next actions over decorative marketing composition.",
|
|
58
70
|
`- Primary repeated action: ${primaryAction}.`,
|
|
59
71
|
"",
|
|
72
|
+
"## Visual Preset",
|
|
73
|
+
"",
|
|
74
|
+
`- Preset: ${resolveStyleName(style)} (${preset.label}).`,
|
|
75
|
+
`- Direction: ${preset.summary}`,
|
|
76
|
+
"- Presets are compact SDTK-DESIGN guidance adapted from reference patterns, not imported runtime code.",
|
|
77
|
+
"",
|
|
60
78
|
"## Typography",
|
|
61
79
|
"",
|
|
62
|
-
|
|
63
|
-
"- Page title: 28px, 36px line-height, semibold.",
|
|
64
|
-
"- Section heading: 18px, 26px line-height, semibold.",
|
|
65
|
-
"- Body text: 15px, 22px line-height, regular.",
|
|
66
|
-
"- Label text: 13px, 18px line-height, medium.",
|
|
80
|
+
...linesForBullets(preset.typography),
|
|
67
81
|
"- Do not scale font size with viewport width; keep letter spacing at 0.",
|
|
68
82
|
"",
|
|
69
83
|
"## Color Tokens",
|
|
70
84
|
"",
|
|
71
|
-
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
|
|
76
|
-
"- `color-success`: #0F8A5F for confirmed progress.",
|
|
77
|
-
"- `color-warning`: #B7791F for attention without blocking.",
|
|
78
|
-
"- `color-danger`: #B42318 for destructive or failed states.",
|
|
79
|
-
"- `color-border`: #D9DEE7 for quiet dividers and input borders.",
|
|
85
|
+
...linesForBullets(preset.colors),
|
|
86
|
+
"",
|
|
87
|
+
"## Surface / Background Strategy",
|
|
88
|
+
"",
|
|
89
|
+
`- ${preset.surface}`,
|
|
80
90
|
"",
|
|
81
91
|
"## Spacing",
|
|
82
92
|
"",
|
|
@@ -94,6 +104,7 @@ function systemContent(briefContent, screenMapContent) {
|
|
|
94
104
|
"- Icon buttons: square 36px control with tooltip when the icon is not self-evident.",
|
|
95
105
|
"- Disabled state: 45% opacity with no hover elevation.",
|
|
96
106
|
"- CTA copy should use verbs tied to the workflow, such as Add, Save, Continue, or Review.",
|
|
107
|
+
`- Preset CTA treatment: ${preset.cta}`,
|
|
97
108
|
"",
|
|
98
109
|
"## Card Style",
|
|
99
110
|
"",
|
|
@@ -102,6 +113,11 @@ function systemContent(briefContent, screenMapContent) {
|
|
|
102
113
|
"- Border: 1px solid `color-border`; avoid heavy shadows.",
|
|
103
114
|
"- Card content order: status, title, next action, supporting metadata.",
|
|
104
115
|
"- Avoid nested cards and decorative gradient backgrounds.",
|
|
116
|
+
`- Preset density rule: ${preset.density}`,
|
|
117
|
+
"",
|
|
118
|
+
"## Table / Dashboard Density",
|
|
119
|
+
"",
|
|
120
|
+
`- ${preset.dashboard}`,
|
|
105
121
|
"",
|
|
106
122
|
"## Form Style",
|
|
107
123
|
"",
|
|
@@ -111,6 +127,15 @@ function systemContent(briefContent, screenMapContent) {
|
|
|
111
127
|
"- Prefer segmented controls or toggles for short option sets.",
|
|
112
128
|
"- Forms should ask for the minimum needed before the first useful action.",
|
|
113
129
|
"",
|
|
130
|
+
"## Component Recipe Hints",
|
|
131
|
+
"",
|
|
132
|
+
...linesForBullets(preset.components),
|
|
133
|
+
"",
|
|
134
|
+
"## Mobile Layout Rules",
|
|
135
|
+
"",
|
|
136
|
+
`- ${preset.mobile}`,
|
|
137
|
+
"- Keep text within parent containers at mobile widths and avoid viewport-scaled type.",
|
|
138
|
+
"",
|
|
114
139
|
"## Tone",
|
|
115
140
|
"",
|
|
116
141
|
`- Use practical language around ${toneObject}; avoid enterprise jargon.`,
|
|
@@ -120,6 +145,7 @@ function systemContent(briefContent, screenMapContent) {
|
|
|
120
145
|
"",
|
|
121
146
|
"## Accessibility Baseline",
|
|
122
147
|
"",
|
|
148
|
+
`- Preset accessibility emphasis: ${preset.accessibility}`,
|
|
123
149
|
"- Maintain visible keyboard focus for all interactive controls.",
|
|
124
150
|
"- Use 4.5:1 contrast for body text and 3:1 for large text and essential UI boundaries.",
|
|
125
151
|
"- Do not rely on color alone for status; pair status color with text or icon labels.",
|
|
@@ -136,7 +162,8 @@ function systemContent(briefContent, screenMapContent) {
|
|
|
136
162
|
].join("\n");
|
|
137
163
|
}
|
|
138
164
|
|
|
139
|
-
function runDesignSystem({ projectPath, force = false }) {
|
|
165
|
+
function runDesignSystem({ projectPath, force = false, style = DEFAULT_STYLE }) {
|
|
166
|
+
const styleName = resolveStyleName(style);
|
|
140
167
|
const resolvedProjectPath = resolveProjectPath(projectPath || process.cwd());
|
|
141
168
|
if (!fs.existsSync(resolvedProjectPath) || !fs.statSync(resolvedProjectPath).isDirectory()) {
|
|
142
169
|
throw new ValidationError(`--project-path is not a valid directory: ${resolvedProjectPath}. No project files were changed.`);
|
|
@@ -156,12 +183,13 @@ function runDesignSystem({ projectPath, force = false }) {
|
|
|
156
183
|
const briefContent = fs.readFileSync(paths.designBriefPath, "utf-8");
|
|
157
184
|
const screenMapContent = fs.readFileSync(paths.screenMapPath, "utf-8");
|
|
158
185
|
fs.mkdirSync(path.dirname(paths.designSystemPath), { recursive: true });
|
|
159
|
-
fs.writeFileSync(paths.designSystemPath, systemContent(briefContent, screenMapContent), "utf-8");
|
|
186
|
+
fs.writeFileSync(paths.designSystemPath, systemContent(briefContent, screenMapContent, styleName), "utf-8");
|
|
160
187
|
|
|
161
188
|
return {
|
|
162
189
|
projectPath: resolvedProjectPath,
|
|
163
190
|
relativeDesignSystemPath: "docs/design/DESIGN_SYSTEM.md",
|
|
164
191
|
forced: Boolean(force),
|
|
192
|
+
style: styleName,
|
|
165
193
|
};
|
|
166
194
|
}
|
|
167
195
|
|
|
@@ -172,9 +200,11 @@ function cmdSystem(args) {
|
|
|
172
200
|
const result = runDesignSystem({
|
|
173
201
|
projectPath: flags["project-path"],
|
|
174
202
|
force: Boolean(flags.force),
|
|
203
|
+
style: flags.style,
|
|
175
204
|
});
|
|
176
205
|
|
|
177
206
|
console.log(`[design] Wrote ${result.relativeDesignSystemPath}: ${result.projectPath}`);
|
|
207
|
+
console.log(`[design] Style: ${result.style}`);
|
|
178
208
|
console.log(`[design] Overwrite: ${result.forced ? "enabled by --force" : "not needed"}`);
|
|
179
209
|
console.log("[design] No .sdtk/atlas, SDTK-WIKI output, source files, network, or app code was modified.");
|
|
180
210
|
console.log("[design] Next: sdtk-design handoff");
|
package/src/index.js
CHANGED
|
@@ -4,6 +4,7 @@ const { cmdBrief } = require("./commands/brief");
|
|
|
4
4
|
const { cmdHandoff } = require("./commands/handoff");
|
|
5
5
|
const { cmdHelp } = require("./commands/help");
|
|
6
6
|
const { cmdInit } = require("./commands/init");
|
|
7
|
+
const { cmdPrototype } = require("./commands/prototype");
|
|
7
8
|
const { cmdReview } = require("./commands/review");
|
|
8
9
|
const { cmdScreens } = require("./commands/screens");
|
|
9
10
|
const { cmdStart } = require("./commands/start");
|
|
@@ -66,6 +67,9 @@ async function run(argv) {
|
|
|
66
67
|
if (command === "review") {
|
|
67
68
|
return cmdReview(args);
|
|
68
69
|
}
|
|
70
|
+
if (command === "prototype") {
|
|
71
|
+
return cmdPrototype(args);
|
|
72
|
+
}
|
|
69
73
|
if (command === "start") {
|
|
70
74
|
return cmdStart(args);
|
|
71
75
|
}
|