@atom-forge/brickee 0.0.0-stage → 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/CHANGELOG.md +24 -0
- package/LICENSE +21 -0
- package/README-AI.md +283 -0
- package/README.md +41 -2
- package/dist/Editor.svelte +1968 -0
- package/dist/Editor.svelte.d.ts +22 -0
- package/dist/ImagePicker.svelte +131 -0
- package/dist/ImagePicker.svelte.d.ts +13 -0
- package/dist/LinkPrompt.svelte +42 -0
- package/dist/LinkPrompt.svelte.d.ts +8 -0
- package/dist/PluginHost.svelte +41 -0
- package/dist/PluginHost.svelte.d.ts +13 -0
- package/dist/Preview.svelte +186 -0
- package/dist/Preview.svelte.d.ts +35 -0
- package/dist/PropsBar.svelte +395 -0
- package/dist/PropsBar.svelte.d.ts +20 -0
- package/dist/dom.d.ts +29 -0
- package/dist/dom.js +224 -0
- package/dist/i18n.d.ts +7 -0
- package/dist/i18n.js +18 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +16 -0
- package/dist/kit/Empty.svelte +24 -0
- package/dist/kit/Empty.svelte.d.ts +8 -0
- package/dist/kit/Frame.svelte +76 -0
- package/dist/kit/Frame.svelte.d.ts +15 -0
- package/dist/kit/util.d.ts +13 -0
- package/dist/kit/util.js +28 -0
- package/dist/locales/hu.d.ts +2 -0
- package/dist/locales/hu.js +147 -0
- package/dist/markdown.d.ts +25 -0
- package/dist/markdown.js +219 -0
- package/dist/media.d.ts +17 -0
- package/dist/media.js +12 -0
- package/dist/model.d.ts +21 -0
- package/dist/model.js +45 -0
- package/dist/palette.d.ts +19 -0
- package/dist/palette.js +23 -0
- package/dist/plugins/Gap.svelte +28 -0
- package/dist/plugins/Gap.svelte.d.ts +15 -0
- package/dist/plugins/GapPreview.svelte +17 -0
- package/dist/plugins/GapPreview.svelte.d.ts +5 -0
- package/dist/plugins/Map.svelte +47 -0
- package/dist/plugins/Map.svelte.d.ts +12 -0
- package/dist/plugins/MapPreview.svelte +26 -0
- package/dist/plugins/MapPreview.svelte.d.ts +5 -0
- package/dist/plugins/Table.svelte +563 -0
- package/dist/plugins/Table.svelte.d.ts +28 -0
- package/dist/plugins/TablePreview.svelte +62 -0
- package/dist/plugins/TablePreview.svelte.d.ts +5 -0
- package/dist/plugins/YouTube.svelte +52 -0
- package/dist/plugins/YouTube.svelte.d.ts +8 -0
- package/dist/plugins/YouTubePreview.svelte +76 -0
- package/dist/plugins/YouTubePreview.svelte.d.ts +5 -0
- package/dist/plugins/index.d.ts +20 -0
- package/dist/plugins/index.js +94 -0
- package/dist/plugins/util.d.ts +3 -0
- package/dist/plugins/util.js +8 -0
- package/dist/schema.d.ts +11 -0
- package/dist/schema.js +25 -0
- package/dist/scroll.d.ts +18 -0
- package/dist/scroll.js +57 -0
- package/dist/types.d.ts +133 -0
- package/dist/types.js +43 -0
- package/dist/view.d.ts +6 -0
- package/dist/view.js +11 -0
- package/docs/en/bundled-plugins.md +99 -0
- package/docs/en/documents-and-markdown.md +115 -0
- package/docs/en/editor-and-preview.md +141 -0
- package/docs/en/getting-started.md +81 -0
- package/docs/en/host-contexts.md +275 -0
- package/docs/en/index.md +38 -0
- package/docs/en/recipes-and-pitfalls.md +122 -0
- package/docs/en/server-side.md +95 -0
- package/docs/en/upgrading.md +55 -0
- package/docs/en/writing-plugins.md +305 -0
- package/docs/hu/bundled-plugins.md +99 -0
- package/docs/hu/documents-and-markdown.md +115 -0
- package/docs/hu/editor-and-preview.md +141 -0
- package/docs/hu/getting-started.md +81 -0
- package/docs/hu/host-contexts.md +275 -0
- package/docs/hu/index.md +38 -0
- package/docs/hu/recipes-and-pitfalls.md +122 -0
- package/docs/hu/server-side.md +95 -0
- package/docs/hu/upgrading.md +55 -0
- package/docs/hu/writing-plugins.md +305 -0
- package/package.json +110 -5
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Első lépések
|
|
2
|
+
|
|
3
|
+
[Tartalom](index.md) · [Következő →](editor-and-preview.md)
|
|
4
|
+
|
|
5
|
+
## Mi a Brickee
|
|
6
|
+
|
|
7
|
+
A Brickee blokkszerkesztő: a dokumentum blokkok listája, mindegyik a saját sorában szerkeszthető, húzással átrendezhető, és a fogantyújáról más típusúvá alakítható. A magban lévő blokkok markdown blokkok — bekezdések, hat címsorszint, felsorolás, számozott lista és teendőlista, idézetek, kód és elválasztók —, így egy pluginok nélküli dokumentum sima markdownként olvasható és másolható.
|
|
8
|
+
|
|
9
|
+
Minden más plugin. A plugin egy egyszerű objektum (`BlockPlugin`), amely megnevez egy blokktípust, és a következőket adja hozzá:
|
|
10
|
+
|
|
11
|
+
- egy **nézetet** — a szerkesztőben megjelenő Svelte-komponenst;
|
|
12
|
+
- egy **előnézetet** — a blokkot az oldalon megjelenítő Svelte-komponenst;
|
|
13
|
+
- **mezőket** — a blokk tetején megjelenő beállításokat (szöveg, szín, választó, csúszka, kép…);
|
|
14
|
+
- opcionálisan egy **markdown alakot**, amelyet a dokumentum markdownként való másolásakor vagy exportálásakor használ.
|
|
15
|
+
|
|
16
|
+
A csomag négy általános plugint is tartalmaz — táblázat, YouTube-videó, térkép és térköz —, de ezek is ugyanolyan pluginok, mint bármelyik más: a magban semmi sem függ tőlük, és csak azokat adod át, amelyeket szeretnél. A képblokkokat, dobozokat és más, az oldalra jellemző blokkokat te írod meg pluginként.
|
|
17
|
+
|
|
18
|
+
## Telepítés
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
bun add @atom-forge/brickee @atom-forge/ui @lucide/svelte
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
| Peer dependency | Miért |
|
|
25
|
+
|---|---|
|
|
26
|
+
| `svelte` `^5.0.0` | A szerkesztő, az előnézet és a pluginok Svelte 5 komponensek. |
|
|
27
|
+
| `@atom-forge/ui` `>=0.0.37` | A felugró ablakok (linkbekérő, képválasztó) és a blokkmezők űrlapvezérlői. |
|
|
28
|
+
| `@lucide/svelte` `>=1.0.0` | A blokkok ikonjai. |
|
|
29
|
+
| `zod` `^4.0.0` (opcionális) | Csak az `@atom-forge/brickee/schema` szerveroldali sémájához. |
|
|
30
|
+
|
|
31
|
+
## A befogadó alkalmazás beállítása
|
|
32
|
+
|
|
33
|
+
A blokkmezők és a felugró ablakok `@atom-forge/ui` komponensek, ezért az alkalmazást úgy kell beállítani, ahogy az `@atom-forge/ui` megköveteli:
|
|
34
|
+
|
|
35
|
+
- Tailwind CSS 4, importált `@atom-forge/ui` téma-CSS-sel, a `dist` mappáját pedig add hozzá Tailwind `@source`-ként;
|
|
36
|
+
- az alkalmazás az `@atom-forge/ui` `Root` komponense alatt renderelődjön, amely a témát és az overlay-kontextusokat biztosítja.
|
|
37
|
+
|
|
38
|
+
A legfelső szintű `Editor` saját felugróablak-kezelőt hoz létre, és saját felugróablak-tárolót renderel; a pluginblokkokba ágyazott szerkesztők ezt használják közösen.
|
|
39
|
+
|
|
40
|
+
> **Hiányzó téma**
|
|
41
|
+
>
|
|
42
|
+
> Az `@atom-forge/ui` téma-CSS nélkül a szerkesztő továbbra is működik, de a blokkmezők, a színválasztó, a csúszka és a felugró ablakok stílus nélkül jelennek meg.
|
|
43
|
+
|
|
44
|
+
Az előnézet csak azt a kevés stílust adja hozzá, amelyre saját magának szüksége van (teendő-jelölőnégyzetek, képszélességek, körbefuttatás). A címsorok, bekezdések és listák tipográfiája az előnézetet megjelenítő oldalról jön.
|
|
45
|
+
|
|
46
|
+
## Egy első szerkesztő
|
|
47
|
+
|
|
48
|
+
```svelte
|
|
49
|
+
<script lang="ts">
|
|
50
|
+
import { Editor, Preview, type StoredBlock } from '@atom-forge/brickee';
|
|
51
|
+
import { PLUGINS } from '@atom-forge/brickee/plugins';
|
|
52
|
+
|
|
53
|
+
let value = $state<StoredBlock[]>([]);
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<Editor bind:value plugins={PLUGINS} />
|
|
57
|
+
|
|
58
|
+
<article>
|
|
59
|
+
<Preview blocks={value} plugins={PLUGINS} />
|
|
60
|
+
</article>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
- A `value` a dokumentum JSON-ként (`StoredBlock[]`). A szerkesztő minden változáskor visszaírja; mentsd el úgy, ahogy van.
|
|
64
|
+
- A `plugins` felsorolja azokat a pluginblokkokat, amelyeket a szerkesztő megjeleníthet és felkínálhat. Ha elhagyod, egyszerű markdown-szerkesztőt kapsz.
|
|
65
|
+
- A `Preview` ugyanazt a dokumentumot ugyanazokkal a pluginokkal rendereli, úgy, ahogy az oldal megjeleníti.
|
|
66
|
+
|
|
67
|
+
Üres sorban gépelj `/` jelet a blokkmenü megnyitásához.
|
|
68
|
+
|
|
69
|
+
## Belépési pontok
|
|
70
|
+
|
|
71
|
+
| Import | Tartalom |
|
|
72
|
+
|---|---|
|
|
73
|
+
| `@atom-forge/brickee` | `Editor`, `Preview`, a kit (`Frame`, `Empty`, segédfüggvények), a tárolt alak, a markdown-átalakítások, a kontextusok, a paletta, a típusok. |
|
|
74
|
+
| `@atom-forge/brickee/plugins` | A mellékelt pluginok (`table`, `youtube`, `map`, `gap`), a mind a négyet tartalmazó `PLUGINS` és a segédfüggvényeik. |
|
|
75
|
+
| `@atom-forge/brickee/schema` | `blocksSchema` és `blocksSchemaFor` (zod), szerveroldali validáláshoz. |
|
|
76
|
+
| `@atom-forge/brickee/model` | A tárolt alak Svelte nélkül: `StoredBlock`, `MD`, `isMd`, `acceptsId`, `blocksToPlainText`… |
|
|
77
|
+
| `@atom-forge/brickee/locales/hu` | `hu`: a magyar felületi szövegek. |
|
|
78
|
+
|
|
79
|
+
> **Csak az kerül a bundle-be, amit importálsz**
|
|
80
|
+
>
|
|
81
|
+
> A mellékelt pluginok saját belépési ponton érhetők el. Az az alkalmazás, amely csak az `@atom-forge/brickee`-t importálja, a markdown-szerkesztőt kapja, pluginkód nélkül.
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
# Az alkalmazás kontextusai
|
|
2
|
+
|
|
3
|
+
[← Előző](writing-plugins.md) · [Tartalom](index.md) · [Következő →](server-side.md)
|
|
4
|
+
|
|
5
|
+
A szerkesztőnek nincsenek propjai az alkalmazás fogalmaihoz. Amit a befogadó alkalmazás tud — a képeit, az éppen mutatott oldalszélességet, a nyelvét —, az három Svelte-kontextuson keresztül jut el a pluginokhoz. Mindegyikhez tartozik egy `provide…` függvény, amelyet a szerkesztő vagy az előnézet fölötti komponens inicializálásakor hívsz meg, és egy `use…` függvény a plugin-komponensek számára.
|
|
6
|
+
|
|
7
|
+
| Kontextus | Megadás | Olvasás | Mit hordoz |
|
|
8
|
+
|---|---|---|---|
|
|
9
|
+
| Média | `media` prop, vagy `provideMedia(() => list)` | `useMedia()` | A képek, amelyek közül a blokkok választhatnak. |
|
|
10
|
+
| Nézet | `provideView(() => key)` | `useView()` | A nézet, amelyet a nézetenkénti mezők szerkesztenek. |
|
|
11
|
+
| Szöveg | `messages` prop, vagy `provideText(() => messages)` | `useText()` | Felületi szövegek az alkalmazás nyelvén. |
|
|
12
|
+
|
|
13
|
+
A beágyazott szerkesztők és előnézetek mindhármat a szülőjüktől öröklik.
|
|
14
|
+
|
|
15
|
+
## Média
|
|
16
|
+
|
|
17
|
+
A blokkok soha nem tárolnak kép-URL-t. A képmező egy `MediaItem` **azonosítóját** tárolja, a szerkesztő, az előnézet és a pluginok pedig a dokumentum médiájában keresik ki az elemet:
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
interface MediaItem {
|
|
21
|
+
id: string; // a blokk propsában tárolva
|
|
22
|
+
name: string; // fájlnév vagy cím, a választóban jelenik meg
|
|
23
|
+
url: string; // a kép címe
|
|
24
|
+
group?: string; // címsor a választóban (pl. a melléklet kategóriája)
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
A mellékelt pluginok nem használnak képeket; a képblokkokat neked kell megírnod, mert az elrendezésük az oldalé. Egy minimális `photo` plugin — képmező, alternatív szöveg és magasságcsúszka:
|
|
29
|
+
|
|
30
|
+
```svelte
|
|
31
|
+
<!-- PhotoView.svelte -->
|
|
32
|
+
<script lang="ts" module>
|
|
33
|
+
export interface PhotoProps extends Record<string, unknown> {
|
|
34
|
+
/** Egy MediaItem azonosítója. */
|
|
35
|
+
image: string;
|
|
36
|
+
alt: string;
|
|
37
|
+
/** A magasság a szélesség %-ában (20–150), vagy beállítatlan a kép saját alakjához. */
|
|
38
|
+
ratio?: unknown;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** CSS aspect-ratio egy tárolt magasságból, vagy undefined. */
|
|
42
|
+
export const aspect = (v: unknown) => {
|
|
43
|
+
const n = Number(v);
|
|
44
|
+
return n >= 20 && n <= 150 ? `100 / ${n}` : undefined;
|
|
45
|
+
};
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<script lang="ts">
|
|
49
|
+
import { ImageIcon } from '@lucide/svelte';
|
|
50
|
+
import { Empty, findMedia, useMedia, type PluginViewProps } from '@atom-forge/brickee';
|
|
51
|
+
|
|
52
|
+
let { props = $bindable(), blocks = $bindable() }: PluginViewProps<PhotoProps> = $props();
|
|
53
|
+
const media = useMedia();
|
|
54
|
+
const item = $derived(findMedia(media(), props.image));
|
|
55
|
+
</script>
|
|
56
|
+
|
|
57
|
+
{#if item}
|
|
58
|
+
<img src={item.url} alt={props.alt} style="max-width: 100%" />
|
|
59
|
+
{:else}
|
|
60
|
+
<Empty icon={ImageIcon} text="Pick an image above" />
|
|
61
|
+
{/if}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
```svelte
|
|
65
|
+
<!-- PhotoPreview.svelte -->
|
|
66
|
+
<script lang="ts">
|
|
67
|
+
import { baseValue, findMedia, useMedia, type PluginPreviewProps } from '@atom-forge/brickee';
|
|
68
|
+
import { aspect, type PhotoProps } from './PhotoView.svelte';
|
|
69
|
+
|
|
70
|
+
let { props }: PluginPreviewProps<PhotoProps> = $props();
|
|
71
|
+
const media = useMedia();
|
|
72
|
+
const item = $derived(findMedia(media(), props.image));
|
|
73
|
+
</script>
|
|
74
|
+
|
|
75
|
+
{#if item}
|
|
76
|
+
<img src={item.url} alt={props.alt ?? ''} style:aspect-ratio={aspect(baseValue(props.ratio))} />
|
|
77
|
+
{/if}
|
|
78
|
+
|
|
79
|
+
<style>
|
|
80
|
+
img {
|
|
81
|
+
width: 100%;
|
|
82
|
+
object-fit: cover;
|
|
83
|
+
}
|
|
84
|
+
</style>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
// photo.ts
|
|
89
|
+
import { ImageIcon } from '@lucide/svelte';
|
|
90
|
+
import { findMedia, mdText, type BlockPlugin } from '@atom-forge/brickee';
|
|
91
|
+
import PhotoView, { type PhotoProps } from './PhotoView.svelte';
|
|
92
|
+
import PhotoPreview from './PhotoPreview.svelte';
|
|
93
|
+
|
|
94
|
+
export const photo: BlockPlugin<PhotoProps> = {
|
|
95
|
+
type: 'photo',
|
|
96
|
+
label: 'Photo',
|
|
97
|
+
hint: 'One picked image',
|
|
98
|
+
keys: 'photo image picture',
|
|
99
|
+
icon: ImageIcon,
|
|
100
|
+
props: () => ({ image: '', alt: '' }),
|
|
101
|
+
fields: [
|
|
102
|
+
{ key: 'image', label: 'Image', kind: 'image' },
|
|
103
|
+
{ key: 'alt', label: 'Alt text', kind: 'text', placeholder: 'What the image shows' },
|
|
104
|
+
{ key: 'ratio', label: 'Height', kind: 'slider', min: 20, max: 150, unit: '%', none: 'Original' }
|
|
105
|
+
],
|
|
106
|
+
tag: () => 'photo',
|
|
107
|
+
content: 'none',
|
|
108
|
+
markdown: (p, { media }) => {
|
|
109
|
+
const url = findMedia(media, p.image)?.url;
|
|
110
|
+
return url ? `` : '';
|
|
111
|
+
},
|
|
112
|
+
view: PhotoView,
|
|
113
|
+
preview: PhotoPreview
|
|
114
|
+
};
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
A szerkesztőnek és az előnézetnek ugyanazt a médiát add:
|
|
118
|
+
|
|
119
|
+
```svelte
|
|
120
|
+
<script lang="ts">
|
|
121
|
+
import { Editor, Preview, type MediaItem, type StoredBlock } from '@atom-forge/brickee';
|
|
122
|
+
import { photo } from './photo';
|
|
123
|
+
|
|
124
|
+
let { value = $bindable(), media }: { value: StoredBlock[]; media: MediaItem[] } = $props();
|
|
125
|
+
</script>
|
|
126
|
+
|
|
127
|
+
<Editor bind:value plugins={[photo]} {media} />
|
|
128
|
+
<Preview blocks={value} plugins={[photo]} {media} />
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Plugin-komponensben a listát a `useMedia()`-val olvasd ki — függvényt ad vissza, így a lista mindig friss marad —, egy elemet pedig a `findMedia(list, id)`-vel keress meg, ahogy a photo nézete és előnézete is teszi.
|
|
132
|
+
|
|
133
|
+
> **Bélyegképek a szerkesztőben**
|
|
134
|
+
>
|
|
135
|
+
> A szerkesztőnek csak kis képekre van szüksége. Mivel a blokkok azonosítókat tárolnak, a szerkesztőnek adhatsz egy bélyegkép-URL-ekből álló listát, az oldalon lévő előnézetnek pedig egy teljes méretű URL-ekből állót, ugyanazokkal az azonosítókkal.
|
|
136
|
+
|
|
137
|
+
Tipikus forrás egy oldal feltöltött mellékletei vagy egy médiatár. Minden képnek, amelyre egy dokumentum hivatkozik, szerepelnie kell a listában, különben a blokkja semmit sem renderel.
|
|
138
|
+
|
|
139
|
+
## Nézetenkénti értékek
|
|
140
|
+
|
|
141
|
+
Egyes beállítások attól függnek, hogyan jelenik meg az oldal: egy képnek telefonon más képarány kellhet, mint széles képernyőn. A `views` beállítással rendelkező `slider` mező nézetenként tárol értéket:
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
import type { BlockPlugin } from '@atom-forge/brickee';
|
|
145
|
+
import { gap } from '@atom-forge/brickee/plugins';
|
|
146
|
+
import { photo } from './photo';
|
|
147
|
+
|
|
148
|
+
export const VIEWS = [
|
|
149
|
+
{ key: 'desktop', label: 'Desktop' },
|
|
150
|
+
{ key: 'tablet', label: 'Tablet' },
|
|
151
|
+
{ key: 'phone', label: 'Phone' }
|
|
152
|
+
];
|
|
153
|
+
|
|
154
|
+
/** Ugyanaz a plugin, az egyik mezője nézetenként állítva. */
|
|
155
|
+
const perView = (plugin: BlockPlugin, key: string): BlockPlugin => ({
|
|
156
|
+
...plugin,
|
|
157
|
+
fields: plugin.fields?.map((f) => (f.key === key ? { ...f, views: VIEWS } : f))
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
export const plugins = [perView(photo, 'ratio'), perView(gap, 'lines')];
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Hogy milyen nézetek léteznek, és melyik látszik éppen, az az alkalmazás dolga. Az alkalmazás a `provideView`-val közli a szerkesztővel az aktuális nézetet, jellemzően egy szerkesztő melletti szélességváltóból:
|
|
164
|
+
|
|
165
|
+
```svelte
|
|
166
|
+
<script lang="ts">
|
|
167
|
+
import { Editor, provideView, type StoredBlock } from '@atom-forge/brickee';
|
|
168
|
+
import { plugins } from './blocks';
|
|
169
|
+
|
|
170
|
+
let { value = $bindable(), view }: { value: StoredBlock[]; view: string } = $props();
|
|
171
|
+
provideView(() => view);
|
|
172
|
+
</script>
|
|
173
|
+
|
|
174
|
+
<Editor bind:value {plugins} />
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Hogyan viselkednek az értékek:
|
|
178
|
+
|
|
179
|
+
- Az első nézet az **alap**. Minden további nézet, amíg nincs saját értéke, az előtte lévő nézet értékét veszi át; a mező ilyenkor örököltként jelölve mutatja az értéket.
|
|
180
|
+
- A mező az aktuális nézet értékét szerkeszti, és a saját címkéje mellett a nézet címkéjét is mutatja. `provideView` nélkül, vagy ha a kulcs nem szerepel a `views`-ban, az alapértéket szerkeszti.
|
|
181
|
+
- Tárolás: ha csak alapérték van → önmagában, egyszerű értékként tárolódik (`"ratio": "56"`); ha más nézeteknek saját értékük van → nézet szerint kulcsolt objektumként (`"ratio": { "desktop": "56", "phone": "100" }`). Azok a dokumentumok, amelyek még azelőtt íródtak, hogy egy mező nézetenkéntivé vált, érvényesek maradnak.
|
|
182
|
+
|
|
183
|
+
Az előnézet a `viewValues(value, keys)`-szel olvassa ki őket — minden nézet értékét, az öröklést alkalmazva —, vagy csak az alapértéket a `baseValue(value)`-val. A photo előnézetének ez a változata CSS-változókon keresztül szélességenként egy-egy képarányt ad a böngészőnek:
|
|
184
|
+
|
|
185
|
+
```svelte
|
|
186
|
+
<script lang="ts">
|
|
187
|
+
import { findMedia, useMedia, viewValues, type PluginPreviewProps } from '@atom-forge/brickee';
|
|
188
|
+
import { aspect, type PhotoProps } from './PhotoView.svelte';
|
|
189
|
+
|
|
190
|
+
let { props }: PluginPreviewProps<PhotoProps> = $props();
|
|
191
|
+
const media = useMedia();
|
|
192
|
+
const item = $derived(findMedia(media(), props.image));
|
|
193
|
+
// desktop, tablet, phone: mindegyikhez egy CSS aspect-ratio ('auto': a kép saját alakja)
|
|
194
|
+
const r = $derived(viewValues(props.ratio, ['desktop', 'tablet', 'phone']).map((v) => aspect(v) ?? 'auto'));
|
|
195
|
+
</script>
|
|
196
|
+
|
|
197
|
+
{#if item}
|
|
198
|
+
<img src={item.url} alt={props.alt ?? ''} style:--r-desktop={r[0]} style:--r-tablet={r[1]} style:--r-phone={r[2]} />
|
|
199
|
+
{/if}
|
|
200
|
+
|
|
201
|
+
<style>
|
|
202
|
+
img {
|
|
203
|
+
width: 100%;
|
|
204
|
+
object-fit: cover;
|
|
205
|
+
aspect-ratio: var(--r-phone);
|
|
206
|
+
}
|
|
207
|
+
@media (min-width: 640px) {
|
|
208
|
+
img {
|
|
209
|
+
aspect-ratio: var(--r-tablet);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
@media (min-width: 1024px) {
|
|
213
|
+
img {
|
|
214
|
+
aspect-ratio: var(--r-desktop);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
</style>
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
> **Csak csúszkák**
|
|
221
|
+
>
|
|
222
|
+
> A `views` a `slider` mezőkön támogatott. A többi mezőfajta figyelmen kívül hagyja.
|
|
223
|
+
|
|
224
|
+
## Felületi szövegek
|
|
225
|
+
|
|
226
|
+
A szerkesztő és a pluginok angolul íródtak, és az angol szöveg a fordításának kulcsa. Add át a `messages`-t — egy objektumot, amely az angol szövegeket a te nyelvedre képezi le — a legfelső szintű szerkesztőnek és előnézetnek:
|
|
227
|
+
|
|
228
|
+
```svelte
|
|
229
|
+
<script lang="ts">
|
|
230
|
+
import { Editor, type StoredBlock } from '@atom-forge/brickee';
|
|
231
|
+
import { PLUGINS } from '@atom-forge/brickee/plugins';
|
|
232
|
+
import { hu } from '@atom-forge/brickee/locales/hu';
|
|
233
|
+
|
|
234
|
+
let value = $state<StoredBlock[]>([]);
|
|
235
|
+
</script>
|
|
236
|
+
|
|
237
|
+
<Editor bind:value plugins={PLUGINS} messages={hu} />
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Az `@atom-forge/brickee/locales/hu` a `hu`-t exportálja: a szerkesztő és az összes mellékelt plugin magyar szövegeit. Bővítsd ki a saját pluginjaid és mezőid szövegeivel:
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
import type { Messages } from '@atom-forge/brickee';
|
|
244
|
+
import { hu } from '@atom-forge/brickee/locales/hu';
|
|
245
|
+
|
|
246
|
+
export const messages: Messages = {
|
|
247
|
+
...hu,
|
|
248
|
+
Button: 'Gomb',
|
|
249
|
+
'A link as a button': 'Egy link gombként',
|
|
250
|
+
Desktop: 'Asztali',
|
|
251
|
+
Phone: 'Telefon'
|
|
252
|
+
};
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Amit a szerkesztő magától lefordít:
|
|
256
|
+
|
|
257
|
+
- a beépített blokkok és a pluginok `label`, `hint` és `keys` értékeit (a perjeles menü az angol és a lefordított szavak között is keres);
|
|
258
|
+
- egy plugin `tag`-jének részeit, ` · `-nál darabolva;
|
|
259
|
+
- a mezők címkéit, helyőrzőit, az opciók címkéit, a `none` címkéket és a nézetcímkéket;
|
|
260
|
+
- az `Empty` szövegét és a szerkesztő saját felületét.
|
|
261
|
+
|
|
262
|
+
Azt a szöveget, amelyet egy plugin maga renderel — a nézetében vagy az előnézetében —, a `useText()`-en keresztül add ki:
|
|
263
|
+
|
|
264
|
+
```svelte
|
|
265
|
+
<script lang="ts">
|
|
266
|
+
import { useText, type PluginPreviewProps } from '@atom-forge/brickee';
|
|
267
|
+
|
|
268
|
+
let { props }: PluginPreviewProps = $props();
|
|
269
|
+
const tr = useText();
|
|
270
|
+
</script>
|
|
271
|
+
|
|
272
|
+
<p>{tr('Map: {place}', { place: String(props.q ?? '') })}</p>
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
A `{name}` helyőrzőket a második argumentum tölti ki. Komponenseken kívül a `translator(messages)` ugyanilyen függvényt ad vissza. A `messages`-ből hiányzó szöveg angol marad.
|
package/docs/hu/index.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Brickee
|
|
2
|
+
|
|
3
|
+
Az `@atom-forge/brickee` blokkszerkesztő Svelte 5-höz. A magja egy markdown blokkszerkesztő — bekezdések, címsorok, listák, teendők, idézetek, kód, elválasztók —, minden más blokk pedig **plugin**: egy blokk, amelynek van szerkesztőnézete, oldali előnézete, vannak mezői, és opcionálisan markdown alakja. A dokumentumok JSON-ként tárolódnak.
|
|
4
|
+
|
|
5
|
+
Ezek az oldalak a [Brickee könyv](https://books.atom-forge.eu) alapján készültek, és angol nyelvű változatuk, a [`../en/index.md`](../en/index.md) fordításai; eltérés esetén az angol változat a mérvadó. Kódoló ágenseknek tömör referencia a [`README-AI.md`](../../README-AI.md).
|
|
6
|
+
|
|
7
|
+
A csomag három rétegből épül fel:
|
|
8
|
+
|
|
9
|
+
```mermaid
|
|
10
|
+
flowchart TB
|
|
11
|
+
core["Mag: markdown blokkok, Editor, Preview, tárolt alak, kit"]
|
|
12
|
+
bundled["Mellékelt pluginok: táblázat, YouTube, térkép, térköz"]
|
|
13
|
+
own["Saját pluginok: ugyanaz a BlockPlugin alak"]
|
|
14
|
+
core --> bundled
|
|
15
|
+
core --> own
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
- **Mag** (`@atom-forge/brickee`) — a markdown blokkok, az `Editor` és a `Preview`, a tárolt alak és annak markdown-átalakításai, valamint a **kit**, amellyel a pluginok készülnek. Pluginok nélkül egyszerű markdown blokkszerkesztő.
|
|
19
|
+
- **Mellékelt pluginok** (`@atom-forge/brickee/plugins`) — ugyanolyan pluginok, mint bármelyik más, és csak abból készültek, amit a mag exportál. Csak azokat kapcsolod be, amelyekre szükséged van.
|
|
20
|
+
- **A saját pluginjaid** — ugyanaz a `BlockPlugin` alak, az alkalmazásodban.
|
|
21
|
+
|
|
22
|
+
Maga a szerkesztő semmit sem tud az alkalmazásodról. Amire egy alkalmazásnak szüksége van — a képei, az oldalszélességei, a nyelve —, az **kontextusokon** (média, nézet, szöveg) vagy a pluginok **mezőin** keresztül jut el a pluginokhoz, soha nem külön szerkesztő-propokon át.
|
|
23
|
+
|
|
24
|
+
## Tartalom
|
|
25
|
+
|
|
26
|
+
1. [Első lépések](getting-started.md) — a három réteg, telepítés, a befogadó alkalmazás beállítása, és egy első szerkesztő az előnézetével.
|
|
27
|
+
2. [A szerkesztő és az előnézet](editor-and-preview.md) — az `Editor` és a `Preview` propjai, a paletta, a szerkesztési funkciók és a görgetés-szinkron.
|
|
28
|
+
3. [Dokumentumok és markdown](documents-and-markdown.md) — a tárolt alak (`StoredBlock`), a beépített blokkok, valamint az átalakítás markdownból és markdownba.
|
|
29
|
+
4. [Mellékelt pluginok](bundled-plugins.md) — mit tartalmaz az `@atom-forge/brickee/plugins`, és hogyan írhatsz felül egy előnézetet vagy adhatsz hozzá mezőket.
|
|
30
|
+
5. [Pluginok írása](writing-plugins.md) — a `BlockPlugin` felépítése, mezők, nézetek és előnézetek, tárolók, markdown alakok és a kit.
|
|
31
|
+
6. [Az alkalmazás kontextusai](host-contexts.md) — média, nézetenkénti értékek és felületi szövegek.
|
|
32
|
+
7. [A szerveren](server-side.md) — sémavalidálás, sima szöveg és védett tartalom.
|
|
33
|
+
8. [Receptek és buktatók](recipes-and-pitfalls.md) — teljes minták és az elkerülendő hibák.
|
|
34
|
+
9. [Frissítés](upgrading.md) — mit kell módosítanod a kódodban, amikor újabb verzióra váltasz.
|
|
35
|
+
|
|
36
|
+
A könyvben van egy AI Notes fejezet is: utasítások, amelyeket a csomagot használó projekt ágens-utasításfájljába másolhatsz.
|
|
37
|
+
|
|
38
|
+
A Svelte-példák teljes komponensek, hacsak másként nem jelzik. Az alkalmazásbeli értékek, például a képek listája vagy az aktuális oldalszélesség, azt jelölik, amit az alkalmazásod biztosít.
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Receptek és buktatók
|
|
2
|
+
|
|
3
|
+
[← Előző](server-side.md) · [Tartalom](index.md) · [Következő →](upgrading.md)
|
|
4
|
+
|
|
5
|
+
## Egy hely a blokkbeállításoknak
|
|
6
|
+
|
|
7
|
+
Egy alkalmazás pluginjait, palettáit és szövegeit tartsd egyetlen modulban, a szerkesztőt pedig csomagold be egy saját komponensbe. Az oldalak ezután a csomagolót használják, és soha nem ismétlik meg a beállítást.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
// lib/blocks.ts
|
|
11
|
+
import type { BlockPlugin, Messages } from '@atom-forge/brickee';
|
|
12
|
+
import * as base from '@atom-forge/brickee/plugins';
|
|
13
|
+
import { hu } from '@atom-forge/brickee/locales/hu';
|
|
14
|
+
import SiteYouTube from './SiteYouTube.svelte';
|
|
15
|
+
import { photo } from './photo';
|
|
16
|
+
import { button } from './button';
|
|
17
|
+
|
|
18
|
+
const withPreview = (plugin: BlockPlugin, preview: BlockPlugin['preview']): BlockPlugin => ({ ...plugin, preview });
|
|
19
|
+
|
|
20
|
+
export const plugins: BlockPlugin[] = [
|
|
21
|
+
withPreview(base.youtube, SiteYouTube),
|
|
22
|
+
base.table,
|
|
23
|
+
base.map,
|
|
24
|
+
base.gap,
|
|
25
|
+
photo,
|
|
26
|
+
button
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
/** A teljes paletta, az oldal saját lapjainak szerkesztőihez. */
|
|
30
|
+
export const PAGE_PALETTE = ['md:p', 'md:h2', 'md:h3', 'md:ul', 'md:ol', 'md:quote', 'md:hr', ...plugins.map((p) => p.type)];
|
|
31
|
+
|
|
32
|
+
/** Egy kisebb, a felhasználói hozzászólásokhoz. */
|
|
33
|
+
export const COMMENT_PALETTE = ['md:p', 'md:ul', 'md:ol', 'md:quote', 'photo'];
|
|
34
|
+
|
|
35
|
+
export const messages: Messages = { ...hu, Button: 'Gomb', 'A link as a button': 'Egy link gombként' };
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```svelte
|
|
39
|
+
<!-- lib/BlockEditor.svelte -->
|
|
40
|
+
<script lang="ts">
|
|
41
|
+
import { Editor, provideView, type MediaItem, type StoredBlock } from '@atom-forge/brickee';
|
|
42
|
+
import { messages, PAGE_PALETTE, plugins } from './blocks';
|
|
43
|
+
|
|
44
|
+
let {
|
|
45
|
+
value = $bindable(),
|
|
46
|
+
media = [],
|
|
47
|
+
palette = PAGE_PALETTE,
|
|
48
|
+
view
|
|
49
|
+
}: { value: StoredBlock[]; media?: MediaItem[]; palette?: string[]; view?: string } = $props();
|
|
50
|
+
|
|
51
|
+
provideView(() => view);
|
|
52
|
+
</script>
|
|
53
|
+
|
|
54
|
+
<Editor bind:value {plugins} {palette} {media} {messages} />
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
A közzétett oldalt a `<Preview blocks={doc} {plugins} {media} {messages} />`-val és ugyanazokkal a `plugins`-szal rendereld, így egy blokk ugyanúgy néz ki a szerkesztő előnézetében és az oldalon.
|
|
58
|
+
|
|
59
|
+
## A teljes dokumentum másolása markdownként
|
|
60
|
+
|
|
61
|
+
A kijelölt blokkok másolása már most is markdownt tesz a vágólapra. Egy, a teljes dokumentumot másoló „Copy as markdown” gombhoz:
|
|
62
|
+
|
|
63
|
+
```svelte
|
|
64
|
+
<script lang="ts">
|
|
65
|
+
import { fromStored, toMarkdown, type MediaItem, type StoredBlock } from '@atom-forge/brickee';
|
|
66
|
+
import { plugins } from './blocks';
|
|
67
|
+
|
|
68
|
+
let { doc, media = [] }: { doc: StoredBlock[]; media?: MediaItem[] } = $props();
|
|
69
|
+
|
|
70
|
+
// Kattintáskezelőben fut, így a csak böngészőben működő toMarkdown itt biztonságos.
|
|
71
|
+
const copy = () => navigator.clipboard.writeText(toMarkdown(doc.map(fromStored), { plugins, media }));
|
|
72
|
+
</script>
|
|
73
|
+
|
|
74
|
+
<button type="button" onclick={copy}>Copy as markdown</button>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Dokumentum indítása markdownból
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
import { fromMarkdown, toStored, type StoredBlock } from '@atom-forge/brickee';
|
|
81
|
+
|
|
82
|
+
// Böngészőben: a toStored a DOM-on keresztül olvassa be a soron belüli HTML-t.
|
|
83
|
+
export const fromText = (text: string): StoredBlock[] => fromMarkdown(text).map(toStored);
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Ne feledd, hogy minden nem üres sorból külön blokk lesz.
|
|
87
|
+
|
|
88
|
+
## Fejlesztés helyi másolattal
|
|
89
|
+
|
|
90
|
+
Ha a csomag egy helyi checkoutját linkeled be egy alkalmazásba (`bun link`), a linkelt mappa a saját `node_modules`-át hozza magával. Vedd rá a Vite-ot, hogy a közös csomagokból az alkalmazás egyetlen példányát használja, különben a Svelte-kontextusok — a popupkezelő, a téma — nem találhatók meg a két példány között:
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
// az alkalmazás vite.config.ts-e
|
|
94
|
+
export default defineConfig({
|
|
95
|
+
plugins: [sveltekit()],
|
|
96
|
+
resolve: {
|
|
97
|
+
dedupe: ['svelte', '@atom-forge/ui', '@lucide/svelte', 'zod']
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Az alkalmazás a csomag lefordított `dist/` mappáját olvassa, ezért minden változtatás után buildeld újra a csomagot.
|
|
103
|
+
|
|
104
|
+
## Buktatók
|
|
105
|
+
|
|
106
|
+
| Tünet | Ok | Megoldás |
|
|
107
|
+
|---|---|---|
|
|
108
|
+
| A blokkmezők és a popupok stílus nélkülinek tűnnek | Hiányzik az `@atom-forge/ui` téma CSS-e vagy a Tailwind `@source`-a | Állítsd be az `@atom-forge/ui`-t a dokumentációja szerint, és az alkalmazást a `Root`-ja alatt rendereld. |
|
|
109
|
+
| A popupok nem nyílnak meg, vagy „context not found” hibák linkelt csomaggal | A `svelte` vagy az `@atom-forge/ui` két példányban van jelen | Vedd fel őket a Vite `resolve.dedupe` listájába. |
|
|
110
|
+
| Egy plugin blokkja „Unknown block” feliratot mutat | A pluginja hiányzik a `plugins`-ból | Egy dokumentumtípus minden szerkesztőjének és előnézetének ugyanazokat a pluginokat add át. |
|
|
111
|
+
| Egy blokk hiányzik a `Preview`-ból | A pluginjának nincs `preview`-ja | Adj a pluginnak `preview`-t (a mellékelt pluginoknak van alapértelmezett), vagy rendereld a blokkot a saját megjelenítőddel. |
|
|
112
|
+
| Egy plugin blokkja hiányzik az oldalról | Az előnézet más `plugins`-t kapott, vagy a kép azonosítója nincs a `media`-ban | Ugyanazt a pluginlistát és médiát használd a szerkesztőhöz és az előnézethez. |
|
|
113
|
+
| Egy doboz nem tehető egy másik dobozba | A beágyazott szerkesztők egy szint mélyek | A tárolókat tartalomblokkok befogadására tervezd, ne más tárolókéra. |
|
|
114
|
+
| Egy blokk nem érhető el egy tárolón belül | Az `accepts` vagy az alkalmazás `palette`-je kihagyja | Vedd fel a palettaazonosítót az `accepts`-be (vagy használd az `'md:*'`-ot az összes beépítetthez). |
|
|
115
|
+
| Egy egyedi blokk kétszer jelenik meg | A séma nem kényszeríti ki a `unique`-ot | Ellenőrizd a szerveren, ha az alkalmazásod számít rá. |
|
|
116
|
+
| A védett tartalom mindenkinek látszik | A `gate` csak megjelöli a blokkokat | Renderelés előtt vágd meg a dokumentumot a szerveren. |
|
|
117
|
+
| `document is not defined` | A `toMarkdown` vagy a `toStored` SSR közben futott | Csak a böngészőben hívd őket. |
|
|
118
|
+
| Egy propsból jövő szín vagy link elrontja az oldalt | A props felhasználói bemenet | Használd a `safeColor`-t, ellenőrizd a linkeket, és propsszal soha ne használj `{@html}`-t. |
|
|
119
|
+
| Egy felülírt plugin elveszíti a blokkjait | Megváltozott a `type`-ja | Egy plugin szétterítésekor tartsd meg a `type`-ot. |
|
|
120
|
+
| `bind:blocks` hiba egy saját nézetben | A `props` vagy a `blocks` nincs bindable-ként deklarálva | Deklaráld mindkettőt `$bindable()`-lel. |
|
|
121
|
+
| Az érték soha nem üres tömb | A szerkesztő üres dokumentumnál egy üres bekezdést mutat (és ír) | Az olyan dokumentumot, amelyben csak üres bekezdések vannak, kezeld üresként, például a `blocksToPlainText(doc).trim() === ''` segítségével. |
|
|
122
|
+
| Az előnézet nem követi a szerkesztő görgetését | Az actionök nem a görgethető dobozokon vannak | A `use:sync.source` / `use:sync.target` közvetlenül az `overflow` dobozokra kerüljön. |
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# A szerveren
|
|
2
|
+
|
|
3
|
+
[← Előző](host-contexts.md) · [Tartalom](index.md) · [Következő →](recipes-and-pitfalls.md)
|
|
4
|
+
|
|
5
|
+
A tárolt dokumentum a böngésző által küldött JSON, ezért a szervernek mentés előtt ellenőriznie kell. Két belépési pontnak nincs Svelte-függősége, ezek szerveroldali kódhoz készültek:
|
|
6
|
+
|
|
7
|
+
- `@atom-forge/brickee/model` — `StoredBlock`, `MD`, `MAX_INDENT`, `MAX_DEPTH`, `isMd`, `acceptsId`, `inlineToPlainText`, `blocksToPlainText`;
|
|
8
|
+
- `@atom-forge/brickee/schema` — `blocksSchema` és `blocksSchemaFor`, `zod`-dal építve (opcionális peer dependency: telepítsd, ha ezt a belépési pontot használod).
|
|
9
|
+
|
|
10
|
+
## Dokumentum validálása
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
// content.server.ts
|
|
14
|
+
import { blocksSchemaFor } from '@atom-forge/brickee/schema';
|
|
15
|
+
import { plugins } from '$lib/blocks';
|
|
16
|
+
|
|
17
|
+
const contentSchema = blocksSchemaFor(plugins);
|
|
18
|
+
|
|
19
|
+
export function parseContent(input: unknown) {
|
|
20
|
+
const result = contentSchema.safeParse(input);
|
|
21
|
+
if (!result.success) throw new Error('Invalid content');
|
|
22
|
+
return result.data; // StoredBlock[]
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
A `blocksSchema` bármely dokumentum alakját ellenőrzi; a `blocksSchemaFor(plugins)` ehhez hozzáveszi a tárolók `accepts` listáit. Minden pluginból csak a `type` és az `accepts` kell neki, így az a szerver, amely nem akarja importálni a plugin-komponenseket, csak ezeket is átadhatja:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
const contentSchema = blocksSchemaFor([
|
|
30
|
+
{ type: 'note', accepts: ['md:*', 'youtube'] },
|
|
31
|
+
{ type: 'youtube' }
|
|
32
|
+
]);
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Amit a séma ellenőriz:
|
|
36
|
+
|
|
37
|
+
| Szabály | Korlát |
|
|
38
|
+
|---|---|
|
|
39
|
+
| Blokkkulcsok | Csak `type`, `indent`, `text`, `props`, `blocks` (szigorú objektumok). |
|
|
40
|
+
| `type` | `^[a-z][a-z0-9:-]{0,39}$` |
|
|
41
|
+
| `indent` | Egész szám, 0–6. |
|
|
42
|
+
| `text` | Legfeljebb 100 000 karakter. |
|
|
43
|
+
| `props` | Legfeljebb 60 karakteres kulcsok, JSON-értékek. |
|
|
44
|
+
| `blocks` | Tárolónként legfeljebb 500 beágyazott blokk, csak egy szint mélyen. |
|
|
45
|
+
| Dokumentum | Legfeljebb 2000 legfelső szintű blokk és JSON-ként 1 000 000 karakter. |
|
|
46
|
+
| `accepts` (`blocksSchemaFor`) | Minden beágyazott blokkot befogad a tárolója. |
|
|
47
|
+
|
|
48
|
+
Amit **nem** ellenőriz: hogy egy típus ismert-e, hogy egy egyedi blokk csak egyszer fordul-e elő, és hogy mit tartalmaz a props. Az alkalmazásod által megkövetelt szabályokhoz adj hozzá saját finomításokat – például az ismeretlen blokktípusok elutasításához:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import type { StoredBlock } from '@atom-forge/brickee/model';
|
|
52
|
+
import { blocksSchemaFor } from '@atom-forge/brickee/schema';
|
|
53
|
+
import { plugins } from '$lib/blocks';
|
|
54
|
+
|
|
55
|
+
const BUILT_IN = ['md:p', 'md:h1', 'md:h2', 'md:h3', 'md:h4', 'md:h5', 'md:h6', 'md:ul', 'md:ol', 'md:todo', 'md:quote', 'md:code', 'md:hr'];
|
|
56
|
+
const known = new Set([...BUILT_IN, ...plugins.map((p) => p.type)]);
|
|
57
|
+
const allKnown = (list: StoredBlock[]): boolean => list.every((b) => known.has(b.type) && allKnown(b.blocks ?? []));
|
|
58
|
+
|
|
59
|
+
export const contentSchema = blocksSchemaFor(plugins).refine(allKnown, 'Unknown block type.');
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
> **Alak, nem biztonság**
|
|
63
|
+
>
|
|
64
|
+
> A séma szabályos és korlátos méretű dokumentumokat biztosít; a propsokat viszont nem teszi biztonságosan renderelhetővé. A renderelők minden szöveget escape-elnek, és a hivatkozásokat biztonságos sémákra korlátozzák, a saját propsait pedig minden plugin-előnézetnek magának kell megtisztítania (lásd [Pluginok írása](writing-plugins.md)).
|
|
65
|
+
|
|
66
|
+
## Egyszerű szöveg
|
|
67
|
+
|
|
68
|
+
A `blocksToPlainText(blocks)` sorrendben összegyűjti egy dokumentum minden szövegét, üres sorokkal elválasztva: a blokkszövegeket jelölések és hivatkozáscélok nélkül, a szóközt tartalmazó szöveges propsokat (címek, képaláírások – azonosítók és színek nem), a táblázatsorokat és a beágyazott blokkokat. Keresőindexekhez, leadekhez és meta descriptionökhöz használd. Az `inlineToPlainText(md)` ugyanezt teszi egyetlen inline markdown szöveggel.
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
import { blocksToPlainText, type StoredBlock } from '@atom-forge/brickee/model';
|
|
72
|
+
|
|
73
|
+
export const description = (doc: StoredBlock[]) => blocksToPlainText(doc).slice(0, 160);
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Renderelés
|
|
77
|
+
|
|
78
|
+
A `Preview` hagyományos Svelte-komponens, és szerveren is renderelhető; a mag renderelője és a mellékelt előnézetek nem használnak böngésző-API-kat. Csak a markdown-export útvonalnak (`toMarkdown`, `toStored`) kell a böngésző.
|
|
79
|
+
|
|
80
|
+
## Védett tartalom
|
|
81
|
+
|
|
82
|
+
Egy kapus blokk (egy `gate: true` beállítású plugin, például egy csak támogatóknak szóló elválasztó) csak annyit tesz, hogy az előnézet megjelöli az utána következő blokkokat. Hogy a védett részt elzárd azoktól az olvasóktól, akik nem láthatják, vágd el a dokumentumot a szerveren, mielőtt az oldalhoz érne:
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import type { StoredBlock } from '@atom-forge/brickee/model';
|
|
86
|
+
|
|
87
|
+
/** A dokumentum az első kapus blokkig, azt is beleértve, hozzáférés nélküli olvasóknak. */
|
|
88
|
+
export function publicPart(doc: StoredBlock[], gateTypes: string[], canRead: boolean): StoredBlock[] {
|
|
89
|
+
if (canRead) return doc;
|
|
90
|
+
const at = doc.findIndex((b) => gateTypes.includes(b.type));
|
|
91
|
+
return at < 0 ? doc : doc.slice(0, at + 1);
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Hívd meg a kapus pluginjaid típusaival (például `['paywall']`) és az olvasó hozzáférésével. A hozzáférés nélküli olvasók a kapus blokkig látják a tartalmat, az előzetesével együtt; a hozzáféréssel rendelkezők a teljes dokumentumot kapják, és az előnézet megjelöli számukra a védett részt.
|