anentrypoint-design 0.0.122 → 0.0.124
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 +253 -253
- package/app-shell.css +931 -594
- package/colors_and_type.css +226 -226
- package/community.css +933 -2255
- package/dist/247420.css +2276 -3075
- package/dist/247420.js +14 -14
- package/package.json +80 -80
- package/src/bootstrap.js +25 -25
- package/src/components/chat.js +199 -199
- package/src/components/community.js +190 -208
- package/src/components/content.js +269 -269
- package/src/components/editor-primitives.js +100 -0
- package/src/components/files-modals.js +107 -107
- package/src/components/files.js +118 -118
- package/src/components/freddie/helpers.js +50 -50
- package/src/components/freddie.js +33 -33
- package/src/components/shell.js +117 -117
- package/src/components/theme-toggle.js +70 -70
- package/src/components.js +59 -67
- package/src/debug.js +30 -30
- package/src/deck-stage.js +21 -21
- package/src/highlight.js +65 -32
- package/src/index.js +86 -86
- package/src/kits/os/about-app.js +52 -52
- package/src/kits/os/app-panes.css +152 -152
- package/src/kits/os/browser-app.js +58 -58
- package/src/kits/os/files-app.js +44 -44
- package/src/kits/os/freddie/helpers.js +59 -59
- package/src/kits/os/freddie/pages-chat.js +143 -143
- package/src/kits/os/freddie/pages-core.js +101 -101
- package/src/kits/os/freddie/pages-os.js +51 -51
- package/src/kits/os/freddie/pages-tools.js +183 -183
- package/src/kits/os/freddie/routes.js +24 -24
- package/src/kits/os/freddie-dashboard.css +51 -51
- package/src/kits/os/freddie-dashboard.js +101 -101
- package/src/kits/os/icons.js +17 -17
- package/src/kits/os/index.js +17 -17
- package/src/kits/os/launcher.css +61 -61
- package/src/kits/os/launcher.js +79 -79
- package/src/kits/os/monitor-app.js +34 -34
- package/src/kits/os/shell.js +214 -214
- package/src/kits/os/terminal-app.js +45 -45
- package/src/kits/os/theme.css +450 -450
- package/src/kits/os/validate.css +19 -19
- package/src/kits/os/validator-app.js +55 -55
- package/src/kits/os/wm.css +115 -115
- package/src/kits/os/wm.js +111 -111
- package/src/markdown.js +39 -39
- package/src/motion.js +35 -35
- package/src/page-html.js +196 -196
- package/src/styles.js +25 -25
- package/src/theme.js +99 -99
- package/src/web-components/ds-chat.js +116 -116
- package/dist/.nojekyll +0 -0
- package/dist/app-shell.css +0 -594
- package/dist/colors_and_type.css +0 -197
- package/dist/favicon.svg +0 -1
- package/dist/index.html +0 -308
- package/dist/preview/buttons.html +0 -28
- package/dist/preview/colors-core.html +0 -45
- package/dist/preview/colors-lore.html +0 -28
- package/dist/preview/colors-semantic.html +0 -34
- package/dist/preview/dateline.html +0 -19
- package/dist/preview/dropzone.html +0 -30
- package/dist/preview/file-grid.html +0 -19
- package/dist/preview/file-row.html +0 -20
- package/dist/preview/file-toolbar.html +0 -40
- package/dist/preview/file-viewer.html +0 -31
- package/dist/preview/header.html +0 -24
- package/dist/preview/icons-unicode.html +0 -26
- package/dist/preview/index-row.html +0 -25
- package/dist/preview/inputs.html +0 -22
- package/dist/preview/manifesto.html +0 -52
- package/dist/preview/motion-default.js +0 -106
- package/dist/preview/rules.html +0 -16
- package/dist/preview/spacing.html +0 -18
- package/dist/preview/stamps-lore.html +0 -20
- package/dist/preview/stamps.html +0 -14
- package/dist/preview/theme-ink.html +0 -15
- package/dist/preview/type-display.html +0 -16
- package/dist/preview/type-mono.html +0 -15
- package/dist/preview/type-prose.html +0 -11
- package/dist/preview/type-scale.html +0 -20
- package/dist/preview/wordmarks.html +0 -28
- package/dist/robots.txt +0 -8
- package/dist/site/content/globals/navigation.yaml +0 -5
- package/dist/site/content/globals/site.yaml +0 -16
- package/dist/site/content/pages/freddie.yaml +0 -88
- package/dist/site/content/pages/home.yaml +0 -190
- package/dist/site/theme.mjs +0 -368
- package/dist/sitemap.xml +0 -31
- package/dist/slides/deck-stage-overlay.js +0 -63
- package/dist/slides/deck-stage-state.js +0 -81
- package/dist/slides/deck-stage-style.js +0 -117
- package/dist/slides/deck-stage.js +0 -159
- package/dist/slides/index.html +0 -276
- package/dist/src/bootstrap.js +0 -25
- package/dist/src/components/chat.js +0 -199
- package/dist/src/components/community.js +0 -167
- package/dist/src/components/content.js +0 -213
- package/dist/src/components/files-modals.js +0 -107
- package/dist/src/components/files.js +0 -118
- package/dist/src/components/freddie/helpers.js +0 -50
- package/dist/src/components/freddie.js +0 -33
- package/dist/src/components/shell.js +0 -117
- package/dist/src/components/theme-toggle.js +0 -70
- package/dist/src/components.js +0 -52
- package/dist/src/debug.js +0 -30
- package/dist/src/deck-stage.js +0 -21
- package/dist/src/highlight.js +0 -32
- package/dist/src/index.js +0 -86
- package/dist/src/kits/os/about-app.js +0 -52
- package/dist/src/kits/os/app-panes.css +0 -152
- package/dist/src/kits/os/browser-app.js +0 -58
- package/dist/src/kits/os/files-app.js +0 -44
- package/dist/src/kits/os/freddie/helpers.js +0 -59
- package/dist/src/kits/os/freddie/pages-chat.js +0 -143
- package/dist/src/kits/os/freddie/pages-core.js +0 -101
- package/dist/src/kits/os/freddie/pages-os.js +0 -51
- package/dist/src/kits/os/freddie/pages-tools.js +0 -183
- package/dist/src/kits/os/freddie/routes.js +0 -24
- package/dist/src/kits/os/freddie-dashboard.css +0 -51
- package/dist/src/kits/os/freddie-dashboard.js +0 -101
- package/dist/src/kits/os/icons.js +0 -17
- package/dist/src/kits/os/index.js +0 -5
- package/dist/src/kits/os/launcher.css +0 -61
- package/dist/src/kits/os/launcher.js +0 -79
- package/dist/src/kits/os/monitor-app.js +0 -34
- package/dist/src/kits/os/shell.js +0 -214
- package/dist/src/kits/os/terminal-app.js +0 -45
- package/dist/src/kits/os/theme.css +0 -412
- package/dist/src/kits/os/validate.css +0 -19
- package/dist/src/kits/os/validator-app.js +0 -55
- package/dist/src/kits/os/wm.css +0 -115
- package/dist/src/kits/os/wm.js +0 -111
- package/dist/src/markdown.js +0 -39
- package/dist/src/motion.js +0 -35
- package/dist/src/page-html.js +0 -196
- package/dist/src/styles.js +0 -25
- package/dist/src/theme.js +0 -99
- package/dist/src/web-components/ds-chat.js +0 -45
- package/dist/ui_kits/aicat/README.md +0 -7
- package/dist/ui_kits/aicat/app.js +0 -156
- package/dist/ui_kits/aicat/index.html +0 -26
- package/dist/ui_kits/aicat/sample-square.png +0 -0
- package/dist/ui_kits/aicat/sample-svg.svg +0 -1
- package/dist/ui_kits/aicat/sample.pdf +0 -32
- package/dist/ui_kits/blog/README.md +0 -3
- package/dist/ui_kits/blog/index.html +0 -90
- package/dist/ui_kits/chat/README.md +0 -5
- package/dist/ui_kits/chat/app.js +0 -110
- package/dist/ui_kits/chat/index.html +0 -26
- package/dist/ui_kits/chat/sample-square.png +0 -0
- package/dist/ui_kits/chat/sample-svg.svg +0 -1
- package/dist/ui_kits/chat/sample.pdf +0 -32
- package/dist/ui_kits/community/app.js +0 -134
- package/dist/ui_kits/community/index.html +0 -24
- package/dist/ui_kits/dashboard/app.js +0 -92
- package/dist/ui_kits/dashboard/index.html +0 -26
- package/dist/ui_kits/docs/README.md +0 -3
- package/dist/ui_kits/docs/index.html +0 -123
- package/dist/ui_kits/error_404/app.js +0 -56
- package/dist/ui_kits/error_404/index.html +0 -26
- package/dist/ui_kits/file_browser/README.md +0 -48
- package/dist/ui_kits/file_browser/app.js +0 -231
- package/dist/ui_kits/file_browser/index.html +0 -33
- package/dist/ui_kits/gallery/app.js +0 -121
- package/dist/ui_kits/gallery/index.html +0 -26
- package/dist/ui_kits/homepage/README.md +0 -7
- package/dist/ui_kits/homepage/app.js +0 -167
- package/dist/ui_kits/homepage/index.html +0 -46
- package/dist/ui_kits/project_page/README.md +0 -3
- package/dist/ui_kits/project_page/app.js +0 -154
- package/dist/ui_kits/project_page/index.html +0 -45
- package/dist/ui_kits/search/app.js +0 -107
- package/dist/ui_kits/search/index.html +0 -26
- package/dist/ui_kits/settings/app.js +0 -133
- package/dist/ui_kits/settings/index.html +0 -26
- package/dist/ui_kits/signin/app.js +0 -115
- package/dist/ui_kits/signin/index.html +0 -26
- package/dist/ui_kits/slide_deck/app.js +0 -174
- package/dist/ui_kits/slide_deck/index.html +0 -26
- package/dist/ui_kits/system_primer/app.js +0 -152
- package/dist/ui_kits/system_primer/index.html +0 -26
- package/dist/ui_kits/terminal/app.js +0 -150
- package/dist/ui_kits/terminal/index.html +0 -26
- package/dist/vendor/webjsx/applyDiff.js +0 -182
- package/dist/vendor/webjsx/attributes.js +0 -154
- package/dist/vendor/webjsx/constants.js +0 -4
- package/dist/vendor/webjsx/createDOMElement.js +0 -52
- package/dist/vendor/webjsx/createElement.js +0 -75
- package/dist/vendor/webjsx/elementTags.js +0 -115
- package/dist/vendor/webjsx/factory.js +0 -6
- package/dist/vendor/webjsx/index.js +0 -6
- package/dist/vendor/webjsx/jsx-dev-runtime.js +0 -2
- package/dist/vendor/webjsx/jsx-runtime.js +0 -30
- package/dist/vendor/webjsx/jsx.js +0 -2
- package/dist/vendor/webjsx/package.json +0 -39
- package/dist/vendor/webjsx/renderSuspension.js +0 -25
- package/dist/vendor/webjsx/types.js +0 -5
- package/dist/vendor/webjsx/utils.js +0 -84
- package/src/components/overlays.js +0 -151
- package/src/components/surfaces.js +0 -399
- package/src/components/voice.js +0 -132
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
// Overlay surface — toast, banner, mobile header, drawer, boot splash,
|
|
2
|
-
// context menu, command palette, emoji picker, reply bar.
|
|
3
|
-
// All factories: props → vnode. No internal state, no lifecycle (refs OK).
|
|
4
|
-
|
|
5
|
-
import * as webjsx from '../../vendor/webjsx/index.js';
|
|
6
|
-
const h = webjsx.createElement;
|
|
7
|
-
|
|
8
|
-
export function Toast({ message, tone = 'info', visible } = {}) {
|
|
9
|
-
if (!visible) return null;
|
|
10
|
-
return h('div', { class: `cm-toast tone-${tone}`, role: 'status' },
|
|
11
|
-
h('span', { class: 'cm-toast-msg' }, message || '')
|
|
12
|
-
);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function Banner({ tone = 'info', message, action, onAction, visible, dismissable, onDismiss } = {}) {
|
|
16
|
-
if (!visible) return null;
|
|
17
|
-
return h('div', { class: `cm-banner tone-${tone}`, role: 'alert' },
|
|
18
|
-
h('span', { class: 'cm-banner-msg' }, message || ''),
|
|
19
|
-
action ? h('button', {
|
|
20
|
-
class: 'cm-banner-action',
|
|
21
|
-
onclick: onAction,
|
|
22
|
-
title: action.label || ''
|
|
23
|
-
}, action.icon ? h('span', { class: 'cm-banner-action-icon' }, action.icon) : null, action.label || '') : null,
|
|
24
|
-
dismissable ? h('button', { class: 'cm-banner-dismiss', onclick: onDismiss, title: 'Dismiss' }, '✕') : null
|
|
25
|
-
);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function MobileHeader({ title, onMenu, onMembers } = {}) {
|
|
29
|
-
return h('div', { class: 'cm-mobile-header' },
|
|
30
|
-
h('button', { class: 'cm-mh-btn', onclick: onMenu, title: 'Menu' }, '☰'),
|
|
31
|
-
h('span', { class: 'cm-mh-title' }, title || ''),
|
|
32
|
-
h('button', { class: 'cm-mh-btn', onclick: onMembers, title: 'Members' }, '👥')
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function DrawerOverlay({ open, onClose, children, side = 'left' } = {}) {
|
|
37
|
-
if (!open) return null;
|
|
38
|
-
return h('div', { class: 'cm-drawer-overlay' },
|
|
39
|
-
h('div', { class: 'cm-drawer-backdrop', onclick: onClose }),
|
|
40
|
-
h('div', {
|
|
41
|
-
class: `cm-drawer-content side-${side}`,
|
|
42
|
-
onclick: (e) => e.stopPropagation()
|
|
43
|
-
}, ...(Array.isArray(children) ? children : [children]))
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function BootOverlay({ progress = 0, phase, error, visible } = {}) {
|
|
48
|
-
if (!visible) return null;
|
|
49
|
-
const pct = Math.max(0, Math.min(1, progress)) * 100;
|
|
50
|
-
return h('div', { class: 'cm-boot-overlay', role: 'dialog' },
|
|
51
|
-
h('div', { class: 'cm-boot-spinner' }),
|
|
52
|
-
h('div', { class: 'cm-boot-phase' }, phase || 'Loading…'),
|
|
53
|
-
h('div', { class: 'cm-boot-progress' },
|
|
54
|
-
h('div', { class: 'cm-boot-bar', style: `width:${pct}%` })
|
|
55
|
-
),
|
|
56
|
-
error ? h('div', { class: 'cm-boot-error' }, String(error)) : null
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export function ContextMenu({ items = [], x = 0, y = 0, open, onClose } = {}) {
|
|
61
|
-
if (!open) return null;
|
|
62
|
-
return h('div', {
|
|
63
|
-
class: 'cm-context-menu',
|
|
64
|
-
style: `left:${x}px;top:${y}px`,
|
|
65
|
-
onclick: (e) => e.stopPropagation()
|
|
66
|
-
},
|
|
67
|
-
h('div', { class: 'cm-cm-list' },
|
|
68
|
-
...items.map(it => it.separator
|
|
69
|
-
? h('div', { class: 'cm-cm-sep', key: it.id || 'sep' })
|
|
70
|
-
: h('button', {
|
|
71
|
-
class: 'cm-cm-item' + (it.danger ? ' danger' : ''),
|
|
72
|
-
'data-id': it.id || '',
|
|
73
|
-
onclick: (e) => { e.stopPropagation(); it.onClick && it.onClick(e); onClose && onClose(); }
|
|
74
|
-
},
|
|
75
|
-
it.icon ? h('span', { class: 'cm-cm-icon' }, it.icon) : null,
|
|
76
|
-
h('span', { class: 'cm-cm-label' }, it.label || '')
|
|
77
|
-
)
|
|
78
|
-
)
|
|
79
|
-
)
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export function CommandPalette({ items = [], query = '', onQuery, onSelect, open, onClose } = {}) {
|
|
84
|
-
if (!open) return null;
|
|
85
|
-
return h('div', { class: 'cm-command-palette-wrap' },
|
|
86
|
-
h('div', { class: 'cm-command-palette-backdrop', onclick: onClose }),
|
|
87
|
-
h('div', { class: 'cm-command-palette', onclick: (e) => e.stopPropagation() },
|
|
88
|
-
h('input', {
|
|
89
|
-
class: 'cm-cp-input',
|
|
90
|
-
type: 'text',
|
|
91
|
-
placeholder: 'Type a command…',
|
|
92
|
-
value: query,
|
|
93
|
-
oninput: (e) => onQuery && onQuery(e.target.value),
|
|
94
|
-
autofocus: true
|
|
95
|
-
}),
|
|
96
|
-
h('div', { class: 'cm-cp-list' },
|
|
97
|
-
...items.map((it, i) => h('button', {
|
|
98
|
-
class: 'cm-cp-item' + (it.selected ? ' selected' : ''),
|
|
99
|
-
'data-id': it.id || '',
|
|
100
|
-
onclick: () => onSelect && onSelect(it, i)
|
|
101
|
-
},
|
|
102
|
-
it.icon ? h('span', { class: 'cm-cp-icon' }, it.icon) : null,
|
|
103
|
-
h('span', { class: 'cm-cp-label' }, it.label || ''),
|
|
104
|
-
it.hint ? h('span', { class: 'cm-cp-hint' }, it.hint) : null
|
|
105
|
-
))
|
|
106
|
-
)
|
|
107
|
-
)
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const DEFAULT_EMOJI_CATEGORIES = [
|
|
112
|
-
{ id: 'smileys', name: 'Smileys', emojis: ['😀','😃','😄','😁','😆','😅','🤣','😂','🙂','🙃','😉','😊','😇','🥰','😍','🤩','😘','😗','😚','😙','🥲','😋','😛','😜','🤪','😝','🤑','🤗','🤭','🤫'] },
|
|
113
|
-
{ id: 'hearts', name: 'Hearts', emojis: ['❤️','🧡','💛','💚','💙','💜','🖤','🤍','🤎','💔','❣️','💕','💞','💓','💗','💖','💘','💝','💟','♥️','💌','💋','💍','💎','🌹','🌷','🌻','🌸','🌺','💐'] },
|
|
114
|
-
{ id: 'animals', name: 'Animals', emojis: ['🐶','🐱','🐭','🐹','🐰','🦊','🐻','🐼','🐨','🐯','🦁','🐮','🐷','🐸','🐵','🐔','🐧','🐦','🐤','🦆','🦅','🦉','🦇','🐺','🐗','🐴','🦄','🐝','🐛','🦋'] },
|
|
115
|
-
{ id: 'food', name: 'Food', emojis: ['🍏','🍎','🍐','🍊','🍋','🍌','🍉','🍇','🍓','🫐','🍈','🍒','🍑','🥭','🍍','🥥','🥝','🍅','🍆','🥑','🥦','🥬','🥒','🌶️','🌽','🥕','🧄','🧅','🥔','🍞'] },
|
|
116
|
-
{ id: 'activities', name: 'Activities', emojis: ['⚽','🏀','🏈','⚾','🥎','🎾','🏐','🏉','🎱','🪀','🏓','🏸','🥅','🏒','🏑','🥍','🏏','🪃','⛳','🪁','🏹','🎣','🤿','🥊','🥋','🎽','🛹','🛼','🛷','⛸️'] },
|
|
117
|
-
{ id: 'symbols', name: 'Symbols', emojis: ['✅','❌','⭕','🚫','♻️','✳️','❇️','⚠️','🔱','⚜️','🔰','✴️','🆚','🆗','🆙','🆒','🆕','🆓','0️⃣','1️⃣','2️⃣','3️⃣','4️⃣','5️⃣','6️⃣','7️⃣','8️⃣','9️⃣','🔟','💯'] }
|
|
118
|
-
];
|
|
119
|
-
|
|
120
|
-
export function EmojiPicker({ recent = [], categories, onSelect, onClose, open } = {}) {
|
|
121
|
-
if (!open) return null;
|
|
122
|
-
const cats = categories && categories.length ? categories : DEFAULT_EMOJI_CATEGORIES;
|
|
123
|
-
return h('div', { class: 'cm-emoji-picker', onclick: (e) => e.stopPropagation() },
|
|
124
|
-
h('input', { class: 'cm-ep-search', type: 'text', placeholder: 'Search emoji…' }),
|
|
125
|
-
h('div', { class: 'cm-ep-grid' },
|
|
126
|
-
recent.length ? h('div', { class: 'cm-ep-category' }, 'Recent') : null,
|
|
127
|
-
...recent.map((e, i) => h('button', {
|
|
128
|
-
class: 'cm-ep-btn', key: 'r' + i,
|
|
129
|
-
onclick: () => onSelect && onSelect(e)
|
|
130
|
-
}, e)),
|
|
131
|
-
...cats.flatMap(cat => [
|
|
132
|
-
h('div', { class: 'cm-ep-category', key: 'c-' + cat.id }, cat.name),
|
|
133
|
-
...cat.emojis.map((e, i) => h('button', {
|
|
134
|
-
class: 'cm-ep-btn', key: cat.id + '-' + i,
|
|
135
|
-
onclick: () => onSelect && onSelect(e)
|
|
136
|
-
}, e))
|
|
137
|
-
])
|
|
138
|
-
)
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export function ReplyBar({ quotedMessage, quotedAuthor, onCancel } = {}) {
|
|
143
|
-
return h('div', { class: 'cm-reply-bar' },
|
|
144
|
-
h('div', { class: 'cm-rb-quote' },
|
|
145
|
-
h('span', { class: 'cm-rb-label' }, 'Replying to '),
|
|
146
|
-
h('span', { class: 'cm-rb-author' }, quotedAuthor || ''),
|
|
147
|
-
h('span', { class: 'cm-rb-msg' }, quotedMessage ? ': ' + String(quotedMessage).slice(0, 80) : '')
|
|
148
|
-
),
|
|
149
|
-
h('button', { class: 'cm-rb-cancel', onclick: onCancel, title: 'Cancel reply' }, '✕')
|
|
150
|
-
);
|
|
151
|
-
}
|
|
@@ -1,399 +0,0 @@
|
|
|
1
|
-
// Surfaces — thread panel, forum view, page view, auth modal, settings popover, voice settings modal.
|
|
2
|
-
// Pure factories: props → vnode. Render nothing when modals are not open.
|
|
3
|
-
|
|
4
|
-
import * as webjsx from '../../vendor/webjsx/index.js';
|
|
5
|
-
const h = webjsx.createElement;
|
|
6
|
-
|
|
7
|
-
function timeAgo(t) {
|
|
8
|
-
if (!t) return '';
|
|
9
|
-
const d = typeof t === 'number' ? t : Date.parse(t);
|
|
10
|
-
if (!Number.isFinite(d)) return String(t);
|
|
11
|
-
const s = Math.max(0, Math.floor((Date.now() - d) / 1000));
|
|
12
|
-
if (s < 60) return s + 's';
|
|
13
|
-
if (s < 3600) return Math.floor(s / 60) + 'm';
|
|
14
|
-
if (s < 86400) return Math.floor(s / 3600) + 'h';
|
|
15
|
-
return Math.floor(s / 86400) + 'd';
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function ThreadPanel({ threads = [], activeId, onSelect, onCreate, onClose, open, title = 'Threads' } = {}) {
|
|
19
|
-
if (open !== true) return null;
|
|
20
|
-
return h('aside', { class: 'cm-thread-panel', role: 'complementary' },
|
|
21
|
-
h('div', { class: 'cm-tp-header' },
|
|
22
|
-
h('span', { class: 'cm-tp-title' }, title),
|
|
23
|
-
h('div', { class: 'cm-tp-header-actions' },
|
|
24
|
-
onCreate ? h('button', { class: 'cm-tp-new', onclick: onCreate, title: 'New thread' }, '+') : null,
|
|
25
|
-
onClose ? h('button', { class: 'cm-tp-close', onclick: onClose, title: 'Close' }, '✕') : null
|
|
26
|
-
)
|
|
27
|
-
),
|
|
28
|
-
h('div', { class: 'cm-tp-list' },
|
|
29
|
-
...threads.map(t => h('div', {
|
|
30
|
-
class: 'cm-tp-item' + (t.id === activeId ? ' active' : '') + (t.unread ? ' unread' : ''),
|
|
31
|
-
onclick: () => onSelect && onSelect(t.id),
|
|
32
|
-
'data-id': t.id
|
|
33
|
-
},
|
|
34
|
-
h('div', { class: 'cm-tp-item-row' },
|
|
35
|
-
h('span', { class: 'cm-tp-item-title' }, t.title || '(untitled)'),
|
|
36
|
-
h('span', { class: 'cm-tp-item-time' }, timeAgo(t.time))
|
|
37
|
-
),
|
|
38
|
-
t.lastMessage ? h('div', { class: 'cm-tp-item-msg' },
|
|
39
|
-
t.author ? h('span', { class: 'cm-tp-item-author' }, t.author + ': ') : null,
|
|
40
|
-
t.lastMessage
|
|
41
|
-
) : null,
|
|
42
|
-
t.unread ? h('span', { class: 'cm-tp-item-dot' }) : null
|
|
43
|
-
))
|
|
44
|
-
)
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function ForumView({ posts = [], onSelect, onSearch, onNewPost, query, sortBy = 'recent', onSort } = {}) {
|
|
49
|
-
const sorts = [
|
|
50
|
-
{ id: 'recent', label: 'Recent' },
|
|
51
|
-
{ id: 'popular', label: 'Popular' },
|
|
52
|
-
{ id: 'unanswered', label: 'Unanswered' }
|
|
53
|
-
];
|
|
54
|
-
return h('div', { class: 'cm-forum-view' },
|
|
55
|
-
h('div', { class: 'cm-fv-toolbar' },
|
|
56
|
-
h('input', {
|
|
57
|
-
class: 'cm-fv-search',
|
|
58
|
-
type: 'search',
|
|
59
|
-
placeholder: 'Search posts…',
|
|
60
|
-
value: query || '',
|
|
61
|
-
oninput: (e) => onSearch && onSearch(e.target.value)
|
|
62
|
-
}),
|
|
63
|
-
h('select', {
|
|
64
|
-
class: 'cm-fv-sort',
|
|
65
|
-
value: sortBy,
|
|
66
|
-
onchange: (e) => onSort && onSort(e.target.value)
|
|
67
|
-
}, ...sorts.map(s => h('option', { value: s.id, selected: s.id === sortBy ? 'selected' : null }, s.label))),
|
|
68
|
-
onNewPost ? h('button', { class: 'cm-fv-new', onclick: onNewPost, title: 'New post' }, '+ New') : null
|
|
69
|
-
),
|
|
70
|
-
h('div', { class: 'cm-fv-list' },
|
|
71
|
-
...posts.map(p => h('div', {
|
|
72
|
-
class: 'cm-fv-post',
|
|
73
|
-
onclick: () => onSelect && onSelect(p.id),
|
|
74
|
-
'data-id': p.id
|
|
75
|
-
},
|
|
76
|
-
h('div', { class: 'cm-fv-post-head' },
|
|
77
|
-
h('span', { class: 'cm-fv-post-title' }, p.title || '(untitled)'),
|
|
78
|
-
h('span', { class: 'cm-fv-post-meta' },
|
|
79
|
-
p.author ? h('span', { class: 'cm-fv-post-author' }, p.author) : null,
|
|
80
|
-
h('span', { class: 'cm-fv-post-time' }, timeAgo(p.time)),
|
|
81
|
-
h('span', { class: 'cm-fv-post-replies' }, (p.replyCount || 0) + ' replies')
|
|
82
|
-
)
|
|
83
|
-
),
|
|
84
|
-
p.snippet ? h('div', { class: 'cm-fv-post-snippet' }, p.snippet) : null,
|
|
85
|
-
p.tags && p.tags.length ? h('div', { class: 'cm-fv-post-tags' },
|
|
86
|
-
...p.tags.map(tg => h('span', { class: 'cm-fv-post-tag' }, tg))
|
|
87
|
-
) : null
|
|
88
|
-
))
|
|
89
|
-
)
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export function PageView({ content, html, title, onEdit, isAdmin } = {}) {
|
|
94
|
-
const bodyAttrs = { class: 'cm-pv-content' };
|
|
95
|
-
if (html != null) {
|
|
96
|
-
bodyAttrs.ref = (el) => { if (el) el.innerHTML = String(html); };
|
|
97
|
-
}
|
|
98
|
-
return h('div', { class: 'cm-page-view' },
|
|
99
|
-
h('div', { class: 'cm-pv-head' },
|
|
100
|
-
title ? h('h1', { class: 'cm-pv-title' }, title) : null,
|
|
101
|
-
isAdmin && onEdit ? h('button', { class: 'cm-pv-edit', onclick: onEdit, title: 'Edit' }, 'Edit') : null
|
|
102
|
-
),
|
|
103
|
-
html != null
|
|
104
|
-
? h('div', bodyAttrs)
|
|
105
|
-
: h('div', bodyAttrs, content || null)
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export function AuthModal({ mode = 'extension', error, onConnectExtension, onGenerate, onImport, onModeChange, open, onClose, busy } = {}) {
|
|
110
|
-
if (open !== true) return null;
|
|
111
|
-
const tabs = [
|
|
112
|
-
{ id: 'extension', label: 'Extension' },
|
|
113
|
-
{ id: 'generate', label: 'Generate' },
|
|
114
|
-
{ id: 'import', label: 'Import' }
|
|
115
|
-
];
|
|
116
|
-
let importRef = null;
|
|
117
|
-
return h('div', { class: 'cm-modal-backdrop', onclick: onClose },
|
|
118
|
-
h('div', {
|
|
119
|
-
class: 'cm-auth-modal',
|
|
120
|
-
onclick: (e) => e.stopPropagation(),
|
|
121
|
-
role: 'dialog'
|
|
122
|
-
},
|
|
123
|
-
h('div', { class: 'cm-am-head' },
|
|
124
|
-
h('span', { class: 'cm-am-title' }, 'Sign in'),
|
|
125
|
-
onClose ? h('button', { class: 'cm-am-close', onclick: onClose, title: 'Close' }, '✕') : null
|
|
126
|
-
),
|
|
127
|
-
h('div', { class: 'cm-am-tabs', role: 'tablist' },
|
|
128
|
-
...tabs.map(t => h('button', {
|
|
129
|
-
class: 'cm-am-tab' + (mode === t.id ? ' active' : ''),
|
|
130
|
-
onclick: () => onModeChange && onModeChange(t.id),
|
|
131
|
-
'data-mode': t.id
|
|
132
|
-
}, t.label))
|
|
133
|
-
),
|
|
134
|
-
mode === 'extension' ? h('div', { class: 'cm-am-pane' },
|
|
135
|
-
h('p', { class: 'cm-am-text' }, 'Connect using a NIP-07 browser extension (e.g. nos2x, Alby).'),
|
|
136
|
-
h('button', {
|
|
137
|
-
class: 'cm-am-btn',
|
|
138
|
-
onclick: onConnectExtension,
|
|
139
|
-
disabled: busy ? 'disabled' : null
|
|
140
|
-
}, busy ? 'Connecting…' : 'Connect extension')
|
|
141
|
-
) : null,
|
|
142
|
-
mode === 'generate' ? h('div', { class: 'cm-am-pane' },
|
|
143
|
-
h('p', { class: 'cm-am-text' }, 'Generate a fresh keypair. Keep your secret key safe — losing it means losing your identity.'),
|
|
144
|
-
h('div', { class: 'cm-am-warn' }, 'Warning: store the generated nsec somewhere safe before continuing.'),
|
|
145
|
-
h('button', {
|
|
146
|
-
class: 'cm-am-btn',
|
|
147
|
-
onclick: onGenerate,
|
|
148
|
-
disabled: busy ? 'disabled' : null
|
|
149
|
-
}, busy ? 'Generating…' : 'Generate keypair')
|
|
150
|
-
) : null,
|
|
151
|
-
mode === 'import' ? h('div', { class: 'cm-am-pane' },
|
|
152
|
-
h('p', { class: 'cm-am-text' }, 'Paste your nsec secret key to import an existing identity.'),
|
|
153
|
-
h('textarea', {
|
|
154
|
-
class: 'cm-am-textarea',
|
|
155
|
-
placeholder: 'nsec1…',
|
|
156
|
-
rows: 3,
|
|
157
|
-
ref: (el) => { importRef = el; }
|
|
158
|
-
}),
|
|
159
|
-
h('button', {
|
|
160
|
-
class: 'cm-am-btn',
|
|
161
|
-
onclick: () => onImport && onImport(importRef ? importRef.value.trim() : ''),
|
|
162
|
-
disabled: busy ? 'disabled' : null
|
|
163
|
-
}, busy ? 'Importing…' : 'Import')
|
|
164
|
-
) : null,
|
|
165
|
-
error ? h('div', { class: 'cm-am-error', role: 'alert' }, String(error)) : null
|
|
166
|
-
)
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
function renderSettingsItem(item) {
|
|
171
|
-
if (!item) return null;
|
|
172
|
-
if (item.kind === 'header') return h('div', { class: 'cm-sp-header' }, item.label || '');
|
|
173
|
-
if (item.kind === 'text') return h('div', { class: 'cm-sp-text' }, item.label || '');
|
|
174
|
-
if (item.kind === 'toggle') {
|
|
175
|
-
return h('label', { class: 'cm-sp-row cm-sp-toggle' },
|
|
176
|
-
h('span', { class: 'cm-sp-row-label' }, item.label || ''),
|
|
177
|
-
h('input', {
|
|
178
|
-
type: 'checkbox',
|
|
179
|
-
checked: item.value ? 'checked' : null,
|
|
180
|
-
onchange: (e) => item.onChange && item.onChange(e.target.checked)
|
|
181
|
-
})
|
|
182
|
-
);
|
|
183
|
-
}
|
|
184
|
-
if (item.kind === 'select') {
|
|
185
|
-
return h('label', { class: 'cm-sp-row cm-sp-select' },
|
|
186
|
-
h('span', { class: 'cm-sp-row-label' }, item.label || ''),
|
|
187
|
-
h('select', {
|
|
188
|
-
value: item.value,
|
|
189
|
-
onchange: (e) => item.onChange && item.onChange(e.target.value)
|
|
190
|
-
}, ...(item.options || []).map(o => h('option', {
|
|
191
|
-
value: o.value != null ? o.value : o.id,
|
|
192
|
-
selected: (o.value != null ? o.value : o.id) === item.value ? 'selected' : null
|
|
193
|
-
}, o.label)))
|
|
194
|
-
);
|
|
195
|
-
}
|
|
196
|
-
if (item.kind === 'button') {
|
|
197
|
-
return h('div', { class: 'cm-sp-row' },
|
|
198
|
-
h('button', {
|
|
199
|
-
class: 'cm-sp-btn' + (item.danger ? ' danger' : ''),
|
|
200
|
-
onclick: item.onClick
|
|
201
|
-
}, item.label || '')
|
|
202
|
-
);
|
|
203
|
-
}
|
|
204
|
-
return null;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
export function SettingsPopover({ sections = [], open, onClose, anchorX, anchorY, title = 'Settings' } = {}) {
|
|
208
|
-
if (open !== true) return null;
|
|
209
|
-
const style = (anchorX != null && anchorY != null)
|
|
210
|
-
? `left:${anchorX}px;top:${anchorY}px`
|
|
211
|
-
: null;
|
|
212
|
-
return h('div', { class: 'cm-modal-backdrop transparent', onclick: onClose },
|
|
213
|
-
h('div', {
|
|
214
|
-
class: 'cm-settings-popover',
|
|
215
|
-
style,
|
|
216
|
-
onclick: (e) => e.stopPropagation(),
|
|
217
|
-
role: 'dialog'
|
|
218
|
-
},
|
|
219
|
-
h('div', { class: 'cm-sp-head' },
|
|
220
|
-
h('span', { class: 'cm-sp-title' }, title),
|
|
221
|
-
onClose ? h('button', { class: 'cm-sp-close', onclick: onClose, title: 'Close' }, '✕') : null
|
|
222
|
-
),
|
|
223
|
-
...sections.map(sec => h('div', { class: 'cm-sp-section', 'data-id': sec.id },
|
|
224
|
-
sec.label ? h('div', { class: 'cm-sp-section-label' }, sec.label) : null,
|
|
225
|
-
...(sec.items || []).map(renderSettingsItem)
|
|
226
|
-
))
|
|
227
|
-
)
|
|
228
|
-
);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
export function VoiceSettingsModal({
|
|
232
|
-
mode = 'ptt',
|
|
233
|
-
devices = { input: [], output: [] },
|
|
234
|
-
inputId,
|
|
235
|
-
outputId,
|
|
236
|
-
volume = 0.7,
|
|
237
|
-
bitrate = 64,
|
|
238
|
-
vadThreshold = 0.15,
|
|
239
|
-
rnnoise = true,
|
|
240
|
-
autoGain = true,
|
|
241
|
-
forceTurn = false,
|
|
242
|
-
isAdmin,
|
|
243
|
-
channelMode,
|
|
244
|
-
allowedRoles,
|
|
245
|
-
onModeChange,
|
|
246
|
-
onInputChange,
|
|
247
|
-
onOutputChange,
|
|
248
|
-
onVolumeChange,
|
|
249
|
-
onBitrateChange,
|
|
250
|
-
onVadChange,
|
|
251
|
-
onRnnoiseToggle,
|
|
252
|
-
onAutoGainToggle,
|
|
253
|
-
onForceTurnToggle,
|
|
254
|
-
onChannelModeChange,
|
|
255
|
-
onSave,
|
|
256
|
-
onCancel,
|
|
257
|
-
open
|
|
258
|
-
} = {}) {
|
|
259
|
-
if (open !== true) return null;
|
|
260
|
-
const modes = [
|
|
261
|
-
{ id: 'ptt', label: 'Push-to-talk' },
|
|
262
|
-
{ id: 'realtime', label: 'Open mic (realtime)' }
|
|
263
|
-
];
|
|
264
|
-
const channelModes = [
|
|
265
|
-
{ id: 'ptt', label: 'PTT only' },
|
|
266
|
-
{ id: 'realtime', label: 'Realtime' },
|
|
267
|
-
{ id: 'free', label: 'User choice' }
|
|
268
|
-
];
|
|
269
|
-
return h('div', { class: 'cm-modal-backdrop', onclick: onCancel },
|
|
270
|
-
h('div', {
|
|
271
|
-
class: 'cm-voice-settings-modal',
|
|
272
|
-
onclick: (e) => e.stopPropagation(),
|
|
273
|
-
role: 'dialog'
|
|
274
|
-
},
|
|
275
|
-
h('div', { class: 'cm-vsm-head' },
|
|
276
|
-
h('span', { class: 'cm-vsm-title' }, 'Voice settings'),
|
|
277
|
-
onCancel ? h('button', { class: 'cm-vsm-close', onclick: onCancel, title: 'Close' }, '✕') : null
|
|
278
|
-
),
|
|
279
|
-
|
|
280
|
-
h('div', { class: 'cm-vsm-section' },
|
|
281
|
-
h('div', { class: 'cm-vsm-section-label' }, 'Audio devices'),
|
|
282
|
-
h('label', { class: 'cm-vsm-row' },
|
|
283
|
-
h('span', { class: 'cm-vsm-row-label' }, 'Input'),
|
|
284
|
-
h('select', {
|
|
285
|
-
value: inputId,
|
|
286
|
-
onchange: (e) => onInputChange && onInputChange(e.target.value)
|
|
287
|
-
}, ...(devices.input || []).map(d => h('option', {
|
|
288
|
-
value: d.deviceId || d.id,
|
|
289
|
-
selected: (d.deviceId || d.id) === inputId ? 'selected' : null
|
|
290
|
-
}, d.label || d.name || 'Unknown')))
|
|
291
|
-
),
|
|
292
|
-
h('label', { class: 'cm-vsm-row' },
|
|
293
|
-
h('span', { class: 'cm-vsm-row-label' }, 'Output'),
|
|
294
|
-
h('select', {
|
|
295
|
-
value: outputId,
|
|
296
|
-
onchange: (e) => onOutputChange && onOutputChange(e.target.value)
|
|
297
|
-
}, ...(devices.output || []).map(d => h('option', {
|
|
298
|
-
value: d.deviceId || d.id,
|
|
299
|
-
selected: (d.deviceId || d.id) === outputId ? 'selected' : null
|
|
300
|
-
}, d.label || d.name || 'Unknown')))
|
|
301
|
-
),
|
|
302
|
-
h('label', { class: 'cm-vsm-row' },
|
|
303
|
-
h('span', { class: 'cm-vsm-row-label' }, 'Output volume'),
|
|
304
|
-
h('input', {
|
|
305
|
-
type: 'range', min: '0', max: '1', step: '0.01', value: String(volume),
|
|
306
|
-
oninput: (e) => onVolumeChange && onVolumeChange(parseFloat(e.target.value))
|
|
307
|
-
}),
|
|
308
|
-
h('span', { class: 'cm-vsm-row-val' }, Math.round(volume * 100) + '%')
|
|
309
|
-
)
|
|
310
|
-
),
|
|
311
|
-
|
|
312
|
-
h('div', { class: 'cm-vsm-section' },
|
|
313
|
-
h('div', { class: 'cm-vsm-section-label' }, 'Voice mode'),
|
|
314
|
-
h('div', { class: 'cm-vsm-radio' },
|
|
315
|
-
...modes.map(m => h('button', {
|
|
316
|
-
class: 'cm-vsm-radio-btn' + (mode === m.id ? ' active' : ''),
|
|
317
|
-
onclick: () => onModeChange && onModeChange(m.id),
|
|
318
|
-
'data-mode': m.id
|
|
319
|
-
}, m.label))
|
|
320
|
-
)
|
|
321
|
-
),
|
|
322
|
-
|
|
323
|
-
h('div', { class: 'cm-vsm-section' },
|
|
324
|
-
h('div', { class: 'cm-vsm-section-label' }, 'Audio processing'),
|
|
325
|
-
h('label', { class: 'cm-vsm-row cm-vsm-toggle' },
|
|
326
|
-
h('span', { class: 'cm-vsm-row-label' }, 'Noise suppression (RNNoise)'),
|
|
327
|
-
h('input', {
|
|
328
|
-
type: 'checkbox',
|
|
329
|
-
checked: rnnoise ? 'checked' : null,
|
|
330
|
-
onchange: (e) => onRnnoiseToggle && onRnnoiseToggle(e.target.checked)
|
|
331
|
-
})
|
|
332
|
-
),
|
|
333
|
-
h('label', { class: 'cm-vsm-row cm-vsm-toggle' },
|
|
334
|
-
h('span', { class: 'cm-vsm-row-label' }, 'Auto gain control'),
|
|
335
|
-
h('input', {
|
|
336
|
-
type: 'checkbox',
|
|
337
|
-
checked: autoGain ? 'checked' : null,
|
|
338
|
-
onchange: (e) => onAutoGainToggle && onAutoGainToggle(e.target.checked)
|
|
339
|
-
})
|
|
340
|
-
),
|
|
341
|
-
h('label', { class: 'cm-vsm-row' },
|
|
342
|
-
h('span', { class: 'cm-vsm-row-label' }, 'VAD threshold'),
|
|
343
|
-
h('input', {
|
|
344
|
-
type: 'range', min: '0', max: '1', step: '0.01', value: String(vadThreshold),
|
|
345
|
-
oninput: (e) => onVadChange && onVadChange(parseFloat(e.target.value))
|
|
346
|
-
}),
|
|
347
|
-
h('span', { class: 'cm-vsm-row-val' }, vadThreshold.toFixed(2))
|
|
348
|
-
)
|
|
349
|
-
),
|
|
350
|
-
|
|
351
|
-
h('div', { class: 'cm-vsm-section' },
|
|
352
|
-
h('div', { class: 'cm-vsm-section-label' }, 'Quality'),
|
|
353
|
-
h('label', { class: 'cm-vsm-row' },
|
|
354
|
-
h('span', { class: 'cm-vsm-row-label' }, 'Bitrate'),
|
|
355
|
-
h('input', {
|
|
356
|
-
type: 'range', min: '8', max: '128', step: '1', value: String(bitrate),
|
|
357
|
-
oninput: (e) => onBitrateChange && onBitrateChange(parseInt(e.target.value, 10))
|
|
358
|
-
}),
|
|
359
|
-
h('span', { class: 'cm-vsm-row-val' }, bitrate + ' kbps')
|
|
360
|
-
)
|
|
361
|
-
),
|
|
362
|
-
|
|
363
|
-
h('div', { class: 'cm-vsm-section' },
|
|
364
|
-
h('div', { class: 'cm-vsm-section-label' }, 'Network'),
|
|
365
|
-
h('label', { class: 'cm-vsm-row cm-vsm-toggle' },
|
|
366
|
-
h('span', { class: 'cm-vsm-row-label' }, 'Force TURN relay'),
|
|
367
|
-
h('input', {
|
|
368
|
-
type: 'checkbox',
|
|
369
|
-
checked: forceTurn ? 'checked' : null,
|
|
370
|
-
onchange: (e) => onForceTurnToggle && onForceTurnToggle(e.target.checked)
|
|
371
|
-
})
|
|
372
|
-
)
|
|
373
|
-
),
|
|
374
|
-
|
|
375
|
-
isAdmin ? h('div', { class: 'cm-vsm-section cm-vsm-admin' },
|
|
376
|
-
h('div', { class: 'cm-vsm-section-label' }, 'Channel admin'),
|
|
377
|
-
h('div', { class: 'cm-vsm-row' },
|
|
378
|
-
h('span', { class: 'cm-vsm-row-label' }, 'Channel mode'),
|
|
379
|
-
h('div', { class: 'cm-vsm-radio' },
|
|
380
|
-
...channelModes.map(m => h('button', {
|
|
381
|
-
class: 'cm-vsm-radio-btn' + (channelMode === m.id ? ' active' : ''),
|
|
382
|
-
onclick: () => onChannelModeChange && onChannelModeChange(m.id),
|
|
383
|
-
'data-mode': m.id
|
|
384
|
-
}, m.label))
|
|
385
|
-
)
|
|
386
|
-
),
|
|
387
|
-
allowedRoles != null ? h('div', { class: 'cm-vsm-row' },
|
|
388
|
-
h('span', { class: 'cm-vsm-row-label' }, 'Allowed roles'),
|
|
389
|
-
h('span', { class: 'cm-vsm-row-val' }, Array.isArray(allowedRoles) ? allowedRoles.join(', ') || '(any)' : String(allowedRoles))
|
|
390
|
-
) : null
|
|
391
|
-
) : null,
|
|
392
|
-
|
|
393
|
-
h('div', { class: 'cm-vsm-actions' },
|
|
394
|
-
h('button', { class: 'cm-vsm-cancel', onclick: onCancel }, 'Cancel'),
|
|
395
|
-
h('button', { class: 'cm-vsm-save', onclick: onSave }, 'Save')
|
|
396
|
-
)
|
|
397
|
-
)
|
|
398
|
-
);
|
|
399
|
-
}
|