diff --git a/app/icons/cog.svg b/app/icons/cog.svg deleted file mode 100644 index 5601b5489..000000000 --- a/app/icons/cog.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/app/icons/mail.svg b/app/icons/mail.svg deleted file mode 100644 index 808c58579..000000000 --- a/app/icons/mail.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/index.ejs b/app/index.ejs index 915b22ea1..495eeaff7 100644 --- a/app/index.ejs +++ b/app/index.ejs @@ -12,7 +12,7 @@ <%= snippets %> -
+
diff --git a/app/soapbox/components/__tests__/avatar.test.js b/app/soapbox/components/__tests__/avatar.test.js index 6b50083ed..55abca520 100644 --- a/app/soapbox/components/__tests__/avatar.test.js +++ b/app/soapbox/components/__tests__/avatar.test.js @@ -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('', () => { - const account = fromJS({ + const account = normalizeAccount({ username: 'alice', acct: 'alice', display_name: 'Alice', diff --git a/app/soapbox/components/avatar.js b/app/soapbox/components/avatar.js deleted file mode 100644 index d5000264d..000000000 --- a/app/soapbox/components/avatar.js +++ /dev/null @@ -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 ( - - ); - } - -} diff --git a/app/soapbox/components/avatar.tsx b/app/soapbox/components/avatar.tsx new file mode 100644 index 000000000..9d4fbaa7c --- /dev/null +++ b/app/soapbox/components/avatar.tsx @@ -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 = ({ 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 ( + + ); +}; + +export default Avatar; diff --git a/app/soapbox/components/landing-gradient.tsx b/app/soapbox/components/landing-gradient.tsx new file mode 100644 index 000000000..53e500d28 --- /dev/null +++ b/app/soapbox/components/landing-gradient.tsx @@ -0,0 +1,8 @@ +import React from 'react'; + +/** Fullscreen gradient used as a backdrop to public pages. */ +const LandingGradient: React.FC = () => ( +
+); + +export default LandingGradient; diff --git a/app/soapbox/components/list.tsx b/app/soapbox/components/list.tsx index 3adc81c38..e7d858334 100644 --- a/app/soapbox/components/list.tsx +++ b/app/soapbox/components/list.tsx @@ -37,8 +37,8 @@ const ListItem: React.FC = ({ label, hint, children, onClick }) => { return ( diff --git a/app/soapbox/components/sidebar-navigation.tsx b/app/soapbox/components/sidebar-navigation.tsx index 3ce3b9e28..c87b7ba07 100644 --- a/app/soapbox/components/sidebar-navigation.tsx +++ b/app/soapbox/components/sidebar-navigation.tsx @@ -123,7 +123,7 @@ const SidebarNavigation = () => { return ( } /> ); @@ -158,7 +158,7 @@ const SidebarNavigation = () => { } /> diff --git a/app/soapbox/components/still_image.js b/app/soapbox/components/still_image.js deleted file mode 100644 index 323960a37..000000000 --- a/app/soapbox/components/still_image.js +++ /dev/null @@ -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 ( -
- {alt} - {hoverToPlay && } -
- ); - } - -} diff --git a/app/soapbox/components/still_image.tsx b/app/soapbox/components/still_image.tsx new file mode 100644 index 000000000..d2ee256a3 --- /dev/null +++ b/app/soapbox/components/still_image.tsx @@ -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
container. */ + className?: string, + /** URL to the image */ + src: string, + /** Extra CSS styles on the outer
element. */ + style?: React.CSSProperties, +} + +/** Renders images on a canvas, only playing GIFs if autoPlayGif is enabled. */ +const StillImage: React.FC = ({ alt, className, src, style }) => { + const settings = useSettings(); + const autoPlayGif = settings.get('autoPlayGif'); + + const canvas = useRef(null); + const img = useRef(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 ( +
+ {alt} + {hoverToPlay && } +
+ ); +}; + +export default StillImage; diff --git a/app/soapbox/components/ui/avatar/avatar.tsx b/app/soapbox/components/ui/avatar/avatar.tsx index 6818509e8..1b02c6d25 100644 --- a/app/soapbox/components/ui/avatar/avatar.tsx +++ b/app/soapbox/components/ui/avatar/avatar.tsx @@ -25,7 +25,7 @@ const Avatar = (props: IAvatar) => { return ( { 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 ( - + {themeCss && } diff --git a/app/soapbox/features/auth_layout/index.tsx b/app/soapbox/features/auth_layout/index.tsx index 8c7ac36fc..c694f173b 100644 --- a/app/soapbox/features/auth_layout/index.tsx +++ b/app/soapbox/features/auth_layout/index.tsx @@ -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 ( -
-
+
+ -
-
- - {logo ? ( - {siteTitle} - ) : ( - - )} - -
+
+
+
+ + {logo ? ( + {siteTitle} + ) : ( + + )} + +
-
-
- - - - - - - - - - - +
+
+ + + + + + + + + + + - - - - - + + + + + +
-
diff --git a/app/soapbox/features/compose/components/compose_form_button.tsx b/app/soapbox/features/compose/components/compose_form_button.tsx index 0cef5b30b..da28d6618 100644 --- a/app/soapbox/features/compose/components/compose_form_button.tsx +++ b/app/soapbox/features/compose/components/compose_form_button.tsx @@ -21,7 +21,7 @@ const ComposeFormButton: React.FC = ({ return (
{shortNumberFormat(account.get('statuses_count'))}
{shortNumberFormat(account.get('followers_count'))}
-
{account.get('last_status_at') === null ? : }
+
{account.get('last_status_at') === null ? : }
); diff --git a/app/soapbox/features/landing_page/index.tsx b/app/soapbox/features/landing_page/index.tsx index a33b9e871..226438d03 100644 --- a/app/soapbox/features/landing_page/index.tsx +++ b/app/soapbox/features/landing_page/index.tsx @@ -72,7 +72,7 @@ const LandingPage = () => {
-

+

{instance.title}

diff --git a/app/soapbox/features/notifications/components/notification.tsx b/app/soapbox/features/notifications/components/notification.tsx index 97a2818fe..26f56025f 100644 --- a/app/soapbox/features/notifications/components/notification.tsx +++ b/app/soapbox/features/notifications/components/notification.tsx @@ -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 = (props) => { return ( ); } else { @@ -286,10 +286,11 @@ const Notification: React.FC = (props) => { {renderIcon()} -
+
{message} diff --git a/app/soapbox/features/onboarding/onboarding-wizard.tsx b/app/soapbox/features/onboarding/onboarding-wizard.tsx index 0b530fd2a..4087e4f03 100644 --- a/app/soapbox/features/onboarding/onboarding-wizard.tsx +++ b/app/soapbox/features/onboarding/onboarding-wizard.tsx @@ -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 (
-
+
diff --git a/app/soapbox/features/onboarding/steps/avatar-selection-step.tsx b/app/soapbox/features/onboarding/steps/avatar-selection-step.tsx index 27d3d842d..08cfb07bd 100644 --- a/app/soapbox/features/onboarding/steps/avatar-selection-step.tsx +++ b/app/soapbox/features/onboarding/steps/avatar-selection-step.tsx @@ -73,7 +73,7 @@ const AvatarSelectionStep = ({ onNext }: { onNext: () => void }) => {
-
+
@@ -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} diff --git a/app/soapbox/features/onboarding/steps/completed-step.tsx b/app/soapbox/features/onboarding/steps/completed-step.tsx index 310093691..60f6fba13 100644 --- a/app/soapbox/features/onboarding/steps/completed-step.tsx +++ b/app/soapbox/features/onboarding/steps/completed-step.tsx @@ -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 }) => ( - + diff --git a/app/soapbox/features/public_layout/components/sonar.tsx b/app/soapbox/features/public_layout/components/sonar.tsx index 62c50a42d..f6a8ce21e 100644 --- a/app/soapbox/features/public_layout/components/sonar.tsx +++ b/app/soapbox/features/public_layout/components/sonar.tsx @@ -8,7 +8,7 @@ const Sonar = () => (
-
+
); diff --git a/app/soapbox/features/public_layout/index.js b/app/soapbox/features/public_layout/index.js index a96e269e3..30c206838 100644 --- a/app/soapbox/features/public_layout/index.js +++ b/app/soapbox/features/public_layout/index.js @@ -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 (
-
+
diff --git a/app/soapbox/features/ui/components/background_shapes.tsx b/app/soapbox/features/ui/components/background_shapes.tsx index bc4e3694c..2f9427eba 100644 --- a/app/soapbox/features/ui/components/background_shapes.tsx +++ b/app/soapbox/features/ui/components/background_shapes.tsx @@ -25,8 +25,8 @@ const BackgroundShapes: React.FC = ({ position = 'fixed' }) = - - + + diff --git a/app/soapbox/features/ui/components/modals/report-modal/steps/reason-step.tsx b/app/soapbox/features/ui/components/modals/report-modal/steps/reason-step.tsx index e50c47741..86d5dde48 100644 --- a/app/soapbox/features/ui/components/modals/report-modal/steps/reason-step.tsx +++ b/app/soapbox/features/ui/components/modals/report-modal/steps/reason-step.tsx @@ -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' /> ); diff --git a/app/soapbox/features/verification/email_passthru.js b/app/soapbox/features/verification/email_passthru.js index dac2cc3bd..131d5dd1a 100644 --- a/app/soapbox/features/verification/email_passthru.js +++ b/app/soapbox/features/verification/email_passthru.js @@ -31,7 +31,7 @@ const Success = () => { return ( - + {intl.formatMessage(messages.emailConfirmedHeading)} diff --git a/app/soapbox/features/verification/steps/email-verification.js b/app/soapbox/features/verification/steps/email-verification.js index be83406cc..fba2862c1 100644 --- a/app/soapbox/features/verification/steps/email-verification.js +++ b/app/soapbox/features/verification/steps/email-verification.js @@ -34,7 +34,7 @@ const EmailSent = ({ handleSubmit }) => { return (
- +
We sent you an email diff --git a/app/soapbox/features/verification/waitlist_page.js b/app/soapbox/features/verification/waitlist_page.js index a40e62835..ef2d573ae 100644 --- a/app/soapbox/features/verification/waitlist_page.js +++ b/app/soapbox/features/verification/waitlist_page.js @@ -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 ( -
+
+ +
diff --git a/app/soapbox/normalizers/soapbox/soapbox_config.ts b/app/soapbox/normalizers/soapbox/soapbox_config.ts index aad2a13da..cab8dc44c 100644 --- a/app/soapbox/normalizers/soapbox/soapbox_config.ts +++ b/app/soapbox/normalizers/soapbox/soapbox_config.ts @@ -52,8 +52,6 @@ const DEFAULT_COLORS = ImmutableMap({ 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)); diff --git a/app/styles/components/columns.scss b/app/styles/components/columns.scss index 98f9a5584..160fef0b4 100644 --- a/app/styles/components/columns.scss +++ b/app/styles/components/columns.scss @@ -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; } } diff --git a/app/styles/components/datepicker.scss b/app/styles/components/datepicker.scss index f5a25d018..60cb58409 100644 --- a/app/styles/components/datepicker.scss +++ b/app/styles/components/datepicker.scss @@ -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; } diff --git a/app/styles/polls.scss b/app/styles/polls.scss index 33eb45875..a49315450 100644 --- a/app/styles/polls.scss +++ b/app/styles/polls.scss @@ -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 { diff --git a/app/styles/utilities.scss b/app/styles/utilities.scss index 30eb71eed..cb7f1919f 100644 --- a/app/styles/utilities.scss +++ b/app/styles/utilities.scss @@ -13,5 +13,5 @@ } .mention { - @apply text-primary-600 hover:underline; + @apply text-primary-600 dark:text-primary-400 hover:underline; } diff --git a/tailwind.config.js b/tailwind.config.js index 70278445b..0aa665e2e 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -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', diff --git a/tailwind/__tests__/colors-test.js b/tailwind/__tests__/colors-test.js index cf11f1461..89836edb7 100644 --- a/tailwind/__tests__/colors-test.js +++ b/tailwind/__tests__/colors-test.js @@ -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)'); }); });