create-mithril-lynx 0.0.1 → 0.0.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 +34 -12
- package/package.json +3 -5
- package/src/index.js +30 -6
- package/templates/basic-activity/common/src/style.css +59 -0
- package/templates/basic-activity/js/src/index.js +43 -0
- package/templates/basic-activity/ts/src/index.ts +48 -0
- package/templates/blank/common/src/style.css +16 -0
- package/templates/blank/js/src/index.js +11 -0
- package/templates/blank/ts/src/index.ts +11 -0
- /package/{template-js → templates/hello-world/js}/src/index.js +0 -0
- /package/{template-common → templates/_shared/common}/README.md +0 -0
- /package/{template-common → templates/_shared/common}/gitignore +0 -0
- /package/{template-js → templates/_shared/js}/lynx.config.js +0 -0
- /package/{template-js → templates/_shared/js}/package.json +0 -0
- /package/{template-js → templates/_shared/js}/src/main-thread.js +0 -0
- /package/{template-ts → templates/_shared/ts}/lynx.config.ts +0 -0
- /package/{template-ts → templates/_shared/ts}/package.json +0 -0
- /package/{template-ts → templates/_shared/ts}/src/main-thread.ts +0 -0
- /package/{template-ts → templates/_shared/ts}/src/rspeedy-env.d.ts +0 -0
- /package/{template-ts → templates/_shared/ts}/src/tsconfig.json +0 -0
- /package/{template-ts → templates/_shared/ts}/tsconfig.json +0 -0
- /package/{template-ts → templates/_shared/ts}/tsconfig.node.json +0 -0
- /package/{template-common → templates/hello-world/common}/src/assets/arrow.png +0 -0
- /package/{template-common → templates/hello-world/common}/src/assets/lynx-logo.png +0 -0
- /package/{template-common → templates/hello-world/common}/src/assets/mithril-logo.png +0 -0
- /package/{template-common → templates/hello-world/common}/src/style.css +0 -0
- /package/{template-ts → templates/hello-world/ts}/src/index.ts +0 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# create-mithril-lynx
|
|
2
2
|
|
|
3
|
-
Scaffolds a new [`mithril-lynx`](https://github.com/carlos-sweb/mithril-lynx) app
|
|
3
|
+
Scaffolds a new [`mithril-lynx`](https://github.com/carlos-sweb/mithril-lynx) app. Three templates, matching the "Hello World" / "Blank" / "Basic Activity" naming most native app scaffolds already use, each available in TypeScript or JavaScript.
|
|
4
4
|
|
|
5
5
|
## Usage
|
|
6
6
|
|
|
@@ -8,35 +8,57 @@ Scaffolds a new [`mithril-lynx`](https://github.com/carlos-sweb/mithril-lynx) ap
|
|
|
8
8
|
npm create mithril-lynx@latest
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
Prompts for a project name and a variant (TypeScript or JavaScript), scaffolds it, and offers to install dependencies for you.
|
|
11
|
+
Prompts for a project name, a template, and a variant (TypeScript or JavaScript), scaffolds it, and offers to install dependencies for you.
|
|
12
12
|
|
|
13
13
|
### Non-interactive
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
npx create-mithril-lynx my-app --ts
|
|
17
|
-
npx create-mithril-lynx my-app --js --no-install
|
|
16
|
+
npx create-mithril-lynx my-app --hello-world --ts
|
|
17
|
+
npx create-mithril-lynx my-app --basic-activity --js --no-install
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
##
|
|
20
|
+
## Templates
|
|
21
|
+
|
|
22
|
+
| Template | What it is |
|
|
23
|
+
|---|---|
|
|
24
|
+
| **Hello World** (recommended) | The Mithril.js analog of Lynx's official React hello-world ([`lynx-examples/examples/hello-world`](https://github.com/lynx-family/lynx-examples/tree/main/examples/hello-world)) — same layout, same "tap the logo" interaction, running through Mithril hyperscript instead of JSX. |
|
|
25
|
+
| **Blank** | A single centered line of text. Nothing else — the starting point when you don't want any of Hello World's styling/assets in your way. |
|
|
26
|
+
| **Basic Activity** | Two screens (Main → Details) wired with [`mithril-lynx/navigation`](https://github.com/carlos-sweb/mithril-lynx#navigation) — a stack-based, in-memory navigator (deliberately not `m.route`; see that package's README for why Lynx pages can't use URL-based routing). Includes a reusable app-bar-with-back-button pattern. Confirmed working end to end on a real device: `push()` with data, the back button, and `pop()` all round-trip correctly. |
|
|
27
|
+
|
|
28
|
+
## Variants
|
|
21
29
|
|
|
22
30
|
| Variant | Adds over the base template |
|
|
23
31
|
|---|---|
|
|
24
32
|
| **TypeScript** (recommended) | `.ts` source files, `tsconfig.json` (project references, matching `@lynx-js/rspeedy`'s own generated config), `@rsbuild/plugin-type-check`, `@types/mithril` for real editor autocomplete on `m()` calls. |
|
|
25
33
|
| **JavaScript** | Same app, plain `.js` with ES module `import`/`export` — no type-checking, no `tsconfig.json`. |
|
|
26
34
|
|
|
27
|
-
Both variants share `template-common/`: the logo/arrow image assets, `style.css`, `.gitignore`, and the project's own `README.md`.
|
|
28
|
-
|
|
29
35
|
## Package structure
|
|
30
36
|
|
|
31
37
|
```
|
|
32
38
|
create-mithril-lynx/
|
|
33
|
-
src/index.js
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
39
|
+
src/index.js the CLI itself
|
|
40
|
+
templates/
|
|
41
|
+
_shared/
|
|
42
|
+
common/ gitignore, project README — shared by every template
|
|
43
|
+
js/ lynx.config.js, package.json, main-thread.js — shared by every JS variant
|
|
44
|
+
ts/ lynx.config.ts, tsconfig*, package.json, main-thread.ts — shared by every TS variant
|
|
45
|
+
hello-world/
|
|
46
|
+
common/src/ logo/arrow assets, style.css
|
|
47
|
+
js/src/index.js
|
|
48
|
+
ts/src/index.ts
|
|
49
|
+
blank/
|
|
50
|
+
common/src/style.css
|
|
51
|
+
js/src/index.js
|
|
52
|
+
ts/src/index.ts
|
|
53
|
+
basic-activity/
|
|
54
|
+
common/src/style.css
|
|
55
|
+
js/src/index.js
|
|
56
|
+
ts/src/index.ts
|
|
37
57
|
```
|
|
38
58
|
|
|
39
|
-
`src/index.js` copies `template
|
|
59
|
+
`src/index.js` copies, in order, `templates/_shared/common` → `templates/_shared/<variant>` → `templates/<template>/common` → `templates/<template>/<variant>` into the target directory (later copies never need to overwrite earlier ones — each layer contributes different files), renames `gitignore` to `.gitignore` (npm doesn't publish dotfiles reliably otherwise), and replaces `{{PROJECT_NAME}}`/`{{MITHRIL_LYNX_VERSION}}` placeholders in `package.json` and `README.md`.
|
|
60
|
+
|
|
61
|
+
Every template's `src/index.{js,ts}` exports the same shape (`{ root }`), so `_shared/{js,ts}/src/main-thread.{js,ts}` — the actual `__RenderPage` wiring — is 100% shared and never duplicated per template.
|
|
40
62
|
|
|
41
63
|
## License
|
|
42
64
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-mithril-lynx",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "Scaffolds a new mithril-lynx app —
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "Scaffolds a new mithril-lynx app — Hello World, Blank, or Basic Activity (with navigation), in JavaScript or TypeScript.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"repository": {
|
|
@@ -17,9 +17,7 @@
|
|
|
17
17
|
},
|
|
18
18
|
"files": [
|
|
19
19
|
"src",
|
|
20
|
-
"
|
|
21
|
-
"template-js",
|
|
22
|
-
"template-ts"
|
|
20
|
+
"templates"
|
|
23
21
|
],
|
|
24
22
|
"engines": {
|
|
25
23
|
"node": "^20.19.0 || >=22.12.0"
|
package/src/index.js
CHANGED
|
@@ -10,7 +10,16 @@ const scriptDir = path.dirname(fileURLToPath(import.meta.url));
|
|
|
10
10
|
const packageRoot = path.join(scriptDir, "..");
|
|
11
11
|
const cwd = process.cwd();
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
// 0.0.2+ — "basic-activity" needs mithril-lynx/navigation, added after 0.0.1
|
|
14
|
+
// was published.
|
|
15
|
+
const MITHRIL_LYNX_VERSION = "0.0.2";
|
|
16
|
+
|
|
17
|
+
const TEMPLATES = [
|
|
18
|
+
{ value: "hello-world", label: "Hello World", hint: "recommended" },
|
|
19
|
+
{ value: "blank", label: "Blank" },
|
|
20
|
+
{ value: "basic-activity", label: "Basic Activity", hint: "multi-screen navigation" },
|
|
21
|
+
];
|
|
22
|
+
const TEMPLATE_VALUES = TEMPLATES.map((t) => t.value);
|
|
14
23
|
|
|
15
24
|
function isValidPackageName(name) {
|
|
16
25
|
return /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(name);
|
|
@@ -40,13 +49,14 @@ function targetDirHasConflict(value) {
|
|
|
40
49
|
|
|
41
50
|
async function main() {
|
|
42
51
|
// Non-interactive escape hatch for scripting/CI:
|
|
43
|
-
// create-mithril-lynx my-app --ts
|
|
44
|
-
// create-mithril-lynx my-app --js --no-install
|
|
52
|
+
// create-mithril-lynx my-app --ts --hello-world
|
|
53
|
+
// create-mithril-lynx my-app --js --basic-activity --no-install
|
|
45
54
|
const args = process.argv.slice(2);
|
|
46
55
|
const positional = args.find((a) => !a.startsWith("-"));
|
|
47
56
|
const variantFlag = args.includes("--ts") ? "ts" : args.includes("--js") ? "js" : undefined;
|
|
57
|
+
const templateFlag = TEMPLATE_VALUES.find((t) => args.includes(`--${t}`));
|
|
48
58
|
const noInstall = args.includes("--no-install");
|
|
49
|
-
const nonInteractive = positional != null && variantFlag != null;
|
|
59
|
+
const nonInteractive = positional != null && variantFlag != null && templateFlag != null;
|
|
50
60
|
|
|
51
61
|
intro("create-mithril-lynx");
|
|
52
62
|
|
|
@@ -73,6 +83,15 @@ async function main() {
|
|
|
73
83
|
? rawName
|
|
74
84
|
: rawName.trim().toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-~]/g, "-");
|
|
75
85
|
|
|
86
|
+
let template = templateFlag;
|
|
87
|
+
if (template == null) {
|
|
88
|
+
template = await select({
|
|
89
|
+
message: "Select a template",
|
|
90
|
+
options: TEMPLATES,
|
|
91
|
+
});
|
|
92
|
+
if (isCancel(template)) return bail();
|
|
93
|
+
}
|
|
94
|
+
|
|
76
95
|
let variant = variantFlag;
|
|
77
96
|
if (variant == null) {
|
|
78
97
|
variant = await select({
|
|
@@ -88,8 +107,13 @@ async function main() {
|
|
|
88
107
|
const targetDir = path.join(cwd, rawName);
|
|
89
108
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
90
109
|
|
|
91
|
-
|
|
92
|
-
|
|
110
|
+
// Layered copy: shared build plumbing (gitignore/README, then
|
|
111
|
+
// lynx.config/tsconfig/main-thread for the chosen variant), then the
|
|
112
|
+
// chosen template's own app content (style.css/assets, then src/index).
|
|
113
|
+
copyDir(path.join(packageRoot, "templates/_shared/common"), targetDir);
|
|
114
|
+
copyDir(path.join(packageRoot, "templates/_shared", variant), targetDir);
|
|
115
|
+
copyDir(path.join(packageRoot, "templates", template, "common"), targetDir);
|
|
116
|
+
copyDir(path.join(packageRoot, "templates", template, variant), targetDir);
|
|
93
117
|
|
|
94
118
|
const gitignorePath = path.join(targetDir, "gitignore");
|
|
95
119
|
if (fs.existsSync(gitignorePath)) {
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
background-color: #fff;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.Page {
|
|
6
|
+
min-height: 100vh;
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.AppBar {
|
|
12
|
+
height: 56px;
|
|
13
|
+
display: flex;
|
|
14
|
+
align-items: center;
|
|
15
|
+
padding: 0 16px;
|
|
16
|
+
background-color: #6200ee;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.AppBar-back {
|
|
20
|
+
font-size: 22px;
|
|
21
|
+
font-weight: 700;
|
|
22
|
+
color: #fff;
|
|
23
|
+
margin-right: 16px;
|
|
24
|
+
padding: 4px 8px;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.AppBar-title {
|
|
28
|
+
font-size: 20px;
|
|
29
|
+
font-weight: 600;
|
|
30
|
+
color: #fff;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.Content {
|
|
34
|
+
flex: 1;
|
|
35
|
+
display: flex;
|
|
36
|
+
flex-direction: column;
|
|
37
|
+
align-items: center;
|
|
38
|
+
justify-content: center;
|
|
39
|
+
padding: 24px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.Description {
|
|
43
|
+
font-size: 16px;
|
|
44
|
+
color: #333;
|
|
45
|
+
text-align: center;
|
|
46
|
+
margin-bottom: 24px;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.Button {
|
|
50
|
+
padding: 12px 24px;
|
|
51
|
+
border-radius: 8px;
|
|
52
|
+
background-color: #6200ee;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.Button-label {
|
|
56
|
+
color: #fff;
|
|
57
|
+
font-size: 16px;
|
|
58
|
+
font-weight: 600;
|
|
59
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import m from "mithril";
|
|
2
|
+
import { createNavigator } from "mithril-lynx/navigation";
|
|
3
|
+
|
|
4
|
+
// A reusable app bar: a title, plus a back affordance when `onBack` is
|
|
5
|
+
// given. No m.route involved anywhere in this file — see
|
|
6
|
+
// mithril-lynx/navigation's own docs for why (Lynx pages have no URL to
|
|
7
|
+
// route to). Navigation here is a plain in-memory stack.
|
|
8
|
+
function AppBar(title, onBack) {
|
|
9
|
+
return m("view", { class: "AppBar" }, [
|
|
10
|
+
onBack != null ? m("text", { class: "AppBar-back", ontap: onBack }, "←") : null,
|
|
11
|
+
m("text", { class: "AppBar-title" }, title),
|
|
12
|
+
]);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const MainScreen = {
|
|
16
|
+
view(vnode) {
|
|
17
|
+
return m("view", { class: "Page" }, [
|
|
18
|
+
AppBar("Basic Activity"),
|
|
19
|
+
m("view", { class: "Content" }, [
|
|
20
|
+
m("text", { class: "Description" }, "This is the main screen."),
|
|
21
|
+
m("view", {
|
|
22
|
+
class: "Button",
|
|
23
|
+
ontap: () => vnode.attrs.nav.push(DetailsScreen, { message: "Hello from MainScreen!" }),
|
|
24
|
+
}, [m("text", { class: "Button-label" }, "Next")]),
|
|
25
|
+
]),
|
|
26
|
+
]);
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const DetailsScreen = {
|
|
31
|
+
view(vnode) {
|
|
32
|
+
return m("view", { class: "Page" }, [
|
|
33
|
+
AppBar("Details", () => vnode.attrs.nav.pop()),
|
|
34
|
+
m("view", { class: "Content" }, [
|
|
35
|
+
m("text", { class: "Description" }, vnode.attrs.message),
|
|
36
|
+
]),
|
|
37
|
+
]);
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const nav = createNavigator({ initial: MainScreen });
|
|
42
|
+
|
|
43
|
+
export default { root: m(nav.Navigator) };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import m from "mithril";
|
|
2
|
+
import { createNavigator, type Nav } from "mithril-lynx/navigation";
|
|
3
|
+
|
|
4
|
+
interface DetailsAttrs {
|
|
5
|
+
nav: Nav;
|
|
6
|
+
message: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// A reusable app bar: a title, plus a back affordance when `onBack` is
|
|
10
|
+
// given. No m.route involved anywhere in this file — see
|
|
11
|
+
// mithril-lynx/navigation's own docs for why (Lynx pages have no URL to
|
|
12
|
+
// route to). Navigation here is a plain in-memory stack.
|
|
13
|
+
function AppBar(title: string, onBack?: () => void) {
|
|
14
|
+
return m("view", { class: "AppBar" }, [
|
|
15
|
+
onBack != null ? m("text", { class: "AppBar-back", ontap: onBack }, "←") : null,
|
|
16
|
+
m("text", { class: "AppBar-title" }, title),
|
|
17
|
+
]);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const MainScreen: m.Component<{ nav: Nav }> = {
|
|
21
|
+
view(vnode) {
|
|
22
|
+
return m("view", { class: "Page" }, [
|
|
23
|
+
AppBar("Basic Activity"),
|
|
24
|
+
m("view", { class: "Content" }, [
|
|
25
|
+
m("text", { class: "Description" }, "This is the main screen."),
|
|
26
|
+
m("view", {
|
|
27
|
+
class: "Button",
|
|
28
|
+
ontap: () => vnode.attrs.nav.push(DetailsScreen, { message: "Hello from MainScreen!" }),
|
|
29
|
+
}, [m("text", { class: "Button-label" }, "Next")]),
|
|
30
|
+
]),
|
|
31
|
+
]);
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const DetailsScreen: m.Component<DetailsAttrs> = {
|
|
36
|
+
view(vnode) {
|
|
37
|
+
return m("view", { class: "Page" }, [
|
|
38
|
+
AppBar("Details", () => vnode.attrs.nav.pop()),
|
|
39
|
+
m("view", { class: "Content" }, [
|
|
40
|
+
m("text", { class: "Description" }, vnode.attrs.message),
|
|
41
|
+
]),
|
|
42
|
+
]);
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const nav = createNavigator({ initial: MainScreen });
|
|
47
|
+
|
|
48
|
+
export default { root: m(nav.Navigator) };
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|