anentrypoint-design 0.0.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.
- package/README.md +77 -0
- package/dist/247420.app.js +1 -0
- package/dist/247420.css +1430 -0
- package/dist/247420.js +217 -0
- package/package.json +45 -0
- package/src/app.js +131 -0
- package/src/components.js +280 -0
- package/src/deck-stage.js +17 -0
- package/src/index.js +30 -0
- package/src/styles.js +4 -0
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "anentrypoint-design",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "247420 design system SDK — webjsx + modified ripple-ui, single-file ESM bundle for reproducible use of the AnEntrypoint design.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/247420.js",
|
|
7
|
+
"module": "./dist/247420.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/247420.js",
|
|
11
|
+
"default": "./dist/247420.js"
|
|
12
|
+
},
|
|
13
|
+
"./app": "./dist/247420.app.js",
|
|
14
|
+
"./css": "./dist/247420.css",
|
|
15
|
+
"./package.json": "./package.json"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"src",
|
|
20
|
+
"README.md"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "node scripts/build.mjs"
|
|
24
|
+
},
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/AnEntrypoint/Design.git"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"247420",
|
|
31
|
+
"anentrypoint",
|
|
32
|
+
"design-system",
|
|
33
|
+
"webjsx",
|
|
34
|
+
"rippleui"
|
|
35
|
+
],
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"esbuild": "^0.28.0",
|
|
42
|
+
"postcss": "^8.5.12",
|
|
43
|
+
"postcss-prefix-selector": "^2.1.1"
|
|
44
|
+
}
|
|
45
|
+
}
|
package/src/app.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// Unified 247420 single-page app. Replaces the separate homepage,
|
|
2
|
+
// project_page, writing, and manifesto entry points with one WebJSX page
|
|
3
|
+
// that uses the design-system components and hash routing.
|
|
4
|
+
import { h, mount, installStyles, components as C } from './index.js';
|
|
5
|
+
|
|
6
|
+
const data = {
|
|
7
|
+
nav: [['works', '#/works'], ['writing', '#/writing'], ['manifesto', '#/manifesto'], ['source ↗', 'https://github.com/AnEntrypoint']],
|
|
8
|
+
works: [
|
|
9
|
+
{ code: '001', title: 'gm', sub: 'state machine for coding agents', meta: '2025 · 3k★', body: 'a tiny deterministic state machine that lets llms code without losing their minds. it thinks so you don\'t have to (as much).' },
|
|
10
|
+
{ code: '002', title: 'zellous', sub: 'production push-to-talk', meta: '2024 · live', body: 'hold the button. talk. someone on the other side hears you. opus codec, dynamic rooms, 50-message replay.' },
|
|
11
|
+
{ code: '003', title: 'spoint', sub: 'spawnpoint', meta: '2024 · live', body: 'the directory for "where should we start?" one url, one room, everyone lands in the same place.' },
|
|
12
|
+
{ code: '004', title: 'flatspace', sub: 'flat-file cms', meta: 'wip', body: 'still figuring out what to say about this one. come back tuesday.' },
|
|
13
|
+
{ code: '005', title: 'thebird', sub: '—', meta: 'wip', body: 'yes, the name is a reference. no, we won\'t tell you to what.' },
|
|
14
|
+
{ code: '006', title: 'mcp-repl', sub: 'repl for mcp', meta: '2024 · live', body: 'executenodejs, executedeno, executebash, astgrep_search.' },
|
|
15
|
+
{ code: '007', title: 'mutagen', sub: 'adaptogen server', meta: '2024 · live', body: 'everything to do with a dapp deg3n. read the source.' },
|
|
16
|
+
{ code: '008', title: 'techshaman', sub: 'member site', meta: 'ongoing', body: 'the official website for the techshaman.' }
|
|
17
|
+
],
|
|
18
|
+
posts: [
|
|
19
|
+
{ date: '2026.04.14', title: 'we were here first', tag: 'lore' },
|
|
20
|
+
{ date: '2026.03.22', title: 'gm v0.4 postmortem, or: why state machines', tag: 'gm' },
|
|
21
|
+
{ date: '2026.02.09', title: 'push-to-talk is a protocol, not a feature', tag: 'zellous' },
|
|
22
|
+
{ date: '2025.12.11', title: 'against the vibe-coded interface', tag: 'manifesto' },
|
|
23
|
+
{ date: '2025.10.03', title: 'notes on shipping weird', tag: 'notes' }
|
|
24
|
+
],
|
|
25
|
+
manifesto: [
|
|
26
|
+
{ text: 'we are the creative department of the internet. always open (24/7). always a little bit high on possibility (420).' },
|
|
27
|
+
{ text: 'move fast. break things. document honestly. ship the rough draft. humor is load-bearing.' },
|
|
28
|
+
{ text: 'we will not tolerate simpleton design patterns, trifectas, gradients, or anything silly. nothing lame. we\'re internet natives and not easily pleased.', dim: true }
|
|
29
|
+
],
|
|
30
|
+
currentlyShipping: [
|
|
31
|
+
{ title: 'gm', sub: 'state machine v0.4.1', meta: 'live', live: true },
|
|
32
|
+
{ title: 'zellous', sub: 'push-to-talk', meta: 'live', live: true },
|
|
33
|
+
{ title: 'thebird', sub: '—', meta: 'wip', live: false }
|
|
34
|
+
],
|
|
35
|
+
project: {
|
|
36
|
+
name: 'gm', tagline: 'state machine for coding agents. it thinks, so you don\'t have to (as much).',
|
|
37
|
+
install: 'npx -y @anentrypoint/mcp-gm',
|
|
38
|
+
receipt: [['status', 'live · ships tuesdays'], ['stars', '3,124'], ['license', 'MIT'], ['lang', 'typescript · deno'], ['size', '2.1mb'], ['deps', '0 runtime'], ['authors', 'the collective'], ['first commit', '2024.09.03']],
|
|
39
|
+
changelog: [
|
|
40
|
+
{ date: '2026.04.20', ver: 'v0.4.1', msg: 'ship it. fixed the thing everyone complained about.' },
|
|
41
|
+
{ date: '2026.03.22', ver: 'v0.4.0', msg: 'new state machine runtime. broke everything on purpose.' },
|
|
42
|
+
{ date: '2026.02.09', ver: 'v0.3.7', msg: 'astgrep_search is now astgrep_enhanced_search.' },
|
|
43
|
+
{ date: '2025.12.11', ver: 'v0.3.0', msg: 'first public release. gm, world.' }
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const state = {
|
|
49
|
+
route: parseRoute(),
|
|
50
|
+
opened: -1,
|
|
51
|
+
copied: false
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
function parseRoute() {
|
|
55
|
+
const m = (location.hash || '#/').slice(1).split('/').filter(Boolean);
|
|
56
|
+
return { page: m[0] || 'works', id: m[1] || null };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
window.addEventListener('hashchange', () => {
|
|
60
|
+
state.route = parseRoute();
|
|
61
|
+
render();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
let render;
|
|
65
|
+
|
|
66
|
+
function navigate(name) {
|
|
67
|
+
location.hash = '#/' + name;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function topbar() {
|
|
71
|
+
return C.Topbar({
|
|
72
|
+
brand: '247420', leaf: 'an entrypoint',
|
|
73
|
+
items: data.nav,
|
|
74
|
+
active: state.route.page,
|
|
75
|
+
onNav: navigate
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function crumb() {
|
|
80
|
+
if (state.route.page === 'project') {
|
|
81
|
+
return C.Crumb({
|
|
82
|
+
trail: ['247420', 'gm'], leaf: 'overview',
|
|
83
|
+
right: [C.Chip({ tone: 'accent', children: '● live' }), C.Chip({ tone: 'dim', children: 'v0.4.1' })]
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
return C.Crumb({ trail: ['247420'], leaf: state.route.page });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function status() {
|
|
90
|
+
return C.Status({
|
|
91
|
+
left: ['main', '• 8 works', '• 5 posts'],
|
|
92
|
+
right: ['probably emerging', h('a', { href: 'https://github.com/AnEntrypoint' }, 'source ↗')]
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function pageMain() {
|
|
97
|
+
const r = state.route.page;
|
|
98
|
+
if (r === 'project') {
|
|
99
|
+
return C.ProjectView({
|
|
100
|
+
project: data.project,
|
|
101
|
+
copied: state.copied,
|
|
102
|
+
onCopy: (cmd) => { navigator.clipboard?.writeText(cmd); state.copied = true; render(); setTimeout(() => { state.copied = false; render(); }, 1200); }
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
if (r === 'writing') {
|
|
106
|
+
return [C.Section({ title: '// recent writing', children: C.WritingList({ posts: data.posts }) })];
|
|
107
|
+
}
|
|
108
|
+
if (r === 'manifesto') {
|
|
109
|
+
return [C.Section({ title: '// manifesto · rough draft', children: C.Manifesto({ paragraphs: data.manifesto }) })];
|
|
110
|
+
}
|
|
111
|
+
return C.HomeView({
|
|
112
|
+
state, onNav: navigate,
|
|
113
|
+
onToggleWork: (i) => { state.opened = i; render(); },
|
|
114
|
+
works: data.works, posts: data.posts, manifesto: data.manifesto,
|
|
115
|
+
currentlyShipping: data.currentlyShipping
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function App() {
|
|
120
|
+
return C.AppShell({
|
|
121
|
+
topbar: topbar(),
|
|
122
|
+
crumb: crumb(),
|
|
123
|
+
main: pageMain(),
|
|
124
|
+
status: status(),
|
|
125
|
+
narrow: state.route.page === 'project'
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
await installStyles();
|
|
130
|
+
const root = document.getElementById('root');
|
|
131
|
+
render = mount(root, App);
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import * as webjsx from '../vendor/webjsx/index.js';
|
|
2
|
+
const h = webjsx.createElement;
|
|
3
|
+
|
|
4
|
+
// ---------- primitives ----------
|
|
5
|
+
|
|
6
|
+
export function Brand({ name = '247420', leaf } = {}) {
|
|
7
|
+
return h('span', { class: 'brand' }, name,
|
|
8
|
+
leaf ? h('span', { class: 'slash' }, ' / ') : null,
|
|
9
|
+
leaf || null);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function Chip({ tone = '', children }) {
|
|
13
|
+
return h('span', { class: 'chip' + (tone ? ' ' + tone : '') }, children);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function Btn({ href = '#', primary, children, onClick }) {
|
|
17
|
+
return h('a', {
|
|
18
|
+
class: primary ? 'btn-primary' : 'btn',
|
|
19
|
+
href,
|
|
20
|
+
onclick: onClick
|
|
21
|
+
}, children);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function Glyph({ children, color }) {
|
|
25
|
+
return h('span', { class: 'glyph', style: color ? `color:${color}` : '' }, children);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// ---------- chrome ----------
|
|
29
|
+
|
|
30
|
+
export function Topbar({ brand = '247420', leaf = '', items = [], active = '', onNav, search } = {}) {
|
|
31
|
+
return h('header', { class: 'app-topbar' },
|
|
32
|
+
Brand({ name: brand, leaf }),
|
|
33
|
+
search ? h('label', { class: 'app-search' },
|
|
34
|
+
h('span', { class: 'icon' }, '⌕'),
|
|
35
|
+
h('input', { type: 'search', placeholder: search, 'aria-label': 'search' })
|
|
36
|
+
) : null,
|
|
37
|
+
h('nav', {}, ...items.map(([label, href]) =>
|
|
38
|
+
h('a', {
|
|
39
|
+
key: label,
|
|
40
|
+
href,
|
|
41
|
+
class: active === label.replace(' ↗', '') ? 'active' : '',
|
|
42
|
+
onclick: (e) => {
|
|
43
|
+
if (!String(href).startsWith('http') && onNav) {
|
|
44
|
+
e.preventDefault();
|
|
45
|
+
onNav(label.replace(' ↗', ''));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}, label)
|
|
49
|
+
))
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function Crumb({ trail = [], leaf = '', right } = {}) {
|
|
54
|
+
const parts = [];
|
|
55
|
+
trail.forEach((t, i) => {
|
|
56
|
+
parts.push(h('span', { key: 't' + i }, t));
|
|
57
|
+
parts.push(h('span', { key: 's' + i, class: 'sep' }, '›'));
|
|
58
|
+
});
|
|
59
|
+
parts.push(h('span', { key: 'leaf', class: 'leaf' }, leaf));
|
|
60
|
+
if (right) parts.push(h('span', { key: 'r', style: 'margin-left:auto;display:flex;gap:10px;align-items:center' }, ...(Array.isArray(right) ? right : [right])));
|
|
61
|
+
return h('div', { class: 'app-crumb' }, ...parts);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function Side({ sections = [] } = {}) {
|
|
65
|
+
return h('aside', { class: 'app-side' }, ...sections.flatMap(sec => [
|
|
66
|
+
h('div', { class: 'group', key: sec.group }, sec.group),
|
|
67
|
+
...sec.items.map((item, i) => {
|
|
68
|
+
const { glyph, label, href = '#', active, count, color, onClick } = item;
|
|
69
|
+
return h('a', {
|
|
70
|
+
key: sec.group + i,
|
|
71
|
+
href,
|
|
72
|
+
class: active ? 'active' : '',
|
|
73
|
+
onclick: onClick
|
|
74
|
+
},
|
|
75
|
+
glyph != null ? Glyph({ children: glyph, color }) : null,
|
|
76
|
+
h('span', {}, label),
|
|
77
|
+
count != null ? h('span', { class: 'count' }, String(count)) : null
|
|
78
|
+
);
|
|
79
|
+
})
|
|
80
|
+
]));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function Status({ left = [], right = [] } = {}) {
|
|
84
|
+
return h('footer', { class: 'app-status' },
|
|
85
|
+
...left.map((t, i) => h('span', { key: 'l' + i, class: 'item' }, t)),
|
|
86
|
+
h('span', { class: 'spread' }),
|
|
87
|
+
...right.map((t, i) => h('span', { key: 'r' + i, class: 'item' }, t))
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function AppShell({ topbar, crumb, side, main, status, narrow } = {}) {
|
|
92
|
+
return h('div', { class: 'app' },
|
|
93
|
+
topbar || null,
|
|
94
|
+
crumb || null,
|
|
95
|
+
h('div', { class: 'app-body' + (side ? '' : ' no-side') },
|
|
96
|
+
side || null,
|
|
97
|
+
h('main', { class: 'app-main' + (narrow ? ' narrow' : '') }, ...(Array.isArray(main) ? main : [main]))
|
|
98
|
+
),
|
|
99
|
+
status || null
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ---------- panels & rows ----------
|
|
104
|
+
|
|
105
|
+
export function Panel({ title, count, right, style = '', children }) {
|
|
106
|
+
return h('div', { class: 'panel', style },
|
|
107
|
+
title != null ? h('div', { class: 'panel-head' },
|
|
108
|
+
h('span', {}, title),
|
|
109
|
+
right != null ? right : (count != null ? h('span', {}, String(count)) : null)
|
|
110
|
+
) : null,
|
|
111
|
+
h('div', { class: 'panel-body' }, ...(Array.isArray(children) ? children : [children]))
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function Row({ code, title, sub, meta, active, onClick, key, style }) {
|
|
116
|
+
return h('div', {
|
|
117
|
+
key,
|
|
118
|
+
class: 'row' + (active ? ' active' : ''),
|
|
119
|
+
onclick: onClick,
|
|
120
|
+
style
|
|
121
|
+
},
|
|
122
|
+
code != null ? h('span', { class: 'code' }, code) : null,
|
|
123
|
+
h('span', { class: 'title' }, title, sub ? h('span', { class: 'sub' }, sub) : null),
|
|
124
|
+
meta != null ? h('span', { class: 'meta' }, meta) : null
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function RowLink({ code, title, sub, meta, href = '#', key }) {
|
|
129
|
+
return h('a', { key, class: 'row', href },
|
|
130
|
+
code != null ? h('span', { class: 'code' }, code) : null,
|
|
131
|
+
h('span', { class: 'title' }, title, sub ? h('span', { class: 'sub' }, sub) : null),
|
|
132
|
+
meta != null ? h('span', { class: 'meta' }, meta) : null
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ---------- content blocks ----------
|
|
137
|
+
|
|
138
|
+
export function Heading({ level = 1, children, style = '' }) {
|
|
139
|
+
return h('h' + level, { style }, children);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function Lede({ children }) {
|
|
143
|
+
return h('p', { class: 'lede' }, children);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function Hero({ title, body, accent, badge, badgeCount }) {
|
|
147
|
+
return h('div', { style: 'padding:32px 32px 24px 32px' },
|
|
148
|
+
h('h1', { style: 'font-size:36px;font-weight:600;margin:0 0 4px 0;color:var(--panel-text);letter-spacing:-0.01em' }, title),
|
|
149
|
+
body ? h('p', { style: 'font-size:14px;line-height:1.55;color:var(--panel-text-2);max-width:64ch;margin:0 0 20px 0' },
|
|
150
|
+
body,
|
|
151
|
+
accent ? h('span', { style: 'color:var(--panel-accent);font-weight:500' }, ' ' + accent) : null
|
|
152
|
+
) : null,
|
|
153
|
+
badge ? Panel({ title: badge, count: badgeCount, style: 'max-width:560px;margin:0', children: [] }) : null
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function Install({ cmd, copied, onCopy }) {
|
|
158
|
+
return h('div', { class: 'cli' },
|
|
159
|
+
h('span', { class: 'prompt' }, '$'),
|
|
160
|
+
h('span', { class: 'cmd' }, cmd),
|
|
161
|
+
h('span', { class: 'copy', onclick: () => onCopy && onCopy(cmd) }, copied ? 'copied' : 'copy')
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function Receipt({ rows = [] }) {
|
|
166
|
+
return h('table', { class: 'kv' },
|
|
167
|
+
h('tbody', {}, ...rows.map(([k, v], i) =>
|
|
168
|
+
h('tr', { key: i }, h('td', {}, k), h('td', {}, v))
|
|
169
|
+
))
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function Changelog({ entries = [] }) {
|
|
174
|
+
return Panel({
|
|
175
|
+
style: 'max-width:900px',
|
|
176
|
+
children: entries.map((e, i) =>
|
|
177
|
+
h('div', { key: i, class: 'row', style: 'grid-template-columns:100px 70px 1fr' },
|
|
178
|
+
h('span', { class: 'code' }, e.date),
|
|
179
|
+
h('span', { style: 'color:var(--panel-accent);font-family:var(--ff-mono);font-size:12px' }, e.ver),
|
|
180
|
+
h('span', { class: 'title' }, e.msg)
|
|
181
|
+
)
|
|
182
|
+
)
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export function WorksList({ works = [], openedIndex = -1, onToggle }) {
|
|
187
|
+
return Panel({
|
|
188
|
+
title: `works · ${String(works.length).padStart(2, '0')} of ~${works.length}`,
|
|
189
|
+
right: h('a', { href: 'https://github.com/AnEntrypoint', style: 'color:var(--panel-accent);text-decoration:none' }, 'all repos ↗'),
|
|
190
|
+
children: works.map((w, i) => {
|
|
191
|
+
const isOpen = openedIndex === i;
|
|
192
|
+
return h('div', { key: i },
|
|
193
|
+
Row({
|
|
194
|
+
code: w.code, title: w.title, sub: w.sub,
|
|
195
|
+
meta: w.meta + ' ' + (isOpen ? '−' : '+'),
|
|
196
|
+
active: isOpen,
|
|
197
|
+
onClick: () => onToggle && onToggle(isOpen ? -1 : i)
|
|
198
|
+
}),
|
|
199
|
+
isOpen ? h('div', { style: 'padding:14px 20px 18px 86px;background:var(--panel-2);color:var(--panel-text);font-size:13px;line-height:1.6' },
|
|
200
|
+
h('p', { style: 'margin:0 0 12px 0;max-width:64ch' }, w.body),
|
|
201
|
+
h('div', { style: 'display:flex;gap:8px' },
|
|
202
|
+
Btn({ primary: true, href: w.href || '#', children: 'open ↗' }),
|
|
203
|
+
Btn({ href: w.source || '#', children: 'source' })
|
|
204
|
+
)
|
|
205
|
+
) : null
|
|
206
|
+
);
|
|
207
|
+
})
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function WritingList({ posts = [] }) {
|
|
212
|
+
return Panel({
|
|
213
|
+
children: posts.map((p, i) =>
|
|
214
|
+
RowLink({ key: i, code: p.date, title: p.title, meta: '§ ' + p.tag, href: p.href || '#' })
|
|
215
|
+
)
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export function Manifesto({ paragraphs = [], maxWidth = 820 }) {
|
|
220
|
+
return Panel({
|
|
221
|
+
style: `max-width:${maxWidth}px`,
|
|
222
|
+
children: h('div', { style: 'padding:20px 24px;font-size:14px;line-height:1.7;color:var(--panel-text)' },
|
|
223
|
+
...paragraphs.map((p, i) => h('p', {
|
|
224
|
+
key: i,
|
|
225
|
+
style: 'margin:0 0 12px 0' + (p.dim ? ';color:var(--panel-text-2)' : '')
|
|
226
|
+
}, p.text || p))
|
|
227
|
+
)
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export function Section({ title, children }) {
|
|
232
|
+
return h('div', { style: 'padding:20px 32px' },
|
|
233
|
+
title ? h('h3', {}, title) : null,
|
|
234
|
+
...(Array.isArray(children) ? children : [children])
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// ---------- assembled page views ----------
|
|
239
|
+
|
|
240
|
+
export function HomeView({ state, onNav, onToggleWork, works, posts, manifesto, currentlyShipping }) {
|
|
241
|
+
return [
|
|
242
|
+
Hero({
|
|
243
|
+
title: 'the creative department of the internet.',
|
|
244
|
+
body: '247420 is a collective of mercurials. we ship fast, break things on purpose, and document honestly.',
|
|
245
|
+
accent: 'humor is load-bearing.'
|
|
246
|
+
}),
|
|
247
|
+
currentlyShipping ? h('div', { style: 'padding:0 32px 24px 32px' },
|
|
248
|
+
Panel({
|
|
249
|
+
title: 'currently shipping',
|
|
250
|
+
count: currentlyShipping.length,
|
|
251
|
+
style: 'max-width:560px;margin:0',
|
|
252
|
+
children: currentlyShipping.map((row, i) =>
|
|
253
|
+
Row({
|
|
254
|
+
key: i,
|
|
255
|
+
code: h('span', { style: `color:${row.live ? 'var(--panel-accent)' : 'var(--panel-text-3)'}` }, row.live ? '●' : '○'),
|
|
256
|
+
title: row.title, sub: row.sub, meta: row.meta
|
|
257
|
+
})
|
|
258
|
+
)
|
|
259
|
+
})
|
|
260
|
+
) : null,
|
|
261
|
+
Section({ title: '// works', children: WorksList({ works, openedIndex: state.opened, onToggle: onToggleWork }) }),
|
|
262
|
+
Section({ title: '// recent writing', children: WritingList({ posts }) }),
|
|
263
|
+
Section({ title: '// manifesto · rough draft', children: Manifesto({ paragraphs: manifesto }) })
|
|
264
|
+
];
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export function ProjectView({ project, copied, onCopy }) {
|
|
268
|
+
return [
|
|
269
|
+
Heading({ level: 1, children: project.name }),
|
|
270
|
+
Lede({ children: project.tagline }),
|
|
271
|
+
Heading({ level: 3, children: 'install' }),
|
|
272
|
+
Install({ cmd: project.install, copied, onCopy }),
|
|
273
|
+
Heading({ level: 3, children: 'receipt' }),
|
|
274
|
+
Receipt({ rows: project.receipt }),
|
|
275
|
+
Heading({ level: 3, children: 'changelog' }),
|
|
276
|
+
Changelog({ entries: project.changelog })
|
|
277
|
+
];
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export { h };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Lazy registration: <deck-stage> requires HTMLElement / customElements,
|
|
2
|
+
// which only exist in the browser. Calling registerDeckStage() in a
|
|
3
|
+
// browser context performs the side-effect import and defines the element.
|
|
4
|
+
let _registered = false;
|
|
5
|
+
export async function registerDeckStage() {
|
|
6
|
+
if (_registered) return customElements.get('deck-stage');
|
|
7
|
+
if (typeof customElements === 'undefined' || typeof HTMLElement === 'undefined') {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
await import('../slides/deck-stage.js');
|
|
11
|
+
_registered = true;
|
|
12
|
+
return customElements.get('deck-stage');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function getDeckStage() {
|
|
16
|
+
return (typeof customElements !== 'undefined') ? customElements.get('deck-stage') : null;
|
|
17
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as webjsx from '../vendor/webjsx/index.js';
|
|
2
|
+
import { loadCss, scope } from './styles.js';
|
|
3
|
+
import { registerDeckStage, getDeckStage } from './deck-stage.js';
|
|
4
|
+
import * as components from './components.js';
|
|
5
|
+
|
|
6
|
+
let _installed = false;
|
|
7
|
+
export async function installStyles(target) {
|
|
8
|
+
if (_installed && !target) return;
|
|
9
|
+
const css = await loadCss();
|
|
10
|
+
const root = target || document.head;
|
|
11
|
+
const tag = document.createElement('style');
|
|
12
|
+
tag.setAttribute('data-247420', '');
|
|
13
|
+
tag.textContent = css;
|
|
14
|
+
root.appendChild(tag);
|
|
15
|
+
if (!target) _installed = true;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function mount(rootEl, viewFn, { autoScope = true } = {}) {
|
|
19
|
+
if (autoScope && rootEl && rootEl.classList && !rootEl.classList.contains(scope.slice(1))) {
|
|
20
|
+
rootEl.classList.add(scope.slice(1));
|
|
21
|
+
}
|
|
22
|
+
const render = () => webjsx.applyDiff(rootEl, viewFn(render));
|
|
23
|
+
render();
|
|
24
|
+
return render;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { webjsx, loadCss, scope, registerDeckStage, getDeckStage, components };
|
|
28
|
+
export const h = webjsx.createElement;
|
|
29
|
+
export const applyDiff = webjsx.applyDiff;
|
|
30
|
+
export default { webjsx, loadCss, scope, installStyles, mount, h, applyDiff, registerDeckStage, getDeckStage, components };
|
package/src/styles.js
ADDED