juxscript 1.1.397 → 1.1.399
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 +428 -200
- package/bin/cli.js +2 -212
- package/dist/charts/barChart.d.ts +119 -0
- package/dist/charts/barChart.d.ts.map +1 -0
- package/dist/charts/barChart.js +644 -0
- package/dist/charts/barChart.js.map +1 -0
- package/dist/charts/lineChart.d.ts +104 -0
- package/dist/charts/lineChart.d.ts.map +1 -0
- package/dist/charts/lineChart.js +466 -0
- package/dist/charts/lineChart.js.map +1 -0
- package/dist/charts/pieChart.d.ts +93 -0
- package/dist/charts/pieChart.d.ts.map +1 -0
- package/dist/charts/pieChart.js +397 -0
- package/dist/charts/pieChart.js.map +1 -0
- package/dist/components/barChart.d.ts +18 -2
- package/dist/components/barChart.d.ts.map +1 -1
- package/dist/components/barChart.js +175 -140
- package/dist/components/barChart.js.map +1 -1
- package/dist/components/button.d.ts +6 -0
- package/dist/components/button.d.ts.map +1 -1
- package/dist/components/button.js +18 -0
- package/dist/components/button.js.map +1 -1
- package/dist/components/checkbox.d.ts +6 -0
- package/dist/components/checkbox.d.ts.map +1 -1
- package/dist/components/checkbox.js +34 -0
- package/dist/components/checkbox.js.map +1 -1
- package/dist/components/input.d.ts +3 -0
- package/dist/components/input.d.ts.map +1 -1
- package/dist/components/input.js +17 -0
- package/dist/components/input.js.map +1 -1
- package/dist/components/lineChart.d.ts +19 -2
- package/dist/components/lineChart.d.ts.map +1 -1
- package/dist/components/lineChart.js +233 -97
- package/dist/components/lineChart.js.map +1 -1
- package/dist/components/link.d.ts +3 -0
- package/dist/components/link.d.ts.map +1 -1
- package/dist/components/link.js +17 -0
- package/dist/components/link.js.map +1 -1
- package/dist/components/list.d.ts +3 -0
- package/dist/components/list.d.ts.map +1 -1
- package/dist/components/list.js +17 -0
- package/dist/components/list.js.map +1 -1
- package/dist/components/nav.d.ts +3 -0
- package/dist/components/nav.d.ts.map +1 -1
- package/dist/components/nav.js +17 -0
- package/dist/components/nav.js.map +1 -1
- package/dist/components/pieChart.d.ts +7 -0
- package/dist/components/pieChart.d.ts.map +1 -1
- package/dist/components/pieChart.js +113 -16
- package/dist/components/pieChart.js.map +1 -1
- package/dist/components/radio.d.ts +3 -0
- package/dist/components/radio.d.ts.map +1 -1
- package/dist/components/radio.js +17 -0
- package/dist/components/radio.js.map +1 -1
- package/dist/components/select.d.ts +3 -0
- package/dist/components/select.d.ts.map +1 -1
- package/dist/components/select.js +17 -0
- package/dist/components/select.js.map +1 -1
- package/dist/components/table.d.ts +3 -0
- package/dist/components/table.d.ts.map +1 -1
- package/dist/components/table.js +17 -0
- package/dist/components/table.js.map +1 -1
- package/dist/components/tabs.d.ts +3 -0
- package/dist/components/tabs.d.ts.map +1 -1
- package/dist/components/tabs.js +17 -0
- package/dist/components/tabs.js.map +1 -1
- package/dist/components/tag.d.ts +3 -0
- package/dist/components/tag.d.ts.map +1 -1
- package/dist/components/tag.js +18 -0
- package/dist/components/tag.js.map +1 -1
- package/dist/index.d.ts +23 -19
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -19
- package/dist/index.js.map +1 -1
- package/dist/shapes/c.d.ts +53 -0
- package/dist/shapes/c.d.ts.map +1 -0
- package/dist/shapes/c.js +127 -0
- package/dist/shapes/c.js.map +1 -0
- package/dist/shapes/flex.d.ts +49 -0
- package/dist/shapes/flex.d.ts.map +1 -0
- package/dist/shapes/flex.js +122 -0
- package/dist/shapes/flex.js.map +1 -0
- package/dist/shapes/g.d.ts +21 -0
- package/dist/shapes/g.d.ts.map +1 -0
- package/dist/shapes/g.js +52 -0
- package/dist/shapes/g.js.map +1 -0
- package/dist/tools/devtools.d.ts +3 -0
- package/dist/tools/devtools.d.ts.map +1 -0
- package/dist/tools/devtools.js +182 -0
- package/dist/tools/devtools.js.map +1 -0
- package/dist/utils/colors.d.ts +32 -5
- package/dist/utils/colors.d.ts.map +1 -1
- package/dist/utils/colors.js +32 -6
- package/dist/utils/colors.js.map +1 -1
- package/dist/utils/tooltip.d.ts +5 -0
- package/dist/utils/tooltip.d.ts.map +1 -0
- package/dist/utils/tooltip.js +52 -0
- package/dist/utils/tooltip.js.map +1 -0
- package/dist/utils/trend.d.ts +9 -0
- package/dist/utils/trend.d.ts.map +1 -0
- package/dist/utils/trend.js +35 -0
- package/dist/utils/trend.js.map +1 -0
- package/dist/widgets/calendar.d.ts +74 -0
- package/dist/widgets/calendar.d.ts.map +1 -0
- package/dist/widgets/calendar.js +308 -0
- package/dist/widgets/calendar.js.map +1 -0
- package/dist/widgets/sidebar.d.ts +90 -0
- package/dist/widgets/sidebar.d.ts.map +1 -0
- package/dist/widgets/sidebar.js +353 -0
- package/dist/widgets/sidebar.js.map +1 -0
- package/package.json +3 -2
- package/components/calendar/calendar-usage.jux +0 -0
- package/components/calendar/calendar.jux +0 -0
- package/components/sidebar/index.jux +0 -272
- package/components/sidebar/usage.jux +0 -7
package/README.md
CHANGED
|
@@ -1,271 +1,499 @@
|
|
|
1
|
-
#
|
|
1
|
+
# JUX — Build UIs in Pure JavaScript. No Markup Required.
|
|
2
2
|
|
|
3
|
+
> **JUX** is a headless UI authoring framework. Build reactive web applications with 100% JavaScript — no HTML templates, no JSX, no markup of any kind.
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
- IF YOU ARE CURRENTLY USING THIS PACKAGE COOL! But it is still a little fragile.
|
|
6
|
-
- We are working on opening our repo to public and working on our documentation pages.
|
|
7
|
-
+ Stay tuned! For now, you will see our roadmap here!
|
|
5
|
+
Think of it like a more reactive [Streamlit](https://streamlit.io), but for the web, written entirely in JavaScript. Author your UI top-down, procedurally — components appear in the order you call them.
|
|
8
6
|
|
|
7
|
+
```bash
|
|
8
|
+
npx juxscript create my-app
|
|
9
|
+
cd my-app
|
|
10
|
+
npm run dev
|
|
9
11
|
```
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
- [X] Layouts (100% done.)
|
|
23
|
-
- [ ] *Authoring Layout Pages* - `docs`
|
|
24
|
-
- [ ] *Authoring Application Pages* - `docs`
|
|
25
|
-
- [ ] *Authoring Custom Components* - `docs`
|
|
26
|
-
|
|
27
|
-
- [ ] Render Dependency Tree
|
|
28
|
-
> Idea here is, one element may be a predicate for another. Will need promises. **predicting problems with slow-loading components that depend on containers from other components. May to to separate concerns with container "building" vs. content addition OR use async processes (promises).
|
|
29
|
-
- [X] Reactivity (90% done.)
|
|
30
|
-
- [ ] Client Components (99% of what would be needed.)
|
|
31
|
-
- [X] Charts
|
|
32
|
-
- [X] Poor Intellisense support? Could be this issue. - fixed.
|
|
33
|
-
- [ ] Api Wrapper
|
|
34
|
-
- [X] Params/Active State for Menu/Nav matching - built in.
|
|
35
|
-
- [ ] CDN Bundle (import CDN/'state', 'jux' from cdn.)
|
|
36
|
-
- [ ] Icon
|
|
37
|
-
|
|
38
|
-
- [ ] Quickstart Boilerplates (20% done,notion.jux)
|
|
39
|
-
- [ ] Mobile Nav
|
|
40
|
-
- [ ] `npx jux present notion|default` etc..
|
|
41
|
-
- [ ] Server side components (api and database)
|
|
42
|
-
- [ ] Quick deploy option
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
## *JUX* Authoring UI's in pure javascript.
|
|
46
|
-
|
|
47
|
-
> Build beautiful, reactive UI's using only javascript. **No markup required.**
|
|
48
|
-
> A clean authorship layer capable of being taught to non-developers, strong enough to be used by real developers.
|
|
49
|
-
|
|
50
|
-
>> **jux** challenges the idea that markup based systems are the most efficient way to author web applications.
|
|
51
|
-
## AI friendly - **use less tokens!**
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
```diff
|
|
55
|
-
- Markup is expensive!
|
|
56
|
-
Have you ever considered the energy requirements to ship chunks of HTML markup like Vue or React components?
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Hello World
|
|
16
|
+
|
|
17
|
+
```js
|
|
18
|
+
// jux/index.jux
|
|
19
|
+
import { jux } from 'juxscript';
|
|
20
|
+
|
|
21
|
+
jux.h1('greeting', { content: 'Hello, World!' });
|
|
22
|
+
jux.p('intro', { content: 'Welcome to JUX — no HTML required.' });
|
|
23
|
+
jux.btn('click-me', { content: 'Click me' });
|
|
57
24
|
```
|
|
58
25
|
|
|
59
|
-
|
|
60
|
-
> As a user, I want to be efficient with the LLM's. I want my code to be clean. I want to avoid repeating myself. I ultimately, want to write less code. Less code is better code.
|
|
26
|
+
That's it. Three lines render a heading, a paragraph, and a button. The order you write them is the order they appear on the page.
|
|
61
27
|
|
|
62
|
-
|
|
28
|
+
---
|
|
63
29
|
|
|
64
|
-
|
|
30
|
+
## Why JUX?
|
|
65
31
|
|
|
66
|
-
|
|
32
|
+
- **Zero markup** — no HTML, no JSX, no templates
|
|
33
|
+
- **Procedural authoring** — top-down code flow, just like writing a script
|
|
34
|
+
- **Built-in reactivity** — `pageState` connects components automatically
|
|
35
|
+
- **Headless components** — styled by default, fully customisable
|
|
36
|
+
- **Any npm package** — standard ESM imports work out of the box
|
|
37
|
+
- **AI friendly** — less code, fewer tokens, cleaner prompts
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Getting Started
|
|
42
|
+
|
|
43
|
+
### Create a new project
|
|
67
44
|
|
|
68
45
|
```bash
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
npm install juxscript
|
|
46
|
+
npx juxscript create my-app
|
|
47
|
+
cd my-app
|
|
48
|
+
npm run dev
|
|
49
|
+
```
|
|
74
50
|
|
|
75
|
-
|
|
76
|
-
npx jux init
|
|
51
|
+
This scaffolds a new project, installs dependencies, and starts a hot-reload dev server.
|
|
77
52
|
|
|
78
|
-
|
|
79
|
-
|
|
53
|
+
### Add to an existing project
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npm install juxscript
|
|
57
|
+
npx juxscript init # creates jux/ directory and juxconfig.js
|
|
58
|
+
npm run dev
|
|
80
59
|
```
|
|
81
|
-
> install
|
|
82
|
-
`npm i juxscript`
|
|
83
60
|
|
|
84
|
-
|
|
61
|
+
### VS Code setup
|
|
62
|
+
|
|
63
|
+
JUX files use the `.jux` extension but are plain JavaScript. Tell VS Code:
|
|
85
64
|
|
|
86
65
|
```json
|
|
87
|
-
|
|
66
|
+
// .vscode/settings.json
|
|
88
67
|
{
|
|
89
68
|
"files.associations": {
|
|
90
|
-
"*.jux": "javascript"
|
|
91
|
-
"*.juxt": "javascript"
|
|
69
|
+
"*.jux": "javascript"
|
|
92
70
|
},
|
|
93
|
-
"javascript.validate.enable": false
|
|
94
|
-
"[javascript]": {
|
|
95
|
-
"editor.defaultFormatter": "vscode.typescript-language-features"
|
|
96
|
-
}
|
|
71
|
+
"javascript.validate.enable": false
|
|
97
72
|
}
|
|
98
73
|
```
|
|
99
74
|
|
|
100
|
-
|
|
101
|
-
`npm run dev`
|
|
75
|
+
---
|
|
102
76
|
|
|
103
|
-
|
|
104
|
-
`npm run build:examples`
|
|
77
|
+
## The `jux` Namespace
|
|
105
78
|
|
|
79
|
+
Every component is accessed through the `jux` object. Import it once and everything you need is there.
|
|
106
80
|
|
|
107
|
-
|
|
81
|
+
```js
|
|
82
|
+
import { jux } from 'juxscript';
|
|
83
|
+
```
|
|
108
84
|
|
|
109
|
-
|
|
110
|
-
Check out the presets, they speed this process up. Just modify them with your goals, such as logo, menu options, nav etc.
|
|
111
|
-
2. Build your Pages
|
|
112
|
-
Just get to work, using the **jux** component library to build most of what you need, filling in any details with *javascript* logically arranged the way you want. Think, authoring SFC but with only the composition layer.
|
|
113
|
-
3. Test it out!
|
|
114
|
-
Jux comes with a watcher system built in, so you can see your edits to *.jux* files live.
|
|
85
|
+
### Text & headings
|
|
115
86
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
87
|
+
```js
|
|
88
|
+
jux.h1('page-title', { content: 'Dashboard' });
|
|
89
|
+
jux.h2('section', { content: 'Overview' });
|
|
90
|
+
jux.p('description', { content: 'Here is your summary.' });
|
|
91
|
+
jux.span('note', { content: 'Updated just now' });
|
|
92
|
+
jux.pre('code-block', { content: 'const x = 42;' });
|
|
93
|
+
```
|
|
119
94
|
|
|
120
|
-
|
|
95
|
+
### Form inputs
|
|
96
|
+
|
|
97
|
+
```js
|
|
98
|
+
jux.input('username', { label: 'Username', placeholder: 'Enter name...' });
|
|
99
|
+
jux.email('email', { label: 'Email' });
|
|
100
|
+
jux.password('pass', { label: 'Password' });
|
|
101
|
+
jux.number('quantity', { label: 'Quantity', value: '1' });
|
|
102
|
+
jux.select('color', {
|
|
103
|
+
label: 'Favourite colour',
|
|
104
|
+
options: [
|
|
105
|
+
{ label: 'Red', value: 'red' },
|
|
106
|
+
{ label: 'Green', value: 'green' },
|
|
107
|
+
{ label: 'Blue', value: 'blue' }
|
|
108
|
+
]
|
|
109
|
+
});
|
|
110
|
+
jux.checkbox('agree', { label: 'I agree to the terms' });
|
|
111
|
+
jux.radio('size', {
|
|
112
|
+
label: 'Size',
|
|
113
|
+
options: [
|
|
114
|
+
{ label: 'Small', value: 'sm' },
|
|
115
|
+
{ label: 'Medium', value: 'md' },
|
|
116
|
+
{ label: 'Large', value: 'lg' }
|
|
117
|
+
]
|
|
118
|
+
});
|
|
119
|
+
```
|
|
121
120
|
|
|
122
|
-
###
|
|
123
|
-
- [ ] Laying out JUX files in a rational way.
|
|
124
|
-
> Develop a higher-level layout javascript grammar for building layouts and palettes of style using *ZERO markup*.
|
|
121
|
+
### Buttons & links
|
|
125
122
|
|
|
126
|
-
|
|
127
|
-
|
|
123
|
+
```js
|
|
124
|
+
jux.btn('save', { content: 'Save', variant: 'default' });
|
|
125
|
+
jux.btn('delete', { content: 'Delete', variant: 'destructive' });
|
|
126
|
+
jux.btn('cancel', { content: 'Cancel', variant: 'outline' });
|
|
127
|
+
jux.a('home-link', { content: 'Home', href: '/' });
|
|
128
|
+
```
|
|
128
129
|
|
|
129
|
-
###
|
|
130
|
+
### Layout & containers
|
|
130
131
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
```js
|
|
133
|
+
// c(width, height, padding, borderRadius)
|
|
134
|
+
const card = jux.c('100%', 'auto', '1rem', '8px');
|
|
134
135
|
|
|
135
|
-
|
|
136
|
+
// Render something inside the card
|
|
137
|
+
jux.p('card-text', { content: 'I live inside the card', target: card.id });
|
|
138
|
+
```
|
|
136
139
|
|
|
137
|
-
###
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
140
|
+
### Lists & tables
|
|
141
|
+
|
|
142
|
+
```js
|
|
143
|
+
jux.list('todo-list', {
|
|
144
|
+
items: [
|
|
145
|
+
{ id: 'a', content: 'Buy milk', icon: '🛒' },
|
|
146
|
+
{ id: 'b', content: 'Write code', icon: '💻' }
|
|
147
|
+
],
|
|
148
|
+
selectable: true
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
jux.table('users-table', {
|
|
152
|
+
columns: [
|
|
153
|
+
{ key: 'name', label: 'Name' },
|
|
154
|
+
{ key: 'email', label: 'Email' },
|
|
155
|
+
{ key: 'role', label: 'Role' }
|
|
156
|
+
],
|
|
157
|
+
items: [
|
|
158
|
+
{ name: 'Alice', email: 'alice@example.com', role: 'Admin' },
|
|
159
|
+
{ name: 'Bob', email: 'bob@example.com', role: 'User' }
|
|
160
|
+
]
|
|
161
|
+
});
|
|
162
|
+
```
|
|
144
163
|
|
|
145
|
-
###
|
|
164
|
+
### Navigation
|
|
146
165
|
|
|
147
|
-
|
|
166
|
+
```js
|
|
167
|
+
jux.nav('main-nav', {
|
|
168
|
+
items: [
|
|
169
|
+
{ id: 'nav-home', icon: '🏠', label: 'Home', path: '/' },
|
|
170
|
+
{ id: 'nav-settings', icon: '⚙️', label: 'Settings', path: '/settings' }
|
|
171
|
+
]
|
|
172
|
+
});
|
|
173
|
+
```
|
|
148
174
|
|
|
149
|
-
|
|
175
|
+
### Tabs
|
|
176
|
+
|
|
177
|
+
```js
|
|
178
|
+
const tabs = jux.tabs('page-tabs');
|
|
179
|
+
tabs.addTab({ id: 'overview', label: 'Overview', content: 'Overview content here.' });
|
|
180
|
+
tabs.addTab({ id: 'details', label: 'Details', content: 'Details content here.' });
|
|
181
|
+
tabs.activeTab('overview');
|
|
182
|
+
tabs.render('#app');
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Data fetching
|
|
186
|
+
|
|
187
|
+
```js
|
|
188
|
+
const api = await jux.data('my-api', { url: '/api/users' });
|
|
189
|
+
// api.value contains the response
|
|
190
|
+
console.log(api.getValue());
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Styles
|
|
194
|
+
|
|
195
|
+
```js
|
|
196
|
+
jux.include('/css/shadcn.css'); // inject a stylesheet link
|
|
197
|
+
jux.style('custom', 'body { margin: 0; }'); // inject inline CSS
|
|
198
|
+
```
|
|
150
199
|
|
|
151
|
-
> *At this point*, we are speaking almost 100% towards UI interfaces.
|
|
152
|
-
> Servers should be 'loosely coupled.'. This allows for a standard.
|
|
153
|
-
>>> In the future, we could introduce an *auto api* feature, similar to *next.js* api heuristic for folders and files.
|
|
154
200
|
---
|
|
155
201
|
|
|
202
|
+
## Reactivity with `pageState`
|
|
156
203
|
|
|
157
|
-
|
|
204
|
+
`pageState` is JUX's reactivity layer. Every component you create is automatically registered in `pageState`, keyed by its `id`. Read values, react to events, and update the DOM — all from plain JavaScript.
|
|
158
205
|
|
|
159
|
-
|
|
206
|
+
```js
|
|
207
|
+
import { jux, pageState } from 'juxscript';
|
|
208
|
+
```
|
|
160
209
|
|
|
161
|
-
|
|
162
|
-
- [ ] Chore: Cleanup our `machinery/server.js` to separate concerns and build our actual endpoints we need to build software here.
|
|
210
|
+
### Reading & writing state
|
|
163
211
|
|
|
164
|
-
|
|
212
|
+
```js
|
|
213
|
+
jux.input('search', { label: 'Search' });
|
|
214
|
+
jux.p('result', { content: '' });
|
|
165
215
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
216
|
+
// Whenever 'search' changes, update 'result'
|
|
217
|
+
pageState.__watch(() => {
|
|
218
|
+
pageState['result'].content = 'You typed: ' + pageState['search'].value;
|
|
219
|
+
});
|
|
220
|
+
```
|
|
170
221
|
|
|
171
|
-
|
|
172
|
-
- [ ] Chore for this? This takes more analysis, discussion.
|
|
222
|
+
### Reacting to events
|
|
173
223
|
|
|
174
|
-
|
|
175
|
-
-
|
|
176
|
-
|
|
177
|
-
> API's
|
|
178
|
-
- [ ] Base payload creater and consumer as a **jux** component. *jux.api*??
|
|
224
|
+
```js
|
|
225
|
+
jux.btn('submit-btn', { content: 'Submit' });
|
|
226
|
+
jux.p('status', { content: 'Waiting...' });
|
|
179
227
|
|
|
180
|
-
|
|
228
|
+
pageState.__watch(() => {
|
|
229
|
+
if (pageState['submit-btn'].click) {
|
|
230
|
+
pageState['status'].content = 'Submitted! ✅';
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
```
|
|
181
234
|
|
|
182
|
-
|
|
235
|
+
Available event flags: `click`, `change`, `input`, `blur`, `focus`, `keydown`, `keyup`, `hover`, `active`, `focused`.
|
|
183
236
|
|
|
184
|
-
|
|
185
|
-
Currently it looks like this:
|
|
186
|
-
- [ ] Chore: **WHAT IS ACTUALLY BEING USED AND WHERE?**
|
|
237
|
+
### Chaining reactions
|
|
187
238
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
239
|
+
Reactions re-run whenever any `pageState` value they read changes — just like a spreadsheet. Chain them freely:
|
|
240
|
+
|
|
241
|
+
```js
|
|
242
|
+
jux.input('first-name', { label: 'First name' });
|
|
243
|
+
jux.input('last-name', { label: 'Last name' });
|
|
244
|
+
jux.p('full-name', { content: '' });
|
|
245
|
+
|
|
246
|
+
// Reacts to either input changing
|
|
247
|
+
pageState.__watch(() => {
|
|
248
|
+
const first = pageState['first-name'].value;
|
|
249
|
+
const last = pageState['last-name'].value;
|
|
250
|
+
pageState['full-name'].content = `${first} ${last}`.trim();
|
|
251
|
+
});
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Conditional rendering
|
|
255
|
+
|
|
256
|
+
Because authoring is top-down procedural code, you can use plain `if` statements:
|
|
257
|
+
|
|
258
|
+
```js
|
|
259
|
+
jux.input('promo-code', { label: 'Promo code' });
|
|
260
|
+
|
|
261
|
+
pageState.__watch(() => {
|
|
262
|
+
if (pageState['promo-code'].value === 'JUXROCKS') {
|
|
263
|
+
jux.p('promo-msg', { content: '🎉 10% discount applied!' });
|
|
207
264
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
server: {
|
|
211
|
-
port: process.env.PORT || 3000,
|
|
212
|
-
host: process.env.HOST || 'localhost'
|
|
213
|
-
},
|
|
214
|
-
|
|
215
|
-
};
|
|
216
|
-
```
|
|
217
|
-
**As a user, I will want to control where JUX sends queries.**
|
|
218
|
-
**As a user, I may want to specify a default proxy for backend. I may also want to specify, explicitly, URL's to hit other service endpoints**
|
|
219
|
-
- [ ] Escape hatch (backend API proxy vs default)
|
|
220
|
-
- [ ] As a user, I may want to run my own server for backend requests/proxies.
|
|
221
|
-
- [ ] As a user, I may want to hit multiple endpoints in the same JUX file.
|
|
265
|
+
});
|
|
266
|
+
```
|
|
222
267
|
|
|
223
|
-
|
|
268
|
+
### Visibility toggling
|
|
224
269
|
|
|
225
|
-
|
|
270
|
+
```js
|
|
271
|
+
jux.p('hint', { content: 'Fill in all fields first.' });
|
|
226
272
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
273
|
+
pageState.__watch(() => {
|
|
274
|
+
pageState['hint'].visible = pageState['username'].value === '';
|
|
275
|
+
});
|
|
276
|
+
```
|
|
231
277
|
|
|
232
278
|
---
|
|
233
|
-
## REACTIVITY LAYER.
|
|
234
|
-
### Goal for Reactivity
|
|
235
|
-
> We are shooting for better than nasty amounts of javascript, not as sophisticated as vue/react.
|
|
236
279
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
280
|
+
## Layout with `c` (Container)
|
|
281
|
+
|
|
282
|
+
`c` is a lightweight container that handles sizing and layout without any CSS classes.
|
|
283
|
+
|
|
284
|
+
```js
|
|
285
|
+
import { jux, c } from 'juxscript';
|
|
286
|
+
|
|
287
|
+
// c(width, height, padding, borderRadius)
|
|
288
|
+
const sidebar = c('260px', '100vh', '1rem', '0');
|
|
289
|
+
const main = c('calc(100% - 260px)', '100vh', '2rem', '0');
|
|
290
|
+
|
|
291
|
+
// Nest components inside a container using target
|
|
292
|
+
jux.h2('sidebar-title', { content: 'Menu', target: sidebar.id });
|
|
293
|
+
jux.h1('page-heading', { content: 'Welcome', target: main.id });
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## Component Presets
|
|
299
|
+
|
|
300
|
+
Copy ready-made components into your project with:
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
npx juxscript comp sidebar
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
Available presets:
|
|
307
|
+
|
|
308
|
+
| Preset | Description |
|
|
309
|
+
|-----------|------------------------------------------|
|
|
310
|
+
| `sidebar` | Collapsible sidebar with nav sections |
|
|
311
|
+
|
|
312
|
+
More presets coming soon. Contribute your own to `components/`.
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## Advanced: Charts
|
|
317
|
+
|
|
318
|
+
JUX ships with a bar chart component you can drop into any page.
|
|
319
|
+
|
|
320
|
+
### Horizontal bar chart
|
|
321
|
+
|
|
322
|
+
```js
|
|
323
|
+
import { juxBarChart } from './bar.jux';
|
|
324
|
+
|
|
325
|
+
juxBarChart('revenue-chart', [
|
|
326
|
+
{ x: 4200, label: 'Jan' },
|
|
327
|
+
{ x: 5800, label: 'Feb' },
|
|
328
|
+
{ x: 3900, label: 'Mar' },
|
|
329
|
+
{ x: 7100, label: 'Apr' }
|
|
330
|
+
], {
|
|
331
|
+
title: 'Monthly Revenue',
|
|
332
|
+
subtitle: 'USD, 2024',
|
|
333
|
+
orientation: 'horizontal',
|
|
334
|
+
colors: 'blue',
|
|
335
|
+
width: 600,
|
|
336
|
+
showValues: true
|
|
337
|
+
}).render('#app');
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Vertical bar chart
|
|
341
|
+
|
|
342
|
+
```js
|
|
343
|
+
juxBarChart('visitors', [
|
|
344
|
+
{ x: 1200, label: 'Mon' },
|
|
345
|
+
{ x: 980, label: 'Tue' },
|
|
346
|
+
{ x: 1540, label: 'Wed' }
|
|
347
|
+
], {
|
|
348
|
+
orientation: 'vertical',
|
|
349
|
+
colors: 'green',
|
|
350
|
+
width: 500
|
|
351
|
+
}).render('#app');
|
|
352
|
+
```
|
|
242
353
|
|
|
243
|
-
###
|
|
244
|
-
- [ ] JWT Authentication (`authJWT`) (demo `examples` only)
|
|
245
|
-
- [ ] Token generation (demo `examples` only)
|
|
246
|
-
- [ ] Token validation middleware (demo `examples` only)
|
|
247
|
-
- [ ] Refresh token logic (demo `examples` only)
|
|
248
|
-
- [ ] *Login system PAGES! Ships with `vendor` assets like lib files/layouts etc.*
|
|
249
|
-
- [ ] Login
|
|
250
|
-
- [ ] Logout
|
|
251
|
-
- [ ] Profile
|
|
354
|
+
### Chart options
|
|
252
355
|
|
|
356
|
+
| Option | Default | Description |
|
|
357
|
+
|---------------|----------------|---------------------------------------------|
|
|
358
|
+
| `orientation` | `'horizontal'` | `'horizontal'` or `'vertical'` |
|
|
359
|
+
| `colors` | `'green'` | Palette name or array of hex colours |
|
|
360
|
+
| `title` | `''` | Chart title |
|
|
361
|
+
| `subtitle` | `''` | Chart subtitle |
|
|
362
|
+
| `width` | `500` | Width in pixels |
|
|
363
|
+
| `aspectRatio` | `'16:9'` | `'16:9'`, `'4:3'`, `'1:1'`, `'21:9'`, etc. |
|
|
364
|
+
| `showValues` | `false` | Show value labels on bars |
|
|
365
|
+
| `ticks` | `4` | Number of axis tick marks |
|
|
366
|
+
| `animate` | `true` | Animate bars on load |
|
|
253
367
|
|
|
254
|
-
###
|
|
255
|
-
- [ ] API documentation
|
|
256
|
-
- [ ] Testing setup
|
|
368
|
+
### Colour palettes
|
|
257
369
|
|
|
370
|
+
```js
|
|
371
|
+
import { jux } from 'juxscript';
|
|
258
372
|
|
|
373
|
+
// Named palettes
|
|
374
|
+
jux.palette('green'); // greens
|
|
375
|
+
jux.palette('blue'); // blues
|
|
376
|
+
jux.palette('multi'); // multi-colour
|
|
259
377
|
|
|
378
|
+
// Or pass a custom array
|
|
379
|
+
colors: ['#6366f1', '#8b5cf6', '#a78bfa']
|
|
380
|
+
```
|
|
260
381
|
|
|
382
|
+
---
|
|
261
383
|
|
|
262
|
-
|
|
263
|
-
|
|
384
|
+
## Authoring a Full Page — Realistic Example
|
|
385
|
+
|
|
386
|
+
```js
|
|
387
|
+
// jux/dashboard.jux
|
|
388
|
+
import { jux, pageState } from 'juxscript';
|
|
389
|
+
import { juxBarChart } from './bar.jux';
|
|
390
|
+
|
|
391
|
+
// ── Layout ─────────────────────────────────────────────────────
|
|
392
|
+
jux.h1('dash-title', { content: 'Sales Dashboard' });
|
|
393
|
+
jux.p('dash-subtitle', { content: 'Real-time overview' });
|
|
394
|
+
|
|
395
|
+
// ── Filters ────────────────────────────────────────────────────
|
|
396
|
+
jux.select('period', {
|
|
397
|
+
label: 'Period',
|
|
398
|
+
options: [
|
|
399
|
+
{ label: 'This week', value: 'week' },
|
|
400
|
+
{ label: 'This month', value: 'month' },
|
|
401
|
+
{ label: 'This year', value: 'year' }
|
|
402
|
+
]
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
// ── Chart ──────────────────────────────────────────────────────
|
|
406
|
+
juxBarChart('sales-chart', [
|
|
407
|
+
{ x: 3200, label: 'Mon' },
|
|
408
|
+
{ x: 4100, label: 'Tue' },
|
|
409
|
+
{ x: 2900, label: 'Wed' },
|
|
410
|
+
{ x: 5300, label: 'Thu' },
|
|
411
|
+
{ x: 4800, label: 'Fri' }
|
|
412
|
+
], { title: 'Sales This Week', colors: 'blue', width: 600 }).render('#app');
|
|
413
|
+
|
|
414
|
+
// ── Table ──────────────────────────────────────────────────────
|
|
415
|
+
jux.table('top-products', {
|
|
416
|
+
columns: [
|
|
417
|
+
{ key: 'name', label: 'Product' },
|
|
418
|
+
{ key: 'sales', label: 'Sales' },
|
|
419
|
+
{ key: 'rev', label: 'Revenue' }
|
|
420
|
+
],
|
|
421
|
+
items: [
|
|
422
|
+
{ name: 'Widget A', sales: 320, rev: '$6,400' },
|
|
423
|
+
{ name: 'Widget B', sales: 210, rev: '$4,200' }
|
|
424
|
+
]
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
// ── Reactivity ─────────────────────────────────────────────────
|
|
428
|
+
jux.p('selected-period', { content: 'Showing: This week' });
|
|
429
|
+
|
|
430
|
+
pageState.__watch(() => {
|
|
431
|
+
const p = pageState['period'].value;
|
|
432
|
+
if (p) pageState['selected-period'].content = 'Showing: ' + p;
|
|
433
|
+
});
|
|
434
|
+
```
|
|
264
435
|
|
|
265
|
-
|
|
436
|
+
---
|
|
266
437
|
|
|
267
|
-
|
|
438
|
+
## CLI Reference
|
|
268
439
|
|
|
269
|
-
|
|
440
|
+
```bash
|
|
441
|
+
npx juxscript create <name> # Scaffold a new project
|
|
442
|
+
npx juxscript init # Init JUX in an existing directory
|
|
443
|
+
npx juxscript serve # Start production server
|
|
444
|
+
npx juxscript serve --hot # Start dev server with hot reload
|
|
445
|
+
npx juxscript build # Build for production
|
|
446
|
+
npx juxscript comp [name] # Add a component preset
|
|
447
|
+
npx juxscript comp [name] -f # Force overwrite (backs up existing)
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
---
|
|
451
|
+
|
|
452
|
+
## Project Structure
|
|
453
|
+
|
|
454
|
+
```
|
|
455
|
+
my-app/
|
|
456
|
+
├── jux/
|
|
457
|
+
│ ├── index.jux ← entry page (rendered at /)
|
|
458
|
+
│ ├── about.jux ← rendered at /about
|
|
459
|
+
│ └── sidebar/ ← component presets live here
|
|
460
|
+
│ └── index.jux
|
|
461
|
+
├── public/
|
|
462
|
+
│ └── styles.css
|
|
463
|
+
├── juxconfig.js
|
|
464
|
+
└── package.json
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
---
|
|
468
|
+
|
|
469
|
+
## Configuration (`juxconfig.js`)
|
|
470
|
+
|
|
471
|
+
```js
|
|
472
|
+
export const config = {
|
|
473
|
+
directories: {
|
|
474
|
+
src: 'jux',
|
|
475
|
+
public: 'public',
|
|
476
|
+
dist: '.jux-dist'
|
|
477
|
+
},
|
|
478
|
+
server: {
|
|
479
|
+
port: 3000,
|
|
480
|
+
host: 'localhost'
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
---
|
|
270
486
|
|
|
271
|
-
|
|
487
|
+
## Roadmap
|
|
488
|
+
|
|
489
|
+
- [x] Core component library (inputs, buttons, tables, lists, nav, tabs, charts)
|
|
490
|
+
- [x] `pageState` reactivity system
|
|
491
|
+
- [x] Router with nested routes and layouts
|
|
492
|
+
- [x] Hot-reload dev server
|
|
493
|
+
- [x] Component presets (`jux comp`)
|
|
494
|
+
- [ ] Cross-page state store
|
|
495
|
+
- [ ] Distributable static site bundles
|
|
496
|
+
- [ ] Data drivers (file, S3, database)
|
|
497
|
+
- [ ] CDN bundle
|
|
498
|
+
- [ ] Icon component
|
|
499
|
+
- [ ] More component presets (mobile nav, login page, profile page)
|