Merge branch 'landing-page-dark-mode' into 'develop'

Add "dark mode" support to Landing Page

See merge request soapbox-pub/soapbox-fe!1344
site-logo
Justin 2022-05-11 11:19:18 +00:00
commit 4e47ee1bea
12 zmienionych plików z 23 dodań i 302 usunięć

Wyświetl plik

@ -1,19 +0,0 @@
import { staticClient } from '../api';
export const FETCH_BETA_PAGE_REQUEST = 'FETCH_BETA_PAGE_REQUEST';
export const FETCH_BETA_PAGE_SUCCESS = 'FETCH_BETA_PAGE_SUCCESS';
export const FETCH_BETA_PAGE_FAIL = 'FETCH_BETA_PAGE_FAIL';
export function fetchBetaPage(slug = 'index', locale) {
return (dispatch, getState) => {
dispatch({ type: FETCH_BETA_PAGE_REQUEST, slug, locale });
const filename = `${slug}${locale ? `.${locale}` : ''}.html`;
return staticClient.get(`/instance/beta/${filename}`).then(({ data: html }) => {
dispatch({ type: FETCH_BETA_PAGE_SUCCESS, slug, locale, html });
return html;
}).catch(error => {
dispatch({ type: FETCH_BETA_PAGE_FAIL, slug, locale, error });
throw error;
});
};
}

Wyświetl plik

@ -2,7 +2,7 @@ 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' />
<div className='fixed h-screen w-full bg-gradient-to-tr from-primary-50 dark:from-slate-900/50 via-white dark:via-slate-900 to-gradient-end/10 dark:to-slate-900/50' />
);
export default LandingGradient;

Wyświetl plik

@ -9,7 +9,7 @@ const Checkbox = React.forwardRef<HTMLInputElement, ICheckbox>((props, ref) => {
{...props}
ref={ref}
type='checkbox'
className='focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded'
className='dark:bg-slate-800 dark:border-gray-600 focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded'
/>
);
});

Wyświetl plik

@ -183,7 +183,6 @@ const SoapboxMount = () => {
{!me && <Route exact path='/' component={PublicLayout} />}
<Route exact path='/about/:slug?' component={PublicLayout} />
<Route exact path='/beta/:slug?' component={PublicLayout} />
<Route exact path='/mobile/:slug?' component={PublicLayout} />
<Route path='/login' component={AuthLayout} />
{(features.accountCreation && instance.registrations) && (

Wyświetl plik

@ -1,108 +0,0 @@
import React from 'react';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { injectIntl, FormattedMessage } from 'react-intl';
import { connect } from 'react-redux';
import { fetchBetaPage } from 'soapbox/actions/beta';
import { getSettings } from 'soapbox/actions/settings';
import { getSoapboxConfig } from 'soapbox/actions/soapbox';
import { languages } from '../preferences';
const mapStateToProps = state => ({
locale: getSettings(state).get('locale'),
betaPages: getSoapboxConfig(state).get('betaPages'),
});
@connect(mapStateToProps)
@injectIntl
class BetaPage extends ImmutablePureComponent {
state = {
pageHtml: '',
locale: this.props.locale,
}
loadPageHtml = () => {
const { dispatch, match, betaPages } = this.props;
const { locale } = this.state;
const { slug } = match.params;
const page = betaPages.get(slug || 'beta');
const fetchLocale = page && locale !== page.get('default') && page.get('locales').includes(locale);
dispatch(fetchBetaPage(slug, fetchLocale && locale)).then(html => {
this.setState({ pageHtml: html });
}).catch(error => {
// TODO: Better error handling. 404 page?
this.setState({ pageHtml: '<h1>Page not found</h1>' });
});
}
setLocale = (locale) => () => {
this.setState({ locale });
};
componentDidMount() {
this.loadPageHtml();
}
componentDidUpdate(prevProps, prevState) {
const { locale, match, betaPages } = this.props;
const { locale: prevLocale, betaPages: prevBetaPages } = prevProps;
const { locale: stateLocale } = this.state;
const { locale: prevStateLocale } = prevState;
const { slug } = match.params;
const { slug: prevSlug } = prevProps.match.params;
if (locale !== prevLocale) this.setState({ locale });
if (
slug !== prevSlug ||
stateLocale !== prevStateLocale ||
(!prevBetaPages.get(slug || 'beta') && betaPages.get(slug || 'beta'))
)
this.loadPageHtml();
}
render() {
const { match, betaPages } = this.props;
const { slug } = match.params;
const page = betaPages.get(slug || 'beta');
const defaultLocale = page && page.get('default');
const alsoAvailable = page && (
<div className='rich-formatting also-available'>
<FormattedMessage id='beta.also_available' defaultMessage='Available in:' />
{' '}
<ul>
<li>
<a href='#' onClick={this.setLocale(defaultLocale)}>
{languages[defaultLocale] || defaultLocale}
</a>
</li>
{
page.get('locales').map(locale => (
<li key={locale}>
<a href='#' onClick={this.setLocale(locale)}>
{languages[locale] || locale}
</a>
</li>
))
}
</ul>
</div>
);
return (
<div>
<div
dangerouslySetInnerHTML={{ __html: this.state.pageHtml }}
/>
{alsoAvailable}
</div>
);
}
}
export default BetaPage;

Wyświetl plik

@ -68,13 +68,14 @@ const LandingPage = () => {
return (
<main className='mt-16 sm:mt-24' data-testid='homepage'>
<div className='mx-auto max-w-7xl'>
<div className='lg:grid lg:grid-cols-12 lg:gap-8 py-12'>
<div className='grid grid-cols-1 lg:grid-cols-12 gap-8 py-12'>
<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-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'>
{instance.description}
</Text>

Wyświetl plik

@ -1,3 +1,4 @@
import classNames from 'classnames';
import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { useDispatch } from 'react-redux';
@ -27,10 +28,10 @@ const Header = () => {
const dispatch = useDispatch();
const intl = useIntl();
const { logo } = useSoapboxConfig();
const { logo, logoDarkMode } = useSoapboxConfig();
const features = useFeatures();
const instance = useAppSelector((state) => state.instance);
const isOpen = instance.get('registrations', false) === true;
const isOpen = instance.get('registrations', false) === true;
const pepeOpen = useAppSelector(state => state.verification.getIn(['instance', 'registrations'], false) === true);
const [isLoading, setLoading] = React.useState(false);
@ -76,7 +77,11 @@ const Header = () => {
<Sonar />
</div>
<Link to='/' className='z-10'>
<img alt='Logo' src={logo} className='h-6 w-auto cursor-pointer' />
<img alt='Logo' src={logo} className={classNames('h-6 w-auto cursor-pointer', { 'dark:hidden': logoDarkMode })} />
{logoDarkMode && (
<img alt='Logo' src={logoDarkMode} className='h-6 w-auto cursor-pointer hidden dark:block' />
)}
<span className='hidden'>{intl.formatMessage(messages.home)}</span>
</Link>
</div>

Wyświetl plik

@ -3,10 +3,10 @@ import React from 'react';
const Sonar = () => (
<div className='relative'>
<div className='relative w-48 h-48'>
<div className='animate-sonar-scale-4 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-3 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-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='animate-sonar-scale-4 absolute top-0 left-0 w-full h-full rounded-full bg-primary-600/25 dark:bg-primary-400/25 opacity-0 pointer-events-none' />
<div className='animate-sonar-scale-3 absolute top-0 left-0 w-full h-full rounded-full bg-primary-600/25 dark:bg-primary-400/25 opacity-0 pointer-events-none' />
<div className='animate-sonar-scale-2 absolute top-0 left-0 w-full h-full rounded-full bg-primary-600/25 dark:bg-primary-400/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 dark:bg-primary-400/25 opacity-0 pointer-events-none' />
<div className='absolute top-0 left-0 w-48 h-48 bg-white dark:bg-slate-900 rounded-full' />
</div>

Wyświetl plik

@ -13,7 +13,6 @@ import {
import { isStandalone } from 'soapbox/utils/state';
import AboutPage from '../about';
import BetaPage from '../beta';
import LandingPage from '../landing_page';
import MobilePage from '../mobile';
@ -42,15 +41,12 @@ class PublicLayout extends ImmutablePureComponent {
<div className='flex-shrink-0'>
<Header />
<div className='public-layout__top'>
<div className='container'>
<Switch>
<Route exact path='/' component={LandingPage} />
<Route exact path='/about/:slug?' component={AboutPage} />
<Route exact path='/beta/:slug?' component={BetaPage} />
<Route exact path='/mobile/:slug?' component={MobilePage} />
</Switch>
</div>
<div className='relative'>
<Switch>
<Route exact path='/' component={LandingPage} />
<Route exact path='/about/:slug?' component={AboutPage} />
<Route exact path='/mobile/:slug?' component={MobilePage} />
</Switch>
</div>
</div>

Wyświetl plik

@ -110,7 +110,6 @@ export const SoapboxConfigRecord = ImmutableRecord({
limit: 1,
}),
aboutPages: ImmutableMap(),
betaPages: ImmutableMap(),
mobilePages: ImmutableMap(),
authenticatedProfile: true,
singleUserMode: false,

Wyświetl plik

@ -234,158 +234,6 @@ $fluid-breakpoint: $maximum-width + 20px;
}
}
.beta-page {
.app-cta {
display: flex;
align-items: center;
margin: 40px auto;
@media screen and (max-width: 768px) {
flex-direction: column;
}
.copy {
flex: 2;
background: white;
border: 1px solid #eee;
padding: 80px;
border-radius: 10px;
@media screen and (max-width: 768px) {
padding: 60px 20px 20px 20px;
order: 1;
text-align: center;
}
}
.icon {
border-radius: 10px;
transform: scale(1.25);
display: flex;
align-items: center;
justify-content: center;
flex: 1;
padding: 40px;
background: linear-gradient(to bottom, $color-4-light, $color-4);
box-shadow: 0 0 20px 10px rgba(0, 0, 0, 0.1);
@media screen and (max-width: 768px) {
order: 0;
transform: scale(0.75);
margin-bottom: -60px;
}
img {
border-radius: 16px;
box-shadow: 0 0 20px 10px rgba(0, 0, 0, 0.1);
}
}
h1 {
margin: 0 0 20px 0;
font-size: 80px;
line-height: 90px;
font-weight: 600;
background: -webkit-linear-gradient(135deg, $color-9, $color-4-light, $color-2-light);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
@media screen and (max-width: 767px) {
margin-bottom: 30px;
text-align: center;
font-size: 50px;
line-height: 55px;
}
}
}
}
.beta-header {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
.hand-wave {
display: flex;
align-items: center;
justify-content: center;
width: 200px;
height: 200px;
background: white;
border-radius: 50%;
margin-bottom: 20px;
@media screen and (max-width: $fluid-breakpoint) {
width: 120px;
height: 120px;
}
img {
animation: 1s ease-in wave;
max-width: 140px;
@media screen and (max-width: $fluid-breakpoint) {
width: 80px;
height: 80px;
}
}
}
.message {
margin: 40px 0;
padding: 20px;
width: 100%;
background: lighten($color-4-light, 30%);
border-radius: 10px;
p {
color: $color-4;
text-align: center;
font-size: 20px;
font-weight: 500;
}
span {
font-style: italic;
font-weight: 600;
}
}
.group {
display: flex;
align-items: center;
@media screen and (max-width: $fluid-breakpoint) {
display: block;
}
.logo {
padding: 0 40px;
border-right: 10px solid transparentize($color-3, 0.9);
@media screen and (max-width: $fluid-breakpoint) {
border-right: none;
}
}
.text {
padding: 0 40px;
font-weight: 600;
font-size: 80px;
font-style: italic;
color: $color-4-dark;
@media screen and (max-width: $fluid-breakpoint) {
padding: 0;
font-weight: 600;
font-size: 40px;
text-align: center;
}
}
}
}
.faq {
margin-bottom: 80px;

Wyświetl plik

@ -1,7 +1,7 @@
const { parseColorMatrix } = require('./tailwind/colors');
module.exports = {
content: ['./app/**/*.{html,js,ts,tsx}'],
content: ['./app/**/*.{html,js,ts,tsx}', './custom/instance/**/*.html'],
darkMode: 'class',
theme: {
screens: {