@qarakash/blockwriteai 1.0.7

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 qarAkash
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,642 @@
1
+ # BlockWriteAI
2
+
3
+ BlockWriteAI is a drop-in block writing editor for the web. It is built to feel familiar to Editor.js users, but ships as plain CSS and JavaScript files that can be used in PHP, Laravel, CodeIgniter, static HTML, dashboards, or any project that can load a script tag.
4
+
5
+ The editor stores and saves content as JSON first. Projects can render that JSON on any page by adding a BlockWriteAI preview container, while advanced document blocks such as tables, media galleries, attachments, diagrams, charts, signatures, and code editing remain available as plugins.
6
+
7
+ All public assets, package entry points, and browser globals use the `BlockWriteAI` name.
8
+
9
+ ## Highlights
10
+
11
+ - Editor.js-style block JSON output.
12
+ - Plain script tag integration with no build step required.
13
+ - Paragraphs, headings, quotes, callouts, dividers, buttons, toggle blocks, raw HTML, links, embeds, tables, lists, and nested checklists.
14
+ - Floating inline toolbar with typography, colors, highlight, alignment, comments, links, and formatting controls.
15
+ - Multi-image upload, drag and drop, resize, crop, rotate, and gallery layout.
16
+ - Attachment blocks for documents and videos.
17
+ - Code block with formatting, syntax help, language detection, and suggestions.
18
+ - Mermaid-style drawing designer with shapes, arrows, images, text formatting, ruler, workspace resizing, and preview/export support.
19
+ - Charts, LaTeX, audio, drawing, layout columns, signature, signature flow, AI writing, and optional history plugins.
20
+ - Undo, redo, autosave, block actions, drag reordering, and optional JSON save/export buttons.
21
+ - JSON-powered preview mounting for public document pages.
22
+ - JSON save API examples for future database storage.
23
+
24
+ ## Project Structure
25
+
26
+ ```text
27
+ BlockWriteAI/
28
+ package.json
29
+ composer.json
30
+ pyproject.toml
31
+ dist/
32
+ blockwriteai.css
33
+ blockwriteai.js
34
+ blockwriteai-logo.svg
35
+ blockwriteai-favicon.svg
36
+ plugins/
37
+ blockwriteai-advanced-blocks.js
38
+ blockwriteai-drawing.js
39
+ blockwriteai-mermaid.js
40
+ blockwriteai-ai.js
41
+ blockwriteai-code-assist.js
42
+ blockwriteai-history.js
43
+ blockwriteai-signature.js
44
+ blockwriteai-signature-flow.js
45
+ examples/
46
+ index.html
47
+ preview.html
48
+ upload.php
49
+ api/
50
+ document.php
51
+ preview.php
52
+ uploads/
53
+ .gitkeep
54
+ blockwriteai_editor/
55
+ static/blockwriteai/
56
+ src/
57
+ BlockWriteAIAssets.php
58
+ types/
59
+ index.d.ts
60
+ ```
61
+
62
+ ## Installation
63
+
64
+ BlockWriteAI can be consumed as a CDN/script-link package, an npm package, a Python static-assets package, or a Composer package.
65
+
66
+ ### Script Link
67
+
68
+ Use the GitHub CDN link directly from the current main build:
69
+
70
+ ```html
71
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/qarAkash/BlockWriteAI@main/dist/blockwriteai.css">
72
+
73
+ <script src="https://cdn.jsdelivr.net/gh/qarAkash/BlockWriteAI@main/dist/blockwriteai.js"></script>
74
+ <script src="https://cdn.jsdelivr.net/gh/qarAkash/BlockWriteAI@main/dist/plugins/blockwriteai-code-assist.js"></script>
75
+ <script src="https://cdn.jsdelivr.net/gh/qarAkash/BlockWriteAI@main/dist/plugins/blockwriteai-advanced-blocks.js"></script>
76
+ <script src="https://cdn.jsdelivr.net/gh/qarAkash/BlockWriteAI@main/dist/plugins/blockwriteai-ai.js"></script>
77
+ <script src="https://cdn.jsdelivr.net/gh/qarAkash/BlockWriteAI@main/dist/plugins/blockwriteai-signature.js"></script>
78
+ <script src="https://cdn.jsdelivr.net/gh/qarAkash/BlockWriteAI@main/dist/plugins/blockwriteai-signature-flow.js"></script>
79
+ ```
80
+
81
+ `blockwriteai-advanced-blocks.js` is kept as the compatibility bundle. New
82
+ licensed delivery can load Drawing and Mermaid separately:
83
+
84
+ ```html
85
+ <script src="https://cdn.jsdelivr.net/gh/qarAkash/BlockWriteAI@main/dist/plugins/blockwriteai-drawing.js"></script>
86
+ <script src="https://cdn.jsdelivr.net/gh/qarAkash/BlockWriteAI@main/dist/plugins/blockwriteai-mermaid.js"></script>
87
+ ```
88
+
89
+ Load History only when a project needs the history dropdown:
90
+
91
+ ```html
92
+ <script src="https://cdn.jsdelivr.net/gh/qarAkash/BlockWriteAI@main/dist/plugins/blockwriteai-history.js"></script>
93
+ ```
94
+
95
+ For locked production builds, replace `@main` with a release tag after publishing.
96
+
97
+ ### Premium License Gating
98
+
99
+ Drawing, Mermaid drawing, Signature, Signature Flow, and AI can be licensed through
100
+ the BlockWriteAI Platform. Normal editor blocks continue to work without a license.
101
+ Premium tools are shown as locked until the license endpoint returns an active trial
102
+ or subscription.
103
+
104
+ ```js
105
+ const editor = new BlockWriteAI({
106
+ holder: "#editor",
107
+ licenseKey: "bwai_live_xxxxx",
108
+ premium: {
109
+ verifyEndpoint: "http://localhost/blockwriteai-platform/api/license_verify.php",
110
+ usageEndpoint: "http://localhost/blockwriteai-platform/api/ai_usage.php"
111
+ },
112
+ ai: {
113
+ endpoint: "/api/ai.php"
114
+ }
115
+ });
116
+ ```
117
+
118
+ The verify endpoint must return a `features` object with these keys when enabled:
119
+
120
+ ```json
121
+ {
122
+ "drawing": true,
123
+ "mermaid": true,
124
+ "signature": true,
125
+ "signature_flow": true,
126
+ "ai": true
127
+ }
128
+ ```
129
+
130
+ The AI plugin calls `premium.usageEndpoint` before each AI request so the platform
131
+ can enforce the 7-day trial and daily prompt limits.
132
+
133
+ For stronger production security, do not load premium plugin files directly from a
134
+ public CDN. Load the free core first, request the premium plugins from your
135
+ BlockWriteAI Platform, and create the editor only after the server has verified
136
+ the license. The platform serves Drawing, Mermaid, Signature, Signature Flow,
137
+ and AI as separate plugin files after checking the requested feature flags:
138
+
139
+ ```html
140
+ <link rel="stylesheet" href="/BlockWriteAI/dist/blockwriteai.css">
141
+ <script src="/BlockWriteAI/dist/blockwriteai.js"></script>
142
+ <script src="/BlockWriteAI/dist/plugins/blockwriteai-code-assist.js"></script>
143
+ <script>
144
+ async function boot() {
145
+ await BlockWriteAI.loadPremiumPlugins({
146
+ licenseKey: "bwai_live_xxxxx",
147
+ endpoint: "http://localhost/blockwriteai-platform/api/premium_plugins.php",
148
+ features: ["drawing", "mermaid", "signature", "signature_flow", "ai"]
149
+ });
150
+
151
+ window.editor = new BlockWriteAI({
152
+ holder: "#editor",
153
+ licenseKey: "bwai_live_xxxxx",
154
+ premium: {
155
+ verifyEndpoint: "http://localhost/blockwriteai-platform/api/license_verify.php",
156
+ usageEndpoint: "http://localhost/blockwriteai-platform/api/ai_usage.php"
157
+ }
158
+ });
159
+ }
160
+ boot();
161
+ </script>
162
+ ```
163
+
164
+ This matters because browser-only locks can be edited in DevTools. Server-side
165
+ license verification, usage metering, signature event storage, and verified
166
+ premium bundle delivery are the enforceable parts.
167
+
168
+ ### npm
169
+
170
+ Package name:
171
+
172
+ ```text
173
+ @qarakash/blockwriteai
174
+ ```
175
+
176
+ Install:
177
+
178
+ ```bash
179
+ npm install @qarakash/blockwriteai
180
+ ```
181
+
182
+ Bundler entry points:
183
+
184
+ ```js
185
+ import BlockWriteAI from "@qarakash/blockwriteai";
186
+ import "@qarakash/blockwriteai/css";
187
+ import "@qarakash/blockwriteai/plugins/code-assist";
188
+ import "@qarakash/blockwriteai/plugins/advanced";
189
+ import "@qarakash/blockwriteai/plugins/ai";
190
+ import "@qarakash/blockwriteai/plugins/history";
191
+ import "@qarakash/blockwriteai/plugins/signature";
192
+ import "@qarakash/blockwriteai/plugins/signature-flow";
193
+ ```
194
+
195
+ After npm publishing, the same package is also available through npm CDNs:
196
+
197
+ ```html
198
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@qarakash/blockwriteai@1.0.7/dist/blockwriteai.css">
199
+ <script src="https://cdn.jsdelivr.net/npm/@qarakash/blockwriteai@1.0.7/dist/blockwriteai.js"></script>
200
+ ```
201
+
202
+ ### Python
203
+
204
+ Package name:
205
+
206
+ ```text
207
+ blockwriteai-editor
208
+ ```
209
+
210
+ Install:
211
+
212
+ ```bash
213
+ pip install blockwriteai-editor
214
+ ```
215
+
216
+ Copy packaged static files into your Flask, Django, or any Python web app static directory:
217
+
218
+ ```python
219
+ from blockwriteai_editor import copy_static
220
+
221
+ copy_static("static/blockwriteai")
222
+ ```
223
+
224
+ Python helpers are also available for generating asset tags. Pass `history=True` only on pages where you want the optional History dropdown:
225
+
226
+ ```python
227
+ from blockwriteai_editor import stylesheet_tag, script_tags
228
+
229
+ print(stylesheet_tag("/static/blockwriteai"))
230
+ print(script_tags("/static/blockwriteai"))
231
+ print(script_tags("/static/blockwriteai", history=True))
232
+ print(script_tags("/static/blockwriteai", ai=True))
233
+ ```
234
+
235
+ ### PHP / Composer
236
+
237
+ Package name:
238
+
239
+ ```text
240
+ qarakash/blockwriteai
241
+ ```
242
+
243
+ Install:
244
+
245
+ ```bash
246
+ composer require qarakash/blockwriteai
247
+ ```
248
+
249
+ Publish assets into your public folder:
250
+
251
+ ```bash
252
+ cp -R vendor/qarakash/blockwriteai/dist public/blockwriteai
253
+ ```
254
+
255
+ PHP helper. Pass `history: true` only on pages where you want the optional History dropdown, and `ai: true` only on pages where you want the AI drawer:
256
+
257
+ ```php
258
+ use QarAkash\BlockWriteAI\BlockWriteAIAssets;
259
+
260
+ echo BlockWriteAIAssets::stylesheetTag('/blockwriteai');
261
+ echo BlockWriteAIAssets::scriptTags('/blockwriteai');
262
+ echo BlockWriteAIAssets::scriptTags('/blockwriteai', plugins: true, history: true, ai: true);
263
+ ```
264
+
265
+ ## Local XAMPP Demo
266
+
267
+ Copy the `BlockWriteAI` folder into your web root, for example:
268
+
269
+ ```text
270
+ C:\xampp\htdocs\BlockWriteAI
271
+ ```
272
+
273
+ Open:
274
+
275
+ ```text
276
+ http://localhost/BlockWriteAI/examples/
277
+ ```
278
+
279
+ ## Browser Usage
280
+
281
+ ```html
282
+ <link rel="stylesheet" href="/BlockWriteAI/dist/blockwriteai.css">
283
+
284
+ <div id="editor"></div>
285
+
286
+ <script src="/BlockWriteAI/dist/blockwriteai.js"></script>
287
+ <script src="/BlockWriteAI/dist/plugins/blockwriteai-code-assist.js"></script>
288
+ <script src="/BlockWriteAI/dist/plugins/blockwriteai-advanced-blocks.js"></script>
289
+ <script src="/BlockWriteAI/dist/plugins/blockwriteai-signature.js"></script>
290
+ <script src="/BlockWriteAI/dist/plugins/blockwriteai-signature-flow.js"></script>
291
+
292
+ <script>
293
+ const editor = new BlockWriteAI({
294
+ holder: "#editor",
295
+ maxWidth: "960px", // optional; omit for full-width editor shell
296
+ placeholder: "Write something, or press / for blocks",
297
+ data: {
298
+ blocks: [
299
+ {
300
+ type: "paragraph",
301
+ data: {
302
+ text: "Hello from BlockWriteAI",
303
+ alignment: "left"
304
+ }
305
+ }
306
+ ]
307
+ },
308
+ onChange(data) {
309
+ console.log("Changed document", data);
310
+ },
311
+ async onSave(data) {
312
+ await fetch("/save-document.php", {
313
+ method: "POST",
314
+ headers: {
315
+ "Content-Type": "application/json"
316
+ },
317
+ body: JSON.stringify(data)
318
+ });
319
+ }
320
+ });
321
+ </script>
322
+ ```
323
+
324
+ By default, BlockWriteAI mounts the full branded editor shell: logo, product subtitle,
325
+ `Editor` heading, centered AI progress, and the right-aligned JSON sync status. If no
326
+ `data` is provided, the editor starts with one empty paragraph block automatically. Use
327
+ `shell: false` when you only want the raw editor surface, or pass `maxWidth: "960px"` /
328
+ `shell: { maxWidth: "960px" }` to constrain the editor width in your project.
329
+
330
+ Built-in toolbar buttons are intentionally opt-in for package consumers. `saveButton`, `exportButton`, and `exportHtmlButton` default to `false`, so applications can use their own UI and call `editor.save()` when needed.
331
+
332
+ ## Saving JSON
333
+
334
+ BlockWriteAI is designed to save JSON first. In production, store the JSON in your database and render it later in read-only mode or through exported HTML.
335
+
336
+ ```js
337
+ document.querySelector("#save").addEventListener("click", async () => {
338
+ const data = await editor.save();
339
+
340
+ await fetch("/save-document.php", {
341
+ method: "POST",
342
+ headers: {
343
+ "Content-Type": "application/json"
344
+ },
345
+ body: JSON.stringify(data)
346
+ });
347
+ });
348
+ ```
349
+
350
+ The default toolbar includes a Save button. Use `onSave` to receive the JSON response when the user clicks it:
351
+
352
+ ```js
353
+ const editor = new BlockWriteAI({
354
+ holder: "#editor",
355
+ async onSave(data) {
356
+ await fetch("/documents/123", {
357
+ method: "POST",
358
+ headers: {
359
+ "Content-Type": "application/json"
360
+ },
361
+ body: JSON.stringify(data)
362
+ });
363
+ }
364
+ });
365
+ ```
366
+
367
+ ## AI Plugin
368
+
369
+ Load the optional AI plugin only on pages where you want writing assistance. The browser plugin never receives your OpenAI API key; it calls your own server endpoint.
370
+
371
+ ```html
372
+ <script src="/blockwriteai/blockwriteai.js"></script>
373
+ <script src="/blockwriteai/plugins/blockwriteai-ai.js"></script>
374
+
375
+ <script>
376
+ const editor = new BlockWriteAI({
377
+ holder: "#editor",
378
+ ai: {
379
+ endpoint: "/api/blockwriteai-ai.php"
380
+ }
381
+ });
382
+ </script>
383
+ ```
384
+
385
+ The included demo endpoint is `examples/api/ai.php`. For local development, copy `examples/api/openai.local.example.php` to `examples/api/openai.local.php` and add a development key, or set `OPENAI_API_KEY` in the server environment. Do not expose the key in browser JavaScript.
386
+
387
+ The drawer can also be opened without selecting text from the centered AI button in the editor toolbar, or programmatically with `editor.openAI()`.
388
+
389
+ Available AI drawer actions:
390
+
391
+ - Improve writing
392
+ - Fix grammar
393
+ - Summarize
394
+ - Expand
395
+ - Make professional
396
+ - Generate BlockWriteAI blocks from a prompt
397
+
398
+ ## Preview Pages
399
+
400
+ Create any page in your application and add a preview container. BlockWriteAI will load saved JSON and render the document HTML inside that container.
401
+
402
+ ```html
403
+ <link rel="stylesheet" href="/blockwriteai/blockwriteai.css">
404
+
405
+ <div class="blockwriteai-preview" data-source="/documents/123.json"></div>
406
+
407
+ <script src="/blockwriteai/blockwriteai.js"></script>
408
+ <script src="/blockwriteai/plugins/blockwriteai-advanced-blocks.js"></script>
409
+ <script src="/blockwriteai/plugins/blockwriteai-signature.js"></script>
410
+ <script src="/blockwriteai/plugins/blockwriteai-signature-flow.js"></script>
411
+ <script>
412
+ BlockWriteAI.mountPreviews();
413
+ </script>
414
+ ```
415
+
416
+ The JSON endpoint can return either a BlockWriteAI document directly or an API wrapper such as:
417
+
418
+ ```json
419
+ {
420
+ "ok": true,
421
+ "data": {
422
+ "time": 1779540000000,
423
+ "version": "1.0.7",
424
+ "blocks": []
425
+ }
426
+ }
427
+ ```
428
+
429
+ Example PHP receiver:
430
+
431
+ ```php
432
+ <?php
433
+ header('Content-Type: application/json');
434
+
435
+ $json = file_get_contents('php://input');
436
+ $data = json_decode($json, true);
437
+
438
+ if (!$data || !isset($data['blocks']) || !is_array($data['blocks'])) {
439
+ http_response_code(422);
440
+ echo json_encode(['error' => 'Invalid BlockWriteAI document']);
441
+ exit;
442
+ }
443
+
444
+ file_put_contents(__DIR__ . '/saved-document.json', json_encode($data, JSON_PRETTY_PRINT));
445
+
446
+ echo json_encode(['ok' => true]);
447
+ ```
448
+
449
+ ## Uploads
450
+
451
+ The demo includes `examples/upload.php` and stores files under `examples/uploads/`. For production, replace this with your own storage layer.
452
+
453
+ ```js
454
+ const editor = new BlockWriteAI({
455
+ holder: "#editor",
456
+ uploadOutput: ["upload", "base64"],
457
+ upload: {
458
+ image: async (file) => {
459
+ const form = new FormData();
460
+ form.append("file", file);
461
+ form.append("kind", "image");
462
+
463
+ const response = await fetch("/BlockWriteAI/examples/upload.php", {
464
+ method: "POST",
465
+ body: form
466
+ });
467
+
468
+ return response.json();
469
+ },
470
+ file: async (file) => {
471
+ const form = new FormData();
472
+ form.append("file", file);
473
+ form.append("kind", "file");
474
+
475
+ const response = await fetch("/BlockWriteAI/examples/upload.php", {
476
+ method: "POST",
477
+ body: form
478
+ });
479
+
480
+ return response.json();
481
+ }
482
+ }
483
+ });
484
+ ```
485
+
486
+ `uploadOutput` controls what gets written into the saved JSON:
487
+
488
+ - `"base64"` or `["base64"]` stores uploaded media directly in the block JSON. This is the default.
489
+ - `"upload"` or `["upload"]` stores the response from your upload handler, such as a server URL.
490
+ - `["upload", "base64"]` stores both, useful when you want server files plus a portable JSON backup.
491
+
492
+ Expected upload response:
493
+
494
+ ```json
495
+ {
496
+ "url": "/BlockWriteAI/examples/uploads/example.pdf",
497
+ "name": "example.pdf",
498
+ "size": 12345,
499
+ "type": "application/pdf"
500
+ }
501
+ ```
502
+
503
+ When both outputs are enabled, saved image and attachment items include the server response under `upload` and the inline file data under `base64`.
504
+
505
+ ## API Methods
506
+
507
+ ```js
508
+ await editor.save(); // Get JSON document
509
+ editor.getData(); // Get current data synchronously
510
+ editor.render(data); // Replace editor content
511
+ editor.clear(); // Reset editor
512
+ editor.exportHTML(); // Export HTML
513
+ editor.exportMarkdown(); // Export Markdown API, hidden from the default UI
514
+ editor.importHTML(html); // Import HTML into blocks
515
+ editor.setReadOnly(true); // Toggle read-only mode
516
+ editor.undo(); // Undo last change
517
+ editor.redo(); // Redo last undo
518
+ editor.destroy(); // Remove editor instance
519
+ BlockWriteAI.mountPreviews(); // Render JSON into .blockwriteai-preview containers
520
+ ```
521
+
522
+ ## Data Shape
523
+
524
+ ```json
525
+ {
526
+ "time": 1779540000000,
527
+ "version": "1.0.7",
528
+ "blocks": [
529
+ {
530
+ "id": "block-title",
531
+ "type": "heading",
532
+ "data": {
533
+ "level": 2,
534
+ "text": "BlockWriteAI document",
535
+ "alignment": "left"
536
+ }
537
+ },
538
+ {
539
+ "id": "block-body",
540
+ "type": "paragraph",
541
+ "data": {
542
+ "text": "Reusable content saved as JSON."
543
+ }
544
+ }
545
+ ]
546
+ }
547
+ ```
548
+
549
+ ## Tool Control
550
+
551
+ Limit available blocks per project:
552
+
553
+ ```js
554
+ const editor = new BlockWriteAI({
555
+ holder: "#editor",
556
+ tools: [
557
+ "paragraph",
558
+ "heading",
559
+ "image",
560
+ "list",
561
+ "table"
562
+ ]
563
+ });
564
+ ```
565
+
566
+ Disable specific tools:
567
+
568
+ ```js
569
+ const editor = new BlockWriteAI({
570
+ holder: "#editor",
571
+ tools: {
572
+ raw: false,
573
+ attaches: false
574
+ }
575
+ });
576
+ ```
577
+
578
+ ## Autosave
579
+
580
+ ```js
581
+ const editor = new BlockWriteAI({
582
+ holder: "#editor",
583
+ autosave: {
584
+ key: "blockwriteai-draft",
585
+ load: true
586
+ }
587
+ });
588
+ ```
589
+
590
+ ## Security Notes
591
+
592
+ BlockWriteAI sanitizes normal rich text blocks before saving and exporting. Raw HTML blocks are intentionally treated as trusted HTML, so enable the raw HTML tool only for trusted users.
593
+
594
+ For production applications:
595
+
596
+ - Validate JSON on the server.
597
+ - Sanitize output again before public rendering.
598
+ - Restrict upload types and file sizes.
599
+ - Store uploaded files outside executable PHP paths when possible.
600
+ - Add authentication before saving documents.
601
+
602
+ ## GitHub
603
+
604
+ Repository target:
605
+
606
+ ```text
607
+ https://github.com/qarAkash/BlockWriteAI.git
608
+ ```
609
+
610
+ ## Publishing Packages
611
+
612
+ After a release is ready, publish each package from the repository root.
613
+
614
+ Create a Git release tag for script-link/CDN users:
615
+
616
+ ```bash
617
+ git tag v1.0.7
618
+ git push origin v1.0.7
619
+ ```
620
+
621
+ Publish npm:
622
+
623
+ ```bash
624
+ npm publish --access public
625
+ ```
626
+
627
+ Publish Python:
628
+
629
+ ```bash
630
+ python -m build
631
+ python -m twine upload dist/*
632
+ ```
633
+
634
+ Publish Composer:
635
+
636
+ ```text
637
+ Submit https://github.com/qarAkash/BlockWriteAI to Packagist as qarakash/blockwriteai.
638
+ ```
639
+
640
+ ## Status
641
+
642
+ BlockWriteAI is currently an active custom editor library and demo project. It is suitable for continued feature development, integration testing, and database-backed storage work.
@@ -0,0 +1,20 @@
1
+ <svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="BlockWriteAI">
2
+ <defs>
3
+ <linearGradient id="bwai-favicon-bg" x1="8" y1="8" x2="56" y2="56" gradientUnits="userSpaceOnUse">
4
+ <stop offset="0" stop-color="#102033"/>
5
+ <stop offset="1" stop-color="#172A46"/>
6
+ </linearGradient>
7
+ <linearGradient id="bwai-favicon-accent" x1="16" y1="18" x2="48" y2="48" gradientUnits="userSpaceOnUse">
8
+ <stop offset="0" stop-color="#2BEA8A"/>
9
+ <stop offset="1" stop-color="#10B981"/>
10
+ </linearGradient>
11
+ </defs>
12
+ <rect x="6" y="6" width="52" height="52" rx="16" fill="url(#bwai-favicon-bg)"/>
13
+ <rect x="18" y="18" width="10" height="10" rx="2.5" fill="#FFFFFF"/>
14
+ <rect x="31" y="18" width="10" height="10" rx="2.5" fill="#FFFFFF" opacity="0.92"/>
15
+ <rect x="18" y="31" width="10" height="10" rx="2.5" fill="url(#bwai-favicon-accent)"/>
16
+ <path d="M33.2 43.1L45 31.3C45.7 30.6 46.8 30.6 47.5 31.3L51.1 34.9C51.8 35.6 51.8 36.7 51.1 37.4L39.3 49.2L31.5 50.8L33.2 43.1Z" fill="#FFFFFF"/>
17
+ <path d="M43.1 33.3L49.2 39.4" stroke="#10B981" stroke-width="3" stroke-linecap="round"/>
18
+ <circle cx="51" cy="51" r="7" fill="#19B86B" stroke="#FFFFFF" stroke-width="3"/>
19
+ <path d="M49.5 16.5H55.5M52.5 13.5V19.5" stroke="#19B86B" stroke-width="3" stroke-linecap="round"/>
20
+ </svg>