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