@valancex/cli 0.12.0 → 0.13.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/LICENSE +21 -0
- package/README.md +36 -5
- package/dist/add.d.ts +9 -1
- package/dist/add.js +68 -5
- package/dist/archive.d.ts +17 -0
- package/dist/archive.js +111 -0
- package/dist/args.js +2 -2
- package/dist/build.d.ts +3 -0
- package/dist/build.js +93 -29
- package/dist/check.js +2 -2
- package/dist/cli.js +59 -16
- package/dist/compile.d.ts +11 -3
- package/dist/compile.js +42 -15
- package/dist/config.d.ts +3 -0
- package/dist/config.js +4 -0
- package/dist/dev-desktop.d.ts +8 -0
- package/dist/dev-desktop.js +114 -0
- package/dist/dev.d.ts +3 -0
- package/dist/dev.js +33 -5
- package/dist/emit.d.ts +7 -4
- package/dist/emit.js +105 -27
- package/dist/init.js +14 -4
- package/dist/package.d.ts +18 -0
- package/dist/package.js +141 -0
- package/dist/project.js +1 -1
- package/dist/targets.d.ts +6 -1
- package/dist/targets.js +26 -4
- package/dist/ui/init.js +4 -4
- package/dist/ui/run.d.ts +3 -1
- package/dist/ui/run.js +5 -3
- package/dist/vite.d.ts +3 -2
- package/dist/vite.js +3 -3
- package/package.json +6 -3
- package/schemas/valance.desktop.schema.json +17 -0
- package/templates/desktop/README.md +14 -0
- package/templates/desktop/content/404.md +7 -0
- package/templates/desktop/content/guide/getting-started.md +15 -0
- package/templates/desktop/content/index.md +14 -0
- package/templates/desktop/gitignore +4 -0
- package/templates/desktop/src/layout.mprx +23 -0
- package/templates/desktop/src/main.ts +15 -0
- package/templates/desktop/tsconfig.json +18 -0
- package/templates/multi/README.md +13 -0
- package/templates/multi/content/404.md +7 -0
- package/templates/multi/content/guide/getting-started.md +15 -0
- package/templates/multi/content/index.md +14 -0
- package/templates/multi/src/desktop/layout.mprx +21 -0
- package/templates/multi/src/main.ts +23 -0
- package/templates/multi/src/web/layout.mprx +27 -0
- package/templates/multi/src/web/styles.css +28 -0
- package/templates/multi/src/web/theme-toggle.mprx +1 -0
- package/templates/multi/src/web/theme-toggle.ts +10 -0
- package/templates/web/content/guide/getting-started.md +1 -1
- package/views/block.mprx +1 -1
- package/views-desktop/block.mprx +3 -0
- package/views-desktop/blocks.mprx +3 -0
- package/views-desktop/inline.mprx +3 -0
- package/views-desktop/layout.mprx +20 -0
- package/views-desktop/list-block.mprx +3 -0
- package/views-desktop/list-items.mprx +3 -0
- package/views-desktop/runs.mprx +3 -0
- /package/views/{heading.mprx → heading-block.mprx} +0 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# {{name}}
|
|
2
|
+
|
|
3
|
+
A VALANCE application for the desktop, made with `vlx init --desktop`.
|
|
4
|
+
|
|
5
|
+
```console
|
|
6
|
+
$ {{run}} dev # open the window, and update it as you edit
|
|
7
|
+
$ {{run}} build # write the engine to dist/desktop/
|
|
8
|
+
$ {{run}} check # find mistakes in your files without building
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
- `content/` is Markdown: a page's path is its address.
|
|
12
|
+
- `src/layout.mprx` is the window around a page; `src/main.ts` declares it, the state and the commands.
|
|
13
|
+
- `valance.desktop.json` marks the project as a desktop one; `valance.json` names the application.
|
|
14
|
+
- The window is the Desktop PORT's (`valancex-port-desktop`); `vlx build` writes the engine it runs, `dist/desktop/engine.mjs`.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Getting started
|
|
3
|
+
description: Create the project, run it, change a page.
|
|
4
|
+
order: 1
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Getting started
|
|
8
|
+
|
|
9
|
+
Edit `content/index.md` and save: the window shows it.
|
|
10
|
+
|
|
11
|
+
> A link is an address. In a window, following one is the application's own navigation, the same command the web uses.
|
|
12
|
+
|
|
13
|
+
1. Add a page: a Markdown file under `content/`.
|
|
14
|
+
2. Change the window: `src/layout.mprx`, with the components `column`, `row`, `heading`, `text`, `button`, `checkbox` and `textfield`.
|
|
15
|
+
3. Add state or a command: `src/main.ts`.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: {{name}}
|
|
3
|
+
description: A desktop application, written the way a VALANCE application is written.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# {{name}}
|
|
7
|
+
|
|
8
|
+
This is a **VALANCE application** in a window. Everything you are reading is a Markdown file in `content/`; the window around it is `src/layout.mprx`.
|
|
9
|
+
|
|
10
|
+
- Pages are Markdown files. Their path is their address.
|
|
11
|
+
- The layout is a template, drawn with the Desktop PORT's components.
|
|
12
|
+
- `vlx dev` opens the window and updates it as you edit.
|
|
13
|
+
|
|
14
|
+
Start with [Getting started](/guide/getting-started).
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<column>
|
|
2
|
+
<row>
|
|
3
|
+
<button disabled={!canGoBack} on.click={back()}>Back</button>
|
|
4
|
+
<button disabled={!canGoForward} on.click={forward()}>Forward</button>
|
|
5
|
+
<link href={home}>{site}</link>
|
|
6
|
+
<button on.click={toggleNavigation()}>{#if navigation}Hide pages{:else}Show pages{/if}</button>
|
|
7
|
+
</row>
|
|
8
|
+
{#if navigation}
|
|
9
|
+
{#each sections as s (s.id)}
|
|
10
|
+
<column>
|
|
11
|
+
{#if s.title != ""}<text>{s.title}</text>{/if}
|
|
12
|
+
<list ordered={false}>
|
|
13
|
+
{#each s.items as n (n.id)}<listitem><link href={n.href}>{n.label}</link></listitem>{/each}
|
|
14
|
+
</list>
|
|
15
|
+
</column>
|
|
16
|
+
{/each}
|
|
17
|
+
{/if}
|
|
18
|
+
<blocks items={blocks} />
|
|
19
|
+
<row>
|
|
20
|
+
{#if prev.href != ""}<link href={prev.href}>{prev.label}</link>{/if}
|
|
21
|
+
{#if next.href != ""}<link href={next.href}>{next.label}</link>{/if}
|
|
22
|
+
</row>
|
|
23
|
+
</column>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { component, defineApp, field } from "@valancex/common";
|
|
2
|
+
import { Schema } from "effect";
|
|
3
|
+
import layout from "./layout.mprx";
|
|
4
|
+
|
|
5
|
+
// The application, from the top. `layout` is the window's content around a page; the Markdown in content/ is what goes in `<blocks>`. The state is the application's own, beyond "which page is
|
|
6
|
+
// shown": each field is its type and its default, together. A field is a name the layout can read (`navigation`), and the commands below are names it can run (`toggleNavigation()`).
|
|
7
|
+
export default defineApp({
|
|
8
|
+
layout: component(layout),
|
|
9
|
+
state: {
|
|
10
|
+
navigation: field(Schema.Boolean, true),
|
|
11
|
+
},
|
|
12
|
+
commands: (command) => ({
|
|
13
|
+
toggleNavigation: command((state) => ({ ...state, navigation: !state.navigation })),
|
|
14
|
+
}),
|
|
15
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"types": ["node"],
|
|
4
|
+
"target": "ES2022",
|
|
5
|
+
"module": "NodeNext",
|
|
6
|
+
"moduleResolution": "NodeNext",
|
|
7
|
+
"lib": ["ES2022"],
|
|
8
|
+
"strict": true,
|
|
9
|
+
"noUncheckedIndexedAccess": true,
|
|
10
|
+
"exactOptionalPropertyTypes": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"isolatedModules": true,
|
|
13
|
+
"noEmit": true,
|
|
14
|
+
"allowArbitraryExtensions": true,
|
|
15
|
+
"rootDirs": ["src", ".valance/types"]
|
|
16
|
+
},
|
|
17
|
+
"include": ["src"]
|
|
18
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# {{name}}
|
|
2
|
+
|
|
3
|
+
A VALANCE application for the web and the desktop, made with `vlx init --web --desktop`.
|
|
4
|
+
|
|
5
|
+
```console
|
|
6
|
+
$ {{run}} dev -- --web # serve the site (--desktop opens the window instead)
|
|
7
|
+
$ {{run}} build # build every target: dist/web/ and dist/desktop/
|
|
8
|
+
$ {{run}} check # find mistakes in your files, for every target
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
- `content/` is Markdown, and the state and commands in `src/main.ts` are the application's: the same on every target.
|
|
12
|
+
- Each target has its own templates, because each draws with its own vocabulary: `src/web/` and `src/desktop/`. `src/main.ts` says which is whose (`targets`).
|
|
13
|
+
- `valance.web.json` and `valance.desktop.json` say which targets the project has; `valance.json` names the application.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Getting started
|
|
3
|
+
description: Create the project, run it, change a page.
|
|
4
|
+
order: 1
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Getting started
|
|
8
|
+
|
|
9
|
+
Edit `content/index.md` and save: the window shows it.
|
|
10
|
+
|
|
11
|
+
> A link is an address. In a window, following one is the application's own navigation, the same command the web uses.
|
|
12
|
+
|
|
13
|
+
1. Add a page: a Markdown file under `content/`.
|
|
14
|
+
2. Change the window: `src/layout.mprx`, with the components `column`, `row`, `heading`, `text`, `button`, `checkbox` and `textfield`.
|
|
15
|
+
3. Add state or a command: `src/main.ts`.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: {{name}}
|
|
3
|
+
description: A desktop application, written the way a VALANCE application is written.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# {{name}}
|
|
7
|
+
|
|
8
|
+
This is a **VALANCE application** in a window. Everything you are reading is a Markdown file in `content/`; the window around it is `src/layout.mprx`.
|
|
9
|
+
|
|
10
|
+
- Pages are Markdown files. Their path is their address.
|
|
11
|
+
- The layout is a template, drawn with the Desktop PORT's components.
|
|
12
|
+
- `vlx dev --desktop` opens the window and updates it as you edit.
|
|
13
|
+
|
|
14
|
+
Start with [Getting started](/guide/getting-started).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<column>
|
|
2
|
+
<row>
|
|
3
|
+
<link href={home}>{site}</link>
|
|
4
|
+
<button on.click={toggleNavigation()}>{#if navigation}Hide pages{:else}Show pages{/if}</button>
|
|
5
|
+
</row>
|
|
6
|
+
{#if navigation}
|
|
7
|
+
{#each sections as s (s.id)}
|
|
8
|
+
<column>
|
|
9
|
+
{#if s.title != ""}<text>{s.title}</text>{/if}
|
|
10
|
+
<list ordered={false}>
|
|
11
|
+
{#each s.items as n (n.id)}<listitem><link href={n.href}>{n.label}</link></listitem>{/each}
|
|
12
|
+
</list>
|
|
13
|
+
</column>
|
|
14
|
+
{/each}
|
|
15
|
+
{/if}
|
|
16
|
+
<blocks items={blocks} />
|
|
17
|
+
<row>
|
|
18
|
+
{#if prev.href != ""}<link href={prev.href}>{prev.label}</link>{/if}
|
|
19
|
+
{#if next.href != ""}<link href={next.href}>{next.label}</link>{/if}
|
|
20
|
+
</row>
|
|
21
|
+
</column>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { component, defineApp, field } from "@valancex/common";
|
|
2
|
+
import { Schema } from "effect";
|
|
3
|
+
import desktopLayout from "./desktop/layout.mprx";
|
|
4
|
+
import themeToggle from "./web/theme-toggle.js";
|
|
5
|
+
import webLayout from "./web/layout.mprx";
|
|
6
|
+
|
|
7
|
+
// One application, built for each target the project has. What is shared is written once, here: the state (each field is its type and its default, together) and the commands, and the content in
|
|
8
|
+
// content/. What differs is the templates, because each target draws with its own vocabulary: `targets` gives each its layout and its components. Nothing under src/ is part of the application
|
|
9
|
+
// unless it is imported here and listed.
|
|
10
|
+
export default defineApp({
|
|
11
|
+
state: {
|
|
12
|
+
theme: field(Schema.Literal("light", "dark"), "light"), // the web layout's
|
|
13
|
+
navigation: field(Schema.Boolean, true), // the desktop layout's
|
|
14
|
+
},
|
|
15
|
+
commands: (command) => ({
|
|
16
|
+
toggleTheme: command((state) => ({ ...state, theme: state.theme === "light" ? "dark" : "light" })),
|
|
17
|
+
toggleNavigation: command((state) => ({ ...state, navigation: !state.navigation })),
|
|
18
|
+
}),
|
|
19
|
+
targets: {
|
|
20
|
+
web: { layout: component(webLayout), components: [themeToggle] },
|
|
21
|
+
desktop: { layout: component(desktopLayout) },
|
|
22
|
+
},
|
|
23
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<shell class="layout" theme={theme}>
|
|
2
|
+
<header class="bar">
|
|
3
|
+
<link class="brand" href={home} current="false">{site}</link>
|
|
4
|
+
<theme-toggle theme={theme} on.toggle={toggleTheme()} />
|
|
5
|
+
</header>
|
|
6
|
+
<div class="frame">
|
|
7
|
+
<nav class="sidebar" label="Pages">
|
|
8
|
+
{#each sections as s (s.id)}
|
|
9
|
+
<section>
|
|
10
|
+
{#if s.title != ""}<para class="nav-title">{s.title}</para>{/if}
|
|
11
|
+
<list class="nav-list">
|
|
12
|
+
{#each s.items as n (n.id)}
|
|
13
|
+
<item><link class="nav-link" href={n.href} current={n.current}>{n.label}</link></item>
|
|
14
|
+
{/each}
|
|
15
|
+
</list>
|
|
16
|
+
</section>
|
|
17
|
+
{/each}
|
|
18
|
+
</nav>
|
|
19
|
+
<main id="content" tabindex="-1">
|
|
20
|
+
<blocks items={blocks} />
|
|
21
|
+
<nav class="pager" label="Previous and next page">
|
|
22
|
+
{#if prev.href != ""}<link class="pager-link" href={prev.href} current="false">{prev.label}</link>{/if}
|
|
23
|
+
{#if next.href != ""}<link class="pager-link" href={next.href} current="false">{next.label}</link>{/if}
|
|
24
|
+
</nav>
|
|
25
|
+
</main>
|
|
26
|
+
</div>
|
|
27
|
+
</shell>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
:root { --bg: #fff; --fg: #1d2330; --muted: #5c6578; --line: #e3e6ee; --accent: #5b3fd6; --code: #f4f5f9; }
|
|
2
|
+
[data-theme="dark"] { --bg: #12141b; --fg: #e8eaf1; --muted: #9aa3b8; --line: #272b38; --accent: #a78bfa; --code: #1b1e29; }
|
|
3
|
+
|
|
4
|
+
* { box-sizing: border-box; }
|
|
5
|
+
body { margin: 0; font: 16px/1.6 system-ui, sans-serif; background: var(--bg); color: var(--fg); }
|
|
6
|
+
.layout { min-height: 100vh; background: var(--bg); color: var(--fg); }
|
|
7
|
+
|
|
8
|
+
.bar { display: flex; align-items: center; justify-content: space-between; padding: 0.75rem 1.5rem; border-bottom: 1px solid var(--line); }
|
|
9
|
+
.brand { font-weight: 700; color: var(--fg); text-decoration: none; }
|
|
10
|
+
.theme-toggle { font: inherit; padding: 0.25rem 0.75rem; border: 1px solid var(--line); border-radius: 999px; background: transparent; color: var(--fg); cursor: pointer; }
|
|
11
|
+
|
|
12
|
+
.frame { display: grid; grid-template-columns: 14rem 1fr; gap: 2rem; max-width: 60rem; margin: 0 auto; padding: 1.5rem; }
|
|
13
|
+
.sidebar { font-size: 0.95rem; }
|
|
14
|
+
.nav-title { margin: 1rem 0 0.25rem; font-weight: 600; color: var(--muted); text-transform: uppercase; font-size: 0.75rem; letter-spacing: 0.05em; }
|
|
15
|
+
.nav-list { list-style: none; margin: 0; padding: 0; }
|
|
16
|
+
.nav-link { display: block; padding: 0.15rem 0; color: var(--fg); text-decoration: none; }
|
|
17
|
+
.nav-link[aria-current="page"] { color: var(--accent); font-weight: 600; }
|
|
18
|
+
|
|
19
|
+
main { min-width: 0; }
|
|
20
|
+
main h1 { margin-top: 0; }
|
|
21
|
+
a { color: var(--accent); }
|
|
22
|
+
.code { padding: 1rem; overflow-x: auto; background: var(--code); border-radius: 0.5rem; }
|
|
23
|
+
code { font-family: ui-monospace, monospace; font-size: 0.9em; }
|
|
24
|
+
.quote { margin: 1rem 0; padding-left: 1rem; border-left: 3px solid var(--accent); color: var(--muted); }
|
|
25
|
+
.picture { max-width: 100%; }
|
|
26
|
+
.pager { display: flex; justify-content: space-between; margin-top: 3rem; padding-top: 1rem; border-top: 1px solid var(--line); }
|
|
27
|
+
|
|
28
|
+
@media (max-width: 40rem) { .frame { grid-template-columns: 1fr; } }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<button class="theme-toggle" pressed={theme == "dark" ? "true" : "false"} on.click={toggle()}>{theme == "dark" ? "Light" : "Dark"}</button>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { component } from "@valancex/common";
|
|
2
|
+
import { Schema } from "effect";
|
|
3
|
+
import template from "./theme-toggle.mprx";
|
|
4
|
+
|
|
5
|
+
// The interface of `<theme-toggle>`, stated once, where it is defined: what the template reads (`theme`) and what it raises (`toggle`, which carries nothing). Whoever uses it names only that
|
|
6
|
+
// they use it. `.valance/templates.d.ts` gives the template its keys as a type, so a contract that disagrees with the template is an error in the editor.
|
|
7
|
+
export default component(template, {
|
|
8
|
+
props: { theme: Schema.Literal("light", "dark") },
|
|
9
|
+
events: { toggle: Schema.Void },
|
|
10
|
+
});
|
|
@@ -21,7 +21,7 @@ Open the address `vlx dev` prints. Edit this file and save: the page reloads wit
|
|
|
21
21
|
pnpm build
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
The finished site is in `dist/`. Anything that serves files can host it.
|
|
24
|
+
The finished site is in `dist/web/`. Anything that serves files can host it.
|
|
25
25
|
|
|
26
26
|
## Where things are
|
|
27
27
|
|
package/views/block.mprx
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
<mesh-fragment>
|
|
2
|
-
{#if b.kind == "heading"}<heading level={b.level} anchor={b.anchor} spans={b.spans} />{:else if b.kind == "list"}<list-block ordered={b.ordered} items={b.items} />{:else if b.kind == "code"}<pre class="code" tabindex="0"><code>{b.text}</code></pre>{:else if b.kind == "quote"}<quote class="quote"><runs spans={b.spans} /></quote>{:else if b.kind == "image"}<image class="picture" src={b.src} alt={b.alt} loading="lazy" />{:else}<para class="prose"><runs spans={b.spans} /></para>{/if}
|
|
2
|
+
{#if b.kind == "heading"}<heading-block level={b.level} anchor={b.anchor} spans={b.spans} />{:else if b.kind == "list"}<list-block ordered={b.ordered} items={b.items} />{:else if b.kind == "code"}<pre class="code" tabindex="0"><code>{b.text}</code></pre>{:else if b.kind == "quote"}<quote class="quote"><runs spans={b.spans} /></quote>{:else if b.kind == "image"}<image class="picture" src={b.src} alt={b.alt} loading="lazy" />{:else}<para class="prose"><runs spans={b.spans} /></para>{/if}
|
|
3
3
|
</mesh-fragment>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<mesh-fragment>
|
|
2
|
+
{#if b.kind == "heading"}<heading level={b.level}><runs spans={b.spans} /></heading>{:else if b.kind == "list"}<list-block ordered={b.ordered} items={b.items} />{:else if b.kind == "code"}<code>{b.text}</code>{:else if b.kind == "quote"}<blockquote><runs spans={b.spans} /></blockquote>{:else if b.kind == "image"}<image src={b.src} label={b.alt} />{:else}<paragraph><runs spans={b.spans} /></paragraph>{/if}
|
|
3
|
+
</mesh-fragment>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<mesh-fragment>
|
|
2
|
+
{#if kind == "strong"}<strong>{text}</strong>{:else if kind == "emphasis"}<emphasis>{text}</emphasis>{:else if kind == "code"}<code>{text}</code>{:else if kind == "link"}<link href={href}>{text}</link>{:else}<mesh-fragment>{text}</mesh-fragment>{/if}
|
|
3
|
+
</mesh-fragment>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<column>
|
|
2
|
+
<row>
|
|
3
|
+
<button disabled={!canGoBack} on.click={back()}>Back</button>
|
|
4
|
+
<button disabled={!canGoForward} on.click={forward()}>Forward</button>
|
|
5
|
+
<link href={home}>{site}</link>
|
|
6
|
+
</row>
|
|
7
|
+
{#each sections as s (s.id)}
|
|
8
|
+
<column>
|
|
9
|
+
{#if s.title != ""}<text>{s.title}</text>{/if}
|
|
10
|
+
<list ordered={false}>
|
|
11
|
+
{#each s.items as n (n.id)}<listitem><link href={n.href}>{n.label}</link></listitem>{/each}
|
|
12
|
+
</list>
|
|
13
|
+
</column>
|
|
14
|
+
{/each}
|
|
15
|
+
<blocks items={blocks} />
|
|
16
|
+
<row>
|
|
17
|
+
{#if prev.href != ""}<link href={prev.href}>{prev.label}</link>{/if}
|
|
18
|
+
{#if next.href != ""}<link href={next.href}>{next.label}</link>{/if}
|
|
19
|
+
</row>
|
|
20
|
+
</column>
|
|
File without changes
|