@lessonkit/cli 0.9.2 → 1.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/README.md +20 -34
- package/dist/bin.js +83 -132
- package/dist/index.js +83 -132
- package/package.json +3 -2
- package/template/vite-react/README.md +13 -11
- package/template/vite-react/lessonkit.json +6 -1
- package/template/vite-react/package.json +6 -6
- package/template/vite-react/dist/assets/index-CP3MNJ8s.css +0 -1
- package/template/vite-react/dist/assets/index-CRuKbzTV.js +0 -8
- package/template/vite-react/dist/index.html +0 -14
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import { createRequire } from "module";
|
|
|
3
3
|
import { Command } from "commander";
|
|
4
4
|
|
|
5
5
|
// src/commands/init.ts
|
|
6
|
+
import { slugifyId } from "@lessonkit/core";
|
|
6
7
|
import { cp, mkdir, readdir, readFile, writeFile } from "fs/promises";
|
|
7
8
|
import { existsSync } from "fs";
|
|
8
9
|
import { basename, dirname, join, resolve } from "path";
|
|
@@ -99,9 +100,6 @@ function getTemplateDir() {
|
|
|
99
100
|
}
|
|
100
101
|
return candidates[0];
|
|
101
102
|
}
|
|
102
|
-
function slugifyName(name) {
|
|
103
|
-
return name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64) || "my-course";
|
|
104
|
-
}
|
|
105
103
|
async function isDirEmpty(dir) {
|
|
106
104
|
if (!existsSync(dir)) return true;
|
|
107
105
|
const entries = await readdir(dir);
|
|
@@ -151,14 +149,14 @@ async function applyTemplateSubstitutions(projectDir, projectName, slug) {
|
|
|
151
149
|
}
|
|
152
150
|
async function runInit(opts, logger) {
|
|
153
151
|
const cwd = process.cwd();
|
|
154
|
-
const rawName = opts.name ?? (opts.here ?
|
|
152
|
+
const rawName = opts.name ?? (opts.here ? slugifyId(basename(process.cwd()) || "my-course") : void 0);
|
|
155
153
|
if (!rawName && !opts.here) {
|
|
156
154
|
throw new CliError("Project name is required. Usage: lessonkit init <name> or lessonkit init --here", {
|
|
157
155
|
code: "INVALID_PROJECT",
|
|
158
156
|
exitCode: EXIT_INVALID_PROJECT
|
|
159
157
|
});
|
|
160
158
|
}
|
|
161
|
-
const slug =
|
|
159
|
+
const slug = slugifyId(rawName ?? "my-course");
|
|
162
160
|
const projectName = rawName ?? slug;
|
|
163
161
|
const projectDir = opts.here ? cwd : resolve(cwd, slug);
|
|
164
162
|
if (!opts.here && existsSync(projectDir)) {
|
|
@@ -209,18 +207,13 @@ async function runInit(opts, logger) {
|
|
|
209
207
|
import { readFileSync, existsSync as existsSync2 } from "fs";
|
|
210
208
|
import { readFile as readFile2 } from "fs/promises";
|
|
211
209
|
import { dirname as dirname2, join as join2, parse, resolve as resolve2 } from "path";
|
|
212
|
-
import {
|
|
210
|
+
import { parseLessonkitManifest } from "@lessonkit/lxpack";
|
|
213
211
|
var LESSONKIT_JSON = "lessonkit.json";
|
|
214
212
|
var PACKAGE_JSON = "package.json";
|
|
215
|
-
var DEFAULT_PATHS = {
|
|
216
|
-
spaDistDir: "dist",
|
|
217
|
-
lxpackOutDir: ".lxpack/course",
|
|
218
|
-
outputBaseDir: ".lxpack/out"
|
|
219
|
-
};
|
|
220
213
|
function isProjectManifest(configPath) {
|
|
221
214
|
try {
|
|
222
215
|
const raw = JSON.parse(readFileSync(configPath, "utf8"));
|
|
223
|
-
return raw.schemaVersion === 1 && typeof raw.name === "string" && raw.course !== null && typeof raw.course === "object";
|
|
216
|
+
return raw.schemaVersion === 1 && typeof raw.name === "string" && raw.course !== null && typeof raw.course === "object" && !Array.isArray(raw.course);
|
|
224
217
|
} catch {
|
|
225
218
|
return false;
|
|
226
219
|
}
|
|
@@ -253,124 +246,66 @@ async function loadLessonkitJson(projectRoot) {
|
|
|
253
246
|
exitCode: EXIT_INVALID_PROJECT
|
|
254
247
|
});
|
|
255
248
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
exitCode: EXIT_INVALID_PROJECT
|
|
260
|
-
});
|
|
261
|
-
}
|
|
262
|
-
const config = raw;
|
|
263
|
-
const schemaVersion = config.schemaVersion;
|
|
264
|
-
if (schemaVersion !== 1) {
|
|
265
|
-
throw new CliError(`${configPath}: schemaVersion must be 1 (got ${String(schemaVersion)}).`, {
|
|
266
|
-
code: "INVALID_PROJECT",
|
|
267
|
-
exitCode: EXIT_INVALID_PROJECT
|
|
268
|
-
});
|
|
249
|
+
const parsed = parseLessonkitManifest(raw, configPath, projectRoot);
|
|
250
|
+
if (!parsed.ok) {
|
|
251
|
+
throwManifestCliError(configPath, parsed.issues);
|
|
269
252
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
253
|
+
return {
|
|
254
|
+
root: projectRoot,
|
|
255
|
+
schemaVersion: 1,
|
|
256
|
+
name: parsed.manifest.name,
|
|
257
|
+
course: parsed.manifest.course,
|
|
258
|
+
paths: parsed.manifest.paths
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
function throwManifestCliError(configPath, issues) {
|
|
262
|
+
const layoutIssue = issues.find((i) => i.path === "course.layout");
|
|
263
|
+
if (layoutIssue?.message.includes("per-lesson-spa")) {
|
|
264
|
+
throw new CliError(
|
|
265
|
+
`${configPath}: per-lesson-spa layout is not supported by lessonkit package yet. Use single-spa or package via @lessonkit/lxpack directly.`,
|
|
266
|
+
{ code: "INVALID_PROJECT", exitCode: EXIT_INVALID_PROJECT }
|
|
267
|
+
);
|
|
276
268
|
}
|
|
277
|
-
const
|
|
278
|
-
if (
|
|
279
|
-
throw new CliError(`${configPath}: "course" must be an
|
|
269
|
+
const lessonsIssue = issues.find((i) => i.path === "course.lessons");
|
|
270
|
+
if (lessonsIssue) {
|
|
271
|
+
throw new CliError(`${configPath}: "course.lessons" must be an array.`, {
|
|
280
272
|
code: "INVALID_PROJECT",
|
|
281
273
|
exitCode: EXIT_INVALID_PROJECT
|
|
282
274
|
});
|
|
283
275
|
}
|
|
284
|
-
const
|
|
285
|
-
if (
|
|
286
|
-
throw new CliError(`${configPath}: "
|
|
276
|
+
const spaDistTypeIssue = issues.find((i) => i.path === "paths.spaDistDir");
|
|
277
|
+
if (spaDistTypeIssue && spaDistTypeIssue.message.includes("non-empty string")) {
|
|
278
|
+
throw new CliError(`${configPath}: "paths.spaDistDir" must be a non-empty string.`, {
|
|
287
279
|
code: "INVALID_PROJECT",
|
|
288
280
|
exitCode: EXIT_INVALID_PROJECT
|
|
289
281
|
});
|
|
290
282
|
}
|
|
291
|
-
|
|
292
|
-
|
|
283
|
+
const courseSpaIssue = issues.find((i) => i.path === "course.spaDistDir");
|
|
284
|
+
if (courseSpaIssue) {
|
|
285
|
+
throw new CliError(`${configPath}: ${courseSpaIssue.message}`, {
|
|
293
286
|
code: "INVALID_PROJECT",
|
|
294
287
|
exitCode: EXIT_INVALID_PROJECT
|
|
295
288
|
});
|
|
296
289
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
throw new CliError(`${configPath}: invalid course descriptor.`, {
|
|
290
|
+
if (issues.some((i) => i.path.startsWith("paths."))) {
|
|
291
|
+
throw new CliError(`${configPath}: invalid paths.`, {
|
|
300
292
|
code: "INVALID_PROJECT",
|
|
301
293
|
exitCode: EXIT_INVALID_PROJECT,
|
|
302
|
-
issues:
|
|
303
|
-
path: i.path,
|
|
304
|
-
message: i.message
|
|
305
|
-
}))
|
|
294
|
+
issues: issues.map((i) => ({ path: i.path, message: i.message }))
|
|
306
295
|
});
|
|
307
296
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
{ code: "INVALID_PROJECT", exitCode: EXIT_INVALID_PROJECT }
|
|
312
|
-
);
|
|
313
|
-
}
|
|
314
|
-
const pathsRaw = config.paths;
|
|
315
|
-
const paths = { ...DEFAULT_PATHS };
|
|
316
|
-
if (pathsRaw !== void 0 && (typeof pathsRaw !== "object" || pathsRaw === null)) {
|
|
317
|
-
throw new CliError(`${configPath}: "paths" must be an object.`, {
|
|
297
|
+
const schemaIssue = issues.find((i) => i.path === "schemaVersion");
|
|
298
|
+
if (schemaIssue) {
|
|
299
|
+
throw new CliError(`${configPath}: schemaVersion must be 1 (got ${schemaIssue.message.replace(/^must be 1 \(got /, "").replace(/\)$/, "")}).`, {
|
|
318
300
|
code: "INVALID_PROJECT",
|
|
319
301
|
exitCode: EXIT_INVALID_PROJECT
|
|
320
302
|
});
|
|
321
303
|
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
code: "INVALID_PROJECT",
|
|
328
|
-
exitCode: EXIT_INVALID_PROJECT
|
|
329
|
-
});
|
|
330
|
-
}
|
|
331
|
-
paths.spaDistDir = p.spaDistDir;
|
|
332
|
-
}
|
|
333
|
-
if (p.lxpackOutDir !== void 0) {
|
|
334
|
-
if (typeof p.lxpackOutDir !== "string" || !p.lxpackOutDir.trim()) {
|
|
335
|
-
throw new CliError(`${configPath}: "paths.lxpackOutDir" must be a non-empty string.`, {
|
|
336
|
-
code: "INVALID_PROJECT",
|
|
337
|
-
exitCode: EXIT_INVALID_PROJECT
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
paths.lxpackOutDir = p.lxpackOutDir;
|
|
341
|
-
}
|
|
342
|
-
if (p.outputBaseDir !== void 0) {
|
|
343
|
-
if (typeof p.outputBaseDir !== "string" || !p.outputBaseDir.trim()) {
|
|
344
|
-
throw new CliError(`${configPath}: "paths.outputBaseDir" must be a non-empty string.`, {
|
|
345
|
-
code: "INVALID_PROJECT",
|
|
346
|
-
exitCode: EXIT_INVALID_PROJECT
|
|
347
|
-
});
|
|
348
|
-
}
|
|
349
|
-
paths.outputBaseDir = p.outputBaseDir;
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
const courseSpaDistDir = validation.descriptor.spaDistDir?.trim();
|
|
353
|
-
if (courseSpaDistDir && courseSpaDistDir !== paths.spaDistDir) {
|
|
354
|
-
throw new CliError(
|
|
355
|
-
`${configPath}: "course.spaDistDir" (${courseSpaDistDir}) differs from "paths.spaDistDir" (${paths.spaDistDir}). Use paths.spaDistDir for CLI build and package.`,
|
|
356
|
-
{ code: "INVALID_PROJECT", exitCode: EXIT_INVALID_PROJECT }
|
|
357
|
-
);
|
|
358
|
-
}
|
|
359
|
-
const pathIssues = validateProjectPaths(projectRoot, paths);
|
|
360
|
-
if (pathIssues.length) {
|
|
361
|
-
throw new CliError(`${configPath}: invalid paths.`, {
|
|
362
|
-
code: "INVALID_PROJECT",
|
|
363
|
-
exitCode: EXIT_INVALID_PROJECT,
|
|
364
|
-
issues: pathIssues
|
|
365
|
-
});
|
|
366
|
-
}
|
|
367
|
-
return {
|
|
368
|
-
root: projectRoot,
|
|
369
|
-
schemaVersion: 1,
|
|
370
|
-
name,
|
|
371
|
-
course: validation.descriptor,
|
|
372
|
-
paths
|
|
373
|
-
};
|
|
304
|
+
throw new CliError(`${configPath}: invalid lessonkit manifest.`, {
|
|
305
|
+
code: "INVALID_PROJECT",
|
|
306
|
+
exitCode: EXIT_INVALID_PROJECT,
|
|
307
|
+
issues: issues.map((i) => ({ path: i.path, message: i.message }))
|
|
308
|
+
});
|
|
374
309
|
}
|
|
375
310
|
async function loadProject(cwd = process.cwd()) {
|
|
376
311
|
const root = findProjectRoot(cwd);
|
|
@@ -388,7 +323,7 @@ async function readPackageJson(projectRoot) {
|
|
|
388
323
|
}
|
|
389
324
|
}
|
|
390
325
|
function assertViteProject(pkg, projectRoot) {
|
|
391
|
-
const vite = pkg.devDependencies?.vite ?? pkg.dependencies?.vite ?? (existsSync2(join2(projectRoot, "node_modules", ".bin", "vite")) || existsSync2(join2(projectRoot, "node_modules", ".bin", "vite.cmd")) ? "present" : void 0);
|
|
326
|
+
const vite = pkg.devDependencies?.vite ?? pkg.dependencies?.vite ?? (existsSync2(join2(projectRoot, "node_modules", "vite", "bin", "vite.js")) || existsSync2(join2(projectRoot, "node_modules", ".bin", "vite")) || existsSync2(join2(projectRoot, "node_modules", ".bin", "vite.cmd")) ? "present" : void 0);
|
|
392
327
|
if (!vite) {
|
|
393
328
|
throw new CliError(
|
|
394
329
|
`No Vite dependency found in ${join2(projectRoot, PACKAGE_JSON)}. LessonKit projects require Vite.`,
|
|
@@ -396,28 +331,25 @@ function assertViteProject(pkg, projectRoot) {
|
|
|
396
331
|
);
|
|
397
332
|
}
|
|
398
333
|
}
|
|
399
|
-
function
|
|
334
|
+
function resolveViteJs(projectRoot) {
|
|
400
335
|
let dir = resolve2(projectRoot);
|
|
401
336
|
const fsRoot = parse(dir).root;
|
|
402
337
|
while (true) {
|
|
403
|
-
const
|
|
404
|
-
|
|
405
|
-
if (existsSync2(bin)) return bin;
|
|
406
|
-
const binCmd = join2(binDir, "vite.cmd");
|
|
407
|
-
if (existsSync2(binCmd)) return binCmd;
|
|
338
|
+
const viteJs = join2(dir, "node_modules", "vite", "bin", "vite.js");
|
|
339
|
+
if (existsSync2(viteJs)) return viteJs;
|
|
408
340
|
if (dir === fsRoot) break;
|
|
409
341
|
dir = dirname2(dir);
|
|
410
342
|
}
|
|
411
343
|
throw new CliError(
|
|
412
|
-
`Vite
|
|
344
|
+
`Vite not found near ${projectRoot}. Run npm install in the project first.`,
|
|
413
345
|
{ code: "INVALID_PROJECT", exitCode: EXIT_INVALID_PROJECT }
|
|
414
346
|
);
|
|
415
347
|
}
|
|
416
|
-
function
|
|
348
|
+
function assertNode18ForLxpack() {
|
|
417
349
|
const major = Number(process.versions.node.split(".")[0]);
|
|
418
|
-
if (major <
|
|
350
|
+
if (major < 18) {
|
|
419
351
|
throw new CliError(
|
|
420
|
-
`LMS packaging requires Node.js
|
|
352
|
+
`LMS packaging requires Node.js 18+ (current: ${process.versions.node}). See docs/PACKAGING.md.`,
|
|
421
353
|
{ code: "NODE_VERSION", exitCode: EXIT_INVALID_PROJECT }
|
|
422
354
|
);
|
|
423
355
|
}
|
|
@@ -479,17 +411,19 @@ async function runDev(opts) {
|
|
|
479
411
|
const project = await loadProject(opts.cwd ?? process.cwd());
|
|
480
412
|
const pkg = await readPackageJson(project.root);
|
|
481
413
|
assertViteProject(pkg, project.root);
|
|
482
|
-
const
|
|
483
|
-
await runCommand(
|
|
414
|
+
const viteJs = resolveViteJs(project.root);
|
|
415
|
+
await runCommand(process.execPath, [viteJs, ...opts.viteArgs ?? []], { cwd: project.root });
|
|
484
416
|
return { ok: true, command: "dev", projectRoot: project.root };
|
|
485
417
|
}
|
|
486
418
|
async function runBuild(opts) {
|
|
487
419
|
const project = await loadProject(opts.cwd ?? process.cwd());
|
|
488
420
|
const pkg = await readPackageJson(project.root);
|
|
489
421
|
assertViteProject(pkg, project.root);
|
|
490
|
-
const
|
|
422
|
+
const viteJs = resolveViteJs(project.root);
|
|
491
423
|
const buildArgs = resolveViteBuildArgs(project);
|
|
492
|
-
await runCommand(
|
|
424
|
+
await runCommand(process.execPath, [viteJs, ...buildArgs, ...opts.viteArgs ?? []], {
|
|
425
|
+
cwd: project.root
|
|
426
|
+
});
|
|
493
427
|
return { ok: true, command: "build", projectRoot: project.root };
|
|
494
428
|
}
|
|
495
429
|
|
|
@@ -524,7 +458,7 @@ async function runPackage(opts) {
|
|
|
524
458
|
}
|
|
525
459
|
return { ok: true, target, projectRoot: project.root, distDir };
|
|
526
460
|
}
|
|
527
|
-
|
|
461
|
+
assertNode18ForLxpack();
|
|
528
462
|
if (!opts.noBuild || !existsSync3(distDir)) {
|
|
529
463
|
await runBuild({ cwd: project.root, json: opts.json });
|
|
530
464
|
}
|
|
@@ -598,7 +532,10 @@ async function handleCommand(fn, logger, json) {
|
|
|
598
532
|
function createProgram(baseLogger = console) {
|
|
599
533
|
const program = new Command();
|
|
600
534
|
program.name("lessonkit").description("LessonKit CLI").version(version);
|
|
601
|
-
program.command("init").description("Initialize a LessonKit project from the Vite + React template").argument("[name]", "Project directory name").option("--here", "Initialize in the current directory").option("--skip-install", "Skip npm install").option(
|
|
535
|
+
program.command("init").description("Initialize a LessonKit project from the Vite + React template").argument("[name]", "Project directory name").option("--here", "Initialize in the current directory").option("--skip-install", "Skip npm install").option(
|
|
536
|
+
"--force",
|
|
537
|
+
"With --here, allow init when the directory is empty or contains only dotfiles"
|
|
538
|
+
).option("--json", "Emit structured JSON result").action(async (name, opts) => {
|
|
602
539
|
const logger = createLogger({ json: opts.json });
|
|
603
540
|
await handleCommand(
|
|
604
541
|
() => runInit({ name, here: opts.here, skipInstall: opts.skipInstall, force: opts.force, json: opts.json }, logger),
|
|
@@ -632,13 +569,27 @@ function createProgram(baseLogger = console) {
|
|
|
632
569
|
program.command("package").description("Build or package for web / LMS delivery").requiredOption("--target <target>", `Export target (${PACKAGE_TARGETS.join(", ")})`).option("--cwd <dir>", "Project root directory").option("--no-build", "Skip implicit Vite build for LMS targets").option("--out <path>", "Override output artifact path").option("--json", "Emit structured JSON result").action(async (opts) => {
|
|
633
570
|
const logger = createLogger({ json: opts.json });
|
|
634
571
|
await handleCommand(
|
|
635
|
-
() =>
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
572
|
+
async () => {
|
|
573
|
+
const result = await runPackage({
|
|
574
|
+
target: opts.target,
|
|
575
|
+
cwd: opts.cwd,
|
|
576
|
+
noBuild: opts.build === false,
|
|
577
|
+
out: opts.out,
|
|
578
|
+
json: opts.json
|
|
579
|
+
});
|
|
580
|
+
if (!opts.json && result.ok) {
|
|
581
|
+
if (result.target === "react-vite" && "distDir" in result) {
|
|
582
|
+
logger.log(`Built react-vite \u2192 ${result.distDir}`);
|
|
583
|
+
} else if ("outputPath" in result || "outputDir" in result) {
|
|
584
|
+
const dest = result.outputPath ?? result.outputDir;
|
|
585
|
+
const count = "fileCount" in result ? result.fileCount : void 0;
|
|
586
|
+
logger.log(
|
|
587
|
+
`Packaged ${result.target}${dest ? ` \u2192 ${dest}` : ""}${count != null ? ` (${count} files)` : ""}`
|
|
588
|
+
);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
return result;
|
|
592
|
+
},
|
|
642
593
|
logger,
|
|
643
594
|
Boolean(opts.json)
|
|
644
595
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lessonkit/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "LessonKit CLI — init, dev, build, and package learning experiences.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -42,7 +42,8 @@
|
|
|
42
42
|
"lint": "echo \"(no lint configured yet)\""
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@lessonkit/
|
|
45
|
+
"@lessonkit/core": "1.0.0",
|
|
46
|
+
"@lessonkit/lxpack": "1.0.0",
|
|
46
47
|
"commander": "^14.0.1"
|
|
47
48
|
},
|
|
48
49
|
"engines": {
|
|
@@ -1,19 +1,21 @@
|
|
|
1
|
-
# LessonKit
|
|
1
|
+
# LessonKit starter template
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
[](https://github.com/eddiethedean/lessonkit/blob/main/LICENSE)
|
|
3
|
+
Vite + React scaffold for new LessonKit courses. Created by `lessonkit init`.
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
## Run
|
|
5
|
+
## Commands
|
|
9
6
|
|
|
10
7
|
```bash
|
|
11
8
|
npm install
|
|
12
|
-
npm run dev
|
|
9
|
+
npm run dev # lessonkit dev
|
|
10
|
+
npm run build # lessonkit build
|
|
11
|
+
npm run package:scorm12
|
|
13
12
|
```
|
|
14
13
|
|
|
15
|
-
##
|
|
14
|
+
## Files
|
|
15
|
+
|
|
16
|
+
- `src/App.tsx` — course UI (IDs match `lessonkit.json`)
|
|
17
|
+
- `lessonkit.json` — manifest for CLI and LXPack packaging
|
|
18
|
+
|
|
19
|
+
## Docs
|
|
16
20
|
|
|
17
|
-
|
|
18
|
-
- Copied by [`@lessonkit/cli`](https://lessonkit.readthedocs.io/en/latest/reference/cli.html) when you run `lessonkit init`.
|
|
19
|
-
- Package for an LMS with the [packaging guide](https://lessonkit.readthedocs.io/en/latest/guides/react-developers/packaging-and-cli.html).
|
|
21
|
+
[CLI reference](https://lessonkit.readthedocs.io/en/latest/reference/cli.html) · [React quickstart](https://lessonkit.readthedocs.io/en/latest/guides/react-developers/quickstart.html) · [Packaging guide](https://lessonkit.readthedocs.io/en/latest/guides/react-developers/packaging-and-cli.html)
|
|
@@ -13,16 +13,16 @@
|
|
|
13
13
|
"test:coverage": "vitest run --coverage --passWithNoTests=false"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@lessonkit/core": "^0.
|
|
17
|
-
"@lessonkit/react": "^0.
|
|
18
|
-
"@lessonkit/themes": "^0.
|
|
19
|
-
"@lessonkit/xapi": "^0.
|
|
16
|
+
"@lessonkit/core": "^1.0.0",
|
|
17
|
+
"@lessonkit/react": "^1.0.0",
|
|
18
|
+
"@lessonkit/themes": "^1.0.0",
|
|
19
|
+
"@lessonkit/xapi": "^1.0.0",
|
|
20
20
|
"react": "^18.3.1",
|
|
21
21
|
"react-dom": "^18.3.1"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@lessonkit/cli": "^0.
|
|
25
|
-
"@lessonkit/lxpack": "^0.
|
|
24
|
+
"@lessonkit/cli": "^1.0.0",
|
|
25
|
+
"@lessonkit/lxpack": "^1.0.0",
|
|
26
26
|
"@testing-library/react": "^16.3.0",
|
|
27
27
|
"@types/react": "^18.3.23",
|
|
28
28
|
"@types/react-dom": "^18.3.7",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
html,body{height:100%}body{margin:0;background:var(--lk-color-background);color:var(--lk-color-foreground);font-family:var(--lk-font-family);font-size:var(--lk-font-size-base);line-height:var(--lk-line-height-base)}.app-shell{margin:0 auto;padding:var(--lk-space-xl) var(--lk-space-lg);max-width:720px}section,article{border:1px solid var(--lk-color-border);border-radius:var(--lk-radius-lg);padding:var(--lk-space-lg);margin:var(--lk-space-md) 0;background:var(--lk-color-panel);box-shadow:var(--lk-shadow-md)}h1,h2{margin:0 0 var(--lk-space-sm);font-weight:var(--lk-font-weight-strong)}button{border:1px solid var(--lk-color-border);background:var(--lk-color-panel);color:var(--lk-color-foreground);border-radius:var(--lk-radius-md);padding:var(--lk-space-sm) var(--lk-space-md);font-weight:var(--lk-font-weight-strong);cursor:pointer}input[type=radio]{accent-color:var(--lk-color-primary)}label{display:block;margin:var(--lk-space-xs) 0}
|