Skip to content

Commit 9e10fd5

Browse files
GargronClearlyClaire
authored andcommitted
[Glitch] Add ability to view alt text by clicking the ALT badge in web UI
Port a04433f to glitch-soc Signed-off-by: Claire <[email protected]>
1 parent 9b5f073 commit 9e10fd5

File tree

4 files changed

+177
-74
lines changed

4 files changed

+177
-74
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { useState, useCallback, useRef } from 'react';
2+
3+
import { FormattedMessage } from 'react-intl';
4+
5+
import Overlay from 'react-overlays/Overlay';
6+
import type {
7+
OffsetValue,
8+
UsePopperOptions,
9+
} from 'react-overlays/esm/usePopper';
10+
11+
const offset = [0, 4] as OffsetValue;
12+
const popperConfig = { strategy: 'fixed' } as UsePopperOptions;
13+
14+
export const AltTextBadge: React.FC<{
15+
description: string;
16+
}> = ({ description }) => {
17+
const anchorRef = useRef<HTMLButtonElement>(null);
18+
const [open, setOpen] = useState(false);
19+
20+
const handleClick = useCallback(() => {
21+
setOpen((v) => !v);
22+
}, [setOpen]);
23+
24+
const handleClose = useCallback(() => {
25+
setOpen(false);
26+
}, [setOpen]);
27+
28+
return (
29+
<>
30+
<button
31+
ref={anchorRef}
32+
className='media-gallery__alt__label'
33+
onClick={handleClick}
34+
>
35+
ALT
36+
</button>
37+
38+
<Overlay
39+
rootClose
40+
onHide={handleClose}
41+
show={open}
42+
target={anchorRef.current}
43+
placement='top-end'
44+
flip
45+
offset={offset}
46+
popperConfig={popperConfig}
47+
>
48+
{({ props }) => (
49+
<div {...props} className='hover-card-controller'>
50+
<div
51+
className='media-gallery__alt__popover dropdown-animation'
52+
role='tooltip'
53+
>
54+
<h4>
55+
<FormattedMessage
56+
id='alt_text_badge.title'
57+
defaultMessage='Alt text'
58+
/>
59+
</h4>
60+
<p>{description}</p>
61+
</div>
62+
</div>
63+
)}
64+
</Overlay>
65+
</>
66+
);
67+
};

app/javascript/flavours/glitch/components/media_gallery.jsx

+4-3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
1010

1111
import { debounce } from 'lodash';
1212

13+
import { AltTextBadge } from 'flavours/glitch/components/alt_text_badge';
1314
import { Blurhash } from 'flavours/glitch/components/blurhash';
1415
import { formatTime } from 'flavours/glitch/features/video';
1516

@@ -98,7 +99,7 @@ class Item extends PureComponent {
9899
}
99100

100101
if (attachment.get('description')?.length > 0) {
101-
badges.push(<span key='alt' className='media-gallery__alt__label'>ALT</span>);
102+
badges.push(<AltTextBadge key='alt' description={attachment.get('description')} />);
102103
}
103104

104105
const description = attachment.getIn(['translation', 'description']) || attachment.get('description');
@@ -158,9 +159,9 @@ class Item extends PureComponent {
158159
const duration = attachment.getIn(['meta', 'original', 'duration']);
159160

160161
if (attachment.get('type') === 'gifv') {
161-
badges.push(<span key='gif' className='media-gallery__gifv__label'>GIF</span>);
162+
badges.push(<span key='gif' className='media-gallery__alt__label media-gallery__alt__label--non-interactive'>GIF</span>);
162163
} else {
163-
badges.push(<span key='video' className='media-gallery__gifv__label'>{formatTime(Math.floor(duration))}</span>);
164+
badges.push(<span key='video' className='media-gallery__alt__label media-gallery__alt__label--non-interactive'>{formatTime(Math.floor(duration))}</span>);
164165
}
165166

166167
thumbnail = (

app/javascript/flavours/glitch/features/account_gallery/components/media_item.tsx

+10-7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import classNames from 'classnames';
55
import HeadphonesIcon from '@/material-icons/400-24px/headphones-fill.svg?react';
66
import MovieIcon from '@/material-icons/400-24px/movie-fill.svg?react';
77
import VisibilityOffIcon from '@/material-icons/400-24px/visibility_off.svg?react';
8+
import { AltTextBadge } from 'flavours/glitch/components/alt_text_badge';
89
import { Blurhash } from 'flavours/glitch/components/blurhash';
910
import { Icon } from 'flavours/glitch/components/icon';
1011
import { formatTime } from 'flavours/glitch/features/video';
@@ -80,11 +81,7 @@ export const MediaItem: React.FC<{
8081
const badges = [];
8182

8283
if (description && description.length > 0) {
83-
badges.push(
84-
<span key='alt' className='media-gallery__alt__label'>
85-
ALT
86-
</span>,
87-
);
84+
badges.push(<AltTextBadge key='alt' description={description} />);
8885
}
8986

9087
if (!visible) {
@@ -159,13 +156,19 @@ export const MediaItem: React.FC<{
159156

160157
if (type === 'gifv') {
161158
badges.push(
162-
<span key='gif' className='media-gallery__gifv__label'>
159+
<span
160+
key='gif'
161+
className='media-gallery__alt__label media-gallery__alt__label--non-interactive'
162+
>
163163
GIF
164164
</span>,
165165
);
166166
} else {
167167
badges.push(
168-
<span key='video' className='media-gallery__gifv__label'>
168+
<span
169+
key='video'
170+
className='media-gallery__alt__label media-gallery__alt__label--non-interactive'
171+
>
169172
{formatTime(Math.floor(duration))}
170173
</span>,
171174
);

app/javascript/flavours/glitch/styles/components.scss

+96-64
Original file line numberDiff line numberDiff line change
@@ -7475,81 +7475,55 @@ img.modal-warning {
74757475
inset-inline-end: 8px;
74767476
display: flex;
74777477
gap: 2px;
7478-
7479-
&--layout-2 {
7480-
.media-gallery__item:nth-child(1) {
7481-
border-end-end-radius: 0;
7482-
border-start-end-radius: 0;
7483-
}
7484-
7485-
.media-gallery__item:nth-child(2) {
7486-
border-start-start-radius: 0;
7487-
border-end-start-radius: 0;
7488-
}
7489-
}
7490-
7491-
&--layout-3 {
7492-
.media-gallery__item:nth-child(1) {
7493-
border-end-end-radius: 0;
7494-
border-start-end-radius: 0;
7495-
}
7496-
7497-
.media-gallery__item:nth-child(2) {
7498-
border-start-start-radius: 0;
7499-
border-end-start-radius: 0;
7500-
border-end-end-radius: 0;
7501-
}
7502-
7503-
.media-gallery__item:nth-child(3) {
7504-
border-start-start-radius: 0;
7505-
border-end-start-radius: 0;
7506-
border-start-end-radius: 0;
7507-
}
7508-
}
7509-
7510-
&--layout-4 {
7511-
.media-gallery__item:nth-child(1) {
7512-
border-end-end-radius: 0;
7513-
border-start-end-radius: 0;
7514-
border-end-start-radius: 0;
7515-
}
7516-
7517-
.media-gallery__item:nth-child(2) {
7518-
border-start-start-radius: 0;
7519-
border-end-start-radius: 0;
7520-
border-end-end-radius: 0;
7521-
}
7522-
7523-
.media-gallery__item:nth-child(3) {
7524-
border-start-start-radius: 0;
7525-
border-start-end-radius: 0;
7526-
border-end-start-radius: 0;
7527-
border-end-end-radius: 0;
7528-
}
7529-
7530-
.media-gallery__item:nth-child(4) {
7531-
border-start-start-radius: 0;
7532-
border-end-start-radius: 0;
7533-
border-start-end-radius: 0;
7534-
}
7535-
}
75367478
}
75377479

7538-
.media-gallery__alt__label,
7539-
.media-gallery__gifv__label {
7540-
display: flex;
7541-
align-items: center;
7542-
justify-content: center;
7480+
.media-gallery__alt__label {
7481+
display: block;
7482+
text-align: center;
75437483
color: $white;
7484+
border: 0;
75447485
background: rgba($black, 0.65);
75457486
backdrop-filter: blur(10px) saturate(180%) contrast(75%) brightness(70%);
75467487
padding: 3px 8px;
75477488
border-radius: 4px;
75487489
font-size: 12px;
75497490
font-weight: 700;
75507491
z-index: 1;
7551-
pointer-events: none;
75527492
line-height: 20px;
7493+
cursor: pointer;
7494+
pointer-events: auto;
7495+
7496+
&--non-interactive {
7497+
pointer-events: none;
7498+
}
7499+
}
7500+
7501+
.media-gallery__alt__popover {
7502+
background: rgba($black, 0.65);
7503+
backdrop-filter: blur(10px) saturate(180%) contrast(75%) brightness(70%);
7504+
border-radius: 4px;
7505+
box-shadow: var(--dropdown-shadow);
7506+
padding: 16px;
7507+
min-width: 16em;
7508+
min-height: 2em;
7509+
max-width: 22em;
7510+
max-height: 30em;
7511+
overflow-y: auto;
7512+
7513+
h4 {
7514+
font-size: 15px;
7515+
line-height: 20px;
7516+
font-weight: 500;
7517+
color: $white;
7518+
margin-bottom: 8px;
7519+
}
7520+
7521+
p {
7522+
font-size: 15px;
7523+
line-height: 20px;
7524+
color: rgba($white, 0.85);
7525+
white-space: pre-line;
7526+
}
75537527
}
75547528

75557529
.attachment-list {
@@ -7627,6 +7601,64 @@ img.modal-warning {
76277601
grid-template-rows: 1fr 1fr;
76287602
gap: 2px;
76297603

7604+
&--layout-2 {
7605+
.media-gallery__item:nth-child(1) {
7606+
border-end-end-radius: 0;
7607+
border-start-end-radius: 0;
7608+
}
7609+
7610+
.media-gallery__item:nth-child(2) {
7611+
border-start-start-radius: 0;
7612+
border-end-start-radius: 0;
7613+
}
7614+
}
7615+
7616+
&--layout-3 {
7617+
.media-gallery__item:nth-child(1) {
7618+
border-end-end-radius: 0;
7619+
border-start-end-radius: 0;
7620+
}
7621+
7622+
.media-gallery__item:nth-child(2) {
7623+
border-start-start-radius: 0;
7624+
border-end-start-radius: 0;
7625+
border-end-end-radius: 0;
7626+
}
7627+
7628+
.media-gallery__item:nth-child(3) {
7629+
border-start-start-radius: 0;
7630+
border-end-start-radius: 0;
7631+
border-start-end-radius: 0;
7632+
}
7633+
}
7634+
7635+
&--layout-4 {
7636+
.media-gallery__item:nth-child(1) {
7637+
border-end-end-radius: 0;
7638+
border-start-end-radius: 0;
7639+
border-end-start-radius: 0;
7640+
}
7641+
7642+
.media-gallery__item:nth-child(2) {
7643+
border-start-start-radius: 0;
7644+
border-end-start-radius: 0;
7645+
border-end-end-radius: 0;
7646+
}
7647+
7648+
.media-gallery__item:nth-child(3) {
7649+
border-start-start-radius: 0;
7650+
border-start-end-radius: 0;
7651+
border-end-start-radius: 0;
7652+
border-end-end-radius: 0;
7653+
}
7654+
7655+
.media-gallery__item:nth-child(4) {
7656+
border-start-start-radius: 0;
7657+
border-end-start-radius: 0;
7658+
border-start-end-radius: 0;
7659+
}
7660+
}
7661+
76307662
@include fullwidth-gallery;
76317663
}
76327664

0 commit comments

Comments
 (0)