From 9e10fd59b73eb98ab35eed8a27679cb5e6d6fac0 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 26 Sep 2024 15:26:49 +0200 Subject: [PATCH] [Glitch] Add ability to view alt text by clicking the ALT badge in web UI Port a04433f995099854c06fbc7d02245a7d2a3677c0 to glitch-soc Signed-off-by: Claire --- .../glitch/components/alt_text_badge.tsx | 67 ++++++++ .../glitch/components/media_gallery.jsx | 7 +- .../account_gallery/components/media_item.tsx | 17 +- .../flavours/glitch/styles/components.scss | 160 +++++++++++------- 4 files changed, 177 insertions(+), 74 deletions(-) create mode 100644 app/javascript/flavours/glitch/components/alt_text_badge.tsx diff --git a/app/javascript/flavours/glitch/components/alt_text_badge.tsx b/app/javascript/flavours/glitch/components/alt_text_badge.tsx new file mode 100644 index 0000000000..99bec1ee51 --- /dev/null +++ b/app/javascript/flavours/glitch/components/alt_text_badge.tsx @@ -0,0 +1,67 @@ +import { useState, useCallback, useRef } from 'react'; + +import { FormattedMessage } from 'react-intl'; + +import Overlay from 'react-overlays/Overlay'; +import type { + OffsetValue, + UsePopperOptions, +} from 'react-overlays/esm/usePopper'; + +const offset = [0, 4] as OffsetValue; +const popperConfig = { strategy: 'fixed' } as UsePopperOptions; + +export const AltTextBadge: React.FC<{ + description: string; +}> = ({ description }) => { + const anchorRef = useRef(null); + const [open, setOpen] = useState(false); + + const handleClick = useCallback(() => { + setOpen((v) => !v); + }, [setOpen]); + + const handleClose = useCallback(() => { + setOpen(false); + }, [setOpen]); + + return ( + <> + + + + {({ props }) => ( +
+
+

+ +

+

{description}

+
+
+ )} +
+ + ); +}; diff --git a/app/javascript/flavours/glitch/components/media_gallery.jsx b/app/javascript/flavours/glitch/components/media_gallery.jsx index 1e40a26777..4d51bdcdc2 100644 --- a/app/javascript/flavours/glitch/components/media_gallery.jsx +++ b/app/javascript/flavours/glitch/components/media_gallery.jsx @@ -10,6 +10,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import { debounce } from 'lodash'; +import { AltTextBadge } from 'flavours/glitch/components/alt_text_badge'; import { Blurhash } from 'flavours/glitch/components/blurhash'; import { formatTime } from 'flavours/glitch/features/video'; @@ -98,7 +99,7 @@ class Item extends PureComponent { } if (attachment.get('description')?.length > 0) { - badges.push(ALT); + badges.push(); } const description = attachment.getIn(['translation', 'description']) || attachment.get('description'); @@ -158,9 +159,9 @@ class Item extends PureComponent { const duration = attachment.getIn(['meta', 'original', 'duration']); if (attachment.get('type') === 'gifv') { - badges.push(GIF); + badges.push(GIF); } else { - badges.push({formatTime(Math.floor(duration))}); + badges.push({formatTime(Math.floor(duration))}); } thumbnail = ( diff --git a/app/javascript/flavours/glitch/features/account_gallery/components/media_item.tsx b/app/javascript/flavours/glitch/features/account_gallery/components/media_item.tsx index 6279d3c881..e7983c503c 100644 --- a/app/javascript/flavours/glitch/features/account_gallery/components/media_item.tsx +++ b/app/javascript/flavours/glitch/features/account_gallery/components/media_item.tsx @@ -5,6 +5,7 @@ import classNames from 'classnames'; import HeadphonesIcon from '@/material-icons/400-24px/headphones-fill.svg?react'; import MovieIcon from '@/material-icons/400-24px/movie-fill.svg?react'; import VisibilityOffIcon from '@/material-icons/400-24px/visibility_off.svg?react'; +import { AltTextBadge } from 'flavours/glitch/components/alt_text_badge'; import { Blurhash } from 'flavours/glitch/components/blurhash'; import { Icon } from 'flavours/glitch/components/icon'; import { formatTime } from 'flavours/glitch/features/video'; @@ -80,11 +81,7 @@ export const MediaItem: React.FC<{ const badges = []; if (description && description.length > 0) { - badges.push( - - ALT - , - ); + badges.push(); } if (!visible) { @@ -159,13 +156,19 @@ export const MediaItem: React.FC<{ if (type === 'gifv') { badges.push( - + GIF , ); } else { badges.push( - + {formatTime(Math.floor(duration))} , ); diff --git a/app/javascript/flavours/glitch/styles/components.scss b/app/javascript/flavours/glitch/styles/components.scss index 22505202a2..211edcc9be 100644 --- a/app/javascript/flavours/glitch/styles/components.scss +++ b/app/javascript/flavours/glitch/styles/components.scss @@ -7475,72 +7475,13 @@ img.modal-warning { inset-inline-end: 8px; display: flex; gap: 2px; - - &--layout-2 { - .media-gallery__item:nth-child(1) { - border-end-end-radius: 0; - border-start-end-radius: 0; - } - - .media-gallery__item:nth-child(2) { - border-start-start-radius: 0; - border-end-start-radius: 0; - } - } - - &--layout-3 { - .media-gallery__item:nth-child(1) { - border-end-end-radius: 0; - border-start-end-radius: 0; - } - - .media-gallery__item:nth-child(2) { - border-start-start-radius: 0; - border-end-start-radius: 0; - border-end-end-radius: 0; - } - - .media-gallery__item:nth-child(3) { - border-start-start-radius: 0; - border-end-start-radius: 0; - border-start-end-radius: 0; - } - } - - &--layout-4 { - .media-gallery__item:nth-child(1) { - border-end-end-radius: 0; - border-start-end-radius: 0; - border-end-start-radius: 0; - } - - .media-gallery__item:nth-child(2) { - border-start-start-radius: 0; - border-end-start-radius: 0; - border-end-end-radius: 0; - } - - .media-gallery__item:nth-child(3) { - border-start-start-radius: 0; - border-start-end-radius: 0; - border-end-start-radius: 0; - border-end-end-radius: 0; - } - - .media-gallery__item:nth-child(4) { - border-start-start-radius: 0; - border-end-start-radius: 0; - border-start-end-radius: 0; - } - } } -.media-gallery__alt__label, -.media-gallery__gifv__label { - display: flex; - align-items: center; - justify-content: center; +.media-gallery__alt__label { + display: block; + text-align: center; color: $white; + border: 0; background: rgba($black, 0.65); backdrop-filter: blur(10px) saturate(180%) contrast(75%) brightness(70%); padding: 3px 8px; @@ -7548,8 +7489,41 @@ img.modal-warning { font-size: 12px; font-weight: 700; z-index: 1; - pointer-events: none; line-height: 20px; + cursor: pointer; + pointer-events: auto; + + &--non-interactive { + pointer-events: none; + } +} + +.media-gallery__alt__popover { + background: rgba($black, 0.65); + backdrop-filter: blur(10px) saturate(180%) contrast(75%) brightness(70%); + border-radius: 4px; + box-shadow: var(--dropdown-shadow); + padding: 16px; + min-width: 16em; + min-height: 2em; + max-width: 22em; + max-height: 30em; + overflow-y: auto; + + h4 { + font-size: 15px; + line-height: 20px; + font-weight: 500; + color: $white; + margin-bottom: 8px; + } + + p { + font-size: 15px; + line-height: 20px; + color: rgba($white, 0.85); + white-space: pre-line; + } } .attachment-list { @@ -7627,6 +7601,64 @@ img.modal-warning { grid-template-rows: 1fr 1fr; gap: 2px; + &--layout-2 { + .media-gallery__item:nth-child(1) { + border-end-end-radius: 0; + border-start-end-radius: 0; + } + + .media-gallery__item:nth-child(2) { + border-start-start-radius: 0; + border-end-start-radius: 0; + } + } + + &--layout-3 { + .media-gallery__item:nth-child(1) { + border-end-end-radius: 0; + border-start-end-radius: 0; + } + + .media-gallery__item:nth-child(2) { + border-start-start-radius: 0; + border-end-start-radius: 0; + border-end-end-radius: 0; + } + + .media-gallery__item:nth-child(3) { + border-start-start-radius: 0; + border-end-start-radius: 0; + border-start-end-radius: 0; + } + } + + &--layout-4 { + .media-gallery__item:nth-child(1) { + border-end-end-radius: 0; + border-start-end-radius: 0; + border-end-start-radius: 0; + } + + .media-gallery__item:nth-child(2) { + border-start-start-radius: 0; + border-end-start-radius: 0; + border-end-end-radius: 0; + } + + .media-gallery__item:nth-child(3) { + border-start-start-radius: 0; + border-start-end-radius: 0; + border-end-start-radius: 0; + border-end-end-radius: 0; + } + + .media-gallery__item:nth-child(4) { + border-start-start-radius: 0; + border-end-start-radius: 0; + border-start-end-radius: 0; + } + } + @include fullwidth-gallery; }