More cleanup

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak 2024-04-29 18:29:02 +02:00
parent b338662227
commit 665895f8fe
11 changed files with 98 additions and 215 deletions

View file

@ -577,7 +577,7 @@ const MediaGallery: React.FC<IMediaGallery> = (props) => {
return (
<div
className={clsx(className, 'media-gallery', { 'media-gallery--compact': compact })}
className={clsx(className, 'media-gallery', { 'media-gallery--compact !h-12 bg-transparent': compact })}
style={sizeData.style}
ref={node}
>

View file

@ -141,7 +141,7 @@ const Upload: React.FC<IUpload> = ({
const description = dirtyDescription || (dirtyDescription !== '' && media.description) || '';
const focusX = media.meta.getIn(['focus', 'x']) as number | undefined;
const focusY = media.meta.getIn(['focus', 'y']) as number | undefined;
const x = focusX ? ((focusX / 2) + .5) * 100 : undefined;
const x = focusX ? ((focusX / 2) + .5) * 100 : undefined;
const y = focusY ? ((focusY / -2) + .5) * 100 : undefined;
const mediaType = media.type;
const mimeType = media.pleroma.get('mime_type') as string | undefined;
@ -155,7 +155,7 @@ const Upload: React.FC<IUpload> = ({
return (
<div
className='compose-form__upload'
className='relative m-[5px] min-w-[40%] flex-1 overflow-hidden rounded'
tabIndex={0}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
@ -170,11 +170,12 @@ const Upload: React.FC<IUpload> = ({
<Motion defaultStyle={{ scale: 0.8 }} style={{ scale: spring(1, { stiffness: 180, damping: 12 }) }}>
{({ scale }) => (
<div
className={clsx('compose-form__upload-thumbnail', mediaType)}
className={clsx('compose-form__upload-thumbnail relative h-40 w-full overflow-hidden bg-contain bg-center bg-no-repeat', mediaType)}
style={{
transform: `scale(${scale})`,
backgroundImage: mediaType === 'image' ? `url(${media.preview_url})` : undefined,
backgroundPosition: typeof x === 'number' && typeof y === 'number' ? `${x}% ${y}%` : undefined }}
backgroundPosition: typeof x === 'number' && typeof y === 'number' ? `${x}% ${y}%` : undefined,
}}
>
<HStack className='absolute right-2 top-2 z-10' space={2}>
{(withPreview && mediaType !== 'unknown' && Boolean(media.url)) && (
@ -200,11 +201,16 @@ const Upload: React.FC<IUpload> = ({
</HStack>
{onDescriptionChange && (
<div className={clsx('compose-form__upload-description', { active })}>
<div
className={clsx('absolute inset-x-0 bottom-0 z-[2px] bg-gradient-to-b from-transparent via-gray-900/50 to-gray-900/80 p-2.5 opacity-0 transition-opacity duration-100 ease-linear', {
'opacity-100': active,
})}
>
<label>
<span style={{ display: 'none' }}>{intl.formatMessage(messages.description)}</span>
<textarea
className='m-0 w-full rounded-md border border-solid border-white/25 bg-transparent p-2.5 text-sm text-white placeholder:text-white/60'
placeholder={intl.formatMessage(messages.description)}
value={description}
maxLength={descriptionLimit}
@ -230,9 +236,9 @@ const Upload: React.FC<IUpload> = ({
</span>
)}
<div className='compose-form__upload-preview'>
<div className='absolute inset-0 -z-[1] h-full w-full'>
{mediaType === 'video' && (
<video autoPlay playsInline muted loop>
<video className='h-full w-full object-cover' autoPlay playsInline muted loop>
<source src={media.preview_url} />
</video>
)}

View file

@ -119,7 +119,7 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
// List of elements that shouldn't collapse the composer when clicked
// FIXME: Make this less brittle
getClickableArea(),
document.querySelector('.privacy-dropdown__dropdown'),
document.getElementById('privacy-dropdown'),
document.querySelector('em-emoji-picker'),
document.getElementById('modal-overlay'),
].some(element => element?.contains(e.target as any));
@ -209,7 +209,7 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
), [features, id]);
const composeModifiers = !condensed && (
<Stack space={4} className='compose-form__modifiers'>
<Stack space={4} className='font-[inherit] text-sm text-gray-900'>
<UploadForm composeId={id} onSubmit={handleSubmit} />
<PollForm composeId={id} />
@ -253,7 +253,7 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
id='compose_form.scheduled_statuses.message'
defaultMessage='You have scheduled posts. {click_here} to see them.'
values={{ click_here: (
<Link to='/scheduled_statuses'>
<Link className='underline' to='/scheduled_statuses'>
<FormattedMessage
id='compose_form.scheduled_statuses.click_here'
defaultMessage='Click here'

View file

@ -114,25 +114,56 @@ const PrivacyDropdownMenu: React.FC<IPrivacyDropdownMenu> = ({ style, items, pla
};
}, []);
return (
<Motion defaultStyle={{ opacity: 0, scaleX: 0.85, scaleY: 0.75 }} style={{ opacity: spring(1, { damping: 35, stiffness: 400 }), scaleX: spring(1, { damping: 35, stiffness: 400 }), scaleY: spring(1, { damping: 35, stiffness: 400 }) }}>
{({ opacity, scaleX, scaleY }) => (
// It should not be transformed when mounting because the resulting
// size will be used to determine the coordinate of the menu by
// react-overlays
<div className={clsx('privacy-dropdown__dropdown', placement)} style={{ ...style, opacity: opacity, transform: mounted ? `scale(${scaleX}, ${scaleY})` : undefined }} role='listbox' ref={node}>
{items.map(item => (
<div role='option' tabIndex={0} key={item.value} data-index={item.value} onKeyDown={handleKeyDown} onClick={handleClick} className={clsx('privacy-dropdown__option', { active: item.value === value })} aria-selected={item.value === value} ref={item.value === value ? focusedItem : null}>
<div className='privacy-dropdown__option__icon'>
<Icon src={item.icon} />
</div>
<div
id='privacy-dropdown'
className={clsx('absolute z-[1000] ml-10 overflow-hidden rounded-md bg-white text-sm shadow-lg black:border black:border-gray-800 black:bg-black dark:bg-gray-900', {
'block shadow-md': open,
'origin-[50%_100%]': placement === 'top',
'origin-[50%_0]': placement === 'bottom',
})}
style={{ ...style, opacity: opacity, transform: mounted ? `scale(${scaleX}, ${scaleY})` : undefined }}
role='listbox'
ref={node}
>
{items.map(item => {
const active = item.value === value;
return (
<div
role='option'
tabIndex={0}
key={item.value}
data-index={item.value}
onKeyDown={handleKeyDown}
onClick={handleClick}
className={clsx(
'flex cursor-pointer p-2.5 text-sm text-gray-700 hover:bg-gray-100 black:hover:bg-gray-900 dark:text-gray-400 dark:hover:bg-gray-800',
{ 'bg-gray-100 dark:bg-gray-800 black:bg-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700': active },
)}
aria-selected={active}
ref={active ? focusedItem : null}
>
<div className='mr-2.5 flex items-center justify-center rtl:ml-2.5 rtl:mr-0'>
<Icon src={item.icon} />
</div>
<div className='privacy-dropdown__option__content'>
<strong>{item.text}</strong>
{item.meta}
<div
className={clsx('flex-auto text-primary-600 dark:text-primary-400', {
'text-black dark:text-white': active,
})}
>
<strong className='block font-medium text-black dark:text-white'>{item.text}</strong>
{item.meta}
</div>
</div>
</div>
))}
);
})}
</div>
)}
</Motion>
@ -239,8 +270,13 @@ const PrivacyDropdown: React.FC<IPrivacyDropdown> = ({
const valueOption = options.find(item => item.value === value);
return (
<div className={clsx('privacy-dropdown', placement, { active: open })} onKeyDown={handleKeyDown} ref={node}>
<div className={clsx('privacy-dropdown__value', { active: valueOption && options.indexOf(valueOption) === 0 })}>
<div onKeyDown={handleKeyDown} ref={node}>
<div
className={clsx({
'rounded-t-md': open && placement === 'top',
active: valueOption && options.indexOf(valueOption) === 0,
})}
>
<IconButton
className={clsx({
'text-gray-600 hover:text-gray-700 dark:hover:text-gray-500': !open,

View file

@ -11,7 +11,7 @@ interface IWarning {
const Warning: React.FC<IWarning> = ({ message }) => (
<Motion defaultStyle={{ opacity: 0, scaleX: 0.85, scaleY: 0.75 }} style={{ opacity: spring(1, { damping: 35, stiffness: 400 }), scaleX: spring(1, { damping: 35, stiffness: 400 }), scaleY: spring(1, { damping: 35, stiffness: 400 }) }}>
{({ opacity, scaleX, scaleY }) => (
<div className='compose-form__warning' style={{ opacity: opacity, transform: `scale(${scaleX}, ${scaleY})` }}>
<div className='mb-2.5 rounded bg-accent-300 px-2.5 py-2 text-xs text-white shadow-md' style={{ opacity: opacity, transform: `scale(${scaleX}, ${scaleY})` }}>
{message}
</div>
)}

View file

@ -29,7 +29,7 @@ const WarningWrapper: React.FC<IWarningWrapper> = ({ composeId }) => {
defaultMessage='Your account is not {locked}. Anyone can follow you to view your follower-only posts.'
values={{
locked: (
<Link to='/settings/profile'>
<Link className='underline' to='/settings/profile'>
<FormattedMessage id='compose_form.lock_disclaimer.lock' defaultMessage='locked' />
</Link>
),

View file

@ -3,7 +3,7 @@ import React, { Suspense } from 'react';
import { toggleStatusReport } from 'soapbox/actions/reports';
import StatusContent from 'soapbox/components/status-content';
import { Toggle } from 'soapbox/components/ui';
import { Stack, Toggle } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import { MediaGallery, Video, Audio } from '../../ui/util/async-components';
@ -64,19 +64,21 @@ const StatusCheckBox: React.FC<IStatusCheckBox> = ({ id, disabled }) => {
sensitive={status.sensitive}
height={110}
onOpenMedia={noop}
visible
/>
);
}
}
return (
<div className='status-check-box'>
<div className='status-check-box__status'>
<div className='flex items-center justify-between'>
<Stack className='status-check-box__status py-2' space={1}>
<StatusContent status={status} />
<Suspense>{media}</Suspense>
</div>
<div className='status-check-box-toggle'>
</Stack>
<div className='flex items-center justify-center p-2.5'>
<Toggle checked={checked} onChange={onToggle} disabled={disabled} />
</div>
</div>

View file

@ -463,7 +463,7 @@ const Video: React.FC<IVideo> = ({
return (
<div
role='menuitem'
className={clsx('video-player relative box-border max-w-full overflow-hidden rounded-[10px] bg-black text-white [direction:ltr] focus:outline-0', { 'h-full w-full m-0': fullscreen })}
className={clsx('video-player relative box-border max-h-screen max-w-full overflow-hidden rounded-[10px] bg-black text-white [direction:ltr] focus:outline-0', { 'h-full w-full m-0': fullscreen })}
style={playerStyle}
ref={player}
onMouseEnter={handleMouseEnter}

View file

@ -1,159 +1,11 @@
// Language codes that uses CJK fonts
/* stylelint-disable-next-line value-keyword-case -- locale filenames */
$cjk-langs: ja, ko, zh-CN, zh-HK, zh-TW;
.compose-form {
&__warning {
@apply text-xs mb-2.5 px-2.5 py-2 shadow-md rounded bg-accent-300 text-white;
strong {
@apply font-medium;
@each $lang in $cjk-langs {
&:lang(#{$lang}) {
@apply font-bold;
}
}
}
a {
font-weight: 500;
text-decoration: underline;
&:hover,
&:active,
&:focus {
text-decoration: none;
}
}
.compose-form__upload-thumbnail {
&.video {
@apply bg-cover;
background-image: url('../assets/images/video-placeholder.png');
}
&__modifiers {
@apply text-gray-900 text-sm;
font-family: inherit;
}
&__upload {
flex: 1 1 0;
min-width: 40%;
margin: 5px;
position: relative;
border-radius: 4px;
overflow: hidden;
&-description {
@apply bg-gradient-to-b from-transparent via-gray-900/50 to-gray-900/80 absolute z-[2px] bottom-0 left-0 right-0 p-2.5 opacity-0 transition-opacity duration-100 ease-linear;
&.active {
@apply opacity-100;
}
textarea {
@apply bg-transparent text-white border-solid border border-white/25 p-2.5 rounded-md text-sm w-full m-0;
&::placeholder {
@apply text-white/60;
}
}
}
&-preview {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: -1;
video {
width: 100%;
height: 100%;
object-fit: cover;
}
}
&-thumbnail {
background-position: center;
background-size: contain;
background-repeat: no-repeat;
height: 160px;
width: 100%;
overflow: hidden;
position: relative;
&.video {
background-image: url('../assets/images/video-placeholder.png');
background-size: cover;
}
&.audio {
background-image: url('../assets/images/audio-placeholder.png');
background-size: cover;
}
}
}
}
.privacy-dropdown {
&.active {
&.top .privacy-dropdown__value {
@apply rounded-t-md;
}
.privacy-dropdown__dropdown {
@apply block shadow-md;
}
}
&__dropdown {
@apply absolute bg-white dark:bg-gray-900 z-[1000] rounded-md shadow-lg ml-10 text-sm overflow-hidden black:bg-black black:border black:border-gray-800;
&.top {
transform-origin: 50% 100%;
}
&.bottom {
transform-origin: 50% 0;
}
}
&__option {
@apply flex p-2.5 text-sm text-gray-700 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 cursor-pointer black:hover:bg-gray-900;
&.active {
@apply bg-gray-100 dark:bg-gray-800 black:bg-gray-900;
}
&:hover,
&.active {
.privacy-dropdown__option__content,
.privacy-dropdown__option__content strong {
@apply text-black dark:text-white;
}
}
&.active {
@apply hover:bg-gray-200 dark:hover:bg-gray-700;
}
&__icon {
@apply flex items-center justify-center mr-2.5 rtl:mr-0 rtl:ml-2.5;
}
&__content {
@apply flex-auto text-primary-600 dark:text-primary-400;
strong {
@apply block font-medium text-black dark:text-white;
@each $lang in $cjk-langs {
&:lang(#{$lang}) {
@apply font-bold;
}
}
}
}
&.audio {
@apply bg-cover;
background-image: url('../assets/images/audio-placeholder.png');
}
}

View file

@ -60,8 +60,6 @@
}
&--compact {
@apply bg-transparent h-12;
.media-gallery__item {
@apply h-12 w-12 inset-auto float-left mr-[5px] #{!important};

View file

@ -13,34 +13,23 @@
@apply bg-transparent dark:bg-transparent rounded-none shadow-none;
}
.status-check-box {
@apply flex items-center justify-between;
.status-check-box__status {
@apply py-2;
.media-gallery {
@apply max-w-[250px];
}
.status__content {
@apply p-0 text-gray-700 dark:text-gray-500 text-sm whitespace-normal;
}
.video-player,
.audio-player {
@apply mt-2 max-w-[250px];
}
.media-gallery__item-thumbnail {
@apply cursor-default;
}
.status-check-box__status {
.media-gallery {
@apply max-w-[250px];
}
}
.status-check-box-toggle {
@apply items-center flex justify-center p-2.5;
flex: 0 0 auto;
.status__content {
@apply p-0 text-gray-700 dark:text-gray-500 text-sm whitespace-normal;
}
.video-player,
.audio-player {
@apply mt-2 max-w-[250px];
}
.media-gallery__item-thumbnail {
@apply cursor-default;
}
}
.focusable:focus,