create-muten 0.0.10 → 0.0.11
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/index.js +6 -5
- package/package.json +2 -2
- package/template/src/pages/home/home.muten +1 -8
- package/overlays/full/src/app.muten +0 -21
- package/overlays/full/src/cart.store +0 -9
- package/overlays/full/src/pages/products/products.muten +0 -26
- package/overlays/routing/src/app.muten +0 -19
- package/overlays/routing/src/pages/about/about.muten +0 -15
- package/template/src/components/Snippet.js +0 -19
package/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// create-muten — scaffold a new Muten app, with modern interactive prompts (@clack/prompts).
|
|
3
3
|
//
|
|
4
4
|
// npm create muten@latest [name] (or: npx create-muten)
|
|
5
|
-
// create-muten [name] [--template
|
|
5
|
+
// create-muten [name] [--template muten|react|svelte] [--css|--scss] [--tailwind] [--daisyui] [--vercel] [--tauri] [--pm npm|pnpm|yarn|bun] [--no-install]
|
|
6
6
|
//
|
|
7
7
|
// Stylesheet (CSS or SCSS) is the base; Tailwind is an optional add-on ON TOP of CSS (it's a styling
|
|
8
8
|
// library, not a stylesheet replacement). Interactive in a TTY; flags / non-TTY make it scriptable.
|
|
@@ -54,7 +54,6 @@ const WELCOME_CSS = `
|
|
|
54
54
|
.stat-l { color: #71717a; font-size: 12px; line-height: 1.45; margin-top: 6px; }
|
|
55
55
|
.section { display: flex; flex-direction: column; gap: 14px; }
|
|
56
56
|
.h2 { font-size: 22px; font-weight: 700; letter-spacing: -.02em; }
|
|
57
|
-
.snippet { background: #18181b; color: #e4e4e7; border-radius: 14px; padding: 20px 22px; margin: 0; overflow-x: auto; white-space: pre; font: 13px/1.7 ui-monospace, 'SF Mono', Menlo, Consolas, monospace; }
|
|
58
57
|
.note { color: #71717a; font-size: 13px; line-height: 1.55; }
|
|
59
58
|
.cards { display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px; }
|
|
60
59
|
.card { border: 1px solid #e4e4e7; border-radius: 14px; padding: 18px; background: #fff; }
|
|
@@ -120,8 +119,9 @@ const TAURI_NOTE = (pm) => `
|
|
|
120
119
|
This app also ships as a native desktop app via Tauri (\`src-tauri/\`). The SAME \`.muten\` frontend runs in
|
|
121
120
|
an OS-webview window — build the UI exactly like the web app (routing works as-is: the webview runs the SPA,
|
|
122
121
|
no server, no URL bar, no fallback needed).
|
|
123
|
-
- \`${pm} run tauri
|
|
124
|
-
- \`${pm} run tauri
|
|
122
|
+
- \`${pm} run tauri:dev\` — run the desktop app (opens the native window; hot-reloads the frontend).
|
|
123
|
+
- \`${pm} run tauri:build\` — standalone native installer in \`src-tauri/target/release/bundle/\` (frontend embedded, no server).
|
|
124
|
+
- (\`${pm} run tauri\` alone does nothing — the Tauri CLI needs a subcommand like \`dev\`/\`build\`.)
|
|
125
125
|
- Needs the **Rust toolchain** on the machine (https://rustup.rs) — Tauri compiles a small native shell. Not auto-installed.
|
|
126
126
|
- Custom icon: \`${pm} run tauri icon path/to/logo.png\` regenerates \`src-tauri/icons/\`.
|
|
127
127
|
`;
|
|
@@ -247,7 +247,8 @@ async function main() {
|
|
|
247
247
|
conf.build.beforeBuildCommand = `${pm} run build`;
|
|
248
248
|
writeFileSync(confPath, JSON.stringify(conf, null, 2) + '\n');
|
|
249
249
|
addDev({ '@tauri-apps/cli': '^2.0.0' });
|
|
250
|
-
|
|
250
|
+
// `tauri` alone errors (it needs a subcommand) → ship explicit run scripts so `tauri dev`/`build` are obvious.
|
|
251
|
+
pkg.scripts = { ...pkg.scripts, tauri: 'tauri', 'tauri:dev': 'tauri dev', 'tauri:build': 'tauri build' };
|
|
251
252
|
appendAgents(TAURI_NOTE(pm));
|
|
252
253
|
}
|
|
253
254
|
writeFileSync(join(target, 'vite.config.mjs'), viteConfig({ tailwind, svelte, react })); // composed: muten + chosen plugins
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-muten",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.11",
|
|
4
4
|
"description": "Scaffold a new Muten app.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -19,5 +19,5 @@
|
|
|
19
19
|
"picocolors": "^1.0.1"
|
|
20
20
|
},
|
|
21
21
|
"keywords": ["muten", "create-muten", "scaffold", "starter", "cli", "frontend"],
|
|
22
|
-
"files": ["index.js", "template", "template-tauri"
|
|
22
|
+
"files": ["index.js", "template", "template-tauri"]
|
|
23
23
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# The starter welcome page. Skin with class(…) + src/styles.css. Delete it and build your own — or just
|
|
2
|
-
# ask your AI assistant; it has the full muten reference in .claude/.
|
|
3
|
-
# (src/components/Snippet.js) because a .muten string can't hold the quotes/braces of muten source.
|
|
2
|
+
# ask your AI assistant; it has the full muten reference in .claude/. Pure muten — no JS, no escape hatch.
|
|
4
3
|
screen home
|
|
5
4
|
|
|
6
5
|
Page class("welcome") {
|
|
@@ -19,12 +18,6 @@ Page class("welcome") {
|
|
|
19
18
|
Stack class("stat") { Title "0 KB" h3 class("stat-n") Text "on a static page" class("stat-l") }
|
|
20
19
|
}
|
|
21
20
|
|
|
22
|
-
Stack class("section") {
|
|
23
|
-
Title "A whole page, in muten" h2 class("h2")
|
|
24
|
-
Custom Snippet
|
|
25
|
-
Text "Reactivity is automatic — read a state and only that spot re-renders. No hooks, no effects to wire." class("note")
|
|
26
|
-
}
|
|
27
|
-
|
|
28
21
|
Stack class("section") {
|
|
29
22
|
Title "Where to go next" h2 class("h2")
|
|
30
23
|
Stack class("cards") {
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# The app ROOT. `api` is the backend config (one place: base URL + default headers) — every `sources`
|
|
2
|
-
# inherits it. The shell's navbar reads the cart store (global) and shows a live count.
|
|
3
|
-
api {
|
|
4
|
-
base: "https://fakestoreapi.com"
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
shell {
|
|
8
|
-
Header style(row, between, center) class("p-4 shadow bg-white") {
|
|
9
|
-
Link "Shop" -> / class("text-xl font-bold")
|
|
10
|
-
Nav "Main" style(row, gap.md, center) {
|
|
11
|
-
Link "Products" -> /products
|
|
12
|
-
Span "🛒 {cart.count}" class("font-medium")
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
slot
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
routes {
|
|
19
|
-
/ -> home
|
|
20
|
-
/products -> products
|
|
21
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
# An app-global store (any `*.store` under src/). State is shared across pages + the shell, no imports.
|
|
2
|
-
# `get` is a derived value; `action`s are the only way to mutate.
|
|
3
|
-
state { items = [] : list<text> }
|
|
4
|
-
|
|
5
|
-
get count = items.length
|
|
6
|
-
|
|
7
|
-
action add mutates items <- id {
|
|
8
|
-
items.push(id)
|
|
9
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# A real data page: `query` state backed by a `sources` URL (relative → joined to the app's `api.base`).
|
|
2
|
-
# `muten build` fetches it at build and bakes the rows into the HTML (SSG); the runtime then takes over.
|
|
3
|
-
# Clicking "Add" calls the cart store action — the navbar count updates reactively.
|
|
4
|
-
screen products
|
|
5
|
-
|
|
6
|
-
meta { title "Products" }
|
|
7
|
-
|
|
8
|
-
entity Product { title text price text }
|
|
9
|
-
|
|
10
|
-
state { products = query products : list<Product> }
|
|
11
|
-
|
|
12
|
-
sources { products: "/products" }
|
|
13
|
-
|
|
14
|
-
Page style(padding.lg, gap.md) {
|
|
15
|
-
Title "Products" class("text-2xl font-bold")
|
|
16
|
-
when products.loading { Text "Loading…" class("opacity-60") }
|
|
17
|
-
each products as p {
|
|
18
|
-
Stack style(gap.sm) class("p-4 rounded-lg shadow bg-white") {
|
|
19
|
-
Text "{p.title}" class("font-semibold")
|
|
20
|
-
Stack style(row, between, center) {
|
|
21
|
-
Span "$ {p.price}" class("text-lg")
|
|
22
|
-
Button "Add to cart" -> cart.add(p.id) class("px-3 py-1 rounded bg-black text-white")
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# The app ROOT. A persistent `shell { … slot … }` wraps every page (navbar here); `slot` is where the
|
|
2
|
-
# active page mounts. `routes` maps a real-path URL to a page (the folder under src/pages/).
|
|
3
|
-
shell {
|
|
4
|
-
Header style(row, between, center) class("nav") {
|
|
5
|
-
Link "Home" -> /
|
|
6
|
-
Nav "Main" {
|
|
7
|
-
Link "About" -> /about
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
slot
|
|
11
|
-
Footer style(padding.md) {
|
|
12
|
-
Text "Built with Muten"
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
routes {
|
|
17
|
-
/ -> home
|
|
18
|
-
/about -> about
|
|
19
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# A second page. `meta { … }` sets the <head> title/description (og:* auto-derived) — applied on
|
|
2
|
-
# navigation and baked into the static HTML at build. This page has no reactivity, so `muten build`
|
|
3
|
-
# pre-renders it to zero-JS HTML (crawlable).
|
|
4
|
-
screen about
|
|
5
|
-
|
|
6
|
-
meta {
|
|
7
|
-
title "About"
|
|
8
|
-
description "About this Muten app."
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
Page style(padding.lg, gap.md) {
|
|
12
|
-
Title "About"
|
|
13
|
-
Text "Static pages compile to zero-JS HTML at build — crawlable and instant."
|
|
14
|
-
Link "← Home" -> /
|
|
15
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
// Welcome-page code block (a `Custom` host component — the escape hatch for anything muten can't express).
|
|
2
|
-
// The snippet lives here in JS so it can contain quotes and { } that a .muten string can't. Delete with
|
|
3
|
-
// the welcome page. Used from home.muten as: Custom Snippet
|
|
4
|
-
const CODE = `screen home
|
|
5
|
-
|
|
6
|
-
state { count = 0 : number }
|
|
7
|
-
action inc mutates count { count.set(count + 1) }
|
|
8
|
-
|
|
9
|
-
Page style(padding.lg, gap.md) {
|
|
10
|
-
Title "Count: {count}"
|
|
11
|
-
Button "+1" -> inc
|
|
12
|
-
}`;
|
|
13
|
-
|
|
14
|
-
function mount(el) {
|
|
15
|
-
const pre = document.createElement('pre');
|
|
16
|
-
pre.className = 'snippet';
|
|
17
|
-
pre.textContent = CODE;
|
|
18
|
-
el.appendChild(pre);
|
|
19
|
-
}
|