@sigx/cli 0.1.3 → 0.2.1

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.
Files changed (43) hide show
  1. package/dist/commands/create.js +18 -14
  2. package/dist/commands/create.js.map +1 -1
  3. package/dist/templates/lynx/package.json +2 -1
  4. package/dist/templates/lynx/sigx.lynx.config.ts +1 -0
  5. package/dist/templates/lynx/tsconfig.json +1 -0
  6. package/dist/templates/lynx-daisyui/README.md +61 -0
  7. package/dist/templates/lynx-daisyui/assets/adaptive-foreground.png +0 -0
  8. package/dist/templates/lynx-daisyui/assets/icon.png +0 -0
  9. package/dist/templates/lynx-daisyui/assets/splash.png +0 -0
  10. package/dist/templates/lynx-daisyui/lynx.config.ts +20 -0
  11. package/dist/templates/lynx-daisyui/package.json +43 -0
  12. package/dist/templates/lynx-daisyui/postcss.config.js +5 -0
  13. package/dist/templates/lynx-daisyui/sigx.lynx.config.ts +45 -0
  14. package/dist/templates/lynx-daisyui/src/App.tsx +93 -0
  15. package/dist/templates/lynx-daisyui/src/main.thread.tsx +2 -0
  16. package/dist/templates/lynx-daisyui/src/main.tsx +10 -0
  17. package/dist/templates/lynx-daisyui/src/styles.css +3 -0
  18. package/dist/templates/lynx-daisyui/tailwind.config.ts +10 -0
  19. package/dist/templates/lynx-daisyui/tsconfig.json +20 -0
  20. package/dist/templates/lynx-tailwind/package.json +2 -1
  21. package/dist/templates/lynx-tailwind/sigx.lynx.config.ts +1 -0
  22. package/dist/templates/lynx-tailwind/tsconfig.json +1 -0
  23. package/package.json +1 -1
  24. package/templates/lynx/package.json +2 -1
  25. package/templates/lynx/sigx.lynx.config.ts +1 -0
  26. package/templates/lynx/tsconfig.json +1 -0
  27. package/templates/lynx-daisyui/README.md +61 -0
  28. package/templates/lynx-daisyui/assets/adaptive-foreground.png +0 -0
  29. package/templates/lynx-daisyui/assets/icon.png +0 -0
  30. package/templates/lynx-daisyui/assets/splash.png +0 -0
  31. package/templates/lynx-daisyui/lynx.config.ts +20 -0
  32. package/templates/lynx-daisyui/package.json +43 -0
  33. package/templates/lynx-daisyui/postcss.config.js +5 -0
  34. package/templates/lynx-daisyui/sigx.lynx.config.ts +45 -0
  35. package/templates/lynx-daisyui/src/App.tsx +93 -0
  36. package/templates/lynx-daisyui/src/main.thread.tsx +2 -0
  37. package/templates/lynx-daisyui/src/main.tsx +10 -0
  38. package/templates/lynx-daisyui/src/styles.css +3 -0
  39. package/templates/lynx-daisyui/tailwind.config.ts +10 -0
  40. package/templates/lynx-daisyui/tsconfig.json +20 -0
  41. package/templates/lynx-tailwind/package.json +2 -1
  42. package/templates/lynx-tailwind/sigx.lynx.config.ts +1 -0
  43. package/templates/lynx-tailwind/tsconfig.json +1 -0
@@ -60,15 +60,23 @@ var webStylingOptions = [
60
60
  description: "Tailwind with component library"
61
61
  }
62
62
  ];
63
- var lynxStylingOptions = [{
64
- value: "none",
65
- label: "None",
66
- description: "No CSS framework"
67
- }, {
68
- value: "tailwind",
69
- label: "Tailwind CSS",
70
- description: "Tailwind with Lynx preset"
71
- }];
63
+ var lynxStylingOptions = [
64
+ {
65
+ value: "none",
66
+ label: "None",
67
+ description: "No CSS framework"
68
+ },
69
+ {
70
+ value: "tailwind",
71
+ label: "Tailwind CSS",
72
+ description: "Tailwind with Lynx preset"
73
+ },
74
+ {
75
+ value: "daisyui",
76
+ label: "Tailwind + Daisy UI",
77
+ description: "Lynx + @sigx/lynx-daisyui components"
78
+ }
79
+ ];
72
80
  var TEXT_EXTS = new Set([
73
81
  "ts",
74
82
  "tsx",
@@ -149,7 +157,7 @@ function patchWorkspaceDeps(targetDir) {
149
157
  function scaffoldProject(opts) {
150
158
  const targetDir = resolve(process.cwd(), opts.projectName);
151
159
  let templateName;
152
- if (opts.projectType === "lynx") templateName = opts.styling === "tailwind" ? "lynx-tailwind" : "lynx";
160
+ if (opts.projectType === "lynx") templateName = opts.styling !== "none" ? `lynx-${opts.styling}` : "lynx";
153
161
  else templateName = opts.styling !== "none" ? `${opts.projectType}-${opts.styling}` : opts.projectType;
154
162
  const templateDir = resolve(__dirname, "..", "templates", templateName);
155
163
  if (existsSync(targetDir)) return {
@@ -414,10 +422,6 @@ function runHeadless() {
414
422
  console.error(`Error: --styling must be one of ${validStyling.join(", ")}`);
415
423
  return 2;
416
424
  }
417
- if (projectType === "lynx" && styling === "daisyui") {
418
- console.error("Error: --styling=daisyui is not supported for Lynx projects (use none or tailwind)");
419
- return 2;
420
- }
421
425
  console.log(`\n ⚡ Creating SignalX app "${projectName}"`);
422
426
  console.log(` type: ${projectType}`);
423
427
  console.log(` styling: ${styling}\n`);
@@ -1 +1 @@
1
- {"version":3,"file":"create.js","names":[],"sources":["../../src/commands/create.tsx"],"sourcesContent":["/** @jsxImportSource @sigx/terminal */\nimport { signal, component, defineApp, Input, Button, ProgressBar, Select } from '@sigx/terminal';\nimport { existsSync, mkdirSync, readdirSync, statSync, writeFileSync, readFileSync } from 'fs';\nimport { dirname, resolve, join } from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\ntype Step = 'name' | 'type' | 'styling' | 'creating' | 'done';\ntype ProjectType = 'basic' | 'ssr' | 'ssg' | 'lynx';\ntype Styling = 'none' | 'tailwind' | 'daisyui';\n\n// Parse CLI args (supports both interactive default and --flag headless mode).\nconst rawArgs = process.argv.slice(2);\nfunction getFlag(name: string): string | undefined {\n const eq = rawArgs.find(a => a.startsWith(`--${name}=`));\n if (eq) return eq.slice(name.length + 3);\n const idx = rawArgs.indexOf(`--${name}`);\n if (idx !== -1 && rawArgs[idx + 1] && !rawArgs[idx + 1].startsWith('-')) return rawArgs[idx + 1];\n return undefined;\n}\nfunction hasFlag(name: string, short?: string): boolean {\n return rawArgs.includes(`--${name}`) || (short ? rawArgs.includes(`-${short}`) : false);\n}\nconst positionalArgs = rawArgs.filter(a => !a.startsWith('-') && a !== 'create');\nconst argProjectName = positionalArgs[0] || '';\nconst argType = getFlag('type') as ProjectType | undefined;\nconst argStyling = getFlag('styling') as Styling | undefined;\nconst flagYes = hasFlag('yes', 'y');\nconst isNonInteractive = !process.stdout.isTTY || !process.stdin.isTTY || flagYes\n || Boolean(argType && argProjectName);\n\nconst projectTypeOptions = [\n { value: 'basic' as ProjectType, label: 'Basic SPA', description: 'Simple single-page application (web)' },\n { value: 'ssr' as ProjectType, label: 'SSR', description: 'Server-side rendering with Express (web)' },\n { value: 'ssg' as ProjectType, label: 'SSG', description: 'Static site with file-based routing & MDX (web)' },\n { value: 'lynx' as ProjectType, label: 'Lynx', description: 'Native mobile app with Lynx runtime' },\n];\n\nconst webStylingOptions = [\n { value: 'none' as Styling, label: 'None', description: 'No CSS framework' },\n { value: 'tailwind' as Styling, label: 'Tailwind CSS', description: 'Utility-first CSS framework' },\n { value: 'daisyui' as Styling, label: 'Tailwind + Daisy UI', description: 'Tailwind with component library' },\n];\n\nconst lynxStylingOptions = [\n { value: 'none' as Styling, label: 'None', description: 'No CSS framework' },\n { value: 'tailwind' as Styling, label: 'Tailwind CSS', description: 'Tailwind with Lynx preset' },\n];\n\nconst TEXT_EXTS = new Set([\n 'ts', 'tsx', 'js', 'jsx', 'mjs', 'cjs', 'mts', 'cts',\n 'json', 'json5', 'jsonc',\n 'md', 'mdx', 'txt',\n 'html', 'htm', 'css', 'scss', 'sass', 'less',\n 'yml', 'yaml', 'toml', 'xml', 'svg',\n 'gitignore', 'gitattributes', 'editorconfig', 'npmrc', 'nvmrc', 'env',\n]);\n\nfunction isTextExtension(filename: string): boolean {\n // Dotfiles: name after leading dot (.gitignore → \"gitignore\").\n const ext = filename.startsWith('.')\n ? filename.slice(1).toLowerCase()\n : filename.split('.').pop()?.toLowerCase() ?? '';\n return TEXT_EXTS.has(ext);\n}\n\nfunction copyDirectory(src: string, dest: string, projectName: string) {\n if (!existsSync(dest)) {\n mkdirSync(dest, { recursive: true });\n }\n\n const entries = readdirSync(src);\n for (const entry of entries) {\n const srcPath = join(src, entry);\n const destPath = join(dest, entry);\n const stat = statSync(srcPath);\n\n if (stat.isDirectory()) {\n copyDirectory(srcPath, destPath, projectName);\n } else if (isTextExtension(entry)) {\n let content = readFileSync(srcPath, 'utf-8');\n content = content.replace(/\\{\\{projectName\\}\\}/g, projectName);\n writeFileSync(destPath, content);\n } else {\n // Binary asset — copy bytes verbatim. Reading as UTF-8 would corrupt\n // non-ASCII bytes (e.g. PNG magic 0x89 → U+FFFD).\n writeFileSync(destPath, readFileSync(srcPath));\n }\n }\n}\n\n/**\n * Detect if the target directory is inside a pnpm workspace that includes @sigx packages.\n * If so, rewrite @sigx/* dependency versions to workspace:* in package.json.\n */\nfunction patchWorkspaceDeps(targetDir: string) {\n const pkgPath = join(targetDir, 'package.json');\n if (!existsSync(pkgPath)) return;\n\n // Walk up to find pnpm-workspace.yaml\n let dir = dirname(targetDir);\n let isWorkspace = false;\n for (let i = 0; i < 10; i++) {\n if (existsSync(join(dir, 'pnpm-workspace.yaml'))) {\n isWorkspace = true;\n break;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n if (!isWorkspace) return;\n\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n for (const section of ['dependencies', 'devDependencies'] as const) {\n if (!pkg[section]) continue;\n for (const dep of Object.keys(pkg[section])) {\n if (dep.startsWith('@sigx/')) {\n pkg[section][dep] = 'workspace:*';\n }\n }\n }\n writeFileSync(pkgPath, JSON.stringify(pkg, null, 4) + '\\n');\n}\n\nfunction scaffoldProject(opts: {\n projectName: string;\n projectType: ProjectType;\n styling: Styling;\n}): { ok: true } | { ok: false; error: string } {\n const targetDir = resolve(process.cwd(), opts.projectName);\n let templateName: string;\n if (opts.projectType === 'lynx') {\n templateName = opts.styling === 'tailwind' ? 'lynx-tailwind' : 'lynx';\n } else {\n templateName = opts.styling !== 'none' ? `${opts.projectType}-${opts.styling}` : opts.projectType;\n }\n const templateDir = resolve(__dirname, '..', 'templates', templateName);\n if (existsSync(targetDir)) return { ok: false, error: `Directory \"${opts.projectName}\" already exists!` };\n if (!existsSync(templateDir)) return { ok: false, error: `Template \"${templateName}\" not found at ${templateDir}` };\n copyDirectory(templateDir, targetDir, opts.projectName);\n patchWorkspaceDeps(targetDir);\n return { ok: true };\n}\n\nconst CreateSigx = component(() => {\n const state = signal({\n step: 'name' as Step,\n projectName: argProjectName || 'my-sigx-app',\n projectType: 'basic' as ProjectType,\n styling: 'none' as Styling,\n progress: 0,\n error: '',\n });\n\n const createProject = () => {\n state.step = 'creating';\n state.progress = 30;\n const result = scaffoldProject({\n projectName: state.projectName,\n projectType: state.projectType,\n styling: state.styling,\n });\n if (!result.ok) {\n state.error = result.error;\n return;\n }\n state.progress = 100;\n state.step = 'done';\n };\n\n const handleNameSubmit = () => {\n if (state.projectName.trim()) {\n state.step = 'type';\n }\n };\n\n const handleTypeSubmit = () => {\n state.step = 'styling';\n };\n\n const handleStylingSubmit = () => {\n createProject();\n };\n\n const handleExit = () => {\n process.exit(0);\n };\n\n return () => {\n if (state.error) {\n return (\n <box border=\"double\" borderColor=\"red\" label=\" Error \">\n <text color=\"red\"> {state.error}</text>\n <br />\n <br />\n <Button label=\"Exit\" onClick={handleExit} />\n </box>\n );\n }\n\n const projectTypeLabel = (t: ProjectType) => {\n switch (t) {\n case 'basic': return 'Basic SPA';\n case 'ssr': return 'SSR';\n case 'ssg': return 'SSG';\n case 'lynx': return 'Lynx (Native)';\n }\n };\n\n const stylingLabel = (s: Styling) => {\n switch (s) {\n case 'none': return 'None';\n case 'tailwind': return 'Tailwind CSS';\n case 'daisyui': return 'Tailwind + Daisy UI';\n }\n };\n\n // Render step-specific content as a single element to avoid\n // multiple conditional children causing duplicate nodes\n const stepContent = (() => {\n switch (state.step) {\n case 'name':\n return (\n <box>\n <text color=\"gray\"> Step 1 of 3</text>\n <br />\n <br />\n <text color=\"white\"> What is your project called?</text>\n <br />\n <br />\n <Input\n model={() => state.projectName}\n label=\" Project Name \"\n placeholder=\"my-sigx-app\"\n autofocus\n onSubmit={handleNameSubmit}\n />\n <br />\n <text color=\"gray\"> Press Enter to continue</text>\n </box>\n );\n case 'type':\n return (\n <box>\n <text color=\"gray\"> Step 2 of 3</text>\n <br />\n <br />\n <text color=\"white\"> What type of project?</text>\n <br />\n <br />\n <Select\n model={() => state.projectType}\n label=\" Project Type \"\n options={projectTypeOptions}\n showDescription\n autofocus\n onSubmit={handleTypeSubmit}\n />\n <br />\n <text color=\"gray\"> ↑/↓ navigate · Enter select</text>\n </box>\n );\n case 'styling':\n return (\n <box>\n <text color=\"gray\"> Step 3 of 3</text>\n <br />\n <br />\n <text color=\"white\"> Choose a styling approach:</text>\n <br />\n <br />\n <Select\n model={() => state.styling}\n label=\" Styling \"\n options={state.projectType === 'lynx' ? lynxStylingOptions : webStylingOptions}\n showDescription\n autofocus\n onSubmit={handleStylingSubmit}\n />\n <br />\n <text color=\"gray\"> ↑/↓ navigate · Enter select</text>\n </box>\n );\n case 'creating':\n return (\n <box>\n <br />\n <text color=\"yellow\"> Creating project...</text>\n <br />\n <ProgressBar value={state.progress} max={100} width={40} color=\"green\" />\n </box>\n );\n case 'done':\n return (\n <box>\n <br />\n <text color=\"green\"> ✓ Project \"{state.projectName}\" created!</text>\n <br />\n <br />\n <text color=\"gray\"> Type: {projectTypeLabel(state.projectType)}</text>\n <br />\n <text color=\"gray\"> Styling: {stylingLabel(state.styling)}</text>\n <br />\n <br />\n <text color=\"white\"> Next steps:</text>\n <br />\n <br />\n <text color=\"cyan\"> cd {state.projectName}</text>\n <br />\n <text color=\"cyan\"> pnpm install</text>\n <br />\n <text color=\"cyan\"> {state.projectType === 'lynx' ? 'sigx dev' : 'pnpm dev'}</text>\n <br />\n <br />\n <Button label=\"Exit\" onClick={handleExit} />\n </box>\n );\n }\n })();\n\n return (\n <box>\n <text color=\"cyan\"> ⚡ Create SignalX App</text>\n <br />\n {stepContent}\n </box>\n );\n };\n});\n\nfunction runHeadless(): number {\n const validTypes: ProjectType[] = ['basic', 'ssr', 'ssg', 'lynx'];\n const validStyling: Styling[] = ['none', 'tailwind', 'daisyui'];\n\n const projectName = argProjectName || 'my-sigx-app';\n const projectType: ProjectType = argType ?? 'basic';\n const styling: Styling = argStyling ?? 'none';\n\n if (!validTypes.includes(projectType)) {\n console.error(`Error: --type must be one of ${validTypes.join(', ')}`);\n return 2;\n }\n if (!validStyling.includes(styling)) {\n console.error(`Error: --styling must be one of ${validStyling.join(', ')}`);\n return 2;\n }\n if (projectType === 'lynx' && styling === 'daisyui') {\n console.error('Error: --styling=daisyui is not supported for Lynx projects (use none or tailwind)');\n return 2;\n }\n\n console.log(`\\n ⚡ Creating SignalX app \"${projectName}\"`);\n console.log(` type: ${projectType}`);\n console.log(` styling: ${styling}\\n`);\n\n const result = scaffoldProject({ projectName, projectType, styling });\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n return 1;\n }\n\n console.log(` ✓ Project created\\n`);\n console.log(` Next steps:`);\n console.log(` cd ${projectName}`);\n console.log(` pnpm install`);\n console.log(` ${projectType === 'lynx' ? 'sigx dev' : 'pnpm dev'}\\n`);\n return 0;\n}\n\nexport function runCreate() {\n if (isNonInteractive) {\n process.exit(runHeadless());\n }\n defineApp(<CreateSigx />).mount({ clearConsole: true });\n // Keep process alive for TUI\n setInterval(() => { }, 10000);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"create.js","names":[],"sources":["../../src/commands/create.tsx"],"sourcesContent":["/** @jsxImportSource @sigx/terminal */\nimport { signal, component, defineApp, Input, Button, ProgressBar, Select } from '@sigx/terminal';\nimport { existsSync, mkdirSync, readdirSync, statSync, writeFileSync, readFileSync } from 'fs';\nimport { dirname, resolve, join } from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\ntype Step = 'name' | 'type' | 'styling' | 'creating' | 'done';\ntype ProjectType = 'basic' | 'ssr' | 'ssg' | 'lynx';\ntype Styling = 'none' | 'tailwind' | 'daisyui';\n\n// Parse CLI args (supports both interactive default and --flag headless mode).\nconst rawArgs = process.argv.slice(2);\nfunction getFlag(name: string): string | undefined {\n const eq = rawArgs.find(a => a.startsWith(`--${name}=`));\n if (eq) return eq.slice(name.length + 3);\n const idx = rawArgs.indexOf(`--${name}`);\n if (idx !== -1 && rawArgs[idx + 1] && !rawArgs[idx + 1].startsWith('-')) return rawArgs[idx + 1];\n return undefined;\n}\nfunction hasFlag(name: string, short?: string): boolean {\n return rawArgs.includes(`--${name}`) || (short ? rawArgs.includes(`-${short}`) : false);\n}\nconst positionalArgs = rawArgs.filter(a => !a.startsWith('-') && a !== 'create');\nconst argProjectName = positionalArgs[0] || '';\nconst argType = getFlag('type') as ProjectType | undefined;\nconst argStyling = getFlag('styling') as Styling | undefined;\nconst flagYes = hasFlag('yes', 'y');\nconst isNonInteractive = !process.stdout.isTTY || !process.stdin.isTTY || flagYes\n || Boolean(argType && argProjectName);\n\nconst projectTypeOptions = [\n { value: 'basic' as ProjectType, label: 'Basic SPA', description: 'Simple single-page application (web)' },\n { value: 'ssr' as ProjectType, label: 'SSR', description: 'Server-side rendering with Express (web)' },\n { value: 'ssg' as ProjectType, label: 'SSG', description: 'Static site with file-based routing & MDX (web)' },\n { value: 'lynx' as ProjectType, label: 'Lynx', description: 'Native mobile app with Lynx runtime' },\n];\n\nconst webStylingOptions = [\n { value: 'none' as Styling, label: 'None', description: 'No CSS framework' },\n { value: 'tailwind' as Styling, label: 'Tailwind CSS', description: 'Utility-first CSS framework' },\n { value: 'daisyui' as Styling, label: 'Tailwind + Daisy UI', description: 'Tailwind with component library' },\n];\n\nconst lynxStylingOptions = [\n { value: 'none' as Styling, label: 'None', description: 'No CSS framework' },\n { value: 'tailwind' as Styling, label: 'Tailwind CSS', description: 'Tailwind with Lynx preset' },\n { value: 'daisyui' as Styling, label: 'Tailwind + Daisy UI', description: 'Lynx + @sigx/lynx-daisyui components' },\n];\n\nconst TEXT_EXTS = new Set([\n 'ts', 'tsx', 'js', 'jsx', 'mjs', 'cjs', 'mts', 'cts',\n 'json', 'json5', 'jsonc',\n 'md', 'mdx', 'txt',\n 'html', 'htm', 'css', 'scss', 'sass', 'less',\n 'yml', 'yaml', 'toml', 'xml', 'svg',\n 'gitignore', 'gitattributes', 'editorconfig', 'npmrc', 'nvmrc', 'env',\n]);\n\nfunction isTextExtension(filename: string): boolean {\n // Dotfiles: name after leading dot (.gitignore → \"gitignore\").\n const ext = filename.startsWith('.')\n ? filename.slice(1).toLowerCase()\n : filename.split('.').pop()?.toLowerCase() ?? '';\n return TEXT_EXTS.has(ext);\n}\n\nfunction copyDirectory(src: string, dest: string, projectName: string) {\n if (!existsSync(dest)) {\n mkdirSync(dest, { recursive: true });\n }\n\n const entries = readdirSync(src);\n for (const entry of entries) {\n const srcPath = join(src, entry);\n const destPath = join(dest, entry);\n const stat = statSync(srcPath);\n\n if (stat.isDirectory()) {\n copyDirectory(srcPath, destPath, projectName);\n } else if (isTextExtension(entry)) {\n let content = readFileSync(srcPath, 'utf-8');\n content = content.replace(/\\{\\{projectName\\}\\}/g, projectName);\n writeFileSync(destPath, content);\n } else {\n // Binary asset — copy bytes verbatim. Reading as UTF-8 would corrupt\n // non-ASCII bytes (e.g. PNG magic 0x89 → U+FFFD).\n writeFileSync(destPath, readFileSync(srcPath));\n }\n }\n}\n\n/**\n * Detect if the target directory is inside a pnpm workspace that includes @sigx packages.\n * If so, rewrite @sigx/* dependency versions to workspace:* in package.json.\n */\nfunction patchWorkspaceDeps(targetDir: string) {\n const pkgPath = join(targetDir, 'package.json');\n if (!existsSync(pkgPath)) return;\n\n // Walk up to find pnpm-workspace.yaml\n let dir = dirname(targetDir);\n let isWorkspace = false;\n for (let i = 0; i < 10; i++) {\n if (existsSync(join(dir, 'pnpm-workspace.yaml'))) {\n isWorkspace = true;\n break;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n if (!isWorkspace) return;\n\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n for (const section of ['dependencies', 'devDependencies'] as const) {\n if (!pkg[section]) continue;\n for (const dep of Object.keys(pkg[section])) {\n if (dep.startsWith('@sigx/')) {\n pkg[section][dep] = 'workspace:*';\n }\n }\n }\n writeFileSync(pkgPath, JSON.stringify(pkg, null, 4) + '\\n');\n}\n\nfunction scaffoldProject(opts: {\n projectName: string;\n projectType: ProjectType;\n styling: Styling;\n}): { ok: true } | { ok: false; error: string } {\n const targetDir = resolve(process.cwd(), opts.projectName);\n let templateName: string;\n if (opts.projectType === 'lynx') {\n templateName = opts.styling !== 'none' ? `lynx-${opts.styling}` : 'lynx';\n } else {\n templateName = opts.styling !== 'none' ? `${opts.projectType}-${opts.styling}` : opts.projectType;\n }\n const templateDir = resolve(__dirname, '..', 'templates', templateName);\n if (existsSync(targetDir)) return { ok: false, error: `Directory \"${opts.projectName}\" already exists!` };\n if (!existsSync(templateDir)) return { ok: false, error: `Template \"${templateName}\" not found at ${templateDir}` };\n copyDirectory(templateDir, targetDir, opts.projectName);\n patchWorkspaceDeps(targetDir);\n return { ok: true };\n}\n\nconst CreateSigx = component(() => {\n const state = signal({\n step: 'name' as Step,\n projectName: argProjectName || 'my-sigx-app',\n projectType: 'basic' as ProjectType,\n styling: 'none' as Styling,\n progress: 0,\n error: '',\n });\n\n const createProject = () => {\n state.step = 'creating';\n state.progress = 30;\n const result = scaffoldProject({\n projectName: state.projectName,\n projectType: state.projectType,\n styling: state.styling,\n });\n if (!result.ok) {\n state.error = result.error;\n return;\n }\n state.progress = 100;\n state.step = 'done';\n };\n\n const handleNameSubmit = () => {\n if (state.projectName.trim()) {\n state.step = 'type';\n }\n };\n\n const handleTypeSubmit = () => {\n state.step = 'styling';\n };\n\n const handleStylingSubmit = () => {\n createProject();\n };\n\n const handleExit = () => {\n process.exit(0);\n };\n\n return () => {\n if (state.error) {\n return (\n <box border=\"double\" borderColor=\"red\" label=\" Error \">\n <text color=\"red\"> {state.error}</text>\n <br />\n <br />\n <Button label=\"Exit\" onClick={handleExit} />\n </box>\n );\n }\n\n const projectTypeLabel = (t: ProjectType) => {\n switch (t) {\n case 'basic': return 'Basic SPA';\n case 'ssr': return 'SSR';\n case 'ssg': return 'SSG';\n case 'lynx': return 'Lynx (Native)';\n }\n };\n\n const stylingLabel = (s: Styling) => {\n switch (s) {\n case 'none': return 'None';\n case 'tailwind': return 'Tailwind CSS';\n case 'daisyui': return 'Tailwind + Daisy UI';\n }\n };\n\n // Render step-specific content as a single element to avoid\n // multiple conditional children causing duplicate nodes\n const stepContent = (() => {\n switch (state.step) {\n case 'name':\n return (\n <box>\n <text color=\"gray\"> Step 1 of 3</text>\n <br />\n <br />\n <text color=\"white\"> What is your project called?</text>\n <br />\n <br />\n <Input\n model={() => state.projectName}\n label=\" Project Name \"\n placeholder=\"my-sigx-app\"\n autofocus\n onSubmit={handleNameSubmit}\n />\n <br />\n <text color=\"gray\"> Press Enter to continue</text>\n </box>\n );\n case 'type':\n return (\n <box>\n <text color=\"gray\"> Step 2 of 3</text>\n <br />\n <br />\n <text color=\"white\"> What type of project?</text>\n <br />\n <br />\n <Select\n model={() => state.projectType}\n label=\" Project Type \"\n options={projectTypeOptions}\n showDescription\n autofocus\n onSubmit={handleTypeSubmit}\n />\n <br />\n <text color=\"gray\"> ↑/↓ navigate · Enter select</text>\n </box>\n );\n case 'styling':\n return (\n <box>\n <text color=\"gray\"> Step 3 of 3</text>\n <br />\n <br />\n <text color=\"white\"> Choose a styling approach:</text>\n <br />\n <br />\n <Select\n model={() => state.styling}\n label=\" Styling \"\n options={state.projectType === 'lynx' ? lynxStylingOptions : webStylingOptions}\n showDescription\n autofocus\n onSubmit={handleStylingSubmit}\n />\n <br />\n <text color=\"gray\"> ↑/↓ navigate · Enter select</text>\n </box>\n );\n case 'creating':\n return (\n <box>\n <br />\n <text color=\"yellow\"> Creating project...</text>\n <br />\n <ProgressBar value={state.progress} max={100} width={40} color=\"green\" />\n </box>\n );\n case 'done':\n return (\n <box>\n <br />\n <text color=\"green\"> ✓ Project \"{state.projectName}\" created!</text>\n <br />\n <br />\n <text color=\"gray\"> Type: {projectTypeLabel(state.projectType)}</text>\n <br />\n <text color=\"gray\"> Styling: {stylingLabel(state.styling)}</text>\n <br />\n <br />\n <text color=\"white\"> Next steps:</text>\n <br />\n <br />\n <text color=\"cyan\"> cd {state.projectName}</text>\n <br />\n <text color=\"cyan\"> pnpm install</text>\n <br />\n <text color=\"cyan\"> {state.projectType === 'lynx' ? 'sigx dev' : 'pnpm dev'}</text>\n <br />\n <br />\n <Button label=\"Exit\" onClick={handleExit} />\n </box>\n );\n }\n })();\n\n return (\n <box>\n <text color=\"cyan\"> ⚡ Create SignalX App</text>\n <br />\n {stepContent}\n </box>\n );\n };\n});\n\nfunction runHeadless(): number {\n const validTypes: ProjectType[] = ['basic', 'ssr', 'ssg', 'lynx'];\n const validStyling: Styling[] = ['none', 'tailwind', 'daisyui'];\n\n const projectName = argProjectName || 'my-sigx-app';\n const projectType: ProjectType = argType ?? 'basic';\n const styling: Styling = argStyling ?? 'none';\n\n if (!validTypes.includes(projectType)) {\n console.error(`Error: --type must be one of ${validTypes.join(', ')}`);\n return 2;\n }\n if (!validStyling.includes(styling)) {\n console.error(`Error: --styling must be one of ${validStyling.join(', ')}`);\n return 2;\n }\n\n console.log(`\\n ⚡ Creating SignalX app \"${projectName}\"`);\n console.log(` type: ${projectType}`);\n console.log(` styling: ${styling}\\n`);\n\n const result = scaffoldProject({ projectName, projectType, styling });\n if (!result.ok) {\n console.error(`Error: ${result.error}`);\n return 1;\n }\n\n console.log(` ✓ Project created\\n`);\n console.log(` Next steps:`);\n console.log(` cd ${projectName}`);\n console.log(` pnpm install`);\n console.log(` ${projectType === 'lynx' ? 'sigx dev' : 'pnpm dev'}\\n`);\n return 0;\n}\n\nexport function runCreate() {\n if (isNonInteractive) {\n process.exit(runHeadless());\n }\n defineApp(<CreateSigx />).mount({ clearConsole: true });\n // Keep process alive for TUI\n setInterval(() => { }, 10000);\n}\n"],"mappings":"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"}
@@ -20,7 +20,8 @@
20
20
  "@sigx/lynx-clipboard": "^0.1.0",
21
21
  "@sigx/lynx-haptics": "^0.1.0",
22
22
  "@sigx/lynx-device-info": "^0.1.0",
23
- "@sigx/lynx-network": "^0.1.0"
23
+ "@sigx/lynx-network": "^0.1.0",
24
+ "@sigx/lynx-websocket": "^0.1.0"
24
25
  },
25
26
  "devDependencies": {
26
27
  "@sigx/cli": "^0.1.0",
@@ -28,6 +28,7 @@ export default defineLynxConfig({
28
28
  '@sigx/lynx-haptics',
29
29
  '@sigx/lynx-device-info',
30
30
  '@sigx/lynx-network',
31
+ '@sigx/lynx-websocket',
31
32
  ],
32
33
  android: {
33
34
  applicationId: 'com.example.{{projectName}}',
@@ -3,6 +3,7 @@
3
3
  "target": "ES2020",
4
4
  "module": "ESNext",
5
5
  "moduleResolution": "bundler",
6
+ "lib": ["ES2020", "DOM"],
6
7
  "strict": true,
7
8
  "esModuleInterop": true,
8
9
  "skipLibCheck": true,
@@ -0,0 +1,61 @@
1
+ # {{projectName}}
2
+
3
+ A native mobile app built with [sigx-lynx](https://github.com/signalxjs/core) and Tailwind CSS.
4
+
5
+ ## Getting Started
6
+
7
+ ### Prerequisites
8
+
9
+ - Node.js 18+
10
+ - pnpm (recommended) or npm
11
+ - [sigx-lynx-go](https://github.com/signalxjs/core/tree/main/go) app on your device/emulator
12
+
13
+ ### Development
14
+
15
+ ```bash
16
+ # Install dependencies
17
+ pnpm install
18
+
19
+ # Start the dev server
20
+ sigx dev
21
+
22
+ # Or use npx
23
+ npx sigx dev
24
+ ```
25
+
26
+ Scan the QR code shown in the terminal with sigx-lynx-go, or enter the URL manually.
27
+
28
+ ### Building
29
+
30
+ ```bash
31
+ sigx build
32
+ ```
33
+
34
+ ### Environment Check
35
+
36
+ ```bash
37
+ sigx doctor
38
+ ```
39
+
40
+ ## Project Structure
41
+
42
+ ```
43
+ {{projectName}}/
44
+ ├── src/
45
+ │ ├── App.tsx # Root component
46
+ │ ├── styles.css # Tailwind entry point
47
+ │ ├── main.tsx # BG-thread entry point
48
+ │ └── main.thread.tsx # Main-thread entry point
49
+ ├── lynx.config.ts # rspeedy build config
50
+ ├── sigx.lynx.config.ts # sigx-lynx native config
51
+ ├── tailwind.config.ts # Tailwind CSS config
52
+ ├── postcss.config.js # PostCSS config
53
+ ├── tsconfig.json
54
+ └── package.json
55
+ ```
56
+
57
+ ## Learn More
58
+
59
+ - [sigx-lynx Documentation](https://github.com/signalxjs/core)
60
+ - [Lynx Runtime](https://lynxjs.org)
61
+ - [Tailwind CSS](https://tailwindcss.com)
@@ -0,0 +1,20 @@
1
+ import { defineConfig } from '@lynx-js/rspeedy';
2
+ import { pluginSigxLynx } from '@sigx/lynx-plugin';
3
+
4
+ export default defineConfig({
5
+ source: {
6
+ entry: {
7
+ main: './src/main.tsx',
8
+ },
9
+ },
10
+ server: {
11
+ host: '0.0.0.0',
12
+ port: 3000,
13
+ },
14
+ plugins: [
15
+ pluginSigxLynx({
16
+ enableCSSInheritance: true,
17
+ enableCSSInlineVariables: true,
18
+ }),
19
+ ],
20
+ });
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "{{projectName}}",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "sigx dev",
8
+ "build": "sigx build",
9
+ "doctor": "sigx doctor",
10
+ "prebuild": "sigx prebuild"
11
+ },
12
+ "dependencies": {
13
+ "@sigx/lynx": "^0.1.2",
14
+ "@sigx/lynx-runtime": "^0.2.4",
15
+ "@sigx/lynx-runtime-main": "^0.2.4",
16
+ "@sigx/lynx-core": "^0.1.0",
17
+ "@sigx/reactivity": "^0.4.1",
18
+ "@sigx/runtime-core": "^0.4.1",
19
+ "@sigx/lynx-storage": "^0.1.0",
20
+ "@sigx/lynx-clipboard": "^0.1.0",
21
+ "@sigx/lynx-haptics": "^0.1.0",
22
+ "@sigx/lynx-device-info": "^0.1.0",
23
+ "@sigx/lynx-network": "^0.1.0",
24
+ "@sigx/lynx-websocket": "^0.1.0",
25
+ "@sigx/lynx-daisyui": "^0.1.0"
26
+ },
27
+ "devDependencies": {
28
+ "@sigx/cli": "^0.1.0",
29
+ "@sigx/lynx-cli": "^0.1.0",
30
+ "@sigx/lynx-plugin": "^0.2.4",
31
+ "@sigx/lynx-dev-client": "^0.1.0",
32
+ "@lynx-js/rspeedy": ">=0.1.0",
33
+ "@lynx-js/css-extract-webpack-plugin": ">=0.1.0",
34
+ "@lynx-js/template-webpack-plugin": ">=0.1.0",
35
+ "@lynx-js/runtime-wrapper-webpack-plugin": ">=0.1.0",
36
+ "@lynx-js/webpack-dev-transport": ">=0.1.0",
37
+ "@lynx-js/tailwind-preset": "^0.4.0",
38
+ "tailwindcss": "^3.4.0",
39
+ "postcss": "^8.4.0",
40
+ "autoprefixer": "^10.4.0",
41
+ "typescript": "^5.9.3"
42
+ }
43
+ }
@@ -0,0 +1,5 @@
1
+ export default {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ },
5
+ };
@@ -0,0 +1,45 @@
1
+ import { defineLynxConfig } from '@sigx/lynx-cli/config';
2
+
3
+ export default defineLynxConfig({
4
+ name: '{{projectName}}',
5
+ version: '0.1.0',
6
+ buildNumber: '1',
7
+
8
+ // App-shell assets — sigx ships sensible defaults in ./assets/.
9
+ // Swap these PNGs to rebrand without touching native code.
10
+ icon: 'assets/icon.png',
11
+ splash: {
12
+ image: 'assets/splash.png',
13
+ backgroundColor: '#FFFFFF',
14
+ },
15
+
16
+ // Custom URL scheme for deep linking ({{projectName}}://...).
17
+ // Comment out if you don't need deep links.
18
+ scheme: '{{projectName}}',
19
+
20
+ // 'portrait' | 'landscape' | 'default'
21
+ orientation: 'portrait',
22
+
23
+ modules: [
24
+ '@sigx/lynx-storage',
25
+ '@sigx/lynx-clipboard',
26
+ '@sigx/lynx-haptics',
27
+ '@sigx/lynx-device-info',
28
+ '@sigx/lynx-network',
29
+ '@sigx/lynx-websocket',
30
+ ],
31
+ android: {
32
+ applicationId: 'com.example.{{projectName}}',
33
+ versionCode: 1,
34
+ minSdk: 24,
35
+ targetSdk: 35,
36
+ adaptiveIcon: {
37
+ foreground: 'assets/adaptive-foreground.png',
38
+ backgroundColor: '#0D9488',
39
+ },
40
+ },
41
+ ios: {
42
+ bundleIdentifier: 'com.example.{{projectName}}',
43
+ deploymentTarget: '15.0',
44
+ },
45
+ });
@@ -0,0 +1,93 @@
1
+ import { signal, component } from '@sigx/lynx';
2
+ import { Badge, Button, Card, Toggle } from '@sigx/lynx-daisyui';
3
+
4
+ const App = component(() => {
5
+ const count = signal(0);
6
+ const autoIncrement = signal(false);
7
+
8
+ let timer: ReturnType<typeof setInterval> | null = null;
9
+ const syncTimer = () => {
10
+ if (autoIncrement.value && !timer) {
11
+ timer = setInterval(() => count.value++, 800);
12
+ } else if (!autoIncrement.value && timer) {
13
+ clearInterval(timer);
14
+ timer = null;
15
+ }
16
+ };
17
+
18
+ return () => (
19
+ <scroll-view scroll-orientation="vertical" class="h-screen bg-base-200">
20
+ <view class="flex flex-col items-center justify-center min-h-screen px-6 py-12 bg-base-200">
21
+ {/* Header group */}
22
+ <view class="flex flex-col items-center gap-4">
23
+ {/* Logo */}
24
+ <view class="w-20 h-20 rounded-2xl bg-primary flex items-center justify-center">
25
+ <text class="text-4xl text-primary-content">⚡</text>
26
+ </view>
27
+
28
+ <text class="text-3xl font-bold text-base-content text-center">
29
+ {{projectName}}
30
+ </text>
31
+
32
+ <text class="text-sm text-base-content/60 text-center max-w-[280px]">
33
+ Built with sigx-lynx + DaisyUI
34
+ </text>
35
+ </view>
36
+
37
+ {/* Counter card */}
38
+ <Card bordered shadow="lg" class="mt-10 w-[300px] bg-base-100">
39
+ <Card.Body>
40
+ <view class="flex flex-row items-center justify-center gap-3">
41
+ <Badge variant="primary" size="lg">{count.value}</Badge>
42
+ <text class="text-base-content/60">×2 =</text>
43
+ <Badge variant="secondary" size="lg">{count.value * 2}</Badge>
44
+ </view>
45
+
46
+ <Card.Actions class="justify-center mt-4 gap-2">
47
+ <Button
48
+ variant="error"
49
+ outline
50
+ size="sm"
51
+ bindpress={() => count.value > 0 && count.value--}
52
+ >
53
+
54
+ </Button>
55
+ <Button
56
+ variant="ghost"
57
+ size="sm"
58
+ bindpress={() => (count.value = 0)}
59
+ >
60
+ Reset
61
+ </Button>
62
+ <Button
63
+ variant="primary"
64
+ size="sm"
65
+ bindpress={() => count.value++}
66
+ >
67
+ +
68
+ </Button>
69
+ </Card.Actions>
70
+
71
+ <view class="flex flex-row items-center justify-between mt-4 pt-4 border-t border-base-300">
72
+ <text class="text-sm text-base-content/70">Auto-increment</text>
73
+ <Toggle
74
+ checked={autoIncrement.value}
75
+ color="success"
76
+ bindchange={(next: boolean) => {
77
+ autoIncrement.value = next;
78
+ syncTimer();
79
+ }}
80
+ />
81
+ </view>
82
+ </Card.Body>
83
+ </Card>
84
+
85
+ <text class="text-xs text-base-content/50 mt-10 text-center">
86
+ Edit src/App.tsx to get started
87
+ </text>
88
+ </view>
89
+ </scroll-view>
90
+ );
91
+ });
92
+
93
+ export default App;
@@ -0,0 +1,2 @@
1
+ // Main-thread entry — bootstraps the Lepus-side globals
2
+ import '@sigx/runtime-lynx-main';
@@ -0,0 +1,10 @@
1
+ import './styles.css';
2
+ import '@sigx/lynx-daisyui/styles';
3
+ import { defineApp } from '@sigx/lynx';
4
+ import App from './App';
5
+
6
+ defineApp(<App />).mount(null);
7
+
8
+ if ((module as any).hot) {
9
+ (module as any).hot.accept();
10
+ }
@@ -0,0 +1,3 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
@@ -0,0 +1,10 @@
1
+ import type { Config } from 'tailwindcss';
2
+ import LynxPreset from '@lynx-js/tailwind-preset';
3
+ import { daisyuiPreset } from '@sigx/lynx-daisyui/preset';
4
+
5
+ export default {
6
+ content: [
7
+ './src/**/*.{tsx,ts,jsx,js}',
8
+ ],
9
+ presets: [LynxPreset, daisyuiPreset],
10
+ } satisfies Config;
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "lib": ["ES2020", "DOM"],
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "resolveJsonModule": true,
12
+ "isolatedModules": true,
13
+ "noEmit": true,
14
+ "jsx": "react-jsx",
15
+ "jsxImportSource": "@sigx/lynx",
16
+ "types": []
17
+ },
18
+ "include": ["src/**/*.ts", "src/**/*.tsx"],
19
+ "exclude": ["node_modules", "dist"]
20
+ }
@@ -20,7 +20,8 @@
20
20
  "@sigx/lynx-clipboard": "^0.1.0",
21
21
  "@sigx/lynx-haptics": "^0.1.0",
22
22
  "@sigx/lynx-device-info": "^0.1.0",
23
- "@sigx/lynx-network": "^0.1.0"
23
+ "@sigx/lynx-network": "^0.1.0",
24
+ "@sigx/lynx-websocket": "^0.1.0"
24
25
  },
25
26
  "devDependencies": {
26
27
  "@sigx/cli": "^0.1.0",
@@ -26,6 +26,7 @@ export default defineLynxConfig({
26
26
  '@sigx/lynx-haptics',
27
27
  '@sigx/lynx-device-info',
28
28
  '@sigx/lynx-network',
29
+ '@sigx/lynx-websocket',
29
30
  ],
30
31
  android: {
31
32
  applicationId: 'com.example.{{projectName}}',
@@ -3,6 +3,7 @@
3
3
  "target": "ES2020",
4
4
  "module": "ESNext",
5
5
  "moduleResolution": "bundler",
6
+ "lib": ["ES2020", "DOM"],
6
7
  "strict": true,
7
8
  "esModuleInterop": true,
8
9
  "skipLibCheck": true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sigx/cli",
3
- "version": "0.1.3",
3
+ "version": "0.2.1",
4
4
  "description": "Unified CLI for SignalX — create, dev, build, and run projects",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -20,7 +20,8 @@
20
20
  "@sigx/lynx-clipboard": "^0.1.0",
21
21
  "@sigx/lynx-haptics": "^0.1.0",
22
22
  "@sigx/lynx-device-info": "^0.1.0",
23
- "@sigx/lynx-network": "^0.1.0"
23
+ "@sigx/lynx-network": "^0.1.0",
24
+ "@sigx/lynx-websocket": "^0.1.0"
24
25
  },
25
26
  "devDependencies": {
26
27
  "@sigx/cli": "^0.1.0",
@@ -28,6 +28,7 @@ export default defineLynxConfig({
28
28
  '@sigx/lynx-haptics',
29
29
  '@sigx/lynx-device-info',
30
30
  '@sigx/lynx-network',
31
+ '@sigx/lynx-websocket',
31
32
  ],
32
33
  android: {
33
34
  applicationId: 'com.example.{{projectName}}',
@@ -3,6 +3,7 @@
3
3
  "target": "ES2020",
4
4
  "module": "ESNext",
5
5
  "moduleResolution": "bundler",
6
+ "lib": ["ES2020", "DOM"],
6
7
  "strict": true,
7
8
  "esModuleInterop": true,
8
9
  "skipLibCheck": true,
@@ -0,0 +1,61 @@
1
+ # {{projectName}}
2
+
3
+ A native mobile app built with [sigx-lynx](https://github.com/signalxjs/core) and Tailwind CSS.
4
+
5
+ ## Getting Started
6
+
7
+ ### Prerequisites
8
+
9
+ - Node.js 18+
10
+ - pnpm (recommended) or npm
11
+ - [sigx-lynx-go](https://github.com/signalxjs/core/tree/main/go) app on your device/emulator
12
+
13
+ ### Development
14
+
15
+ ```bash
16
+ # Install dependencies
17
+ pnpm install
18
+
19
+ # Start the dev server
20
+ sigx dev
21
+
22
+ # Or use npx
23
+ npx sigx dev
24
+ ```
25
+
26
+ Scan the QR code shown in the terminal with sigx-lynx-go, or enter the URL manually.
27
+
28
+ ### Building
29
+
30
+ ```bash
31
+ sigx build
32
+ ```
33
+
34
+ ### Environment Check
35
+
36
+ ```bash
37
+ sigx doctor
38
+ ```
39
+
40
+ ## Project Structure
41
+
42
+ ```
43
+ {{projectName}}/
44
+ ├── src/
45
+ │ ├── App.tsx # Root component
46
+ │ ├── styles.css # Tailwind entry point
47
+ │ ├── main.tsx # BG-thread entry point
48
+ │ └── main.thread.tsx # Main-thread entry point
49
+ ├── lynx.config.ts # rspeedy build config
50
+ ├── sigx.lynx.config.ts # sigx-lynx native config
51
+ ├── tailwind.config.ts # Tailwind CSS config
52
+ ├── postcss.config.js # PostCSS config
53
+ ├── tsconfig.json
54
+ └── package.json
55
+ ```
56
+
57
+ ## Learn More
58
+
59
+ - [sigx-lynx Documentation](https://github.com/signalxjs/core)
60
+ - [Lynx Runtime](https://lynxjs.org)
61
+ - [Tailwind CSS](https://tailwindcss.com)
@@ -0,0 +1,20 @@
1
+ import { defineConfig } from '@lynx-js/rspeedy';
2
+ import { pluginSigxLynx } from '@sigx/lynx-plugin';
3
+
4
+ export default defineConfig({
5
+ source: {
6
+ entry: {
7
+ main: './src/main.tsx',
8
+ },
9
+ },
10
+ server: {
11
+ host: '0.0.0.0',
12
+ port: 3000,
13
+ },
14
+ plugins: [
15
+ pluginSigxLynx({
16
+ enableCSSInheritance: true,
17
+ enableCSSInlineVariables: true,
18
+ }),
19
+ ],
20
+ });
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "{{projectName}}",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "sigx dev",
8
+ "build": "sigx build",
9
+ "doctor": "sigx doctor",
10
+ "prebuild": "sigx prebuild"
11
+ },
12
+ "dependencies": {
13
+ "@sigx/lynx": "^0.1.2",
14
+ "@sigx/lynx-runtime": "^0.2.4",
15
+ "@sigx/lynx-runtime-main": "^0.2.4",
16
+ "@sigx/lynx-core": "^0.1.0",
17
+ "@sigx/reactivity": "^0.4.1",
18
+ "@sigx/runtime-core": "^0.4.1",
19
+ "@sigx/lynx-storage": "^0.1.0",
20
+ "@sigx/lynx-clipboard": "^0.1.0",
21
+ "@sigx/lynx-haptics": "^0.1.0",
22
+ "@sigx/lynx-device-info": "^0.1.0",
23
+ "@sigx/lynx-network": "^0.1.0",
24
+ "@sigx/lynx-websocket": "^0.1.0",
25
+ "@sigx/lynx-daisyui": "^0.1.0"
26
+ },
27
+ "devDependencies": {
28
+ "@sigx/cli": "^0.1.0",
29
+ "@sigx/lynx-cli": "^0.1.0",
30
+ "@sigx/lynx-plugin": "^0.2.4",
31
+ "@sigx/lynx-dev-client": "^0.1.0",
32
+ "@lynx-js/rspeedy": ">=0.1.0",
33
+ "@lynx-js/css-extract-webpack-plugin": ">=0.1.0",
34
+ "@lynx-js/template-webpack-plugin": ">=0.1.0",
35
+ "@lynx-js/runtime-wrapper-webpack-plugin": ">=0.1.0",
36
+ "@lynx-js/webpack-dev-transport": ">=0.1.0",
37
+ "@lynx-js/tailwind-preset": "^0.4.0",
38
+ "tailwindcss": "^3.4.0",
39
+ "postcss": "^8.4.0",
40
+ "autoprefixer": "^10.4.0",
41
+ "typescript": "^5.9.3"
42
+ }
43
+ }
@@ -0,0 +1,5 @@
1
+ export default {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ },
5
+ };
@@ -0,0 +1,45 @@
1
+ import { defineLynxConfig } from '@sigx/lynx-cli/config';
2
+
3
+ export default defineLynxConfig({
4
+ name: '{{projectName}}',
5
+ version: '0.1.0',
6
+ buildNumber: '1',
7
+
8
+ // App-shell assets — sigx ships sensible defaults in ./assets/.
9
+ // Swap these PNGs to rebrand without touching native code.
10
+ icon: 'assets/icon.png',
11
+ splash: {
12
+ image: 'assets/splash.png',
13
+ backgroundColor: '#FFFFFF',
14
+ },
15
+
16
+ // Custom URL scheme for deep linking ({{projectName}}://...).
17
+ // Comment out if you don't need deep links.
18
+ scheme: '{{projectName}}',
19
+
20
+ // 'portrait' | 'landscape' | 'default'
21
+ orientation: 'portrait',
22
+
23
+ modules: [
24
+ '@sigx/lynx-storage',
25
+ '@sigx/lynx-clipboard',
26
+ '@sigx/lynx-haptics',
27
+ '@sigx/lynx-device-info',
28
+ '@sigx/lynx-network',
29
+ '@sigx/lynx-websocket',
30
+ ],
31
+ android: {
32
+ applicationId: 'com.example.{{projectName}}',
33
+ versionCode: 1,
34
+ minSdk: 24,
35
+ targetSdk: 35,
36
+ adaptiveIcon: {
37
+ foreground: 'assets/adaptive-foreground.png',
38
+ backgroundColor: '#0D9488',
39
+ },
40
+ },
41
+ ios: {
42
+ bundleIdentifier: 'com.example.{{projectName}}',
43
+ deploymentTarget: '15.0',
44
+ },
45
+ });
@@ -0,0 +1,93 @@
1
+ import { signal, component } from '@sigx/lynx';
2
+ import { Badge, Button, Card, Toggle } from '@sigx/lynx-daisyui';
3
+
4
+ const App = component(() => {
5
+ const count = signal(0);
6
+ const autoIncrement = signal(false);
7
+
8
+ let timer: ReturnType<typeof setInterval> | null = null;
9
+ const syncTimer = () => {
10
+ if (autoIncrement.value && !timer) {
11
+ timer = setInterval(() => count.value++, 800);
12
+ } else if (!autoIncrement.value && timer) {
13
+ clearInterval(timer);
14
+ timer = null;
15
+ }
16
+ };
17
+
18
+ return () => (
19
+ <scroll-view scroll-orientation="vertical" class="h-screen bg-base-200">
20
+ <view class="flex flex-col items-center justify-center min-h-screen px-6 py-12 bg-base-200">
21
+ {/* Header group */}
22
+ <view class="flex flex-col items-center gap-4">
23
+ {/* Logo */}
24
+ <view class="w-20 h-20 rounded-2xl bg-primary flex items-center justify-center">
25
+ <text class="text-4xl text-primary-content">⚡</text>
26
+ </view>
27
+
28
+ <text class="text-3xl font-bold text-base-content text-center">
29
+ {{projectName}}
30
+ </text>
31
+
32
+ <text class="text-sm text-base-content/60 text-center max-w-[280px]">
33
+ Built with sigx-lynx + DaisyUI
34
+ </text>
35
+ </view>
36
+
37
+ {/* Counter card */}
38
+ <Card bordered shadow="lg" class="mt-10 w-[300px] bg-base-100">
39
+ <Card.Body>
40
+ <view class="flex flex-row items-center justify-center gap-3">
41
+ <Badge variant="primary" size="lg">{count.value}</Badge>
42
+ <text class="text-base-content/60">×2 =</text>
43
+ <Badge variant="secondary" size="lg">{count.value * 2}</Badge>
44
+ </view>
45
+
46
+ <Card.Actions class="justify-center mt-4 gap-2">
47
+ <Button
48
+ variant="error"
49
+ outline
50
+ size="sm"
51
+ bindpress={() => count.value > 0 && count.value--}
52
+ >
53
+
54
+ </Button>
55
+ <Button
56
+ variant="ghost"
57
+ size="sm"
58
+ bindpress={() => (count.value = 0)}
59
+ >
60
+ Reset
61
+ </Button>
62
+ <Button
63
+ variant="primary"
64
+ size="sm"
65
+ bindpress={() => count.value++}
66
+ >
67
+ +
68
+ </Button>
69
+ </Card.Actions>
70
+
71
+ <view class="flex flex-row items-center justify-between mt-4 pt-4 border-t border-base-300">
72
+ <text class="text-sm text-base-content/70">Auto-increment</text>
73
+ <Toggle
74
+ checked={autoIncrement.value}
75
+ color="success"
76
+ bindchange={(next: boolean) => {
77
+ autoIncrement.value = next;
78
+ syncTimer();
79
+ }}
80
+ />
81
+ </view>
82
+ </Card.Body>
83
+ </Card>
84
+
85
+ <text class="text-xs text-base-content/50 mt-10 text-center">
86
+ Edit src/App.tsx to get started
87
+ </text>
88
+ </view>
89
+ </scroll-view>
90
+ );
91
+ });
92
+
93
+ export default App;
@@ -0,0 +1,2 @@
1
+ // Main-thread entry — bootstraps the Lepus-side globals
2
+ import '@sigx/runtime-lynx-main';
@@ -0,0 +1,10 @@
1
+ import './styles.css';
2
+ import '@sigx/lynx-daisyui/styles';
3
+ import { defineApp } from '@sigx/lynx';
4
+ import App from './App';
5
+
6
+ defineApp(<App />).mount(null);
7
+
8
+ if ((module as any).hot) {
9
+ (module as any).hot.accept();
10
+ }
@@ -0,0 +1,3 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
@@ -0,0 +1,10 @@
1
+ import type { Config } from 'tailwindcss';
2
+ import LynxPreset from '@lynx-js/tailwind-preset';
3
+ import { daisyuiPreset } from '@sigx/lynx-daisyui/preset';
4
+
5
+ export default {
6
+ content: [
7
+ './src/**/*.{tsx,ts,jsx,js}',
8
+ ],
9
+ presets: [LynxPreset, daisyuiPreset],
10
+ } satisfies Config;
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "lib": ["ES2020", "DOM"],
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "resolveJsonModule": true,
12
+ "isolatedModules": true,
13
+ "noEmit": true,
14
+ "jsx": "react-jsx",
15
+ "jsxImportSource": "@sigx/lynx",
16
+ "types": []
17
+ },
18
+ "include": ["src/**/*.ts", "src/**/*.tsx"],
19
+ "exclude": ["node_modules", "dist"]
20
+ }
@@ -20,7 +20,8 @@
20
20
  "@sigx/lynx-clipboard": "^0.1.0",
21
21
  "@sigx/lynx-haptics": "^0.1.0",
22
22
  "@sigx/lynx-device-info": "^0.1.0",
23
- "@sigx/lynx-network": "^0.1.0"
23
+ "@sigx/lynx-network": "^0.1.0",
24
+ "@sigx/lynx-websocket": "^0.1.0"
24
25
  },
25
26
  "devDependencies": {
26
27
  "@sigx/cli": "^0.1.0",
@@ -26,6 +26,7 @@ export default defineLynxConfig({
26
26
  '@sigx/lynx-haptics',
27
27
  '@sigx/lynx-device-info',
28
28
  '@sigx/lynx-network',
29
+ '@sigx/lynx-websocket',
29
30
  ],
30
31
  android: {
31
32
  applicationId: 'com.example.{{projectName}}',
@@ -3,6 +3,7 @@
3
3
  "target": "ES2020",
4
4
  "module": "ESNext",
5
5
  "moduleResolution": "bundler",
6
+ "lib": ["ES2020", "DOM"],
6
7
  "strict": true,
7
8
  "esModuleInterop": true,
8
9
  "skipLibCheck": true,