From 9e6ca4fd8265b3e79e2683b49665f3d4e591e206 Mon Sep 17 00:00:00 2001
From: Krzysztof Kocot <“k.kocot0@gmail.com”>
Date: Mon, 10 Feb 2025 11:16:05 +0100
Subject: [PATCH 1/5] Fix rendererd Spoiler content, fix #503

---
 apps/blog/lib/renderer.ts                     |  3 +-
 .../default/plugins/SpoilerPlugin.ts          | 31 +++++++++----------
 2 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/apps/blog/lib/renderer.ts b/apps/blog/lib/renderer.ts
index 76d01e2d7..d042cc378 100644
--- a/apps/blog/lib/renderer.ts
+++ b/apps/blog/lib/renderer.ts
@@ -1,4 +1,4 @@
-import { DefaultRenderer } from '@hive/renderer';
+import { DefaultRenderer, SpoilerPlugin } from '@hive/renderer';
 import { getDoubleSize, proxifyImageUrl } from '@ui/lib/old-profixy';
 import env from '@beam-australia/react-env';
 import imageUserBlocklist from '@hive/ui/config/lists/image-user-blocklist';
@@ -17,6 +17,7 @@ const renderDefaultOptions = {
   ipfsPrefix: '',
   assetsWidth: 640,
   assetsHeight: 480,
+  plugins: [new SpoilerPlugin()],
   imageProxyFn: (url: string) => getDoubleSize(proxifyImageUrl(url, true).replace(/ /g, '%20')),
   usertagUrlFn: (account: string) => '/@' + account,
   hashtagUrlFn: (hashtag: string) => '/trending/' + hashtag,
diff --git a/packages/renderer/src/renderers/default/plugins/SpoilerPlugin.ts b/packages/renderer/src/renderers/default/plugins/SpoilerPlugin.ts
index 52ed65904..59a12cddc 100644
--- a/packages/renderer/src/renderers/default/plugins/SpoilerPlugin.ts
+++ b/packages/renderer/src/renderers/default/plugins/SpoilerPlugin.ts
@@ -4,23 +4,22 @@ export class SpoilerPlugin implements RendererPlugin {
     name = 'spoiler';
 
     preProcess(text: string): string {
-        return text.replace(/^>! *\[(.*?)\] *(.*?)(?:\n|$)([\s\S]*?)(?=^>! *\[|$)/gm, (_, title, firstLine, rest) => {
-            // Get the first line content (after the title)
-            const content = firstLine.trim();
+        // Matches spoiler blocks with optional title and multiple lines
+        return text.replace(/^>!(?:\s*\[(.*?)\])?\s*(.*?)(?:\n|$)((?:\n> ?.*)*)$/gm, (_, title, firstLine, rest) => {
+            // Combines first line and additional lines into single content string
+            const content = [
+                firstLine.trim(),
+                ...rest
+                    .split('\n') // Split additional lines
+                    .map((line: string) => line.trim()) // Remove whitespace
+                    .filter((line: string) => line.startsWith('>')) // Keep only quote lines
+                    .map((line: string) => line.replace(/^> ?/, '')) // Remove quote markers
+            ]
+                .join(' ') // Join all lines with spaces
+                .trim(); // Remove extra whitespace
 
-            // Get the rest of the content (lines starting with >)
-            const restContent = rest
-                .split('\n')
-                .map((line: string) => line.trim())
-                .filter((line: string) => line.startsWith('>'))
-                .map((line: string) => line.replace(/^> ?/, ''))
-                .join(' ')
-                .trim();
-
-            // Combine all content
-            const fullContent = [content, restContent].filter(Boolean).join(' ');
-
-            return `<details class="spoiler"><summary>${title || 'Reveal spoiler'}</summary><p>${fullContent}</p></details>`;
+            // Generate HTML details/summary structure
+            return `<details class="spoiler"><summary>${title || 'Reveal spoiler'}</summary><p>${content}</p></details>`;
         });
     }
 }
-- 
GitLab


From 3d062444a6ff86aaa3aebee9783f6ecd7d392597 Mon Sep 17 00:00:00 2001
From: Krzysztof Kocot <“k.kocot0@gmail.com”>
Date: Mon, 10 Feb 2025 11:46:56 +0100
Subject: [PATCH 2/5] Fix embeds with text before, fix #504

---
 .../default/embedder/embedders/ThreeSpeakEmbedder.ts          | 2 +-
 .../renderers/default/embedder/embedders/TwitterEmbedder.ts   | 4 +++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/packages/renderer/src/renderers/default/embedder/embedders/ThreeSpeakEmbedder.ts b/packages/renderer/src/renderers/default/embedder/embedders/ThreeSpeakEmbedder.ts
index 62793dc39..bad58ea4b 100644
--- a/packages/renderer/src/renderers/default/embedder/embedders/ThreeSpeakEmbedder.ts
+++ b/packages/renderer/src/renderers/default/embedder/embedders/ThreeSpeakEmbedder.ts
@@ -10,7 +10,7 @@ export class ThreeSpeakEmbedder extends AbstractEmbedder {
     public getEmbedMetadata(input: string | HTMLObjectElement): EmbedMetadata | undefined {
         const url = typeof input === 'string' ? input : input.data;
         try {
-            const match = url.match(ThreeSpeakEmbedder.linkRegex);
+            const match = (url.startsWith('\n') ? url.replace('\n', '') : url).match(ThreeSpeakEmbedder.linkRegex);
             if (match && match[1]) {
                 const id = match[1];
                 return {
diff --git a/packages/renderer/src/renderers/default/embedder/embedders/TwitterEmbedder.ts b/packages/renderer/src/renderers/default/embedder/embedders/TwitterEmbedder.ts
index 5aa55d521..232ef9957 100644
--- a/packages/renderer/src/renderers/default/embedder/embedders/TwitterEmbedder.ts
+++ b/packages/renderer/src/renderers/default/embedder/embedders/TwitterEmbedder.ts
@@ -10,7 +10,9 @@ export class TwitterEmbedder extends AbstractEmbedder {
     public getEmbedMetadata(input: string | HTMLObjectElement): EmbedMetadata | undefined {
         const url = typeof input === 'string' ? input : input.data;
         try {
-            const metadata = TwitterEmbedder.getTwitterMetadataFromLink(url);
+            const metadata = TwitterEmbedder.getTwitterMetadataFromLink(url.startsWith('\n') ? url.replace('\n', '') : url);
+            console.log('input', input, 'url', url, 'metadata', metadata);
+
             if (!metadata) {
                 return undefined;
             }
-- 
GitLab


From 7009b1932438e0037c1b40ebae17fda348760ac2 Mon Sep 17 00:00:00 2001
From: Krzysztof Kocot <“k.kocot0@gmail.com”>
Date: Mon, 10 Feb 2025 11:53:41 +0100
Subject: [PATCH 3/5] Remove debug logging from TwitterEmbedder

---
 .../src/renderers/default/embedder/embedders/TwitterEmbedder.ts  | 1 -
 1 file changed, 1 deletion(-)

diff --git a/packages/renderer/src/renderers/default/embedder/embedders/TwitterEmbedder.ts b/packages/renderer/src/renderers/default/embedder/embedders/TwitterEmbedder.ts
index 232ef9957..1db23deee 100644
--- a/packages/renderer/src/renderers/default/embedder/embedders/TwitterEmbedder.ts
+++ b/packages/renderer/src/renderers/default/embedder/embedders/TwitterEmbedder.ts
@@ -11,7 +11,6 @@ export class TwitterEmbedder extends AbstractEmbedder {
         const url = typeof input === 'string' ? input : input.data;
         try {
             const metadata = TwitterEmbedder.getTwitterMetadataFromLink(url.startsWith('\n') ? url.replace('\n', '') : url);
-            console.log('input', input, 'url', url, 'metadata', metadata);
 
             if (!metadata) {
                 return undefined;
-- 
GitLab


From 472e1704673e8df152c2cffbe582d7e7e4ffc7f0 Mon Sep 17 00:00:00 2001
From: Krzysztof Kocot <“k.kocot0@gmail.com”>
Date: Mon, 10 Feb 2025 13:07:13 +0100
Subject: [PATCH 4/5] Add missing spoiler button to MD Editor

---
 apps/blog/components/md-editor.tsx | 38 +++++++++++++++++++++++++++---
 1 file changed, 35 insertions(+), 3 deletions(-)

diff --git a/apps/blog/components/md-editor.tsx b/apps/blog/components/md-editor.tsx
index 0d9d9f415..900c26c52 100644
--- a/apps/blog/components/md-editor.tsx
+++ b/apps/blog/components/md-editor.tsx
@@ -21,6 +21,7 @@ import { useTranslation } from 'next-i18next';
 import imageUserBlocklist from '@ui/config/lists/image-user-blocklist';
 import { cn } from '@ui/lib/utils';
 import { useSignerContext } from '@smart-signer/components/signer-provider';
+import { Button } from '@ui/components';
 
 const logger = getLogger('app');
 
@@ -240,7 +241,38 @@ const MdEditor: FC<MdEditorProps> = ({ onChange, persistedValue = '', placeholde
     }
   });
 
-  const editChoice = (inputRef: MutableRefObject<HTMLInputElement>) => [imgBtn(inputRef)];
+  const spoilerBtn = (): commands.ICommand => ({
+    name: "Add Spoiler",
+    keyCommand: "spoiler",
+    render: (
+      command: commands.ICommand,
+      disabled: boolean | undefined,
+      executeCommand: (
+        arg0: commands.ICommand<string>,
+        arg1: string | undefined
+      ) => void
+    ) => {
+      return (
+        <Button
+          variant="basic"
+          onClick={() => executeCommand(command, command.groupName)}
+          disabled={disabled}
+        >
+          Spoiler
+        </Button>
+      );
+    },
+    execute: (_: commands.ExecuteState, api: TextAreaTextApi) => {
+      const spoilerTemplate = ">! [Click to reveal] Your spoiler content";
+      const newState = api.replaceSelection(spoilerTemplate);
+      api.setSelectionRange({
+        start:
+          newState.selection.start +
+          spoilerTemplate.indexOf("Your spoiler content"),
+        end: newState.selection.end,
+      });
+    },
+  });
 
   return !imageUserBlocklist?.includes(user.username) ? (
     <div>
@@ -264,7 +296,7 @@ const MdEditor: FC<MdEditorProps> = ({ onChange, persistedValue = '', placeholde
             onChange={(value) => {
               setFormValue(value || '');
             }}
-            commands={[...(commands.getCommands() as ICommand[]), imgBtn(inputRef)]}
+            commands={[...(commands.getCommands() as ICommand[]), imgBtn(inputRef), spoilerBtn()]}
             extraCommands={[]}
             className={cn({ '!bg-red-400 !bg-opacity-20': isDrag })}
             onDrop={dropHandler}
@@ -287,7 +319,7 @@ const MdEditor: FC<MdEditorProps> = ({ onChange, persistedValue = '', placeholde
       onChange={(value) => {
         setFormValue(value || '');
       }}
-      commands={[...(commands.getCommands() as ICommand[]), imgBtn(inputRef)]}
+      commands={[...(commands.getCommands() as ICommand[]), imgBtn(inputRef), spoilerBtn()]}
       extraCommands={[]}
       //@ts-ignore
       style={{ '--color-canvas-default': 'var(--background)' }}
-- 
GitLab


From 53d61f4f6703b60e3e5f8c42c8042cb395095500 Mon Sep 17 00:00:00 2001
From: Krzysztof Kocot <“k.kocot0@gmail.com”>
Date: Mon, 10 Feb 2025 14:27:57 +0100
Subject: [PATCH 5/5] Delete p html tags from around details tags to correct
 render collapsible section, fix #580

---
 .../src/renderers/default/embedder/HtmlDOMParser.ts        | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/packages/renderer/src/renderers/default/embedder/HtmlDOMParser.ts b/packages/renderer/src/renderers/default/embedder/HtmlDOMParser.ts
index 160a0ebd6..faaa26d6b 100644
--- a/packages/renderer/src/renderers/default/embedder/HtmlDOMParser.ts
+++ b/packages/renderer/src/renderers/default/embedder/HtmlDOMParser.ts
@@ -72,7 +72,12 @@ export class HtmlDOMParser {
 
     public parse(html: string): HtmlDOMParser {
         try {
-            const doc: Document = this.domParser.parseFromString(html, 'text/html');
+            const fixedHtml = html
+                // Remove wrapping <p> from details
+                .replace(/<p>\s*(<details>[\s\S]*?<\/details>)\s*<\/p>/g, '$1')
+                // Move content after details outside of it
+                .replace(/(<details>[\s\S]*?<\/pre>)([\s\S]*?)(<\/details>)/g, '$1$3$2');
+            const doc: Document = this.domParser.parseFromString(fixedHtml, 'text/html');
             this.traverseDOMNode(doc);
             if (this.mutate) this.postprocessDOM(doc);
             this.parsedDocument = doc;
-- 
GitLab