diff --git a/src/components/Article/FullArticle.tsx b/src/components/Article/FullArticle.tsx index ec6c565a..d956b58b 100644 --- a/src/components/Article/FullArticle.tsx +++ b/src/components/Article/FullArticle.tsx @@ -4,7 +4,7 @@ import { getPagePath } from '@nanostores/router' import { createPopper } from '@popperjs/core' import { Link, Meta } from '@solidjs/meta' import { clsx } from 'clsx' -import { createEffect, For, createMemo, onMount, Show, createSignal, onCleanup } from 'solid-js' +import { createEffect, For, createMemo, onMount, Show, createSignal, onCleanup, on } from 'solid-js' import { isServer } from 'solid-js/web' import { useLocalize } from '../../context/localize' @@ -44,6 +44,11 @@ type Props = { scrollToComments?: boolean } +type IframeSize = { + width: number + height: number +} + export type ArticlePageSearchParams = { scrollTo: 'comments' commentId: string @@ -182,18 +187,6 @@ export const FullArticle = (props: Props) => { actions: { loadReactionsBy }, } = useReactions() - onMount(async () => { - await loadReactionsBy({ - by: { shout: props.article.slug }, - }) - - setIsReactionsLoaded(true) - }) - - onMount(() => { - document.title = props.article.title - }) - const clickHandlers = [] const documentClickHandlers = [] @@ -295,8 +288,50 @@ export const FullArticle = (props: Props) => { } } - const cover = props.article.cover ?? 'production/image/logo_image.png' + // Check iframes size + const articleContainer: { current: HTMLElement } = { current: null } + const updateIframeSizes = () => { + if (!articleContainer?.current || !props.article.body) return + const iframes = articleContainer?.current?.querySelectorAll('iframe') + if (!iframes) return + const containerWidth = articleContainer.current?.offsetWidth + iframes.forEach((iframe) => { + const style = window.getComputedStyle(iframe) + const originalWidth = iframe.getAttribute('width') || style.width.replace('px', '') + const originalHeight = iframe.getAttribute('height') || style.height.replace('px', '') + const width = Number(originalWidth) + const height = Number(originalHeight) + + if (containerWidth < width) { + const aspectRatio = width / height + iframe.style.width = `${containerWidth}px` + iframe.style.height = `${Math.round(containerWidth / aspectRatio) + 40}px` + } + }) + } + + createEffect( + on( + () => props.article, + () => { + updateIframeSizes() + }, + ), + ) + + onMount(async () => { + await loadReactionsBy({ + by: { shout: props.article.slug }, + }) + setIsReactionsLoaded(true) + document.title = props.article.title + window?.addEventListener('resize', updateIframeSizes) + + onCleanup(() => window.removeEventListener('resize', updateIframeSizes)) + }) + + const cover = props.article.cover ?? 'production/image/logo_image.png' const ogImage = getOpenGraphImageUrl(cover, { title: props.article.title, topic: mainTopic().title, @@ -328,6 +363,7 @@ export const FullArticle = (props: Props) => {
(articleContainer.current = el)} class={clsx('col-md-16 col-lg-14 col-xl-12 offset-md-5', styles.articleContent)} onClick={handleArticleBodyClick} > diff --git a/src/components/Editor/Editor.tsx b/src/components/Editor/Editor.tsx index 101f9af2..dafaa7f0 100644 --- a/src/components/Editor/Editor.tsx +++ b/src/components/Editor/Editor.tsx @@ -46,6 +46,8 @@ import { Figcaption } from './extensions/Figcaption' import { Figure } from './extensions/Figure' import { Footnote } from './extensions/Footnote' import { Iframe } from './extensions/Iframe' +import { Span } from './extensions/Span' +import { ToggleTextWrap } from './extensions/ToggleTextWrap' import { TrailingNode } from './extensions/TrailingNode' import { TextBubbleMenu } from './TextBubbleMenu' @@ -201,6 +203,8 @@ export const Editor = (props: Props) => { CustomBlockquote, Bold, Italic, + Span, + ToggleTextWrap, Strike, HorizontalRule.configure({ HTMLAttributes: { @@ -208,7 +212,10 @@ export const Editor = (props: Props) => { }, }), Underline, - Link.configure({ + Link.extend({ + inclusive: false, + }).configure({ + autolink: true, openOnClick: false, }), Heading.configure({ @@ -244,6 +251,7 @@ export const Editor = (props: Props) => { Figure, Figcaption, Footnote, + ToggleTextWrap, CharacterCount.configure(), // https://github.com/ueberdosis/tiptap/issues/2589#issuecomment-1093084689 BubbleMenu.configure({ pluginKey: 'textBubbleMenu', @@ -252,6 +260,9 @@ export const Editor = (props: Props) => { const { doc, selection } = state const { empty } = selection const isEmptyTextBlock = doc.textBetween(from, to).length === 0 && isTextSelection(selection) + if (isEmptyTextBlock) { + e.chain().focus().removeTextWrap({ class: 'highlight-fake-selection' }).run() + } setIsCommonMarkup(e.isActive('figcaption')) const result = (view.hasFocus() && diff --git a/src/components/Editor/Prosemirror.scss b/src/components/Editor/Prosemirror.scss index d84e01da..ca78c9f1 100644 --- a/src/components/Editor/Prosemirror.scss +++ b/src/components/Editor/Prosemirror.scss @@ -311,3 +311,10 @@ footnote { background-color: unset; } } + +.highlight-fake-selection { + background: var(--selection-background); + color: var(--selection-color); + border: solid var(--selection-background); + border-width: 5px 0; +} diff --git a/src/components/Editor/SimplifiedEditor.tsx b/src/components/Editor/SimplifiedEditor.tsx index a4aa4d7b..a549781e 100644 --- a/src/components/Editor/SimplifiedEditor.tsx +++ b/src/components/Editor/SimplifiedEditor.tsx @@ -117,7 +117,10 @@ const SimplifiedEditor = (props: Props) => { Paragraph, Bold, Italic, - Link.configure({ + Link.extend({ + inclusive: false, + }).configure({ + autolink: true, openOnClick: false, }), CharacterCount.configure({ diff --git a/src/components/Editor/TextBubbleMenu/TextBubbleMenu.tsx b/src/components/Editor/TextBubbleMenu/TextBubbleMenu.tsx index c7bb2d32..7457b009 100644 --- a/src/components/Editor/TextBubbleMenu/TextBubbleMenu.tsx +++ b/src/components/Editor/TextBubbleMenu/TextBubbleMenu.tsx @@ -129,11 +129,21 @@ export const TextBubbleMenu = (props: BubbleMenuProps) => { }) }) + const handleOpenLinkForm = () => { + props.editor.chain().focus().addTextWrap({ class: 'highlight-fake-selection' }).run() + setLinkEditorOpen(true) + } + + const handleCloseLinkForm = () => { + setLinkEditorOpen(false) + props.editor.chain().focus().removeTextWrap({ class: 'highlight-fake-selection' }).run() + } + return (
- setLinkEditorOpen(false)} /> + {