@atom-forge/brickee 0.0.1 → 0.0.3
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/CHANGELOG.md +59 -1
- package/README-AI.md +34 -28
- package/dist/Editor.svelte +713 -867
- package/dist/Editor.svelte.d.ts +0 -3
- package/dist/LinkPrompt.svelte +1 -14
- package/dist/Preview.svelte +27 -58
- package/dist/Preview.svelte.d.ts +2 -7
- package/dist/PropsBar.svelte +75 -249
- package/dist/PropsBar.svelte.d.ts +0 -3
- package/dist/code.d.ts +12 -0
- package/dist/code.js +15 -0
- package/dist/dom.d.ts +8 -0
- package/dist/dom.js +9 -0
- package/dist/editor/BlockMenu.svelte +102 -0
- package/dist/editor/BlockMenu.svelte.d.ts +32 -0
- package/dist/editor/FormatBar.svelte +41 -0
- package/dist/editor/FormatBar.svelte.d.ts +16 -0
- package/dist/editor/drag.svelte.d.ts +63 -0
- package/dist/editor/drag.svelte.js +95 -0
- package/dist/editor/history.d.ts +24 -0
- package/dist/editor/history.js +86 -0
- package/dist/editor/sweep.svelte.d.ts +21 -0
- package/dist/editor/sweep.svelte.js +56 -0
- package/dist/html.d.ts +12 -0
- package/dist/html.js +206 -0
- package/dist/i18n.js +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +4 -3
- package/dist/kit/Empty.svelte +4 -15
- package/dist/kit/Frame.svelte +7 -37
- package/dist/locales/hu.js +6 -8
- package/dist/markdown.d.ts +20 -6
- package/dist/markdown.js +380 -85
- package/dist/model.js +2 -3
- package/dist/plugins/Gap.svelte +5 -8
- package/dist/plugins/GapPreview.svelte +4 -6
- package/dist/plugins/Map.svelte +2 -17
- package/dist/plugins/MapPreview.svelte +8 -10
- package/dist/plugins/Table.svelte +233 -282
- package/dist/plugins/TablePreview.svelte +28 -28
- package/dist/plugins/YouTube.svelte +3 -31
- package/dist/plugins/YouTubePreview.svelte +45 -43
- package/dist/plugins/index.js +15 -2
- package/dist/schema.js +1 -1
- package/dist/types.d.ts +27 -10
- package/dist/types.js +8 -1
- package/dist/view.js +1 -1
- package/docs/en/bundled-plugins.md +1 -1
- package/docs/en/documents-and-markdown.md +24 -19
- package/docs/en/editor-and-preview.md +7 -10
- package/docs/en/getting-started.md +14 -2
- package/docs/en/host-contexts.md +26 -132
- package/docs/en/index.md +5 -5
- package/docs/en/recipes-and-pitfalls.md +12 -11
- package/docs/en/server-side.md +0 -17
- package/docs/en/upgrading.md +34 -4
- package/docs/en/writing-plugins.md +147 -21
- package/docs/hu/bundled-plugins.md +1 -1
- package/docs/hu/documents-and-markdown.md +24 -19
- package/docs/hu/editor-and-preview.md +7 -10
- package/docs/hu/getting-started.md +14 -2
- package/docs/hu/host-contexts.md +26 -132
- package/docs/hu/index.md +5 -5
- package/docs/hu/recipes-and-pitfalls.md +12 -11
- package/docs/hu/server-side.md +0 -17
- package/docs/hu/upgrading.md +34 -4
- package/docs/hu/writing-plugins.md +147 -21
- package/package.json +14 -2
- package/dist/ImagePicker.svelte +0 -131
- package/dist/ImagePicker.svelte.d.ts +0 -13
- package/dist/media.d.ts +0 -17
- package/dist/media.js +0 -12
package/dist/html.js
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
// Formatted paste: HTML from a web page, Google Docs, Word… -> markdown -> blocks. Going through markdown reuses
|
|
2
|
+
// everything fromMarkdown does (list nesting, tables for a plugin that takes them, safe links); the HTML is only read,
|
|
3
|
+
// never inserted. Browser only (DOMParser).
|
|
4
|
+
import { codeSpan, escLine, escText, fromMarkdown, mdUrl } from './markdown';
|
|
5
|
+
/** Never read: no text of theirs belongs in a document. */
|
|
6
|
+
const SKIP = new Set(['SCRIPT', 'STYLE', 'HEAD', 'TITLE', 'META', 'LINK', 'TEMPLATE', 'NOSCRIPT', 'SVG', 'CANVAS', 'IFRAME', 'OBJECT', 'EMBED', 'BUTTON', 'SELECT', 'TEXTAREA', 'INPUT', 'VIDEO', 'AUDIO']);
|
|
7
|
+
/** Elements that make blocks; everything else is inline. */
|
|
8
|
+
const BLOCK = new Set([
|
|
9
|
+
'ADDRESS', 'ARTICLE', 'ASIDE', 'BLOCKQUOTE', 'BODY', 'CENTER', 'DD', 'DETAILS', 'DIV', 'DL', 'DT', 'FIELDSET', 'FIGCAPTION', 'FIGURE', 'FOOTER', 'FORM',
|
|
10
|
+
'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HEADER', 'HR', 'HTML', 'LI', 'MAIN', 'NAV', 'OL', 'P', 'PRE', 'SECTION', 'SUMMARY', 'TABLE', 'UL'
|
|
11
|
+
]);
|
|
12
|
+
const BLOCK_SELECTOR = [...BLOCK].map((t) => t.toLowerCase()).join(',');
|
|
13
|
+
/** A block, or an inline element that holds blocks (Google Docs wraps a whole copy in a <b>): a container then. */
|
|
14
|
+
const isBlock = (n) => n instanceof HTMLElement && (BLOCK.has(n.tagName) || (!SKIP.has(n.tagName) && !!n.querySelector(BLOCK_SELECTOR)));
|
|
15
|
+
/** Marks around text, with its spaces kept outside (`** bold**` is no mark). */
|
|
16
|
+
function wrap(inner, open, close = open) {
|
|
17
|
+
const [, a, core, b] = /^(\s*)([\s\S]*?)(\s*)$/.exec(inner);
|
|
18
|
+
return core ? a + open + core + close + b : inner;
|
|
19
|
+
}
|
|
20
|
+
/** The marks a span's inline style stands for (Google Docs writes bold and italic as styles). */
|
|
21
|
+
function styled(el, inner) {
|
|
22
|
+
const s = el.style;
|
|
23
|
+
const weight = s.fontWeight;
|
|
24
|
+
let out = inner;
|
|
25
|
+
if (weight === 'bold' || weight === 'bolder' || Number(weight) >= 600)
|
|
26
|
+
out = wrap(out, '**');
|
|
27
|
+
if (s.fontStyle === 'italic')
|
|
28
|
+
out = wrap(out, '*');
|
|
29
|
+
if (s.textDecoration.includes('line-through') || s.textDecorationLine.includes('line-through'))
|
|
30
|
+
out = wrap(out, '~~');
|
|
31
|
+
if (s.textDecoration.includes('underline') || s.textDecorationLine.includes('underline'))
|
|
32
|
+
out = wrap(out, '<u>', '</u>');
|
|
33
|
+
if (s.verticalAlign === 'super')
|
|
34
|
+
out = wrap(out, '<sup>', '</sup>');
|
|
35
|
+
if (s.verticalAlign === 'sub')
|
|
36
|
+
out = wrap(out, '<sub>', '</sub>');
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
/** Inline content as inline markdown; `\n` where the HTML breaks a line. */
|
|
40
|
+
function inline(nodes) {
|
|
41
|
+
let text = '';
|
|
42
|
+
// HTML collapses neighbouring spaces, also across marks ("a <b> b</b>").
|
|
43
|
+
const out = {
|
|
44
|
+
add(s) {
|
|
45
|
+
text += /[ \n]$/.test(text) || !text ? s.replace(/^ +/, '') : s;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
for (const n of nodes) {
|
|
49
|
+
if (n.nodeType === Node.TEXT_NODE) {
|
|
50
|
+
out.add(escText((n.textContent ?? '').replace(/[ \t\r\n]+/g, ' ')));
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (!(n instanceof HTMLElement) || SKIP.has(n.tagName))
|
|
54
|
+
continue;
|
|
55
|
+
const tag = n.tagName;
|
|
56
|
+
if (tag === 'BR') {
|
|
57
|
+
out.add('\n');
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (tag === 'IMG') {
|
|
61
|
+
// No images in the package: a picture becomes a link to it.
|
|
62
|
+
const src = n.getAttribute('src') ?? '';
|
|
63
|
+
if (/^https?:/i.test(src))
|
|
64
|
+
out.add(`[${escText(n.getAttribute('alt') || src)}](${mdUrl(src)})`);
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (tag === 'CODE' || tag === 'KBD' || tag === 'SAMP' || tag === 'TT') {
|
|
68
|
+
const text = (n.textContent ?? '').replace(/\s+/g, ' ');
|
|
69
|
+
out.add(text.trim() ? codeSpan(text) : text);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
// A block inside inline content (a paragraph in a list item): its own line.
|
|
73
|
+
const inner = isBlock(n) ? `\n${inline(n.childNodes).trim()}\n` : inline(n.childNodes);
|
|
74
|
+
if (tag === 'A') {
|
|
75
|
+
const href = n.getAttribute('href') ?? '';
|
|
76
|
+
out.add(inner.trim() && href && !href.startsWith('#') ? wrap(inner, '[', `](${mdUrl(href)})`) : inner);
|
|
77
|
+
}
|
|
78
|
+
else if (tag === 'B' || tag === 'STRONG') {
|
|
79
|
+
// Google Docs wraps a whole copy in <b style="font-weight:normal">.
|
|
80
|
+
const w = n.style.fontWeight;
|
|
81
|
+
out.add(w === 'normal' || w === '400' ? styled(n, inner) : wrap(inner, '**'));
|
|
82
|
+
}
|
|
83
|
+
else if (tag === 'I' || tag === 'EM' || tag === 'CITE' || tag === 'DFN' || tag === 'VAR')
|
|
84
|
+
out.add(wrap(inner, '*'));
|
|
85
|
+
else if (tag === 'U' || tag === 'INS')
|
|
86
|
+
out.add(wrap(inner, '<u>', '</u>'));
|
|
87
|
+
else if (tag === 'S' || tag === 'DEL' || tag === 'STRIKE')
|
|
88
|
+
out.add(wrap(inner, '~~'));
|
|
89
|
+
else if (tag === 'SUB' || tag === 'SUP')
|
|
90
|
+
out.add(wrap(inner, `<${tag.toLowerCase()}>`, `</${tag.toLowerCase()}>`));
|
|
91
|
+
else
|
|
92
|
+
out.add(styled(n, inner));
|
|
93
|
+
}
|
|
94
|
+
return text;
|
|
95
|
+
}
|
|
96
|
+
/** Inline markdown as the lines of a paragraph: each line escaped where it would read as a block start. */
|
|
97
|
+
const lines = (md) => md
|
|
98
|
+
.split('\n')
|
|
99
|
+
.map((l) => l.trim())
|
|
100
|
+
.filter(Boolean)
|
|
101
|
+
.map(escLine);
|
|
102
|
+
/** A container's children as markdown chunks (blocks); runs of inline content become paragraphs. */
|
|
103
|
+
function chunks(el) {
|
|
104
|
+
const out = [];
|
|
105
|
+
let run = [];
|
|
106
|
+
const flush = () => {
|
|
107
|
+
const ls = lines(inline(run));
|
|
108
|
+
if (ls.length)
|
|
109
|
+
out.push(ls.join('\n'));
|
|
110
|
+
run = [];
|
|
111
|
+
};
|
|
112
|
+
for (const n of el.childNodes) {
|
|
113
|
+
if (n instanceof HTMLElement && SKIP.has(n.tagName))
|
|
114
|
+
continue;
|
|
115
|
+
if (isBlock(n)) {
|
|
116
|
+
flush();
|
|
117
|
+
out.push(...block(n));
|
|
118
|
+
}
|
|
119
|
+
else
|
|
120
|
+
run.push(n);
|
|
121
|
+
}
|
|
122
|
+
flush();
|
|
123
|
+
return out;
|
|
124
|
+
}
|
|
125
|
+
function block(el) {
|
|
126
|
+
const tag = el.tagName;
|
|
127
|
+
if (/^H[1-6]$/.test(tag)) {
|
|
128
|
+
const text = inline(el.childNodes).replace(/\s*\n\s*/g, ' ').trim();
|
|
129
|
+
return text ? [`${'#'.repeat(+tag[1])} ${text}`] : [];
|
|
130
|
+
}
|
|
131
|
+
if (tag === 'HR')
|
|
132
|
+
return ['---'];
|
|
133
|
+
if (tag === 'UL' || tag === 'OL') {
|
|
134
|
+
const md = list(el, 0);
|
|
135
|
+
return md ? [md] : [];
|
|
136
|
+
}
|
|
137
|
+
if (tag === 'PRE') {
|
|
138
|
+
const text = (el.textContent ?? '').replace(/\r/g, '').replace(/\n$/, '');
|
|
139
|
+
const lang = /(?:^|\s)(?:language|lang)-([\w+#.-]+)/.exec(`${el.className} ${el.querySelector('code')?.className ?? ''}`)?.[1] ?? '';
|
|
140
|
+
const fence = '`'.repeat(Math.max(3, ...(text.match(/`+/g) ?? []).map((r) => r.length + 1)));
|
|
141
|
+
return [`${fence}${lang}\n${text}\n${fence}`];
|
|
142
|
+
}
|
|
143
|
+
if (tag === 'BLOCKQUOTE') {
|
|
144
|
+
const inner = chunks(el);
|
|
145
|
+
return inner.length ? [inner.map((c) => c.split('\n').map((l) => `> ${l}`).join('\n')).join('\n>\n')] : [];
|
|
146
|
+
}
|
|
147
|
+
if (tag === 'TABLE')
|
|
148
|
+
return table(el);
|
|
149
|
+
return chunks(el);
|
|
150
|
+
}
|
|
151
|
+
/** A list and its nested lists, `indent` spaces in. */
|
|
152
|
+
function list(el, indent) {
|
|
153
|
+
const pad = ' '.repeat(indent);
|
|
154
|
+
const ordered = el.tagName === 'OL';
|
|
155
|
+
let n = Number(el.getAttribute('start')) || 1;
|
|
156
|
+
const out = [];
|
|
157
|
+
for (const li of el.children) {
|
|
158
|
+
if (li.tagName !== 'LI')
|
|
159
|
+
continue;
|
|
160
|
+
const box = li.querySelector(':scope > input[type="checkbox"], :scope > p > input[type="checkbox"], :scope > label > input[type="checkbox"]');
|
|
161
|
+
const marker = ordered ? `${n++}. ` : box ? `- [${box.checked || box.hasAttribute('checked') ? 'x' : ' '}] ` : '- ';
|
|
162
|
+
const own = [...li.childNodes].filter((c) => !(c instanceof HTMLElement && (c.tagName === 'UL' || c.tagName === 'OL')));
|
|
163
|
+
const [first = '', ...more] = lines(inline(own));
|
|
164
|
+
out.push(pad + marker + first);
|
|
165
|
+
const inner = ' '.repeat(indent + marker.length);
|
|
166
|
+
for (const l of more)
|
|
167
|
+
out.push(inner + l);
|
|
168
|
+
for (const sub of li.children)
|
|
169
|
+
if (sub.tagName === 'UL' || sub.tagName === 'OL') {
|
|
170
|
+
const md = list(sub, indent + marker.length);
|
|
171
|
+
if (md)
|
|
172
|
+
out.push(md);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return out.join('\n');
|
|
176
|
+
}
|
|
177
|
+
/** A table as a GFM table: the first row is the header; the alignment from the header cells. */
|
|
178
|
+
function table(el) {
|
|
179
|
+
const rows = [...el.querySelectorAll('tr')].filter((tr) => tr.closest('table') === el);
|
|
180
|
+
const grid = rows.map((tr) => [...tr.children]
|
|
181
|
+
.filter((c) => c.tagName === 'TD' || c.tagName === 'TH')
|
|
182
|
+
.map((c) => inline(c.childNodes).replace(/\s*\n\s*/g, '<br>').trim().replace(/\|/g, '\\|')));
|
|
183
|
+
if (!grid.length || !grid[0].length)
|
|
184
|
+
return [];
|
|
185
|
+
const width = Math.max(...grid.map((r) => r.length));
|
|
186
|
+
const align = [...rows[0].children].map((c) => {
|
|
187
|
+
const a = (c.style.textAlign || c.getAttribute('align') || '').toLowerCase();
|
|
188
|
+
return a === 'center' ? ':-:' : a === 'right' ? '--:' : '---';
|
|
189
|
+
});
|
|
190
|
+
const row = (r) => `| ${[...r, ...Array(width - r.length).fill('')].join(' | ')} |`;
|
|
191
|
+
return [[row(grid[0]), row(Array.from({ length: width }, (_, i) => align[i] ?? '---')), ...grid.slice(1).map(row)].join('\n')];
|
|
192
|
+
}
|
|
193
|
+
/** HTML (a pasted fragment or a page) as markdown. Browser only. */
|
|
194
|
+
export function markdownFromHtml(html) {
|
|
195
|
+
const doc = new DOMParser().parseFromString(html, 'text/html');
|
|
196
|
+
return chunks(doc.body).join('\n\n');
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* HTML -> blocks, the way the editor takes a formatted paste: headings, paragraphs, lists (nested, numbered with their
|
|
200
|
+
* start, to-dos from checkboxes), quotes, code (`pre`, with a `language-…` class), rules, and inline marks — also
|
|
201
|
+
* Google Docs' styled spans. A table goes to the first of `plugins` that takes tables (`fromTable`). Images become
|
|
202
|
+
* links; scripts, styles and form controls are dropped. Browser only.
|
|
203
|
+
*/
|
|
204
|
+
export function fromHtml(html, opts = {}) {
|
|
205
|
+
return fromMarkdown(markdownFromHtml(html), opts);
|
|
206
|
+
}
|
package/dist/i18n.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// UI text. The editor and the plugins are written in English; a host passes `messages` (English text -> its own) to
|
|
2
2
|
// the top editor or preview, and nested editors and plugin views inherit them. `{name}` placeholders are filled in.
|
|
3
3
|
import { getContext, setContext } from 'svelte';
|
|
4
|
-
const KEY = '
|
|
4
|
+
const KEY = 'brickee:text';
|
|
5
5
|
export const translator = (messages) => (text, vars) => {
|
|
6
6
|
const out = messages?.[text] ?? text;
|
|
7
7
|
return vars ? out.replace(/\{(\w+)\}/g, (m, k) => (k in vars ? String(vars[k]) : m)) : out;
|
package/dist/index.d.ts
CHANGED
|
@@ -5,9 +5,10 @@ export { default as Empty } from './kit/Empty.svelte';
|
|
|
5
5
|
export * from './kit/util';
|
|
6
6
|
export * from './model';
|
|
7
7
|
export { inline, fromStored, toStored, fromMarkdown, toMarkdown } from './markdown';
|
|
8
|
-
export {
|
|
8
|
+
export { fromHtml } from './html';
|
|
9
9
|
export { provideView, useView } from './view';
|
|
10
|
+
export { provideCodeLanguages, useCodeLanguages, type CodeLanguage } from './code';
|
|
10
11
|
export { scrollSync, scrollFraction, setScrollFraction, type ScrollSync } from './scroll';
|
|
11
12
|
export { provideText, useText, translator, type Messages, type Translate } from './i18n';
|
|
12
13
|
export { PALETTE_ITEMS, BUILT_IN_IDS, narrowPalette, type Icon, type PaletteItem } from './palette';
|
|
13
|
-
export type { MarkdownContext, Block, BlockType, Content, PluginPreviewProps, PluginViewProps, PropField, Props, BlockPlugin } from './types';
|
|
14
|
+
export type { MarkdownContext, MarkdownTable, Block, BlockType, Content, PluginPreviewProps, PluginViewProps, PropField, Props, BlockPlugin } from './types';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Brickee: a Svelte 5 block editor. The core is markdown (`md:p`, `md:h2`, `md:code`…) plus the kit to write plugins
|
|
2
2
|
// with; every other block is a plugin with an editor view, a site preview and optionally a markdown form. The bundled
|
|
3
|
-
// plugins (
|
|
3
|
+
// plugins (@atom-forge/brickee/plugins) are plugins like any other. The stored form is `StoredBlock[]` (see model.ts).
|
|
4
4
|
export { default as Editor } from './Editor.svelte';
|
|
5
5
|
export { default as Preview } from './Preview.svelte';
|
|
6
6
|
// The kit: what plugins are written with (box frame, empty state, helpers).
|
|
@@ -9,8 +9,9 @@ export { default as Empty } from './kit/Empty.svelte';
|
|
|
9
9
|
export * from './kit/util';
|
|
10
10
|
export * from './model';
|
|
11
11
|
export { inline, fromStored, toStored, fromMarkdown, toMarkdown } from './markdown';
|
|
12
|
-
export {
|
|
12
|
+
export { fromHtml } from './html';
|
|
13
13
|
export { provideView, useView } from './view';
|
|
14
|
+
export { provideCodeLanguages, useCodeLanguages } from './code';
|
|
14
15
|
export { scrollSync, scrollFraction, setScrollFraction } from './scroll';
|
|
15
16
|
export { provideText, useText, translator } from './i18n';
|
|
16
17
|
export { PALETTE_ITEMS, BUILT_IN_IDS, narrowPalette } from './palette';
|
package/dist/kit/Empty.svelte
CHANGED
|
@@ -7,18 +7,7 @@
|
|
|
7
7
|
const tr = useText();
|
|
8
8
|
</script>
|
|
9
9
|
|
|
10
|
-
<div class="
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
display: flex;
|
|
15
|
-
align-items: center;
|
|
16
|
-
justify-content: center;
|
|
17
|
-
gap: 8px;
|
|
18
|
-
min-height: 96px;
|
|
19
|
-
border: 1px dashed #d4d4da;
|
|
20
|
-
border-radius: 10px;
|
|
21
|
-
color: #a0a0a8;
|
|
22
|
-
font: 14px system-ui, sans-serif;
|
|
23
|
-
}
|
|
24
|
-
</style>
|
|
10
|
+
<div class="flex min-h-24 items-center justify-center gap-2 rounded-[10px] border border-dashed border-frame font-sans text-sm leading-[normal] text-muted-contrast">
|
|
11
|
+
<I size={18} />
|
|
12
|
+
{tr(text)}
|
|
13
|
+
</div>
|
package/dist/kit/Frame.svelte
CHANGED
|
@@ -31,46 +31,16 @@
|
|
|
31
31
|
const fields = claimFields();
|
|
32
32
|
</script>
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
<!-- left padding: room for the inner blocks' handle bar (22px left of the row, which reaches 8px out); the fields reach
|
|
35
|
+
to the frame's edges, its padding taken back -->
|
|
36
|
+
<div class="relative rounded-[10px] border border-frame pt-[0.8em] pr-[1.1em] pb-[0.4em] pl-[calc(30px+0.5em)]">
|
|
35
37
|
{#if fields}
|
|
36
|
-
<div class="
|
|
38
|
+
<div class="mt-[calc(-0.8em+4px)] mr-[calc(-1.1em+4px)] mb-[0.5em] ml-[calc(-30px-0.5em+4px)]">{@render fields()}</div>
|
|
37
39
|
{:else if heading || empty || image}
|
|
38
|
-
<div class="
|
|
39
|
-
{#if image}<img src={image} alt="" draggable="false" />{/if}
|
|
40
|
-
<span class
|
|
40
|
+
<div class="mr-[9em] mb-[0.3em] flex items-center gap-2 font-sans text-[13px] leading-[1.4] font-semibold text-surface-contrast">
|
|
41
|
+
{#if image}<img class="h-7 w-11 rounded object-cover" src={image} alt="" draggable="false" />{/if}
|
|
42
|
+
<span class={heading ? '' : 'font-normal text-muted-contrast'}>{heading || empty}</span>
|
|
41
43
|
</div>
|
|
42
44
|
{/if}
|
|
43
45
|
<Editor bind:value={blocks} {readonly} {palette} {plugins} nested placeholder={placeholder ?? tr('Write inside…')} />
|
|
44
46
|
</div>
|
|
45
|
-
|
|
46
|
-
<style>
|
|
47
|
-
.frame {
|
|
48
|
-
position: relative;
|
|
49
|
-
border: 1px solid #e5e5ea;
|
|
50
|
-
border-radius: 10px;
|
|
51
|
-
/* left: room for the inner blocks' handle bar (22px left of the row, which reaches 8px out) */
|
|
52
|
-
padding: 0.8em 1.1em 0.4em calc(30px + 0.5em);
|
|
53
|
-
}
|
|
54
|
-
/* the fields reach to the frame's edges, the frame's padding taken back */
|
|
55
|
-
.fields {
|
|
56
|
-
margin: calc(-0.8em + 4px) calc(-1.1em + 4px) 0.5em calc(-30px - 0.5em + 4px);
|
|
57
|
-
}
|
|
58
|
-
.head {
|
|
59
|
-
display: flex;
|
|
60
|
-
align-items: center;
|
|
61
|
-
gap: 8px;
|
|
62
|
-
margin: 0 9em 0.3em 0;
|
|
63
|
-
font: 600 13px/1.4 system-ui, sans-serif;
|
|
64
|
-
color: #1d1d1f;
|
|
65
|
-
}
|
|
66
|
-
.head img {
|
|
67
|
-
height: 28px;
|
|
68
|
-
width: 44px;
|
|
69
|
-
object-fit: cover;
|
|
70
|
-
border-radius: 4px;
|
|
71
|
-
}
|
|
72
|
-
.muted {
|
|
73
|
-
font-weight: 400;
|
|
74
|
-
color: #a0a0a8;
|
|
75
|
-
}
|
|
76
|
-
</style>
|
package/dist/locales/hu.js
CHANGED
|
@@ -4,16 +4,14 @@ export const hu = {
|
|
|
4
4
|
'Add a block below': 'Új blokk alá',
|
|
5
5
|
'Drag to move, click to select': 'Húzd az áthelyezéshez, kattints a kijelöléshez',
|
|
6
6
|
Done: 'Kész',
|
|
7
|
+
'Move up': 'Mozgatás fel',
|
|
8
|
+
'Move down': 'Mozgatás le',
|
|
9
|
+
'Select the block': 'A blokk kijelölése',
|
|
10
|
+
'Unknown block: {type}': 'Ismeretlen blokk: {type}',
|
|
7
11
|
inherited: 'örökölt',
|
|
8
12
|
Settings: 'Beállítások',
|
|
9
13
|
'Hide settings': 'Beállítások elrejtése',
|
|
10
14
|
None: 'Nincs',
|
|
11
|
-
Images: 'Képek',
|
|
12
|
-
Choose: 'Választás',
|
|
13
|
-
'Choose…': 'Válassz…',
|
|
14
|
-
'{n} picked': '{n} kiválasztva',
|
|
15
|
-
language: 'nyelv',
|
|
16
|
-
'No images attached to this page yet.': 'Még nincs kép csatolva.',
|
|
17
15
|
'New block at the end': 'Új blokk a végére',
|
|
18
16
|
Formatting: 'Formázás',
|
|
19
17
|
'Turn into': 'Átalakítás',
|
|
@@ -131,15 +129,15 @@ export const hu = {
|
|
|
131
129
|
'Align column right': 'Az oszlop jobbra zárva',
|
|
132
130
|
'Header row': 'Fejléc (első sor)',
|
|
133
131
|
'Footer row (e.g. sums)': 'Lábléc (utolsó sor, pl. összesítő)',
|
|
132
|
+
'Header and footer': 'Fejléc és lábléc',
|
|
133
|
+
'Click a cell to edit its row and column': 'Kattints egy cellába a sora és oszlopa szerkesztéséhez',
|
|
134
134
|
'Drag to move the row': 'Húzd a sor áthelyezéséhez',
|
|
135
135
|
'Drag to move the column': 'Húzd az oszlop áthelyezéséhez',
|
|
136
|
-
'Enter: next row · Shift+Enter: line break · paste from a spreadsheet': 'Enter: következő sor · Shift+Enter: sortörés · táblázatból be is illeszthető',
|
|
137
136
|
Heading: 'Fejléc',
|
|
138
137
|
'Row {r}, column {c}': '{r}. sor, {c}. oszlop',
|
|
139
138
|
'Add a column': 'Új oszlop',
|
|
140
139
|
'Add a row': 'Új sor',
|
|
141
140
|
// előnézet
|
|
142
|
-
'For supporters only': 'Csak támogatóknak',
|
|
143
141
|
'YouTube video': 'YouTube-videó',
|
|
144
142
|
video: 'videó',
|
|
145
143
|
'Play {title}': 'Lejátszás: {title}',
|
package/dist/markdown.d.ts
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
|
-
import type { MediaItem } from './media';
|
|
2
1
|
import { type Block, type BlockPlugin, type StoredBlock } from './types';
|
|
3
2
|
/** Inline markdown -> inline html (b, i, u, sub, sup, strike, code, a, br). Backslash escapes are honoured; links are
|
|
4
|
-
* http(s), mailto, tel or site-relative only.
|
|
3
|
+
* http(s), mailto, tel or site-relative only. Images become links (the package has no notion of images), footnote
|
|
4
|
+
* references superscripts, and inline HTML its marks (other tags are dropped). */
|
|
5
5
|
export declare function inline(md: string): string;
|
|
6
|
+
/** A link target as markdown reads it back: spaces and unbalanced parentheses encoded. */
|
|
7
|
+
export declare function mdUrl(href: string): string;
|
|
8
|
+
/** Plain text as inline markdown: what would read as a mark is escaped (`_` only at a word's edge: snake_case stays). */
|
|
9
|
+
export declare function escText(t: string): string;
|
|
10
|
+
/** Inline markdown for a code span: a fence longer than any backtick run inside, padded when it starts or ends with one. */
|
|
11
|
+
export declare function codeSpan(text: string): string;
|
|
6
12
|
/** Inline html -> inline markdown (browser only). `code` keeps the text verbatim, as in a code block. */
|
|
7
13
|
export declare function htmlToMarkdown(html: string, code?: boolean): string;
|
|
14
|
+
/** A line of text, escaped where markdown would read it as a block start (`1. ` as `1\. `). */
|
|
15
|
+
export declare function escLine(t: string): string;
|
|
8
16
|
/** One block -> its markdown snippet, without indentation. `n` is the ordinal of a numbered item. */
|
|
9
17
|
export declare function blockToMd(b: Block, n?: number): string;
|
|
10
|
-
/** One markdown
|
|
18
|
+
/** One markdown line -> block fields (a heading, a list item, a quote, a rule or a paragraph). */
|
|
11
19
|
export declare function mdToBlock(md: string): Pick<Block, 'type' | 'html' | 'checked' | 'props'>;
|
|
12
20
|
/** Inline html -> the same letters without formatting (line breaks kept), as a code block holds them. */
|
|
13
21
|
export declare function plainHtml(html: string): string;
|
|
@@ -15,11 +23,17 @@ export declare function plainHtml(html: string): string;
|
|
|
15
23
|
export declare function toStored(b: Block): StoredBlock;
|
|
16
24
|
/** Stored block -> editor block with a fresh id. Unknown types (md: or plugin) are kept as they are. */
|
|
17
25
|
export declare function fromStored(s: StoredBlock): Block;
|
|
18
|
-
/**
|
|
19
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Markdown text -> blocks (CommonMark and GFM, as far as blocks can hold them): headings (also setext), lists with
|
|
28
|
+
* their nesting and start number, to-dos, quotes (also nested), fenced and indented code, rules, and paragraphs whose
|
|
29
|
+
* lines are kept as line breaks. Reference links are resolved, footnotes become superscripts. A GFM table goes to the
|
|
30
|
+
* first of `plugins` that takes it (`fromTable`), or stays text.
|
|
31
|
+
*/
|
|
32
|
+
export declare function fromMarkdown(src: string, opts?: {
|
|
33
|
+
plugins?: BlockPlugin[];
|
|
34
|
+
}): Block[];
|
|
20
35
|
/** Blocks -> markdown text (browser only: uses the DOM to read the inline html). A plugin block is written by its
|
|
21
36
|
* plugin's `markdown`; one without it is left out. */
|
|
22
37
|
export declare function toMarkdown(blocks: Block[], opts?: {
|
|
23
38
|
plugins?: BlockPlugin[];
|
|
24
|
-
media?: MediaItem[];
|
|
25
39
|
}): string;
|