More cleanup
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
b338662227
commit
665895f8fe
11 changed files with 98 additions and 215 deletions
|
@ -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}
|
||||
>
|
||||
|
|
|
@ -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>
|
||||
)}
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
)}
|
||||
|
|
|
@ -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>
|
||||
),
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue