dsh-tiddlywiki 0.22.0 → 0.22.2

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-tiddlywiki",
3
3
  "description": "TiddlyWiki 5 as the DSH persistent knowledge base: fifteen tiddlywiki_* agent tools (filtered search/recent/tags/batch/rewrite/trash/lint + git sync & conflict resolve), a full TiddlyWiki editor embedded in the GUI center column (same-origin proxy, works over Tailscale/LAN/domain), a right-side wiki tab, a per-session summary tab, a quick-note card with draft auto-save behind a single knowledge FAB, an optional clip bookmarklet that also saves selected images as attachments, and git-based sync with auto-commit. Mounts via the official dsh plugin system — no DSH source changes.",
4
- "version": "0.22.0",
4
+ "version": "0.22.2",
5
5
  "type": "module",
6
6
  "keywords": [
7
7
  "dsh",
@@ -1,128 +1,128 @@
1
- /**
2
- * CodeMirror 6 Markdown editor for the quick-note widget (replaces the
3
- * hand-rolled regex highlighter in the old markdown.ts — real Lezer syntax
4
- * tree, proper GFM coverage, undo/redo, and a native editing surface).
5
- *
6
- * The widget stays a plain-DOM product: CodeMirror is framework-agnostic, so
7
- * no React is pulled in. The editor is built into a wrapper `<div>`
8
- * (`.dsh-tw-note-editor`) that the widget can append, drag-drop onto, and
9
- * re-read via `getValue()`/`setValue()`.
10
- *
11
- * Theming follows the DSH design tokens (`--dsw-alias-*`) through a
12
- * `HighlightStyle` that maps Markdown tags onto the same palette the old
13
- * `.md-*` rules used, so light/dark both look right.
14
- *
15
- * @module dsh-tiddlywiki/client/markdown-editor
16
- */
17
- import { EditorView, keymap, placeholder, drawSelection } from '@codemirror/view'
18
- import { EditorState } from '@codemirror/state'
19
- import { markdown, markdownLanguage } from '@codemirror/lang-markdown'
20
- import { syntaxHighlighting, HighlightStyle } from '@codemirror/language'
21
- import { defaultKeymap, history, historyKeymap } from '@codemirror/commands'
22
- import { tags as t } from '@lezer/highlight'
23
-
24
- /** Design-token aliases (same values as styles.ts / the old .md-* rules). */
25
- const BRAND = 'var(--dsw-alias-brand-primary, #3e63dd)'
26
- const BRAND_DIM = 'color-mix(in srgb, var(--dsw-alias-brand-primary, #3e63dd) 55%, transparent)'
27
- const SECONDARY = 'var(--dsw-alias-label-secondary, #888)'
28
- const DIMMED = 'var(--dsw-alias-label-dimmed, #999)'
29
- const MONO = 'ui-monospace, "Cascadia Mono", Consolas, "SF Mono", Menlo, monospace'
30
- const CODE_BG = 'color-mix(in srgb, var(--dsw-alias-label-secondary, #888) 12%, transparent)'
31
- const CODE_BLOCK_BG = 'color-mix(in srgb, var(--dsw-alias-label-secondary, #888) 8%, transparent)'
32
-
33
- /** Markdown token → design-token style map (mirrors the old .md-* palette). */
34
- const mdHighlight = HighlightStyle.define([
35
- // Headings (# … ######) — brand + bold.
36
- { tag: [t.heading1, t.heading2, t.heading3, t.heading4, t.heading5, t.heading6], color: BRAND, fontWeight: '700' },
37
- // Markers: #, >, -, *, `, [ ] etc.
38
- { tag: t.processingInstruction, color: BRAND_DIM },
39
- // Inline code + fenced code text — monospace, tinted background.
40
- { tag: t.monospace, fontFamily: MONO, backgroundColor: CODE_BG, borderRadius: '4px', padding: '0 3px' },
41
- // Code block content (inside a fence) gets a slightly wider tint.
42
- { tag: t.content, fontFamily: MONO, backgroundColor: CODE_BLOCK_BG },
43
- { tag: t.strong, fontWeight: '700' },
44
- { tag: t.emphasis, fontStyle: 'italic' },
45
- { tag: t.strikethrough, textDecoration: 'line-through', opacity: '.75' },
46
- { tag: t.link, color: BRAND, textDecoration: 'underline' },
47
- { tag: t.url, color: BRAND_DIM, textDecoration: 'underline dotted' },
48
- { tag: t.quote, fontStyle: 'italic', color: SECONDARY },
49
- { tag: t.contentSeparator, color: DIMMED, textDecoration: 'line-through' },
50
- { tag: t.comment, color: DIMMED },
51
- ])
52
-
53
- /** Public editor surface the quick-note widget consumes. */
54
- export interface MarkdownEditor {
55
- /** Wrapper element (append/drag-target). */
56
- el: HTMLDivElement
57
- /** The CodeMirror EditorView (advanced use / future extensions). */
58
- view: EditorView
59
- getValue(): string
60
- setValue(value: string): void
61
- /** Insert a Markdown line at the current caret (used by file upload). */
62
- insertAtCaret(markdown: string): void
63
- focus(): void
64
- }
65
-
66
- export interface MarkdownEditorOptions {
67
- /** Placeholder text shown when the doc is empty. */
68
- placeholder?: string
69
- /** Called on Ctrl/Cmd+Enter (wired after save is defined by the widget). */
70
- onSave?: () => void
71
- /** Called after every doc change (used for draft auto-save). */
72
- onChange?: () => void
73
- }
74
-
75
- /**
76
- * Build a CodeMirror 6 Markdown editor inside `.dsh-tw-note-editor`.
77
- * GFM base language (strikethrough, tables, task lists, autolinks) — strictly
78
- * more coverage than the old regex highlighter.
79
- */
80
- export function buildMarkdownEditor(opts: MarkdownEditorOptions = {}): MarkdownEditor {
81
- const wrap = document.createElement('div')
82
- wrap.className = 'dsh-tw-note-editor'
83
-
84
- const view = new EditorView({
85
- parent: wrap,
86
- state: EditorState.create({
87
- doc: '',
88
- extensions: [
89
- EditorView.lineWrapping,
90
- history(),
91
- markdown({ base: markdownLanguage }),
92
- syntaxHighlighting(mdHighlight),
93
- drawSelection(),
94
- placeholder(opts.placeholder ?? ''),
95
- keymap.of([
96
- ...defaultKeymap,
97
- ...historyKeymap,
98
- { key: 'Mod-Enter', run: () => { opts.onSave?.(); return true } },
99
- ]),
100
- EditorView.updateListener.of((update) => {
101
- if (update.docChanged) opts.onChange?.()
102
- }),
103
- ],
104
- }),
105
- })
106
-
107
- return {
108
- el: wrap,
109
- view,
110
- getValue: () => view.state.doc.toString(),
111
- setValue(value: string) {
112
- view.dispatch({ changes: { from: 0, to: view.state.doc.length, insert: value } })
113
- },
114
- insertAtCaret(markdownLine: string) {
115
- const { from } = view.state.selection.main
116
- const line = view.state.doc.lineAt(from)
117
- const atLineStart = from === line.from
118
- const insert = `${atLineStart ? '' : '\n'}${markdownLine}\n`
119
- view.dispatch({
120
- changes: { from, insert },
121
- selection: { anchor: from + insert.length },
122
- scrollIntoView: true,
123
- })
124
- view.focus()
125
- },
126
- focus: () => view.focus(),
127
- }
128
- }
1
+ /**
2
+ * CodeMirror 6 Markdown editor for the quick-note widget (replaces the
3
+ * hand-rolled regex highlighter in the old markdown.ts — real Lezer syntax
4
+ * tree, proper GFM coverage, undo/redo, and a native editing surface).
5
+ *
6
+ * The widget stays a plain-DOM product: CodeMirror is framework-agnostic, so
7
+ * no React is pulled in. The editor is built into a wrapper `<div>`
8
+ * (`.dsh-tw-note-editor`) that the widget can append, drag-drop onto, and
9
+ * re-read via `getValue()`/`setValue()`.
10
+ *
11
+ * Theming follows the DSH design tokens (`--dsw-alias-*`) through a
12
+ * `HighlightStyle` that maps Markdown tags onto the same palette the old
13
+ * `.md-*` rules used, so light/dark both look right.
14
+ *
15
+ * @module dsh-tiddlywiki/client/markdown-editor
16
+ */
17
+ import { EditorView, keymap, placeholder, drawSelection } from '@codemirror/view'
18
+ import { EditorState } from '@codemirror/state'
19
+ import { markdown, markdownLanguage } from '@codemirror/lang-markdown'
20
+ import { syntaxHighlighting, HighlightStyle } from '@codemirror/language'
21
+ import { defaultKeymap, history, historyKeymap } from '@codemirror/commands'
22
+ import { tags as t } from '@lezer/highlight'
23
+
24
+ /** Design-token aliases (same values as styles.ts / the old .md-* rules). */
25
+ const BRAND = 'var(--dsw-alias-brand-primary, #3e63dd)'
26
+ const BRAND_DIM = 'color-mix(in srgb, var(--dsw-alias-brand-primary, #3e63dd) 55%, transparent)'
27
+ const SECONDARY = 'var(--dsw-alias-label-secondary, #888)'
28
+ const DIMMED = 'var(--dsw-alias-label-dimmed, #999)'
29
+ const MONO = 'ui-monospace, "Cascadia Mono", Consolas, "SF Mono", Menlo, monospace'
30
+ const CODE_BG = 'color-mix(in srgb, var(--dsw-alias-label-secondary, #888) 12%, transparent)'
31
+ const CODE_BLOCK_BG = 'color-mix(in srgb, var(--dsw-alias-label-secondary, #888) 8%, transparent)'
32
+
33
+ /** Markdown token → design-token style map (mirrors the old .md-* palette). */
34
+ const mdHighlight = HighlightStyle.define([
35
+ // Headings (# … ######) — brand + bold.
36
+ { tag: [t.heading1, t.heading2, t.heading3, t.heading4, t.heading5, t.heading6], color: BRAND, fontWeight: '700' },
37
+ // Markers: #, >, -, *, `, [ ] etc.
38
+ { tag: t.processingInstruction, color: BRAND_DIM },
39
+ // Inline code + fenced code text — monospace, tinted background.
40
+ { tag: t.monospace, fontFamily: MONO, backgroundColor: CODE_BG, borderRadius: '4px', padding: '0 3px' },
41
+ // Code block content (inside a fence) gets a slightly wider tint.
42
+ { tag: t.content, fontFamily: MONO, backgroundColor: CODE_BLOCK_BG },
43
+ { tag: t.strong, fontWeight: '700' },
44
+ { tag: t.emphasis, fontStyle: 'italic' },
45
+ { tag: t.strikethrough, textDecoration: 'line-through', opacity: '.75' },
46
+ { tag: t.link, color: BRAND, textDecoration: 'underline' },
47
+ { tag: t.url, color: BRAND_DIM, textDecoration: 'underline dotted' },
48
+ { tag: t.quote, fontStyle: 'italic', color: SECONDARY },
49
+ { tag: t.contentSeparator, color: DIMMED, textDecoration: 'line-through' },
50
+ { tag: t.comment, color: DIMMED },
51
+ ])
52
+
53
+ /** Public editor surface the quick-note widget consumes. */
54
+ export interface MarkdownEditor {
55
+ /** Wrapper element (append/drag-target). */
56
+ el: HTMLDivElement
57
+ /** The CodeMirror EditorView (advanced use / future extensions). */
58
+ view: EditorView
59
+ getValue(): string
60
+ setValue(value: string): void
61
+ /** Insert a Markdown line at the current caret (used by file upload). */
62
+ insertAtCaret(markdown: string): void
63
+ focus(): void
64
+ }
65
+
66
+ export interface MarkdownEditorOptions {
67
+ /** Placeholder text shown when the doc is empty. */
68
+ placeholder?: string
69
+ /** Called on Ctrl/Cmd+Enter (wired after save is defined by the widget). */
70
+ onSave?: () => void
71
+ /** Called after every doc change (used for draft auto-save). */
72
+ onChange?: () => void
73
+ }
74
+
75
+ /**
76
+ * Build a CodeMirror 6 Markdown editor inside `.dsh-tw-note-editor`.
77
+ * GFM base language (strikethrough, tables, task lists, autolinks) — strictly
78
+ * more coverage than the old regex highlighter.
79
+ */
80
+ export function buildMarkdownEditor(opts: MarkdownEditorOptions = {}): MarkdownEditor {
81
+ const wrap = document.createElement('div')
82
+ wrap.className = 'dsh-tw-note-editor'
83
+
84
+ const view = new EditorView({
85
+ parent: wrap,
86
+ state: EditorState.create({
87
+ doc: '',
88
+ extensions: [
89
+ EditorView.lineWrapping,
90
+ history(),
91
+ markdown({ base: markdownLanguage }),
92
+ syntaxHighlighting(mdHighlight),
93
+ drawSelection(),
94
+ placeholder(opts.placeholder ?? ''),
95
+ keymap.of([
96
+ ...defaultKeymap,
97
+ ...historyKeymap,
98
+ { key: 'Mod-Enter', run: () => { opts.onSave?.(); return true } },
99
+ ]),
100
+ EditorView.updateListener.of((update) => {
101
+ if (update.docChanged) opts.onChange?.()
102
+ }),
103
+ ],
104
+ }),
105
+ })
106
+
107
+ return {
108
+ el: wrap,
109
+ view,
110
+ getValue: () => view.state.doc.toString(),
111
+ setValue(value: string) {
112
+ view.dispatch({ changes: { from: 0, to: view.state.doc.length, insert: value } })
113
+ },
114
+ insertAtCaret(markdownLine: string) {
115
+ const { from } = view.state.selection.main
116
+ const line = view.state.doc.lineAt(from)
117
+ const atLineStart = from === line.from
118
+ const insert = `${atLineStart ? '' : '\n'}${markdownLine}\n`
119
+ view.dispatch({
120
+ changes: { from, insert },
121
+ selection: { anchor: from + insert.length },
122
+ scrollIntoView: true,
123
+ })
124
+ view.focus()
125
+ },
126
+ focus: () => view.focus(),
127
+ }
128
+ }
@@ -1,39 +1,39 @@
1
- /**
2
- * Tiny pub/sub panel state shared by the sidebar entry and the center panel.
3
- *
4
- * @module dsh-tiddlywiki/client/state
5
- */
6
-
7
- export type PanelListener = (open: boolean) => void
8
-
9
- export class PanelState {
10
- private open = false
11
- private readonly listeners = new Set<PanelListener>()
12
-
13
- isOpen(): boolean {
14
- return this.open
15
- }
16
-
17
- toggle(): void {
18
- this.set(!this.open)
19
- }
20
-
21
- openPanel(): void {
22
- this.set(true)
23
- }
24
-
25
- closePanel(): void {
26
- this.set(false)
27
- }
28
-
29
- set(value: boolean): void {
30
- if (this.open === value) return
31
- this.open = value
32
- for (const listener of [...this.listeners]) listener(value)
33
- }
34
-
35
- subscribe(listener: PanelListener): () => void {
36
- this.listeners.add(listener)
37
- return () => { this.listeners.delete(listener) }
38
- }
39
- }
1
+ /**
2
+ * Tiny pub/sub panel state shared by the sidebar entry and the center panel.
3
+ *
4
+ * @module dsh-tiddlywiki/client/state
5
+ */
6
+
7
+ export type PanelListener = (open: boolean) => void
8
+
9
+ export class PanelState {
10
+ private open = false
11
+ private readonly listeners = new Set<PanelListener>()
12
+
13
+ isOpen(): boolean {
14
+ return this.open
15
+ }
16
+
17
+ toggle(): void {
18
+ this.set(!this.open)
19
+ }
20
+
21
+ openPanel(): void {
22
+ this.set(true)
23
+ }
24
+
25
+ closePanel(): void {
26
+ this.set(false)
27
+ }
28
+
29
+ set(value: boolean): void {
30
+ if (this.open === value) return
31
+ this.open = value
32
+ for (const listener of [...this.listeners]) listener(value)
33
+ }
34
+
35
+ subscribe(listener: PanelListener): () => void {
36
+ this.listeners.add(listener)
37
+ return () => { this.listeners.delete(listener) }
38
+ }
39
+ }