From f2d72ca5a19774e8c88bd67023e32565f7c493d4 Mon Sep 17 00:00:00 2001 From: Tim Fischbach Date: Thu, 10 Apr 2025 12:25:46 +0200 Subject: [PATCH] Add display buttons option for external links - Introduced a new configuration option `displayButtons` for the teaser list, allowing users to toggle the visibility of buttons for opening links. - Extract LinkButton component from hotspots tooltip - Add theme properties to allow styling link buttons in light and dark content REDMINE-20984 --- .../locales/new/ext-link-options.de.yml | 4 ++ .../locales/new/ext-link-options.en.yml | 4 ++ .../externalLinkList/editor/index.js | 3 +- .../externalLinkList/frontend/ExternalLink.js | 28 +++++++---- .../frontend/ExternalLink.module.css | 19 +++++--- .../frontend/ExternalLinkList.js | 2 +- .../externalLinkList/stories.js | 36 ++++++++++++++ .../src/contentElements/hotspots/Tooltip.js | 25 ++++------ .../hotspots/Tooltip.module.css | 35 ++------------ .../package/src/frontend/LinkButton.js | 45 +++++++++++++++++ .../src/frontend/LinkButton.module.css | 48 +++++++++++++++++++ .../scrolled/package/src/frontend/index.js | 2 + 12 files changed, 186 insertions(+), 65 deletions(-) create mode 100644 entry_types/scrolled/package/src/frontend/LinkButton.js create mode 100644 entry_types/scrolled/package/src/frontend/LinkButton.module.css diff --git a/entry_types/scrolled/config/locales/new/ext-link-options.de.yml b/entry_types/scrolled/config/locales/new/ext-link-options.de.yml index 2ffbec8f9d..2bf3de7c60 100644 --- a/entry_types/scrolled/config/locales/new/ext-link-options.de.yml +++ b/entry_types/scrolled/config/locales/new/ext-link-options.de.yml @@ -68,3 +68,7 @@ de: small: Klein medium: Mittel large: Groß + displayButtons: + label: "Buttons anzeigen" + inline_help: |- + Zeige Buttons an, um die Links zu öffnen. diff --git a/entry_types/scrolled/config/locales/new/ext-link-options.en.yml b/entry_types/scrolled/config/locales/new/ext-link-options.en.yml index 91197a2bcf..06ccb6bb67 100644 --- a/entry_types/scrolled/config/locales/new/ext-link-options.en.yml +++ b/entry_types/scrolled/config/locales/new/ext-link-options.en.yml @@ -66,3 +66,7 @@ en: small: Small medium: Medium large: Large + displayButtons: + label: "Display buttons" + inline_help: |- + Display buttons to open the links. diff --git a/entry_types/scrolled/package/src/contentElements/externalLinkList/editor/index.js b/entry_types/scrolled/package/src/contentElements/externalLinkList/editor/index.js index e177b281d0..a7b3b32cb1 100644 --- a/entry_types/scrolled/package/src/contentElements/externalLinkList/editor/index.js +++ b/entry_types/scrolled/package/src/contentElements/externalLinkList/editor/index.js @@ -1,6 +1,6 @@ import {editor} from 'pageflow-scrolled/editor'; import {features} from 'pageflow/frontend'; -import {SelectInputView, SliderInputView, SeparatorView} from 'pageflow/ui'; +import {SelectInputView, SliderInputView, SeparatorView, CheckBoxInputView} from 'pageflow/ui'; import {SidebarRouter} from './SidebarRouter'; import {SidebarController} from './SidebarController'; @@ -81,6 +81,7 @@ editor.contentElementTypes.register('externalLinkList', { this.input('textSize', SelectInputView, { values: ['small', 'medium', 'large'] }); + this.input('displayButtons', CheckBoxInputView); }); } }); diff --git a/entry_types/scrolled/package/src/contentElements/externalLinkList/frontend/ExternalLink.js b/entry_types/scrolled/package/src/contentElements/externalLinkList/frontend/ExternalLink.js index 0a7e886997..2017971891 100644 --- a/entry_types/scrolled/package/src/contentElements/externalLinkList/frontend/ExternalLink.js +++ b/entry_types/scrolled/package/src/contentElements/externalLinkList/frontend/ExternalLink.js @@ -11,7 +11,8 @@ import { useContentElementConfigurationUpdate, useContentElementEditorState, useI18n, - utils + utils, + LinkButton } from 'pageflow-scrolled/frontend'; import {Thumbnail} from './Thumbnail'; @@ -89,21 +90,21 @@ export function ExternalLink({id, configuration, ...props}) { return (
  • -
    + styles[`thumbnailSize-${props.thumbnailSize}`] + )}>
    -
    @@ -134,6 +136,14 @@ export function ExternalLink({id, configuration, ...props}) { placeholder={t('pageflow_scrolled.inline_editing.type_text')} onChange={value => handleTextChange('description', value)} />
    } + {configuration.displayButtons && presentOrEditing('link') && + handleTextChange('link', value)} + onLinkChange={value => handleLinkChange(value)} />}
    @@ -142,8 +152,8 @@ export function ExternalLink({id, configuration, ...props}) { ); } -function Link(props) { - if (props.href || props.isEditable) { +function Link({isEnabled, isEditable, ...props}) { + if ((isEnabled && props.href) || isEditable) { return ( .background { - --card-surface-color: var(--theme-external-links-card-surface-color, darkContentSurfaceColor); - --content-text-color: var(--theme-external-links-card-text-color, lightContentTextColor); -} - .textPosition-overlay .background { position: absolute; bottom: 0; diff --git a/entry_types/scrolled/package/src/contentElements/externalLinkList/frontend/ExternalLinkList.js b/entry_types/scrolled/package/src/contentElements/externalLinkList/frontend/ExternalLinkList.js index fb1e461a7d..a41377e89b 100644 --- a/entry_types/scrolled/package/src/contentElements/externalLinkList/frontend/ExternalLinkList.js +++ b/entry_types/scrolled/package/src/contentElements/externalLinkList/frontend/ExternalLinkList.js @@ -98,7 +98,7 @@ export function ExternalLinkList(props) { thumbnailSize={props.configuration.thumbnailSize || 'small'} textPosition={props.configuration.textPosition || 'below'} textSize={props.configuration.textSize || 'small'} - invert={!darkBackground} + darkBackground={darkBackground} loadImages={shouldLoad} outlined={isSelected} highlighted={highlightedIndex === index} diff --git a/entry_types/scrolled/package/src/contentElements/externalLinkList/stories.js b/entry_types/scrolled/package/src/contentElements/externalLinkList/stories.js index 635fff323c..62e1a3d891 100644 --- a/entry_types/scrolled/package/src/contentElements/externalLinkList/stories.js +++ b/entry_types/scrolled/package/src/contentElements/externalLinkList/stories.js @@ -160,6 +160,42 @@ storiesOfContentElement(module, { ] }, }, + { + name: 'With buttons', + configuration: { + displayButtons: true, + itemTexts: { + 1: { + title: editableTextValue('Item 1'), + description: editableTextValue('This is description'), + link: editableTextValue('Read more') + }, + 2: { + title: editableTextValue('Item 2'), + description: editableTextValue('This is another description'), + link: editableTextValue('Read more') + } + }, + itemLinks: { + 1: { + href: 'https://www.pageflow.io/' + }, + 2: { + href: 'https://www.pageflow.io/' + } + }, + links: [ + { + id: '1', + thumbnail: filePermaId('imageFiles', 'turtle') + }, + { + id: '2', + thumbnail: filePermaId('imageFiles', 'turtle') + } + ] + } + }, { name: 'With legacy external links', configuration: { diff --git a/entry_types/scrolled/package/src/contentElements/hotspots/Tooltip.js b/entry_types/scrolled/package/src/contentElements/hotspots/Tooltip.js index 0669a0b00b..df7ca38086 100644 --- a/entry_types/scrolled/package/src/contentElements/hotspots/Tooltip.js +++ b/entry_types/scrolled/package/src/contentElements/hotspots/Tooltip.js @@ -25,7 +25,8 @@ import { useDarkBackground, useFileWithInlineRights, useI18n, - utils + utils, + LinkButton } from 'pageflow-scrolled/frontend'; import {getTooltipInlineStyles} from './getTooltipInlineStyles'; @@ -177,8 +178,7 @@ export function Tooltip({ styles[`maxWidth-${maxWidth}`], styles[`align-${area.tooltipTextAlign}`], light ? styles.light : styles.dark, - {[styles.editable]: isEditable, - [styles.paddingForScrollButtons]: keepInViewport, + {[styles.paddingForScrollButtons]: keepInViewport, [styles.minWidth]: presentOrEditing('link')})} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave} @@ -214,18 +214,13 @@ export function Tooltip({ scaleCategory="hotspotsTooltipDescription" placeholder={t('pageflow_scrolled.inline_editing.type_text')} />} {presentOrEditing('link') && - - handleLinkChange(value)}> - handleTextChange('link', value)} - placeholder={t('pageflow_scrolled.inline_editing.type_text')} /> - › - - } + handleTextChange('link', value)} + onLinkChange={value => handleLinkChange(value)} />} diff --git a/entry_types/scrolled/package/src/contentElements/hotspots/Tooltip.module.css b/entry_types/scrolled/package/src/contentElements/hotspots/Tooltip.module.css index 955b4e6c66..334695b74f 100644 --- a/entry_types/scrolled/package/src/contentElements/hotspots/Tooltip.module.css +++ b/entry_types/scrolled/package/src/contentElements/hotspots/Tooltip.module.css @@ -47,14 +47,17 @@ } .light { + composes: scope-darkContent from global; background-color: lightContentSurfaceColor; color: darkContentTextColor; --content-text-color: darkContentTextColor; --content-link-color: darkContentLinkColor; box-shadow: 0px 3px 3px -2px rgba(0,0,0,0.2), 0px 3px 4px 0px rgba(0,0,0,0.14), 0px 1px 8px 0px rgba(0,0,0,0.12); + --theme-link-button-on-surface-color: var(--theme-widget-primary-color); } .dark { + composes: scope-lightContent from global; background-color: darkContentSurfaceColor; color: lightContentTextColor; --content-text-color: lightContentTextColor; @@ -122,42 +125,10 @@ margin-bottom: 0; } -.link { - display: flex; - justify-content: center; - gap: 0.5em; - border-radius: 5px; - text-decoration: none; - padding: 0.5rem; - background-color: transparent; - color: inherit; - margin-top: 1rem; - font-weight: bold; - border: solid 1px color-mix(in srgb, currentColor, transparent); -} - .textWrapper > :first-child .link { margin-top: 0; } -.link:hover, -.link:active { - border: solid 1px currentColor; -} - -.light .link { - color: var(--theme-widget-primary-color); -} - .box > :first-child .link { margin-top: 0; } - -.editable .link { - opacity: 0.5; -} - -.editable .link:has([data-slate-string]), -.editable .link:focus-within { - opacity: 1; -} diff --git a/entry_types/scrolled/package/src/frontend/LinkButton.js b/entry_types/scrolled/package/src/frontend/LinkButton.js new file mode 100644 index 0000000000..eb44d02a0b --- /dev/null +++ b/entry_types/scrolled/package/src/frontend/LinkButton.js @@ -0,0 +1,45 @@ +import React from 'react'; +import classNames from 'classnames'; +import styles from './LinkButton.module.css'; +import {EditableLink} from './EditableLink'; +import {EditableInlineText} from './EditableInlineText'; +import {Text} from './Text'; +import {utils} from './utils'; +import {useI18n} from './i18n'; +import {useContentElementEditorState} from './useContentElementEditorState'; + +export function LinkButton({ + href, + openInNewTab, + value, + onTextChange, + onLinkChange, + scaleCategory, + className, + actionButtonVisible, + linkPreviewPosition, + linkPreviewDisabled, + children, + ...props +}) { + const {t} = useI18n({locale: 'ui'}); + const {isEditable} = useContentElementEditorState(); + + return ( + + + + {children} + + + ); +} diff --git a/entry_types/scrolled/package/src/frontend/LinkButton.module.css b/entry_types/scrolled/package/src/frontend/LinkButton.module.css new file mode 100644 index 0000000000..9cd999f00d --- /dev/null +++ b/entry_types/scrolled/package/src/frontend/LinkButton.module.css @@ -0,0 +1,48 @@ +:global .scope-lightContent { + --link-button-on-surface-color: var(--theme-light-content-link-button-on-surface-color, + currentColor); + --link-button-surface-color: var(--theme-light-content-link-button-surface-color); +} + +:global .scope-darkContent { + --link-button-on-surface-color: var(--theme-dark-content-link-button-on-surface-color, + var(--theme-widget-primary-color)); + --link-button-surface-color: var(--theme-dark-content-link-button-surface-color); +} + +.button { + display: flex; + width: var(--theme-link-button-width); + justify-content: center; + gap: 0.5em; + border-radius: var(--theme-link-button-border-radius, 5px); + text-decoration: none; + padding: var(--theme-link-button-padding, 0.5rem); + background-color: var(--link-button-surface-color, transparent); + color: var(--link-button-on-surface-color); + margin-top: 1rem; + font-weight: bold; + border: solid 1px var(--link-button-surface-color, + color-mix(in srgb, + var(--link-button-on-surface-color), + transparent)); + cursor: pointer; +} + +.button::after { + content: var(--theme-link-button-symbol, "›"); +} + +.button:hover, +.button:active { + border: solid 1px var(--link-button-surface-color, var(--link-button-on-surface-color)); +} + +.editable { + opacity: 0.5; +} + +.editable:has([data-slate-string]), +.editable:focus-within { + opacity: 1; +} diff --git a/entry_types/scrolled/package/src/frontend/index.js b/entry_types/scrolled/package/src/frontend/index.js index 72ff4356aa..d9b768a372 100644 --- a/entry_types/scrolled/package/src/frontend/index.js +++ b/entry_types/scrolled/package/src/frontend/index.js @@ -131,6 +131,8 @@ export { widthName as contentElementWidthName } from './layouts'; +export {LinkButton} from './LinkButton'; + global.pageflowScrolledRender = async function(seed) { setupI18n(seed.i18n);