From 3021869fd57eb5bd823e1981bdf22ba26b2f353c Mon Sep 17 00:00:00 2001 From: Silabear <56885288+Silabear@users.noreply.github.com> Date: Sun, 9 Aug 2026 19:05:01 +0100 Subject: [PATCH 01/11] draggable gradient modal --- package-lock.json | 7 +++ package.json | 1 + src/lib/components/Modal.svelte | 2 +- .../modals/ColorGradientModal.svelte | 46 ++++++++++++++----- 4 files changed, 43 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index a321708..2989f68 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "@tiptap/starter-kit": "^3.29.2", "idb": "^8.0.3", "modern-screenshot": "^4.7.0", + "sortablejs": "^1.15.7", "svelte-awesome-color-picker": "^4.1.3", "svelte-highlight": "^7.16.2", "tippy.js": "^6.3.7", @@ -3336,6 +3337,12 @@ "node": ">=18" } }, + "node_modules/sortablejs": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.7.tgz", + "integrity": "sha512-Kk8wLQPlS+yi1ZEf48a4+fzHa4yxjC30M/Sr2AnQu+f/MPwvvX9XjZ6OWejiz8crBsLwSq8GHqaxaET7u6ux0A==", + "license": "MIT" + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", diff --git a/package.json b/package.json index 0475e94..53c6fdc 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "@tiptap/starter-kit": "^3.29.2", "idb": "^8.0.3", "modern-screenshot": "^4.7.0", + "sortablejs": "^1.15.7", "svelte-awesome-color-picker": "^4.1.3", "svelte-highlight": "^7.16.2", "tippy.js": "^6.3.7", diff --git a/src/lib/components/Modal.svelte b/src/lib/components/Modal.svelte index 5add675..8702b18 100644 --- a/src/lib/components/Modal.svelte +++ b/src/lib/components/Modal.svelte @@ -28,10 +28,10 @@ export async function open() { opened = true; + await tick(); if (onOpen) { onOpen(); } - await tick(); } export async function close() { diff --git a/src/lib/components/modals/ColorGradientModal.svelte b/src/lib/components/modals/ColorGradientModal.svelte index 37c682a..5ed2e28 100644 --- a/src/lib/components/modals/ColorGradientModal.svelte +++ b/src/lib/components/modals/ColorGradientModal.svelte @@ -1,13 +1,17 @@ - -
+ +

Add colours to the gradient below:

-
+
{#each gradientSteps ?? [] as _, i}
+
{/each} -
+

Preview

+ class="btn mt-2"> Apply Gradient
From a9f1e52c5971ed2e2c8019f89d57528c57f59719 Mon Sep 17 00:00:00 2001 From: Silabear <56885288+Silabear@users.noreply.github.com> Date: Sun, 9 Aug 2026 19:32:48 +0100 Subject: [PATCH 02/11] add JSON format output type --- .../modals/topbar/ExportModal.svelte | 192 +++++++++--------- src/lib/text/nbt/export.ts | 25 ++- 2 files changed, 109 insertions(+), 108 deletions(-) diff --git a/src/lib/components/modals/topbar/ExportModal.svelte b/src/lib/components/modals/topbar/ExportModal.svelte index 8eb8aa4..2328613 100644 --- a/src/lib/components/modals/topbar/ExportModal.svelte +++ b/src/lib/components/modals/topbar/ExportModal.svelte @@ -11,12 +11,14 @@ // Icons import IconItem from "~icons/tabler/swords"; + import IconJSON from "~icons/tabler/braces"; import IconMOTD from "~icons/tabler/speakerphone"; import IconImage from "~icons/tabler/photo"; import IconBack from "~icons/tabler/arrow-back-up"; import IconCopy from "~icons/tabler/copy"; import IconCheck from "~icons/tabler/check"; import IconDownload from "~icons/tabler/download"; + import { json } from "svelte-highlight/languages"; // UI let showOutput: string | null = $state(null); @@ -49,7 +51,9 @@ scale: 4, }; + // output variables var transparent: boolean = $state(true); + var indent: boolean = $state(true) async function exportImage() { const textContainer: HTMLElement = document.querySelector(".ProseMirror")!; @@ -102,6 +106,13 @@ {#if showOutput == null}

You can also export the text in one of these formats too:

+ +
+ {:else if showOutput == "json"} +
+
+ + JSON format +
+ +
+ + {#if $appSettings.syntaxHighlight} + + {:else} +
{editor
+                        ? JSON.stringify(
+                            JSON.parse(
+                                convert(
+                                    editor.getJSON(),
+                                    shouldOptimise,
+                                    "standard",
+                                    true,
+                                )
+                            ),
+                            null,
+                            indent ? 4 : undefined
+                        )
+                        : "Loading..."}
+ {/if} +
+ +
+ + +
+ + {:else if showOutput == "lore"}
@@ -262,101 +355,4 @@
{/if}
- - - + \ No newline at end of file diff --git a/src/lib/text/nbt/export.ts b/src/lib/text/nbt/export.ts index 3c9eec2..5ccb35d 100644 --- a/src/lib/text/nbt/export.ts +++ b/src/lib/text/nbt/export.ts @@ -170,10 +170,25 @@ export function convert( ): string { exportVersion = get(outputVersion); let out = translateJSON(jsonContent, { exportType, optimise }); + + // Convert from JSON string to NBT string if required if (exportVersion.index >= 1 && !forceJson) { // only remove string keys out = out.replaceAll(/(?<=[{,]\s*)"[^"]*"\s*:/gu, (match) => match.replaceAll(`"`, "")); + + // nbt number type fix for shadow colour + // moved from translateJSON function + const shadowColorMatches = out.matchAll(/"shadow_color":(-?\d+)/gu); + for (const match of shadowColorMatches) { + if (match[1]) { + const num = parseInt(match[1]); + if (num > 2 ** 31 - 1 || num < (-2) ** 31) { + out = out.replaceAll(match[0], `"shadow_color":${num}L`); + } + } + } } + return out; } @@ -234,16 +249,6 @@ export function translateJSON(json: JSONContent, options: TranslateOptions): str let finalResult = JSON.stringify(data); - const shadowColorMatches = finalResult.matchAll(/"shadow_color":(-?\d+)/gu); - for (const match of shadowColorMatches) { - if (match[1]) { - const num = parseInt(match[1]); - if (num > 2 ** 31 - 1 || num < (-2) ** 31) { - finalResult = finalResult.replaceAll(match[0], `"shadow_color":${num}L`); - } - } - } - return finalResult; } else if (options.exportType === "item_lore") { let data: (StringyMCText[] | StringyMCText)[] = []; From 45199dc29217d7e096aa2bb35c55fff3e9b647b9 Mon Sep 17 00:00:00 2001 From: Silabear <56885288+Silabear@users.noreply.github.com> Date: Sun, 9 Aug 2026 19:40:27 +0100 Subject: [PATCH 03/11] add json lore output + polish code --- .../modals/topbar/ExportModal.svelte | 32 +++++++------------ 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/src/lib/components/modals/topbar/ExportModal.svelte b/src/lib/components/modals/topbar/ExportModal.svelte index 2328613..a2b76f0 100644 --- a/src/lib/components/modals/topbar/ExportModal.svelte +++ b/src/lib/components/modals/topbar/ExportModal.svelte @@ -30,30 +30,18 @@ shouldOptimise = true, } = $props(); - // Output variables - let exportAsJSON = $state(false); - let extension = $state("png"); // Image output let imgPreview: HTMLImageElement | undefined = $state(); - const functionLUT = new Map< - string, - (element: HTMLElement, options?: Options) => Promise - >(); - - functionLUT.set("png", domToPng); - functionLUT.set("jpeg", domToJpeg); - functionLUT.set("webp", domToWebp); - functionLUT.set("svg", domToSvg); - let renderOptions: Options = { scale: 4, }; // output variables var transparent: boolean = $state(true); - var indent: boolean = $state(true) + var indent: boolean = $state(true); + var jsonLore: boolean = $state(false); async function exportImage() { const textContainer: HTMLElement = document.querySelector(".ProseMirror")!; @@ -76,7 +64,7 @@ async function downloadImage(dataUrl: string) { const link = document.createElement("a"); - link.download = `tellraw-output.${extension}`; + link.download = `tellraw-output.png`; link.href = dataUrl; link.click(); } @@ -90,7 +78,6 @@ async function showImageOutput() { showOutput = "image"; - const func = functionLUT.get(extension); exportImage().then((imgUrl) => { imgPreview!.src = imgUrl; }); @@ -239,27 +226,32 @@ {#if $appSettings.syntaxHighlight}
{:else}
{editor
-                            ? convert(editor.getJSON(), shouldOptimise, "item_lore", exportAsJSON)
+                            ? convert(editor.getJSON(), shouldOptimise, "item_lore", jsonLore)
                             : "Loading..."}
{/if} ] +
+ + +
+ -

Preview

-
+
+ +
+

Preview

+
+ + + +
+ {:else} +
+

Your top 10 most recent gradients are shown below:

+
+
+ {#each recentGradients ?? [] as gradient} +
+
+ +
+ {#each gradient ?? [] as step} + + {/each} +
+
+ +
+ {/each} +
+ + onclick={() => (recentsPageOpen = false)} + class="mt-2 flex h-full w-fit cursor-pointer items-center space-x-2 rounded-md bg-zinc-900 p-2 hover:bg-black/50"> + + Back + + + {/if}
From faf6caad0a42400c8b222ba78f3f1b55a65d3e18 Mon Sep 17 00:00:00 2001 From: Silabear <56885288+Silabear@users.noreply.github.com> Date: Mon, 10 Aug 2026 01:15:35 +0100 Subject: [PATCH 08/11] partial bug fix --- .../components/modals/ColorGradientModal.svelte | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/lib/components/modals/ColorGradientModal.svelte b/src/lib/components/modals/ColorGradientModal.svelte index 0666272..1c17065 100644 --- a/src/lib/components/modals/ColorGradientModal.svelte +++ b/src/lib/components/modals/ColorGradientModal.svelte @@ -1,7 +1,6 @@
- {#if !recentsPageOpen} -

Add colours to the gradient below:

-
- {#key gradientSteps} - {#each gradientSteps ?? [] as _, i} -
- -
- -
- {#if gradientSteps.length > 1} + {#if !recentsPageOpen} +

Add colours to the gradient below:

+
    + {#each gradientSteps as g, i (g.id)} +
  • + +
    + +
    + {#if gradientSteps.length > 1} + + {/if} +
  • + {/each} +
+
+ +
+

Preview

+
+ {editor?.state.doc.textBetween( + editor.state.selection.from, + editor.state.selection.to, + " ", + ) || "error! no text selected"} +
+ +

+ Note: you need to select text in the editor before you try and apply a gradient. +

+ +
+ + + +
+ {:else} +
+

Your top 10 most recent gradients are shown below:

+
+
+ {#each recentGradients ?? [] as gradient} +
+
+ +
+ {#each gradient ?? [] as step} + + {/each} +
+
- {/if} -
- {/each} - {/key} -
-
- -
-

Preview

-
- {editor?.state.doc.textBetween( - editor.state.selection.from, - editor.state.selection.to, - " ", - ) || "error! no text selected"} -
- -

- Note: you need to select text in the editor before you try and apply a gradient. -

- -
- - - -
- {:else} -
-

Your top 10 most recent gradients are shown below:

-
-
- {#each recentGradients ?? [] as gradient} -
-
- -
- {#each gradient ?? [] as step} - - {/each} + class="btn" + onclick={async () => { + // im 90% sure this solution is slow as hell and probably unstable too, but i hate this so much i dont care + gradientSteps = gradient.map((color, i) => ({ id: Date.now() - i, color })); + recentsPageOpen = false; + await tick(); + opened(); + }}>Use
-
- + {/each}
- {/each} -
- - - - {/if} + + + {/if}
diff --git a/src/lib/components/toolbar/Toolbar.svelte b/src/lib/components/toolbar/Toolbar.svelte index 482dda0..ce61965 100644 --- a/src/lib/components/toolbar/Toolbar.svelte +++ b/src/lib/components/toolbar/Toolbar.svelte @@ -28,7 +28,6 @@ let colourDialog: Modal = $state()!; let gradientDialog: Modal = $state()!; - let gradientSteps: string[] = $state(["#ffffff"]); let keybindDialog: Modal = $state()!; @@ -326,7 +325,7 @@ {/await} {#await import("$lib/components/modals/ColorGradientModal.svelte") then modal} - + {/await} {#await import("$lib/components/modals/UnicodeSelectorModal.svelte") then modal} From 0bfbf1c635e22f98f2ae0749578596eca7909329 Mon Sep 17 00:00:00 2001 From: Silabear <56885288+Silabear@users.noreply.github.com> Date: Mon, 10 Aug 2026 17:52:59 +0100 Subject: [PATCH 10/11] polish gradients and fix bugs --- .../components/modals/ColorGradientModal.svelte | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/lib/components/modals/ColorGradientModal.svelte b/src/lib/components/modals/ColorGradientModal.svelte index 77e5bc1..f90f426 100644 --- a/src/lib/components/modals/ColorGradientModal.svelte +++ b/src/lib/components/modals/ColorGradientModal.svelte @@ -81,11 +81,18 @@ chain.run(); // Add to recents if necessary - if (recentGradients.includes(gradientSteps.map((step) => step.color))) { - recentGradients = recentGradients.filter((grad) => grad !== gradientSteps.map((step) => step.color)); + let gradientHexes = gradientSteps.map((step) => step.color) + + const alreadyAppeared = recentGradients.some(elem =>{ + return JSON.stringify(gradientHexes) === JSON.stringify(elem); + }); + + if (alreadyAppeared) { + console.log("gradient has appeared before, removing") + recentGradients = recentGradients.filter((grad) => JSON.stringify(grad) != JSON.stringify(gradientHexes)); } - recentGradients.push(gradientSteps.map((step) => step.color)); + recentGradients.push(gradientHexes); if (recentGradients.length > 10) { recentGradients.shift(); @@ -149,7 +156,6 @@ }} class="flex aspect-square h-9 w-fit items-center justify-center rounded-md bg-zinc-900 p-2 hover:bg-black/20"> -

{i}

{/if} @@ -202,7 +208,7 @@

Your top 10 most recent gradients are shown below:

- {#each recentGradients ?? [] as gradient} + {#each recentGradients.slice().reverse() ?? [] as gradient}
From f9857892d06ef11dfeb8d23de7399dbc9c97d0a2 Mon Sep 17 00:00:00 2001 From: Silabear <56885288+Silabear@users.noreply.github.com> Date: Mon, 10 Aug 2026 19:47:40 +0100 Subject: [PATCH 11/11] changes from cobbles review --- src/lib/components/modals/ColorGradientModal.svelte | 3 +-- src/lib/components/modals/topbar/ExportModal.svelte | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/lib/components/modals/ColorGradientModal.svelte b/src/lib/components/modals/ColorGradientModal.svelte index f90f426..9255ac3 100644 --- a/src/lib/components/modals/ColorGradientModal.svelte +++ b/src/lib/components/modals/ColorGradientModal.svelte @@ -88,8 +88,7 @@ }); if (alreadyAppeared) { - console.log("gradient has appeared before, removing") - recentGradients = recentGradients.filter((grad) => JSON.stringify(grad) != JSON.stringify(gradientHexes)); + recentGradients = recentGradients.filter((grad) => JSON.stringify(grad) !== JSON.stringify(gradientHexes)); } recentGradients.push(gradientHexes); diff --git a/src/lib/components/modals/topbar/ExportModal.svelte b/src/lib/components/modals/topbar/ExportModal.svelte index a2b76f0..7cfc145 100644 --- a/src/lib/components/modals/topbar/ExportModal.svelte +++ b/src/lib/components/modals/topbar/ExportModal.svelte @@ -1,10 +1,9 @@