Merge remote-tracking branch 'origin/develop' into public-layout-improvements
This commit is contained in:
commit
75c4582ce6
37 changed files with 178 additions and 186 deletions
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 0 0-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 0 0-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 0 0-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 0 0-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 0 0 1.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0z"/></svg>
|
Before Width: | Height: | Size: 781 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m3 8 7.89 5.26a2 2 0 0 0 2.22 0L21 8M5 19h14a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2z"/></svg>
|
Before Width: | Height: | Size: 284 B |
|
@ -12,7 +12,7 @@
|
|||
<%= snippets %>
|
||||
</head>
|
||||
<body class="theme-mode-light no-reduce-motion">
|
||||
<div id="soapbox">
|
||||
<div id="soapbox" class="h-full">
|
||||
<div class="loading-indicator-wrapper">
|
||||
<div class="loading-indicator">
|
||||
<div class="loading-indicator__container">
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import { fromJS } from 'immutable';
|
||||
import React from 'react';
|
||||
|
||||
import { normalizeAccount } from 'soapbox/normalizers';
|
||||
|
||||
import { render, screen } from '../../jest/test-helpers';
|
||||
import Avatar from '../avatar';
|
||||
|
||||
describe('<Avatar />', () => {
|
||||
const account = fromJS({
|
||||
const account = normalizeAccount({
|
||||
username: 'alice',
|
||||
acct: 'alice',
|
||||
display_name: 'Alice',
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
import classNames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
|
||||
import StillImage from 'soapbox/components/still_image';
|
||||
|
||||
export default class Avatar extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
account: ImmutablePropTypes.record,
|
||||
size: PropTypes.number,
|
||||
style: PropTypes.object,
|
||||
className: PropTypes.string,
|
||||
};
|
||||
|
||||
render() {
|
||||
const { account, size, className } = this.props;
|
||||
if (!account) return null;
|
||||
|
||||
// : TODO : remove inline and change all avatars to be sized using css
|
||||
const style = !size ? {} : {
|
||||
width: `${size}px`,
|
||||
height: `${size}px`,
|
||||
};
|
||||
|
||||
return (
|
||||
<StillImage
|
||||
className={classNames('rounded-full', {
|
||||
[className]: typeof className !== 'undefined',
|
||||
})}
|
||||
style={style}
|
||||
src={account.get('avatar')}
|
||||
alt=''
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
38
app/soapbox/components/avatar.tsx
Normal file
38
app/soapbox/components/avatar.tsx
Normal file
|
@ -0,0 +1,38 @@
|
|||
import classNames from 'classnames';
|
||||
import React from 'react';
|
||||
|
||||
import StillImage from 'soapbox/components/still_image';
|
||||
|
||||
import type { Account } from 'soapbox/types/entities';
|
||||
|
||||
interface IAvatar {
|
||||
account?: Account | null,
|
||||
size?: number,
|
||||
className?: string,
|
||||
}
|
||||
|
||||
/**
|
||||
* Legacy avatar component.
|
||||
* @see soapbox/components/ui/avatar/avatar.tsx
|
||||
* @deprecated
|
||||
*/
|
||||
const Avatar: React.FC<IAvatar> = ({ account, size, className }) => {
|
||||
if (!account) return null;
|
||||
|
||||
// : TODO : remove inline and change all avatars to be sized using css
|
||||
const style: React.CSSProperties = !size ? {} : {
|
||||
width: `${size}px`,
|
||||
height: `${size}px`,
|
||||
};
|
||||
|
||||
return (
|
||||
<StillImage
|
||||
className={classNames('rounded-full overflow-hidden', className)}
|
||||
style={style}
|
||||
src={account.avatar}
|
||||
alt=''
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default Avatar;
|
8
app/soapbox/components/landing-gradient.tsx
Normal file
8
app/soapbox/components/landing-gradient.tsx
Normal file
|
@ -0,0 +1,8 @@
|
|||
import React from 'react';
|
||||
|
||||
/** Fullscreen gradient used as a backdrop to public pages. */
|
||||
const LandingGradient: React.FC = () => (
|
||||
<div className='fixed h-screen w-full bg-gradient-to-tr from-primary-50 dark:from-slate-700 via-white dark:via-slate-900 to-gradient-end/10 dark:to-slate-900' />
|
||||
);
|
||||
|
||||
export default LandingGradient;
|
|
@ -37,8 +37,8 @@ const ListItem: React.FC<IListItem> = ({ label, hint, children, onClick }) => {
|
|||
return (
|
||||
<Comp
|
||||
className={classNames({
|
||||
'flex items-center justify-between px-3 py-2 first:rounded-t-lg last:rounded-b-lg bg-gradient-to-r from-gradient-purple/20 to-gradient-blue/20 dark:from-slate-900/25 dark:to-slate-900/50': true,
|
||||
'cursor-pointer hover:from-gradient-purple/30 hover:to-gradient-blue/30 dark:hover:from-slate-900/40 dark:hover:to-slate-900/75': typeof onClick !== 'undefined',
|
||||
'flex items-center justify-between px-3 py-2 first:rounded-t-lg last:rounded-b-lg bg-gradient-to-r from-gradient-start/10 to-gradient-end/10 dark:from-slate-900/25 dark:to-slate-900/50': true,
|
||||
'cursor-pointer hover:from-gradient-start/20 hover:to-gradient-end/20 dark:hover:from-slate-900/40 dark:hover:to-slate-900/75': typeof onClick !== 'undefined',
|
||||
})}
|
||||
{...linkProps}
|
||||
>
|
||||
|
|
|
@ -123,7 +123,7 @@ const SidebarNavigation = () => {
|
|||
return (
|
||||
<SidebarNavigationLink
|
||||
to='/messages'
|
||||
icon={require('icons/mail.svg')}
|
||||
icon={require('@tabler/icons/icons/mail.svg')}
|
||||
text={<FormattedMessage id='navigation.direct_messages' defaultMessage='Messages' />}
|
||||
/>
|
||||
);
|
||||
|
@ -158,7 +158,7 @@ const SidebarNavigation = () => {
|
|||
|
||||
<SidebarNavigationLink
|
||||
to='/settings'
|
||||
icon={require('icons/cog.svg')}
|
||||
icon={require('@tabler/icons/icons/settings.svg')}
|
||||
text={<FormattedMessage id='tabs_bar.settings' defaultMessage='Settings' />}
|
||||
/>
|
||||
</>
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
import classNames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { getSettings } from 'soapbox/actions/settings';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
autoPlayGif: getSettings(state).get('autoPlayGif'),
|
||||
});
|
||||
|
||||
export default @connect(mapStateToProps)
|
||||
class StillImage extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
alt: PropTypes.string,
|
||||
autoPlayGif: PropTypes.bool.isRequired,
|
||||
className: PropTypes.node,
|
||||
src: PropTypes.string.isRequired,
|
||||
style: PropTypes.object,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
alt: '',
|
||||
className: '',
|
||||
style: {},
|
||||
}
|
||||
|
||||
hoverToPlay() {
|
||||
const { autoPlayGif, src } = this.props;
|
||||
return src && !autoPlayGif && (src.endsWith('.gif') || src.startsWith('blob:'));
|
||||
}
|
||||
|
||||
setCanvasRef = c => {
|
||||
this.canvas = c;
|
||||
}
|
||||
|
||||
setImageRef = i => {
|
||||
this.img = i;
|
||||
}
|
||||
|
||||
handleImageLoad = () => {
|
||||
if (this.hoverToPlay()) {
|
||||
const img = this.img;
|
||||
const canvas = this.canvas;
|
||||
canvas.width = img.naturalWidth;
|
||||
canvas.height = img.naturalHeight;
|
||||
canvas.getContext('2d').drawImage(img, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { alt, className, src, style } = this.props;
|
||||
const hoverToPlay = this.hoverToPlay();
|
||||
|
||||
return (
|
||||
<div data-testid='still-image-container' className={classNames(className, 'still-image', { 'still-image--play-on-hover': hoverToPlay })} style={style}>
|
||||
<img src={src} alt={alt} ref={this.setImageRef} onLoad={this.handleImageLoad} />
|
||||
{hoverToPlay && <canvas ref={this.setCanvasRef} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
46
app/soapbox/components/still_image.tsx
Normal file
46
app/soapbox/components/still_image.tsx
Normal file
|
@ -0,0 +1,46 @@
|
|||
import classNames from 'classnames';
|
||||
import React, { useRef } from 'react';
|
||||
|
||||
import { useSettings } from 'soapbox/hooks';
|
||||
|
||||
interface IStillImage {
|
||||
/** Image alt text. */
|
||||
alt?: string,
|
||||
/** Extra class names for the outer <div> container. */
|
||||
className?: string,
|
||||
/** URL to the image */
|
||||
src: string,
|
||||
/** Extra CSS styles on the outer <div> element. */
|
||||
style?: React.CSSProperties,
|
||||
}
|
||||
|
||||
/** Renders images on a canvas, only playing GIFs if autoPlayGif is enabled. */
|
||||
const StillImage: React.FC<IStillImage> = ({ alt, className, src, style }) => {
|
||||
const settings = useSettings();
|
||||
const autoPlayGif = settings.get('autoPlayGif');
|
||||
|
||||
const canvas = useRef<HTMLCanvasElement>(null);
|
||||
const img = useRef<HTMLImageElement>(null);
|
||||
|
||||
const hoverToPlay = (
|
||||
src && !autoPlayGif && (src.endsWith('.gif') || src.startsWith('blob:'))
|
||||
);
|
||||
|
||||
const handleImageLoad = () => {
|
||||
if (hoverToPlay && canvas.current && img.current) {
|
||||
canvas.current.width = img.current.naturalWidth;
|
||||
canvas.current.height = img.current.naturalHeight;
|
||||
canvas.current.getContext('2d')?.drawImage(img.current, 0, 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<div data-testid='still-image-container' className={classNames(className, 'still-image', { 'still-image--play-on-hover': hoverToPlay })} style={style}>
|
||||
<img src={src} alt={alt} ref={img} onLoad={handleImageLoad} />
|
||||
{hoverToPlay && <canvas ref={canvas} />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default StillImage;
|
|
@ -25,7 +25,7 @@ const Avatar = (props: IAvatar) => {
|
|||
|
||||
return (
|
||||
<StillImage
|
||||
className={classNames('rounded-full', className)}
|
||||
className={classNames('rounded-full overflow-hidden', className)}
|
||||
style={style}
|
||||
src={src}
|
||||
alt='Avatar'
|
||||
|
|
|
@ -25,7 +25,7 @@ const useButtonStyles = ({
|
|||
accent: 'border-transparent text-white bg-accent-500 hover:bg-accent-300 focus:ring-pink-500 focus:ring-2 focus:ring-offset-2',
|
||||
danger: 'border-transparent text-danger-700 bg-danger-100 hover:bg-danger-200 focus:ring-danger-500 focus:ring-2 focus:ring-offset-2',
|
||||
transparent: 'border-transparent text-gray-800 backdrop-blur-sm bg-white/75 hover:bg-white/80',
|
||||
link: 'border-transparent text-primary-600 hover:bg-gray-100 hover:text-primary-700',
|
||||
link: 'border-transparent text-primary-600 dark:text-primary-400 hover:bg-gray-100 hover:text-primary-700 dark:hover:bg-slate-900/50',
|
||||
};
|
||||
|
||||
const sizes = {
|
||||
|
|
|
@ -13,7 +13,7 @@ type Tags = 'abbr' | 'p' | 'span' | 'pre' | 'time' | 'h1' | 'h2' | 'h3' | 'h4' |
|
|||
const themes = {
|
||||
default: 'text-gray-900 dark:text-gray-100',
|
||||
danger: 'text-danger-600',
|
||||
primary: 'text-primary-600',
|
||||
primary: 'text-primary-600 dark:text-primary-400',
|
||||
muted: 'text-gray-500 dark:text-gray-400',
|
||||
subtle: 'text-gray-400 dark:text-gray-500',
|
||||
success: 'text-success-600',
|
||||
|
|
|
@ -132,7 +132,7 @@ const SoapboxMount = () => {
|
|||
|
||||
const waitlisted = account && !account.source.get('approved', true);
|
||||
|
||||
const bodyClass = classNames('bg-white dark:bg-slate-900 text-base', {
|
||||
const bodyClass = classNames('bg-white dark:bg-slate-900 text-base h-full', {
|
||||
'no-reduce-motion': !settings.get('reduceMotion'),
|
||||
'underline-links': settings.get('underlineLinks'),
|
||||
'dyslexic': settings.get('dyslexicFont'),
|
||||
|
@ -162,7 +162,7 @@ const SoapboxMount = () => {
|
|||
return (
|
||||
<IntlProvider locale={locale} messages={messages}>
|
||||
<Helmet>
|
||||
<html lang={locale} className={classNames({ dark: darkMode })} />
|
||||
<html lang={locale} className={classNames('h-full', { dark: darkMode })} />
|
||||
<body className={bodyClass} />
|
||||
{themeCss && <style id='theme' type='text/css'>{`:root{${themeCss}}`}</style>}
|
||||
<meta name='theme-color' content={soapboxConfig.brandColor} />
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react';
|
||||
import { Link, Redirect, Route, Switch } from 'react-router-dom';
|
||||
|
||||
import LandingGradient from 'soapbox/components/landing-gradient';
|
||||
import SvgIcon from 'soapbox/components/ui/icon/svg-icon';
|
||||
import BundleContainer from 'soapbox/features/ui/containers/bundle_container';
|
||||
import { NotificationsContainer } from 'soapbox/features/ui/util/async-components';
|
||||
|
@ -21,46 +22,47 @@ const AuthLayout = () => {
|
|||
const siteTitle = useAppSelector(state => state.instance.title);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='fixed h-screen w-full bg-gradient-to-tr from-primary-50 dark:from-slate-700 via-white dark:via-slate-900 to-cyan-50 dark:to-cyan-900' />
|
||||
<div className='h-full'>
|
||||
<LandingGradient />
|
||||
|
||||
<main className='relative flex flex-col h-screen'>
|
||||
<header className='py-10 flex justify-center relative'>
|
||||
<Link to='/' className='cursor-pointer'>
|
||||
{logo ? (
|
||||
<img src={logo} alt={siteTitle} className='h-7' />
|
||||
) : (
|
||||
<SvgIcon
|
||||
className='w-7 h-7 dark:text-white'
|
||||
alt={siteTitle}
|
||||
src={require('@tabler/icons/icons/home.svg')}
|
||||
/>
|
||||
)}
|
||||
</Link>
|
||||
</header>
|
||||
<main className='relative min-h-full sm:flex sm:items-center sm:justify-center py-12'>
|
||||
<div className='w-full sm:max-w-lg md:max-w-2xl space-y-8'>
|
||||
<header className='flex justify-center relative'>
|
||||
<Link to='/' className='cursor-pointer'>
|
||||
{logo ? (
|
||||
<img src={logo} alt={siteTitle} className='h-7' />
|
||||
) : (
|
||||
<SvgIcon
|
||||
className='w-7 h-7 dark:text-white'
|
||||
alt={siteTitle}
|
||||
src={require('@tabler/icons/icons/home.svg')}
|
||||
/>
|
||||
)}
|
||||
</Link>
|
||||
</header>
|
||||
|
||||
<div className='flex flex-col justify-center items-center'>
|
||||
<div className='pb-10 sm:mx-auto w-full sm:max-w-lg md:max-w-2xl'>
|
||||
<Card variant='rounded' size='xl'>
|
||||
<CardBody>
|
||||
<Switch>
|
||||
<Route exact path='/verify' component={Verification} />
|
||||
<Route exact path='/verify/email/:token' component={EmailPassthru} />
|
||||
<Route exact path='/login/external' component={ExternalLoginForm} />
|
||||
<Route exact path='/login' component={LoginPage} />
|
||||
<Route exact path='/signup' component={RegistrationForm} />
|
||||
<Route exact path='/reset-password' component={PasswordReset} />
|
||||
<Route exact path='/edit-password' component={PasswordResetConfirm} />
|
||||
<Route path='/invite/:token' component={RegisterInvite} />
|
||||
<div className='flex flex-col justify-center items-center'>
|
||||
<div className='pb-10 sm:mx-auto w-full sm:max-w-lg md:max-w-2xl'>
|
||||
<Card variant='rounded' size='xl'>
|
||||
<CardBody>
|
||||
<Switch>
|
||||
<Route exact path='/verify' component={Verification} />
|
||||
<Route exact path='/verify/email/:token' component={EmailPassthru} />
|
||||
<Route exact path='/login/external' component={ExternalLoginForm} />
|
||||
<Route exact path='/login' component={LoginPage} />
|
||||
<Route exact path='/signup' component={RegistrationForm} />
|
||||
<Route exact path='/reset-password' component={PasswordReset} />
|
||||
<Route exact path='/edit-password' component={PasswordResetConfirm} />
|
||||
<Route path='/invite/:token' component={RegisterInvite} />
|
||||
|
||||
<Redirect from='/auth/password/new' to='/reset-password' />
|
||||
<Redirect from='/auth/password/edit' to='/edit-password' />
|
||||
</Switch>
|
||||
</CardBody>
|
||||
</Card>
|
||||
<Redirect from='/auth/password/new' to='/reset-password' />
|
||||
<Redirect from='/auth/password/edit' to='/edit-password' />
|
||||
</Switch>
|
||||
</CardBody>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
<BundleContainer fetchComponent={NotificationsContainer}>
|
||||
|
|
|
@ -21,7 +21,7 @@ const ComposeFormButton: React.FC<IComposeFormButton> = ({
|
|||
return (
|
||||
<div>
|
||||
<IconButton
|
||||
className={classNames('text-gray-400 hover:text-gray-600', { 'text-primary-600 hover:text-primary-500': active })}
|
||||
className={classNames('text-gray-400 hover:text-gray-600', { 'text-primary-600 hover:text-primary-500 dark:text-primary-400 dark:hover:text-primary-300': active })}
|
||||
src={icon}
|
||||
title={title}
|
||||
disabled={disabled}
|
||||
|
|
|
@ -76,7 +76,7 @@ class AccountCard extends ImmutablePureComponent {
|
|||
<div className='directory__card__extra'>
|
||||
<div className='accounts-table__count'><Text theme='primary' size='sm'>{shortNumberFormat(account.get('statuses_count'))}</Text> <small><FormattedMessage id='account.posts' defaultMessage='Toots' /></small></div>
|
||||
<div className='accounts-table__count'><Text theme='primary' size='sm'>{shortNumberFormat(account.get('followers_count'))}</Text> <small><FormattedMessage id='account.followers' defaultMessage='Followers' /></small></div>
|
||||
<div className='accounts-table__count'>{account.get('last_status_at') === null ? <Text theme='primary' size='sm'><FormattedMessage id='account.never_active' defaultMessage='Never' /></Text> : <RelativeTimestamp className='text-primary-600' timestamp={account.get('last_status_at')} />} <small><FormattedMessage id='account.last_status' defaultMessage='Last active' /></small></div>
|
||||
<div className='accounts-table__count'>{account.get('last_status_at') === null ? <Text theme='primary' size='sm'><FormattedMessage id='account.never_active' defaultMessage='Never' /></Text> : <RelativeTimestamp className='text-primary-600 dark:text-primary-400' timestamp={account.get('last_status_at')} />} <small><FormattedMessage id='account.last_status' defaultMessage='Last active' /></small></div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -72,7 +72,7 @@ const LandingPage = () => {
|
|||
<div className='px-4 sm:px-6 sm:text-center md:max-w-2xl md:mx-auto lg:col-span-6 lg:text-left lg:flex'>
|
||||
<div>
|
||||
<Stack space={3}>
|
||||
<h1 className='text-5xl font-extrabold text-transparent bg-clip-text bg-gradient-to-br from-pink-600 via-primary-500 to-blue-600 sm:mt-5 sm:leading-none lg:mt-6 lg:text-6xl xl:text-7xl'>
|
||||
<h1 className='text-5xl font-extrabold text-transparent bg-clip-text bg-gradient-to-br from-accent-500 via-primary-500 to-gradient-end sm:mt-5 sm:leading-none lg:mt-6 lg:text-6xl xl:text-7xl'>
|
||||
{instance.title}
|
||||
</h1>
|
||||
<Text size='lg'>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import { HotKeys } from 'react-hotkeys';
|
||||
import { FormattedMessage, useIntl } from 'react-intl';
|
||||
import { FormattedMessage, useIntl } from 'react-intl';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
import Icon from '../../../components/icon';
|
||||
|
@ -204,7 +204,7 @@ const Notification: React.FC<INotificaton> = (props) => {
|
|||
return (
|
||||
<Icon
|
||||
src={icons[type]}
|
||||
className='text-primary-600 flex-none'
|
||||
className='text-primary-600 dark:text-primary-400 flex-none'
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
|
@ -286,10 +286,11 @@ const Notification: React.FC<INotificaton> = (props) => {
|
|||
<HStack alignItems='center' space={1.5}>
|
||||
{renderIcon()}
|
||||
|
||||
<div>
|
||||
<div className='truncate'>
|
||||
<Text
|
||||
theme='muted'
|
||||
size='sm'
|
||||
truncate
|
||||
>
|
||||
{message}
|
||||
</Text>
|
||||
|
|
|
@ -4,6 +4,7 @@ import { useDispatch } from 'react-redux';
|
|||
import ReactSwipeableViews from 'react-swipeable-views';
|
||||
|
||||
import { endOnboarding } from 'soapbox/actions/onboarding';
|
||||
import LandingGradient from 'soapbox/components/landing-gradient';
|
||||
import { HStack } from 'soapbox/components/ui';
|
||||
|
||||
import AvatarSelectionStep from './steps/avatar-selection-step';
|
||||
|
@ -68,7 +69,7 @@ const OnboardingWizard = () => {
|
|||
|
||||
return (
|
||||
<div data-testid='onboarding-wizard'>
|
||||
<div className='fixed h-screen w-full bg-gradient-to-tr from-primary-50 dark:from-slate-700 via-white dark:via-slate-900 to-cyan-50 dark:to-cyan-900' />
|
||||
<LandingGradient />
|
||||
|
||||
<main className='h-screen flex flex-col overflow-x-hidden'>
|
||||
<div className='flex flex-col justify-center items-center h-full'>
|
||||
|
|
|
@ -73,7 +73,7 @@ const AvatarSelectionStep = ({ onNext }: { onNext: () => void }) => {
|
|||
<Card variant='rounded' size='xl'>
|
||||
<CardBody>
|
||||
<div>
|
||||
<div className='pb-4 sm:pb-10 mb-4 border-b border-gray-200 border-solid -mx-4 sm:-mx-10'>
|
||||
<div className='pb-4 sm:pb-10 mb-4 border-b border-gray-200 dark:border-slate-900/50 border-solid -mx-4 sm:-mx-10'>
|
||||
<Stack space={2}>
|
||||
<Text size='2xl' align='center' weight='bold'>
|
||||
<FormattedMessage id='onboarding.avatar.title' defaultMessage='Choose a profile picture' />
|
||||
|
@ -102,7 +102,7 @@ const AvatarSelectionStep = ({ onNext }: { onNext: () => void }) => {
|
|||
onClick={openFilePicker}
|
||||
type='button'
|
||||
className={classNames({
|
||||
'absolute bottom-3 right-2 p-1 bg-primary-600 rounded-full ring-2 ring-white hover:bg-primary-700': true,
|
||||
'absolute bottom-3 right-2 p-1 bg-primary-600 rounded-full ring-2 ring-white dark:ring-slate-800 hover:bg-primary-700': true,
|
||||
'opacity-50 pointer-events-none': isSubmitting,
|
||||
})}
|
||||
disabled={isSubmitting}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as React from 'react';
|
||||
import { FormattedMessage } from'react-intl';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { Button, Card, CardBody, Icon, Stack, Text } from 'soapbox/components/ui';
|
||||
|
||||
|
@ -7,7 +7,7 @@ const CompletedStep = ({ onComplete }: { onComplete: () => void }) => (
|
|||
<Card variant='rounded' size='xl'>
|
||||
<CardBody>
|
||||
<Stack space={2}>
|
||||
<Icon strokeWidth={1} src={require('@tabler/icons/icons/confetti.svg')} className='w-16 h-16 mx-auto text-primary-600' />
|
||||
<Icon strokeWidth={1} src={require('@tabler/icons/icons/confetti.svg')} className='w-16 h-16 mx-auto text-primary-600 dark:text-primary-400' />
|
||||
|
||||
<Text size='2xl' align='center' weight='bold'>
|
||||
<FormattedMessage id='onboarding.finished.title' defaultMessage='Onboarding complete' />
|
||||
|
|
|
@ -8,7 +8,7 @@ const Sonar = () => (
|
|||
<div className='animate-sonar-scale-2 absolute top-0 left-0 w-full h-full rounded-full bg-primary-600/25 opacity-0 pointer-events-none' />
|
||||
<div className='animate-sonar-scale-1 absolute top-0 left-0 w-full h-full rounded-full bg-primary-600/25 opacity-0 pointer-events-none' />
|
||||
|
||||
<div className='absolute top-0 left-0 w-48 h-48 bg-white rounded-full' />
|
||||
<div className='absolute top-0 left-0 w-48 h-48 bg-white dark:bg-slate-900 rounded-full' />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -4,6 +4,7 @@ import { connect } from 'react-redux';
|
|||
import { Switch, Route, Redirect } from 'react-router-dom';
|
||||
|
||||
import { getSoapboxConfig } from 'soapbox/actions/soapbox';
|
||||
import LandingGradient from 'soapbox/components/landing-gradient';
|
||||
import BundleContainer from 'soapbox/features/ui/containers/bundle_container';
|
||||
import {
|
||||
NotificationsContainer,
|
||||
|
@ -35,7 +36,7 @@ class PublicLayout extends ImmutablePureComponent {
|
|||
|
||||
return (
|
||||
<div className='h-full'>
|
||||
<div className='fixed h-screen w-full bg-gradient-to-tr from-primary-50 dark:from-slate-700 via-white dark:via-slate-900 to-cyan-50 dark:to-cyan-900' />
|
||||
<LandingGradient />
|
||||
|
||||
<div className='flex flex-col h-screen'>
|
||||
<div className='flex-shrink-0'>
|
||||
|
|
|
@ -25,8 +25,8 @@ const BackgroundShapes: React.FC<IBackgroundShapes> = ({ position = 'fixed' }) =
|
|||
<use xlinkHref='#a' />
|
||||
</mask>
|
||||
<g mask='url(#b)'>
|
||||
<path className='fill-bg-shape-1' d='M1257.79 335.852C1262 527.117 897.55 530.28 792.32 977.19 600.48 981.41 435.29 545.31 431.08 354.046 426.871 162.782 578.976 4.31 770.815.088c191.844-4.222 482.764 144.5 486.974 335.764Z' fillRule='nonzero' filter='url(#c)' transform='translate(309.54 -367.538)' opacity='.1' />
|
||||
<path className='fill-bg-shape-2' d='M71.127 1126.654c206.164 179.412 502.452 211.232 661.777 71.072 159.325-140.163 295.165-510.155 8.23-504.412-320.079 6.405-381.35-817.422-540.675-677.258-31 368-335.497 931.182-129.332 1110.598Z' fillRule='nonzero' filter='url(#d)' transform='translate(309.54 -141.056)' opacity='.1' />
|
||||
<path className='fill-gradient-end opacity-10 dark:fill-gradient-end dark:opacity-5' d='M1257.79 335.852C1262 527.117 897.55 530.28 792.32 977.19 600.48 981.41 435.29 545.31 431.08 354.046 426.871 162.782 578.976 4.31 770.815.088c191.844-4.222 482.764 144.5 486.974 335.764Z' fillRule='nonzero' filter='url(#c)' transform='translate(309.54 -367.538)' />
|
||||
<path className='fill-gradient-start opacity-10 dark:fill-gradient-start dark:opacity-5' d='M71.127 1126.654c206.164 179.412 502.452 211.232 661.777 71.072 159.325-140.163 295.165-510.155 8.23-504.412-320.079 6.405-381.35-817.422-540.675-677.258-31 368-335.497 931.182-129.332 1110.598Z' fillRule='nonzero' filter='url(#d)' transform='translate(309.54 -141.056)' />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
|
@ -120,7 +120,7 @@ const ReasonStep = (_props: IReasonStep) => {
|
|||
value={rule.id}
|
||||
checked={isSelected}
|
||||
readOnly
|
||||
className='h-4 w-4 cursor-pointer text-primary-600 border-gray-300 rounded focus:ring-primary-500'
|
||||
className='h-4 w-4 cursor-pointer text-primary-600 dark:text-primary-400 border-gray-300 rounded focus:ring-primary-500'
|
||||
/>
|
||||
</button>
|
||||
);
|
||||
|
|
|
@ -31,7 +31,7 @@ const Success = () => {
|
|||
|
||||
return (
|
||||
<Stack space={4} alignItems='center'>
|
||||
<Icon src={require('@tabler/icons/icons/circle-check.svg')} className='text-primary-600 h-10 w-10' />
|
||||
<Icon src={require('@tabler/icons/icons/circle-check.svg')} className='text-primary-600 dark:text-primary-400 h-10 w-10' />
|
||||
<Text size='3xl' weight='semibold' align='center'>
|
||||
{intl.formatMessage(messages.emailConfirmedHeading)}
|
||||
</Text>
|
||||
|
|
|
@ -34,7 +34,7 @@ const EmailSent = ({ handleSubmit }) => {
|
|||
|
||||
return (
|
||||
<div className='sm:pt-10 mx-auto flex flex-col items-center justify-center'>
|
||||
<Icon src={require('@tabler/icons/icons/send.svg')} className='text-primary-600 h-12 w-12 mb-5' />
|
||||
<Icon src={require('@tabler/icons/icons/send.svg')} className='text-primary-600 dark:text-primary-400 h-12 w-12 mb-5' />
|
||||
|
||||
<div className='space-y-1 text-center mb-4'>
|
||||
<Text weight='bold' size='3xl'>We sent you an email</Text>
|
||||
|
|
|
@ -5,6 +5,7 @@ import { useDispatch, useSelector } from 'react-redux';
|
|||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { getSoapboxConfig } from 'soapbox/actions/soapbox';
|
||||
import LandingGradient from 'soapbox/components/landing-gradient';
|
||||
import BundleContainer from 'soapbox/features/ui/containers/bundle_container';
|
||||
import { NotificationsContainer } from 'soapbox/features/ui/util/async-components';
|
||||
|
||||
|
@ -23,7 +24,9 @@ const WaitlistPage = ({ account }) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className='h-screen w-full bg-gradient-to-tr from-primary-50 dark:from-slate-700 via-white dark:via-slate-900 to-cyan-50 dark:to-cyan-900'>
|
||||
<div>
|
||||
<LandingGradient />
|
||||
|
||||
<main className='relative flex flex-col h-screen max-w-7xl mx-auto px-2 sm:px-6 lg:px-8'>
|
||||
<header className='relative flex justify-between h-16'>
|
||||
<div className='flex-1 flex items-stretch justify-center relative'>
|
||||
|
|
|
@ -52,8 +52,6 @@ const DEFAULT_COLORS = ImmutableMap<string, any>({
|
|||
800: '#991b1b',
|
||||
900: '#7f1d1d',
|
||||
}),
|
||||
'gradient-purple': '#b8a3f9',
|
||||
'gradient-blue': '#9bd5ff',
|
||||
'sea-blue': '#2feecc',
|
||||
});
|
||||
|
||||
|
@ -158,8 +156,8 @@ const maybeAddMissingColors = (soapboxConfig: SoapboxConfigMap): SoapboxConfigMa
|
|||
const colors = soapboxConfig.get('colors');
|
||||
|
||||
const missing = ImmutableMap({
|
||||
'bg-shape-1': colors.getIn(['accent', '500']),
|
||||
'bg-shape-2': colors.getIn(['primary', '500']),
|
||||
'gradient-start': colors.getIn(['primary', '500']),
|
||||
'gradient-end': colors.getIn(['accent', '500']),
|
||||
});
|
||||
|
||||
return soapboxConfig.set('colors', missing.mergeDeep(colors));
|
||||
|
|
|
@ -771,7 +771,7 @@
|
|||
}
|
||||
|
||||
a {
|
||||
@apply text-primary-600 no-underline hover:underline;
|
||||
@apply text-primary-600 dark:text-primary-400 no-underline hover:underline;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -113,5 +113,5 @@
|
|||
.react-datepicker__month-text--keyboard-selected,
|
||||
.react-datepicker__quarter-text--keyboard-selected,
|
||||
.react-datepicker__year-text--keyboard-selected {
|
||||
@apply bg-primary-50 hover:bg-primary-100 text-primary-600;
|
||||
@apply bg-primary-50 hover:bg-primary-100 text-primary-600 dark:text-primary-400;
|
||||
}
|
||||
|
|
|
@ -193,7 +193,7 @@
|
|||
}
|
||||
|
||||
.button.button-secondary {
|
||||
@apply h-auto py-1.5 px-2.5 text-primary-600 border-primary-600;
|
||||
@apply h-auto py-1.5 px-2.5 text-primary-600 dark:text-primary-400 border-primary-600;
|
||||
}
|
||||
|
||||
li {
|
||||
|
|
|
@ -13,5 +13,5 @@
|
|||
}
|
||||
|
||||
.mention {
|
||||
@apply text-primary-600 hover:underline;
|
||||
@apply text-primary-600 dark:text-primary-400 hover:underline;
|
||||
}
|
||||
|
|
|
@ -41,11 +41,9 @@ module.exports = {
|
|||
success: [50, 100, 200, 300, 400, 500, 600, 700, 800, 900],
|
||||
danger: [50, 100, 200, 300, 400, 500, 600, 700, 800, 900],
|
||||
accent: [300, 500],
|
||||
'gradient-purple': true,
|
||||
'gradient-blue': true,
|
||||
'gradient-start': true,
|
||||
'gradient-end': true,
|
||||
'sea-blue': true,
|
||||
'bg-shape-1': true,
|
||||
'bg-shape-2': true,
|
||||
}),
|
||||
animation: {
|
||||
'sonar-scale-4': 'sonar-scale-4 3s linear infinite',
|
||||
|
|
|
@ -40,14 +40,14 @@ describe('parseColorMatrix()', () => {
|
|||
success: [50, 100, 200, 300, 400, 500, 600, 700, 800, 900],
|
||||
danger: [50, 100, 200, 300, 400, 500, 600, 700, 800, 900],
|
||||
accent: [300, 500],
|
||||
'gradient-purple': true,
|
||||
'gradient-blue': true,
|
||||
'gradient-start': true,
|
||||
'gradient-end': true,
|
||||
'sea-blue': true,
|
||||
};
|
||||
|
||||
const result = parseColorMatrix(colorMatrix);
|
||||
|
||||
expect(result['sea-blue']({})).toEqual('rgb(var(--color-sea-blue))');
|
||||
expect(result['gradient-purple']({ opacityValue: .7 })).toEqual('rgb(var(--color-gradient-purple) / 0.7)');
|
||||
expect(result['gradient-start']({ opacityValue: .7 })).toEqual('rgb(var(--color-gradient-start) / 0.7)');
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue