mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
Merge pull request #3903 from omnivore-app/feat/web-landing-and-onboarding-improvements
feat/web landing and onboarding improvements
This commit is contained in:
commit
0bc84670d6
30 changed files with 510 additions and 316 deletions
198
packages/web/components/elements/AndroidInstallHelp.tsx
Normal file
198
packages/web/components/elements/AndroidInstallHelp.tsx
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
import React from 'react'
|
||||
import {
|
||||
Desktop,
|
||||
DeviceTabletSpeaker,
|
||||
DeviceMobileCamera,
|
||||
} from 'phosphor-react'
|
||||
import { Box, HStack } from './LayoutPrimitives'
|
||||
import { StyledText, StyledAnchor } from './StyledText'
|
||||
|
||||
type MobileInstallHelpProps = {
|
||||
onboarding?: boolean
|
||||
}
|
||||
|
||||
export default function AndroidInstallHelp({
|
||||
onboarding = false,
|
||||
}: MobileInstallHelpProps): JSX.Element {
|
||||
const iosContainerStyles = {
|
||||
marginTop: '12px',
|
||||
width: '100%',
|
||||
height: '40px',
|
||||
display: 'flex',
|
||||
justifyContent: !onboarding ? 'flex-end' : 'initial',
|
||||
}
|
||||
|
||||
return (
|
||||
<Box
|
||||
css={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: '1fr 2fr',
|
||||
gridTemplateRows: !onboarding ? '.5fr .5fr .5fr' : '.5fr',
|
||||
backgroundColor: '$grayBg',
|
||||
padding: '15px',
|
||||
'@lg': {
|
||||
marginTop: '0',
|
||||
paddingTop: '0',
|
||||
gridTemplateColumns: '1fr 2fr 1fr',
|
||||
gridTemplateRows: '1fr',
|
||||
height: '9rem',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
css={{
|
||||
gridColumn: 1 / 2,
|
||||
gridRow: 1 / 2,
|
||||
marginRight: '$3',
|
||||
minWidth: '170px',
|
||||
maxWidth: '200px',
|
||||
alignSelf: 'center',
|
||||
'@lg': {
|
||||
minWidth: '200px',
|
||||
gridColumn: '1',
|
||||
gridRow: '1',
|
||||
},
|
||||
backgroundColor: '$grayBase',
|
||||
display: 'flex',
|
||||
position: 'relative',
|
||||
height: '116px',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
css={{
|
||||
position: 'absolute',
|
||||
top: '-15px',
|
||||
}}
|
||||
>
|
||||
<img
|
||||
srcSet="/static/images/mobile-app-preview.png,
|
||||
/static/images/mobile-app-preview@2x.png 2x"
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box
|
||||
css={{
|
||||
gridColumn: '2',
|
||||
gridRow: '1',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
'@lg': {
|
||||
marginTop: '16px',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<StyledText
|
||||
as={'h3'}
|
||||
css={{
|
||||
fontSize: '18px',
|
||||
fontWeight: 700,
|
||||
marginTop: 0,
|
||||
marginBottom: 0,
|
||||
color: !onboarding ? '$grayTextContrast' : 'rgba(10, 8, 6, 0.8)',
|
||||
lineHeight: '22.5px',
|
||||
'@lg': {
|
||||
fontSize: '16px',
|
||||
lineHeight: '20px',
|
||||
},
|
||||
}}
|
||||
>
|
||||
Install Omnivore for Android
|
||||
</StyledText>
|
||||
</Box>
|
||||
<StyledText
|
||||
css={{
|
||||
size: '14px',
|
||||
my: '$2',
|
||||
fontWeight: 400,
|
||||
color: !onboarding ? '$grayTextContrast' : 'rgba(10, 8, 6, 0.8)',
|
||||
maxWidth: '20rem',
|
||||
lineHeight: '21px',
|
||||
gridColumn: '1 / span 3',
|
||||
gridRow: '2 / 3',
|
||||
alignSelf: 'center',
|
||||
'@lgDown': {
|
||||
display: !onboarding ? 'initial' : 'none',
|
||||
},
|
||||
'@lg': {
|
||||
gridColumn: '2',
|
||||
gridRow: '1',
|
||||
alignSelf: 'center',
|
||||
marginTop: !onboarding ? '$4' : 65,
|
||||
},
|
||||
}}
|
||||
>
|
||||
Use our native Android app (currently a preview release), to save any
|
||||
link, access your full library, and read offline.
|
||||
<br />
|
||||
</StyledText>
|
||||
<HStack
|
||||
alignment="center"
|
||||
css={{
|
||||
gridRow: '3',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gridColumn: '1 / span 2',
|
||||
flexDirection: !onboarding ? 'row-reverse' : 'inherit',
|
||||
justifyContent: !onboarding ? 'space-between' : 'center',
|
||||
mt: !onboarding ? 'inherit' : 10,
|
||||
'@lg': {
|
||||
flexDirection: !onboarding ? 'row-reverse' : 'column-reverse',
|
||||
alignItems: !onboarding ? 'center' : 'flex-end',
|
||||
gridColumn: '3',
|
||||
gridRow: '1',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
css={{
|
||||
m: '0px',
|
||||
marginTop: '12px',
|
||||
width: '100%',
|
||||
height: '60px',
|
||||
display: 'flex',
|
||||
marginRight: '-10px',
|
||||
justifyContent: 'flex-end',
|
||||
}}
|
||||
>
|
||||
<a href="https://omnivore.app/install/android">
|
||||
<img
|
||||
alt="Get it on Google Play"
|
||||
style={{
|
||||
padding: '0px',
|
||||
height: 'auto',
|
||||
width: '140px',
|
||||
marginLeft: 'auto',
|
||||
}}
|
||||
src="https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png"
|
||||
/>
|
||||
</a>
|
||||
</Box>
|
||||
<HStack
|
||||
css={
|
||||
!onboarding
|
||||
? {
|
||||
width: '40%',
|
||||
justifyContent: 'space-between',
|
||||
maxWidth: '13rem',
|
||||
visibility: 'collapse',
|
||||
'@lg': {
|
||||
width: '100%',
|
||||
visibility: 'unset',
|
||||
},
|
||||
}
|
||||
: {
|
||||
width: '40%',
|
||||
justifyContent: 'space-between',
|
||||
maxWidth: '13rem',
|
||||
visibility: 'unset',
|
||||
'@lg': {
|
||||
width: '146px',
|
||||
// maxWidth: '210px'
|
||||
},
|
||||
}
|
||||
}
|
||||
></HStack>
|
||||
</HStack>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
|
@ -18,6 +18,22 @@ export const Button = styled('button', {
|
|||
border: '1px solid $grayBorderHover',
|
||||
},
|
||||
},
|
||||
ctaOmnivoreYellow: {
|
||||
borderRadius: '5px',
|
||||
px: '20px',
|
||||
py: '8px',
|
||||
fontSize: '14px',
|
||||
fontWeight: '500',
|
||||
cursor: 'pointer',
|
||||
border: '0px solid $yellow3',
|
||||
bg: '$omnivoreYellow',
|
||||
color: '#2A2A2A',
|
||||
'&:hover': {
|
||||
opacity: 1.0,
|
||||
border: '0px solid #FFD800',
|
||||
background: `#FFD800`,
|
||||
},
|
||||
},
|
||||
ctaBlue: {
|
||||
borderRadius: '5px',
|
||||
px: '20px',
|
||||
|
|
@ -25,12 +41,12 @@ export const Button = styled('button', {
|
|||
fontSize: '14px',
|
||||
fontWeight: '500',
|
||||
cursor: 'pointer',
|
||||
border: '1px solid $yellow3',
|
||||
border: '0px solid $yellow3',
|
||||
bg: '$ctaBlue',
|
||||
color: 'white',
|
||||
'&:hover': {
|
||||
opacity: '0.6',
|
||||
border: '0px solid $ctaBlue',
|
||||
border: '0px solid #0056D2',
|
||||
background: `#0056D2`,
|
||||
},
|
||||
},
|
||||
tldr: {
|
||||
|
|
@ -69,6 +85,38 @@ export const Button = styled('button', {
|
|||
outline: '1px solid $omnivoreCtaYellow',
|
||||
},
|
||||
},
|
||||
landingCta: {
|
||||
borderRadius: 10,
|
||||
backgroundColor: '#1A1A1A',
|
||||
padding: '12px 100px',
|
||||
color: '#FFFFFF',
|
||||
font: '$inter',
|
||||
fontSize: '20px',
|
||||
fontWeight: '500',
|
||||
textDecoration: 'none',
|
||||
transition: 'background-color ease-out 50ms',
|
||||
boxShadow: `0px 4px 4px 0px rgba(0, 0, 0, 0.15)`,
|
||||
'&:hover': {
|
||||
backgroundColor: '#3D3D3D',
|
||||
outline: '0px solid #1A1A1A',
|
||||
},
|
||||
},
|
||||
landingSimple: {
|
||||
borderRadius: 10,
|
||||
backgroundColor: '#1A1A1A',
|
||||
padding: '10px 20px',
|
||||
color: '#FFFFFF',
|
||||
font: '$inter',
|
||||
fontSize: '20px',
|
||||
fontWeight: '500',
|
||||
textDecoration: 'none',
|
||||
transition: 'background-color ease-out 50ms',
|
||||
'&:hover': {
|
||||
backgroundColor: '#1A1A1A',
|
||||
outline: '0px solid #1A1A1A',
|
||||
boxShadow: `0px 4px 4px 0px rgba(0, 0, 0, 0.15)`,
|
||||
},
|
||||
},
|
||||
cancelGeneric: {
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
|
|
@ -84,6 +132,21 @@ export const Button = styled('button', {
|
|||
outline: '1px solid $omnivoreCtaYellow',
|
||||
},
|
||||
},
|
||||
cancelAuth: {
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
fontFamily: 'Inter',
|
||||
cursor: 'pointer',
|
||||
color: '#6A6968',
|
||||
borderRadius: '5px',
|
||||
border: '1px solid transparent',
|
||||
p: '10px 15px',
|
||||
bg: 'transparent',
|
||||
'&:hover': {
|
||||
backgroundColor: '#2A2A2A',
|
||||
outline: '0px solid #2A2A2A',
|
||||
},
|
||||
},
|
||||
ctaOutlineYellow: {
|
||||
boxSizing: 'border-box',
|
||||
borderColor: 'unset',
|
||||
|
|
|
|||
|
|
@ -4,38 +4,16 @@ import {
|
|||
DeviceTabletSpeaker,
|
||||
DeviceMobileCamera,
|
||||
} from 'phosphor-react'
|
||||
import { Box, HStack } from '../elements/LayoutPrimitives'
|
||||
import { StyledText, StyledAnchor } from '../elements/StyledText'
|
||||
|
||||
const TooltipStyle = {
|
||||
backgroundColor: '#F9D354',
|
||||
color: '#0A0806',
|
||||
}
|
||||
import { Box, HStack } from './LayoutPrimitives'
|
||||
import { StyledText, StyledAnchor } from './StyledText'
|
||||
|
||||
type MobileInstallHelpProps = {
|
||||
onboarding?: boolean
|
||||
}
|
||||
|
||||
export default function MobileInstallHelp({
|
||||
export default function IOSInstallHelp({
|
||||
onboarding = false,
|
||||
}: MobileInstallHelpProps): JSX.Element {
|
||||
const [selectedTooltip, setSelectedTooltip] =
|
||||
React.useState<string>('Available for Mac')
|
||||
const platformSizes = [
|
||||
{
|
||||
label: 'Available for Mac',
|
||||
icon: <Desktop color="#F9D354" />,
|
||||
},
|
||||
{
|
||||
label: 'Available for iPad',
|
||||
icon: <DeviceTabletSpeaker color="#F9D354" />,
|
||||
},
|
||||
{
|
||||
label: 'Available for iPhone',
|
||||
icon: <DeviceMobileCamera color="#F9D354" />,
|
||||
},
|
||||
]
|
||||
|
||||
const iosContainerStyles = {
|
||||
marginTop: '12px',
|
||||
width: '100%',
|
||||
|
|
@ -143,24 +121,9 @@ export default function MobileInstallHelp({
|
|||
},
|
||||
}}
|
||||
>
|
||||
With the Omnivore for iOS and macOS app installed you can save any link
|
||||
using our Share extension.
|
||||
<br />
|
||||
{!onboarding && (
|
||||
<StyledAnchor
|
||||
href="https://docs.omnivore.app/using/saving.html"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
css={{
|
||||
color: '$grayTextContrast',
|
||||
fontSize: '14px',
|
||||
fontWeight: 600,
|
||||
textDecoration: 'underline',
|
||||
}}
|
||||
>
|
||||
Learn more about the iOS and macOS app ->
|
||||
</StyledAnchor>
|
||||
)}
|
||||
With the native Omnivore for iOS and macOS app installed you can save
|
||||
any link, read offline, and listen to your saved items using
|
||||
text-to-speech.
|
||||
</StyledText>
|
||||
<HStack
|
||||
alignment="center"
|
||||
|
|
@ -231,49 +194,7 @@ export default function MobileInstallHelp({
|
|||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
{platformSizes.map((item, idx) => (
|
||||
<Box
|
||||
key={`platformSize-${idx}`}
|
||||
title={item.label}
|
||||
css={{
|
||||
ml: '$1',
|
||||
}}
|
||||
>
|
||||
<StyledAnchor
|
||||
onClick={() => setSelectedTooltip(item.label)}
|
||||
css={{
|
||||
mx: 'auto',
|
||||
borderRadius: '50%',
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
height: 35,
|
||||
width: 35,
|
||||
cursor: 'pointer',
|
||||
backgroundColor: '$labelButtonsBg',
|
||||
...(selectedTooltip !== item.label && {
|
||||
filter: 'grayscale(1)',
|
||||
}),
|
||||
'&:focus': {
|
||||
filter: 'grayscale(0)',
|
||||
},
|
||||
'&:active': {
|
||||
filter: 'grayscale(0)',
|
||||
},
|
||||
'@lg': {
|
||||
transition: 'filter .3s linear',
|
||||
'&:hover': {
|
||||
filter: 'grayscale(0)',
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
{item.icon}
|
||||
</StyledAnchor>
|
||||
</Box>
|
||||
))}
|
||||
</HStack>
|
||||
></HStack>
|
||||
</HStack>
|
||||
</Box>
|
||||
)
|
||||
|
|
@ -9,6 +9,7 @@ export const Recaptcha = (props: RecaptchaProps): JSX.Element => {
|
|||
<>
|
||||
<GoogleReCaptchaCheckbox
|
||||
key="recaptcha"
|
||||
theme="dark"
|
||||
onChange={(token) => {
|
||||
console.log('recaptcha: ', token)
|
||||
props.setRecaptchaToken(token)
|
||||
|
|
|
|||
|
|
@ -45,9 +45,8 @@ export const SplitButton = (props: SplitButtonProps): JSX.Element => {
|
|||
<Button
|
||||
css={{
|
||||
display: 'flex',
|
||||
// minWidth: '70px',
|
||||
bg: '$ctaBlue',
|
||||
color: '#EDEDED',
|
||||
bg: '$omnivoreYellow',
|
||||
color: '#2A2A2A',
|
||||
fontSize: '14px',
|
||||
fontFamily: '$inter',
|
||||
border: '0px solid transparent',
|
||||
|
|
@ -56,7 +55,7 @@ export const SplitButton = (props: SplitButtonProps): JSX.Element => {
|
|||
borderTopRightRadius: '5px',
|
||||
borderBottomRightRadius: '5px',
|
||||
'&:hover': {
|
||||
opacity: 0.6,
|
||||
background: '#FFD800',
|
||||
border: '0px solid transparent',
|
||||
},
|
||||
'&:focus': {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ export function About(props: AboutProps): JSX.Element {
|
|||
<LandingHeader />
|
||||
<VStack
|
||||
alignment="center"
|
||||
css={{ background: '#FEFCF5', color: '#3D3D3D' }}
|
||||
css={{ background: '#2A2A2A', color: '#898989' }}
|
||||
>
|
||||
<VStack
|
||||
css={{
|
||||
|
|
@ -36,7 +36,7 @@ export function About(props: AboutProps): JSX.Element {
|
|||
as="p"
|
||||
css={{
|
||||
fontWeight: '700',
|
||||
color: '#3D3D3D',
|
||||
color: '#EDEDED',
|
||||
fontSize: 45,
|
||||
lineHeight: '53px',
|
||||
padding: '10px 10px 0',
|
||||
|
|
@ -50,9 +50,9 @@ export function About(props: AboutProps): JSX.Element {
|
|||
readers.`}
|
||||
</Box>
|
||||
<Box
|
||||
as="p"
|
||||
as="p"
|
||||
css={{
|
||||
color: 'rgb(125, 125, 125)',
|
||||
color: '#898989',
|
||||
padding: '10px',
|
||||
margin: 0,
|
||||
textAlign: 'center',
|
||||
|
|
@ -69,7 +69,7 @@ export function About(props: AboutProps): JSX.Element {
|
|||
<Box
|
||||
as="p"
|
||||
css={{
|
||||
color: 'rgb(125, 125, 125)',
|
||||
color: '#898989',
|
||||
padding: '10px',
|
||||
margin: 0,
|
||||
textAlign: 'center',
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ export function AuthLayout(props: ProfileLayoutProps): JSX.Element {
|
|||
alignment="center"
|
||||
distribution="center"
|
||||
css={{
|
||||
// bg: '$omnivoreYellow',
|
||||
height: '100vh',
|
||||
bg: '$omnivoreYellow',
|
||||
color: '#898989',
|
||||
background: '#2A2A2A',
|
||||
}}
|
||||
>
|
||||
{props.children}
|
||||
|
|
@ -46,7 +46,7 @@ export function AuthLayout(props: ProfileLayoutProps): JSX.Element {
|
|||
}}
|
||||
>
|
||||
<OmnivoreNameLogo
|
||||
color={theme.colors.omnivoreGray.toString()}
|
||||
color="#898989"
|
||||
href={props.logoDestination ?? '/login'}
|
||||
/>
|
||||
</HStack>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import {
|
|||
appleAuthRedirectURI,
|
||||
} from '../../lib/appConfig'
|
||||
import { AppleIdButton } from './auth/AppleIdButton'
|
||||
import { useEffect, useRef } from 'react'
|
||||
|
||||
export type LoginFormProps = {
|
||||
errorMessage?: string
|
||||
|
|
@ -19,7 +20,7 @@ export function LoginForm(props: LoginFormProps): JSX.Element {
|
|||
fontWeight: '700',
|
||||
fontSize: '45px',
|
||||
lineHeight: '53px',
|
||||
color: '$omnivoreGray',
|
||||
color: '#FFFFFF',
|
||||
m: '0px',
|
||||
})
|
||||
|
||||
|
|
@ -45,13 +46,12 @@ export function LoginForm(props: LoginFormProps): JSX.Element {
|
|||
fontSize: '18px',
|
||||
lineHeight: '120%',
|
||||
m: '0px',
|
||||
color: '$omnivoreGray',
|
||||
color: '#898989',
|
||||
}}
|
||||
>
|
||||
Save articles and read them later in our distraction-free reader.
|
||||
</StyledText>
|
||||
<Link passHref href="/about" style={{ textDecoration: 'none' }}>
|
||||
|
||||
<StyledText
|
||||
css={{
|
||||
fontStyle: 'normal',
|
||||
|
|
@ -59,12 +59,11 @@ export function LoginForm(props: LoginFormProps): JSX.Element {
|
|||
fontSize: '18px',
|
||||
lineHeight: '120%',
|
||||
m: '0px',
|
||||
color: '$omnivoreGray',
|
||||
color: '#898989',
|
||||
}}
|
||||
>
|
||||
Learn More ->
|
||||
</StyledText>
|
||||
|
||||
</Link>
|
||||
|
||||
<SpanBox css={{ height: '24px' }} />
|
||||
|
|
@ -106,7 +105,7 @@ export function LoginForm(props: LoginFormProps): JSX.Element {
|
|||
<Link href="/auth/email-login" passHref legacyBehavior>
|
||||
<StyledTextSpan
|
||||
style="actionLink"
|
||||
css={{ color: '$omnivoreGray', pt: '12px' }}
|
||||
css={{ color: '#EDEDED', pt: '12px' }}
|
||||
>
|
||||
Continue with Email
|
||||
</StyledTextSpan>
|
||||
|
|
@ -114,10 +113,24 @@ export function LoginForm(props: LoginFormProps): JSX.Element {
|
|||
</VStack>
|
||||
<TermAndConditionsFooter />
|
||||
</VStack>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
function GoogleAuthButton() {
|
||||
useEffect(() => {
|
||||
const script = document.createElement('script')
|
||||
|
||||
script.src = 'https://accounts.google.com/gsi/client'
|
||||
script.async = true
|
||||
script.defer = true
|
||||
|
||||
document.body.appendChild(script)
|
||||
|
||||
return () => {
|
||||
document.body.removeChild(script)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Box css={{ overflow: 'hidden' }}>
|
||||
<div
|
||||
|
|
@ -155,16 +168,22 @@ export function TermAndConditionsFooter(): JSX.Element {
|
|||
>
|
||||
By signing up, you agree to Omnivore’s{' '}
|
||||
<Link href="/terms" passHref legacyBehavior>
|
||||
<StyledTextSpan style="captionLink" css={{ color: '$omnivoreGray' }}>
|
||||
<StyledTextSpan
|
||||
style="captionLink"
|
||||
css={{ color: '$omnivoreLightGray' }}
|
||||
>
|
||||
Terms of Service
|
||||
</StyledTextSpan>
|
||||
</Link>{' '}
|
||||
and{' '}
|
||||
<Link href="/privacy" passHref legacyBehavior>
|
||||
<StyledTextSpan style="captionLink" css={{ color: '$omnivoreGray' }}>
|
||||
<StyledTextSpan
|
||||
style="captionLink"
|
||||
css={{ color: '$omnivoreLightGray' }}
|
||||
>
|
||||
Privacy Policy
|
||||
</StyledTextSpan>
|
||||
</Link>
|
||||
</StyledText>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,10 +8,8 @@ import {
|
|||
import { LoginForm } from './LoginForm'
|
||||
import type { LoginFormProps } from './LoginForm'
|
||||
import { OmnivoreNameLogo } from '../elements/images/OmnivoreNameLogo'
|
||||
import { theme } from '../tokens/stitches.config'
|
||||
|
||||
import featureFullWidthImage from '../../public/static/images/login/login-feature-image-full.png'
|
||||
import featureHalfWidthImage from '../../public/static/images/login/login-feature-image-half.png'
|
||||
|
||||
export function LoginLayout(props: LoginFormProps): JSX.Element {
|
||||
return (
|
||||
|
|
@ -37,10 +35,7 @@ export function LoginLayout(props: LoginFormProps): JSX.Element {
|
|||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<OmnivoreNameLogo
|
||||
color={theme.colors.omnivoreGray.toString()}
|
||||
href="/login"
|
||||
/>
|
||||
<OmnivoreNameLogo color="#898989" href="/login" />
|
||||
</Box>
|
||||
</>
|
||||
)
|
||||
|
|
@ -53,9 +48,10 @@ function MobileLoginLayout(props: LoginFormProps) {
|
|||
alignment="center"
|
||||
distribution="center"
|
||||
css={{
|
||||
bg: '$omnivoreYellow',
|
||||
width: '100%',
|
||||
flexGrow: 1,
|
||||
color: '#898989',
|
||||
background: '#2A2A2A',
|
||||
}}
|
||||
>
|
||||
<LoginForm {...props} />
|
||||
|
|
@ -72,8 +68,9 @@ function MediumLoginLayout(props: LoginFormProps) {
|
|||
css={{
|
||||
width: '100vw',
|
||||
height: '100vh',
|
||||
bg: '$omnivoreYellow',
|
||||
overflowY: 'clip',
|
||||
color: '#898989',
|
||||
background: '#2A2A2A',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
|
|
@ -104,11 +101,6 @@ const srcSetToImageSet = (srcFallback: string, srcSet?: string): string => {
|
|||
}
|
||||
|
||||
function OmnivoreIllustration() {
|
||||
const { props: halfWidthImgProps } = getImgProps({
|
||||
src: featureHalfWidthImage,
|
||||
alt: '',
|
||||
})
|
||||
|
||||
const { props: fullWidthImgProps } = getImgProps({
|
||||
src: featureFullWidthImage,
|
||||
alt: '',
|
||||
|
|
@ -123,11 +115,10 @@ function OmnivoreIllustration() {
|
|||
backgroundSize: 'cover',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundPosition: 'left',
|
||||
backgroundImage: srcSetToImageSet(halfWidthImgProps.src, halfWidthImgProps.srcSet),
|
||||
|
||||
'@media (min-aspect-ratio: 2/1)': {
|
||||
backgroundImage: srcSetToImageSet(fullWidthImgProps.src, fullWidthImgProps.srcSet),
|
||||
},
|
||||
backgroundImage: srcSetToImageSet(
|
||||
fullWidthImgProps.src,
|
||||
fullWidthImgProps.srcSet
|
||||
),
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ export function ProfileLayout(props: ProfileLayoutProps): JSX.Element {
|
|||
alignment="center"
|
||||
distribution="center"
|
||||
css={{
|
||||
// bg: '$omnivoreYellow',
|
||||
height: '100vh',
|
||||
bg: '$omnivoreYellow',
|
||||
}}
|
||||
|
|
@ -45,7 +44,7 @@ export function ProfileLayout(props: ProfileLayoutProps): JSX.Element {
|
|||
}}
|
||||
>
|
||||
<OmnivoreNameLogo
|
||||
color={theme.colors.omnivoreGray.toString()}
|
||||
color="#898989"
|
||||
href={props.logoDestination ?? '/login'}
|
||||
/>
|
||||
</HStack>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Box, HStack, VStack } from '../elements/LayoutPrimitives'
|
||||
import { Box, HStack, SpanBox, VStack } from '../elements/LayoutPrimitives'
|
||||
import { navigationCommands } from '../../lib/keyboardShortcuts/navigationShortcuts'
|
||||
import { useKeyboardShortcuts } from '../../lib/keyboardShortcuts/useKeyboardShortcuts'
|
||||
import { useRouter } from 'next/router'
|
||||
|
|
@ -12,12 +12,46 @@ import { logout } from '../../lib/logout'
|
|||
import { SettingsMenu } from './navMenu/SettingsMenu'
|
||||
import { SettingsDropdown } from './navMenu/SettingsDropdown'
|
||||
import { useVerifyAuth } from '../../lib/hooks/useVerifyAuth'
|
||||
import Link from 'next/link'
|
||||
import { CaretLeft } from 'phosphor-react'
|
||||
|
||||
type SettingsLayoutProps = {
|
||||
title?: string
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
const ReturnButton = (): JSX.Element => {
|
||||
return (
|
||||
<SpanBox
|
||||
css={{
|
||||
a: {
|
||||
textDecorationColor: '$thLibraryMenuUnselected',
|
||||
},
|
||||
'a:visited': {
|
||||
textDecorationColor: '$thLibraryMenuUnselected',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Link href="/home">
|
||||
<HStack
|
||||
css={{
|
||||
pl: '20px',
|
||||
pb: '6px',
|
||||
gap: '2px',
|
||||
font: '$inter',
|
||||
fontWeight: '500',
|
||||
color: '$thLibraryMenuUnselected',
|
||||
}}
|
||||
alignment="center"
|
||||
>
|
||||
<CaretLeft />
|
||||
Return to library
|
||||
</HStack>
|
||||
</Link>
|
||||
</SpanBox>
|
||||
)
|
||||
}
|
||||
|
||||
export function SettingsLayout(props: SettingsLayoutProps): JSX.Element {
|
||||
useVerifyAuth()
|
||||
|
||||
|
|
@ -57,7 +91,9 @@ export function SettingsLayout(props: SettingsLayoutProps): JSX.Element {
|
|||
},
|
||||
}}
|
||||
></Box>
|
||||
<Box
|
||||
<HStack
|
||||
alignment="center"
|
||||
distribution="start"
|
||||
css={{
|
||||
p: '15px',
|
||||
display: 'none',
|
||||
|
|
@ -68,10 +104,24 @@ export function SettingsLayout(props: SettingsLayoutProps): JSX.Element {
|
|||
}}
|
||||
>
|
||||
<SettingsDropdown />
|
||||
</Box>
|
||||
<ReturnButton />
|
||||
</HStack>
|
||||
|
||||
<HStack css={{ width: '100%', height: '100%' }} distribution="start">
|
||||
<SettingsMenu />
|
||||
{props.children}
|
||||
<VStack css={{ width: '100%', height: '100%' }}>
|
||||
<SpanBox
|
||||
css={{
|
||||
marginTop: '-50px',
|
||||
'@mdDown': {
|
||||
display: 'none',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ReturnButton />
|
||||
</SpanBox>
|
||||
{props.children}
|
||||
</VStack>
|
||||
</HStack>
|
||||
<Box css={{ height: '120px', width: '100%' }} />
|
||||
</VStack>
|
||||
|
|
|
|||
|
|
@ -15,8 +15,10 @@ const ForgotPasswordForm = (): JSX.Element => {
|
|||
|
||||
return (
|
||||
<VStack css={{ width: '100%', minWidth: '320px', gap: '16px', pb: '16px' }}>
|
||||
<SpanBox css={{ width: '100%' }}>
|
||||
<FormLabel>Email</FormLabel>
|
||||
<VStack css={{ width: '100%', gap: '5px' }}>
|
||||
<FormLabel className="required" css={{ color: '#D9D9D9' }}>
|
||||
Email
|
||||
</FormLabel>
|
||||
<BorderedFormInput
|
||||
key="email"
|
||||
type="email"
|
||||
|
|
@ -24,13 +26,13 @@ const ForgotPasswordForm = (): JSX.Element => {
|
|||
value={email}
|
||||
placeholder="Email"
|
||||
autoFocus={true}
|
||||
css={{ bg: 'white', color: 'black' }}
|
||||
css={{ backgroundColor: '#2A2A2A', color: 'white', border: 'unset' }}
|
||||
onChange={(e) => {
|
||||
e.preventDefault()
|
||||
setEmail(e.target.value)
|
||||
}}
|
||||
/>
|
||||
</SpanBox>
|
||||
</VStack>
|
||||
</VStack>
|
||||
)
|
||||
}
|
||||
|
|
@ -58,16 +60,16 @@ export function EmailForgotPassword(): JSX.Element {
|
|||
alignment="center"
|
||||
css={{
|
||||
padding: '16px',
|
||||
background: 'white',
|
||||
minWidth: '340px',
|
||||
width: '70vw',
|
||||
maxWidth: '576px',
|
||||
borderRadius: '8px',
|
||||
border: '1px solid #3D3D3D',
|
||||
boxShadow: '#B1B1B1 9px 9px 9px -9px',
|
||||
background: '#343434',
|
||||
border: '1px solid #6A6968',
|
||||
boxShadow: '0px 4px 4px 0px rgba(0, 0, 0, 0.15)',
|
||||
}}
|
||||
>
|
||||
<StyledText style="subHeadline" css={{ color: '$omnivoreGray' }}>
|
||||
<StyledText style="subHeadline" css={{ color: '#D9D9D9' }}>
|
||||
Reset your password
|
||||
</StyledText>
|
||||
|
||||
|
|
@ -93,7 +95,7 @@ export function EmailForgotPassword(): JSX.Element {
|
|||
)}
|
||||
|
||||
{errorMessage && <StyledText style="error">{errorMessage}</StyledText>}
|
||||
<Button type="submit" style="ctaDarkYellow" css={{ my: '$2' }}>
|
||||
<Button type="submit" style="ctaBlue" css={{ my: '20px' }}>
|
||||
Reset Password
|
||||
</Button>
|
||||
<Button
|
||||
|
|
@ -112,7 +114,7 @@ export function EmailForgotPassword(): JSX.Element {
|
|||
>
|
||||
<StyledText
|
||||
css={{
|
||||
color: '$omnivoreRed',
|
||||
color: '$omnivoreLightGray',
|
||||
textDecoration: 'underline',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { HStack, SpanBox, VStack } from '../../elements/LayoutPrimitives'
|
||||
import { HStack, VStack } from '../../elements/LayoutPrimitives'
|
||||
import { Button } from '../../elements/Button'
|
||||
import { StyledText, StyledTextSpan } from '../../elements/StyledText'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
|
|
@ -17,8 +17,8 @@ const LoginForm = (): JSX.Element => {
|
|||
|
||||
return (
|
||||
<VStack css={{ width: '100%', minWidth: '320px', gap: '16px', pb: '16px' }}>
|
||||
<SpanBox css={{ width: '100%' }}>
|
||||
<FormLabel>Email</FormLabel>
|
||||
<VStack css={{ width: '100%', gap: '5px' }}>
|
||||
<FormLabel css={{ color: '#D9D9D9' }}>Email</FormLabel>
|
||||
<BorderedFormInput
|
||||
autoFocus={true}
|
||||
key="email"
|
||||
|
|
@ -26,26 +26,26 @@ const LoginForm = (): JSX.Element => {
|
|||
name="email"
|
||||
value={email}
|
||||
placeholder="Email"
|
||||
css={{ backgroundColor: 'white', color: 'black' }}
|
||||
css={{ backgroundColor: '#2A2A2A', color: 'white', border: 'unset' }}
|
||||
onChange={(e) => {
|
||||
e.preventDefault()
|
||||
setEmail(e.target.value)
|
||||
}}
|
||||
/>
|
||||
</SpanBox>
|
||||
</VStack>
|
||||
|
||||
<SpanBox css={{ width: '100%' }}>
|
||||
<FormLabel>Password</FormLabel>
|
||||
<VStack css={{ width: '100%', gap: '5px' }}>
|
||||
<FormLabel css={{ color: '#D9D9D9' }}>Password</FormLabel>
|
||||
<BorderedFormInput
|
||||
key="password"
|
||||
type="password"
|
||||
name="password"
|
||||
value={password}
|
||||
placeholder="Password"
|
||||
css={{ bg: 'white', color: 'black' }}
|
||||
css={{ bg: '#2A2A2A', color: 'white', border: 'unset' }}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
/>
|
||||
</SpanBox>
|
||||
</VStack>
|
||||
</VStack>
|
||||
)
|
||||
}
|
||||
|
|
@ -72,16 +72,16 @@ export function EmailLogin(): JSX.Element {
|
|||
alignment="center"
|
||||
css={{
|
||||
padding: '16px',
|
||||
background: 'white',
|
||||
minWidth: '340px',
|
||||
width: '70vw',
|
||||
maxWidth: '576px',
|
||||
borderRadius: '8px',
|
||||
border: '1px solid #3D3D3D',
|
||||
boxShadow: '#B1B1B1 9px 9px 9px -9px',
|
||||
background: '#343434',
|
||||
border: '1px solid #6A6968',
|
||||
boxShadow: '0px 4px 4px 0px rgba(0, 0, 0, 0.15)',
|
||||
}}
|
||||
>
|
||||
<StyledText style="subHeadline" css={{ color: '$omnivoreGray' }}>
|
||||
<StyledText style="subHeadline" css={{ color: '#D9D9D9' }}>
|
||||
Login
|
||||
</StyledText>
|
||||
|
||||
|
|
@ -118,8 +118,7 @@ export function EmailLogin(): JSX.Element {
|
|||
}}
|
||||
>
|
||||
<Button
|
||||
style={'ctaOutlineYellow'}
|
||||
css={{ color: '$omnivoreGray', borderColor: '$omnivoreLightGray' }}
|
||||
style={'cancelAuth'}
|
||||
type="button"
|
||||
onClick={async (event) => {
|
||||
window.localStorage.removeItem('authVerified')
|
||||
|
|
@ -134,7 +133,13 @@ export function EmailLogin(): JSX.Element {
|
|||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button type="submit" style={'ctaDarkYellow'}>
|
||||
<Button
|
||||
type="submit"
|
||||
style="ctaBlue"
|
||||
css={{
|
||||
padding: '10px 50px',
|
||||
}}
|
||||
>
|
||||
Login
|
||||
</Button>
|
||||
</HStack>
|
||||
|
|
@ -151,7 +156,7 @@ export function EmailLogin(): JSX.Element {
|
|||
>
|
||||
Don't have an account?{' '}
|
||||
<Link href="/auth/email-signup" passHref legacyBehavior>
|
||||
<StyledTextSpan style="actionLink" css={{ color: '$omnivoreGray' }}>
|
||||
<StyledTextSpan style="actionLink" css={{ color: '$ctaBlue' }}>
|
||||
Sign up
|
||||
</StyledTextSpan>
|
||||
</Link>
|
||||
|
|
@ -169,7 +174,10 @@ export function EmailLogin(): JSX.Element {
|
|||
>
|
||||
Forgot your password?{' '}
|
||||
<Link href="/auth/forgot-password" passHref legacyBehavior>
|
||||
<StyledTextSpan style="actionLink" css={{ color: '$omnivoreGray' }}>
|
||||
<StyledTextSpan
|
||||
style="actionLink"
|
||||
css={{ color: '$omnivoreLightGray' }}
|
||||
>
|
||||
Click here
|
||||
</StyledTextSpan>
|
||||
</Link>
|
||||
|
|
|
|||
|
|
@ -39,7 +39,9 @@ const SignUpForm = (): JSX.Element => {
|
|||
return (
|
||||
<VStack css={{ width: '100%', minWidth: '320px', gap: '16px', pb: '16px' }}>
|
||||
<SpanBox css={{ width: '100%' }}>
|
||||
<FormLabel className="required">Email</FormLabel>
|
||||
<FormLabel className="required" css={{ color: '#D9D9D9' }}>
|
||||
Email
|
||||
</FormLabel>
|
||||
<BorderedFormInput
|
||||
autoFocus={true}
|
||||
key="email"
|
||||
|
|
@ -47,7 +49,7 @@ const SignUpForm = (): JSX.Element => {
|
|||
name="email"
|
||||
defaultValue={email}
|
||||
placeholder="Email"
|
||||
css={{ backgroundColor: 'white', color: 'black' }}
|
||||
css={{ backgroundColor: '#2A2A2A', color: 'white', border: 'unset' }}
|
||||
onChange={(e) => {
|
||||
e.preventDefault()
|
||||
setEmail(e.target.value)
|
||||
|
|
@ -56,40 +58,46 @@ const SignUpForm = (): JSX.Element => {
|
|||
/>
|
||||
</SpanBox>
|
||||
<SpanBox css={{ width: '100%' }}>
|
||||
<FormLabel className="required">Password</FormLabel>
|
||||
<FormLabel className="required" css={{ color: '#D9D9D9' }}>
|
||||
Password
|
||||
</FormLabel>
|
||||
<BorderedFormInput
|
||||
key="password"
|
||||
type="password"
|
||||
name="password"
|
||||
defaultValue={password}
|
||||
placeholder="Password"
|
||||
css={{ bg: 'white', color: 'black' }}
|
||||
css={{ backgroundColor: '#2A2A2A', color: 'white', border: 'unset' }}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
required
|
||||
/>
|
||||
</SpanBox>
|
||||
<SpanBox css={{ width: '100%' }}>
|
||||
<FormLabel className="required">Full Name</FormLabel>
|
||||
<FormLabel className="required" css={{ color: '#D9D9D9' }}>
|
||||
Full Name
|
||||
</FormLabel>
|
||||
<BorderedFormInput
|
||||
key="fullname"
|
||||
type="text"
|
||||
name="name"
|
||||
defaultValue={fullname}
|
||||
placeholder="Full Name"
|
||||
css={{ bg: 'white', color: 'black' }}
|
||||
css={{ backgroundColor: '#2A2A2A', color: 'white', border: 'unset' }}
|
||||
onChange={(e) => setFullname(e.target.value)}
|
||||
required
|
||||
/>
|
||||
</SpanBox>
|
||||
<SpanBox css={{ width: '100%' }}>
|
||||
<FormLabel className="required">Username</FormLabel>
|
||||
<FormLabel className="required" css={{ color: '#D9D9D9' }}>
|
||||
Username
|
||||
</FormLabel>
|
||||
<BorderedFormInput
|
||||
key="username"
|
||||
type="text"
|
||||
name="username"
|
||||
defaultValue={username}
|
||||
placeholder="Username"
|
||||
css={{ bg: 'white', color: 'black' }}
|
||||
css={{ backgroundColor: '#2A2A2A', color: 'white', border: 'unset' }}
|
||||
onChange={handleUsernameChange}
|
||||
required
|
||||
/>
|
||||
|
|
@ -145,16 +153,16 @@ export function EmailSignup(): JSX.Element {
|
|||
alignment="center"
|
||||
css={{
|
||||
padding: '16px',
|
||||
background: 'white',
|
||||
minWidth: '340px',
|
||||
width: '70vw',
|
||||
maxWidth: '576px',
|
||||
borderRadius: '8px',
|
||||
border: '1px solid #3D3D3D',
|
||||
boxShadow: '#B1B1B1 9px 9px 9px -9px',
|
||||
background: '#343434',
|
||||
border: '1px solid #6A6968',
|
||||
boxShadow: '0px 4px 4px 0px rgba(0, 0, 0, 0.15)',
|
||||
}}
|
||||
>
|
||||
<StyledText style="subHeadline" css={{ color: '$omnivoreGray' }}>
|
||||
<StyledText style="subHeadline" css={{ color: '#D9D9D9' }}>
|
||||
Sign Up
|
||||
</StyledText>
|
||||
|
||||
|
|
@ -204,11 +212,7 @@ export function EmailSignup(): JSX.Element {
|
|||
}}
|
||||
>
|
||||
<Button
|
||||
style={'ctaOutlineYellow'}
|
||||
css={{
|
||||
color: '$omnivoreGray',
|
||||
borderColor: 'rgba(0, 0, 0, 0.06)',
|
||||
}}
|
||||
style="cancelAuth"
|
||||
type="button"
|
||||
onClick={async () => {
|
||||
window.localStorage.removeItem('authVerified')
|
||||
|
|
@ -223,7 +227,13 @@ export function EmailSignup(): JSX.Element {
|
|||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button type="submit" style={'ctaDarkYellow'}>
|
||||
<Button
|
||||
type="submit"
|
||||
style="ctaBlue"
|
||||
css={{
|
||||
padding: '10px 50px',
|
||||
}}
|
||||
>
|
||||
Sign Up
|
||||
</Button>
|
||||
</HStack>
|
||||
|
|
@ -238,10 +248,7 @@ export function EmailSignup(): JSX.Element {
|
|||
>
|
||||
Already have an account?{' '}
|
||||
<Link href="/auth/email-login" passHref legacyBehavior>
|
||||
<StyledTextSpan
|
||||
style="actionLink"
|
||||
css={{ color: '$omnivoreGray' }}
|
||||
>
|
||||
<StyledTextSpan style="actionLink" css={{ color: '$ctaBlue' }}>
|
||||
Login instead
|
||||
</StyledTextSpan>
|
||||
</Link>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ export function ResetSent(): JSX.Element {
|
|||
css={{
|
||||
width: '100vw',
|
||||
height: '100vh',
|
||||
bg: '$omnivoreYellow',
|
||||
color: '#898989',
|
||||
background: '#2A2A2A',
|
||||
overflowY: 'clip',
|
||||
}}
|
||||
>
|
||||
|
|
@ -17,11 +18,11 @@ export function ResetSent(): JSX.Element {
|
|||
css={{
|
||||
width: '100%',
|
||||
margin: '40px',
|
||||
color: '$omnivoreGray',
|
||||
color: '#898989',
|
||||
'@xl': { margin: '138px' },
|
||||
}}
|
||||
>
|
||||
<h1>Reset email sent</h1>
|
||||
<h1 style={{ color: 'white' }}>Reset email sent</h1>
|
||||
<Box>
|
||||
If there is an account associated with the email specified we sent a
|
||||
password reset link. Click the link to reset your password. You may
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ export function VerifyEmail(): JSX.Element {
|
|||
css={{
|
||||
width: '100vw',
|
||||
height: '100vh',
|
||||
bg: '$omnivoreYellow',
|
||||
color: '#898989',
|
||||
background: '#2A2A2A',
|
||||
overflowY: 'clip',
|
||||
}}
|
||||
>
|
||||
|
|
@ -17,12 +18,11 @@ export function VerifyEmail(): JSX.Element {
|
|||
css={{
|
||||
width: '100%',
|
||||
margin: '40px',
|
||||
color: '$omnivoreGray',
|
||||
'@xl': { margin: '138px' },
|
||||
}}
|
||||
>
|
||||
<h1>Verify your email address</h1>
|
||||
<Box>
|
||||
<h1 style={{ color: 'white' }}>Verify your email address</h1>
|
||||
<Box css={{ color: '#898989' }}>
|
||||
We sent a verification link to the email you provided. Click the
|
||||
link to verify your email. You may need to check your spam folder.
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -240,9 +240,12 @@ const AddFromURL = (props: AddFromURLProps): JSX.Element => {
|
|||
</HStack>
|
||||
)}
|
||||
<Button
|
||||
style="ctaBlue"
|
||||
style="ctaOmnivoreYellow"
|
||||
type="submit"
|
||||
css={{ marginLeft: 'auto', marginTop: 'auto' }}
|
||||
css={{
|
||||
marginLeft: 'auto',
|
||||
marginTop: 'auto',
|
||||
}}
|
||||
>
|
||||
Add
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -8,22 +8,8 @@ const LoginButton = (): JSX.Element => {
|
|||
<Button
|
||||
as={Link}
|
||||
href="/login"
|
||||
style="ctaDarkYellow"
|
||||
css={{
|
||||
display: 'flex',
|
||||
marginLeft: 'auto',
|
||||
borderRadius: 4,
|
||||
background: 'unset',
|
||||
color: '#3D3D3D',
|
||||
height: '42px',
|
||||
fontSize: 24,
|
||||
lineHeight: '24px',
|
||||
fontWeight: 'normal',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
textDecoration: "none",
|
||||
transition: "all ease-in 50ms"
|
||||
}}
|
||||
style="landingSimple"
|
||||
css={{ background: 'transparent' }}
|
||||
>
|
||||
Login
|
||||
</Button>
|
||||
|
|
@ -48,7 +34,7 @@ export function LandingHeader(): JSX.Element {
|
|||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<OmnivoreNameLogo color={'#3D3D3D'} href="/login" />
|
||||
<OmnivoreNameLogo color="#898989" href="/login" />
|
||||
<LoginButton />
|
||||
</Box>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ export function LandingSection(props: LandingSectionProps): JSX.Element {
|
|||
css={{
|
||||
width: '100%',
|
||||
flexWrap: 'wrap',
|
||||
flexDirection: (props?.imagePosition ?? 'left') === 'left' ? 'row-reverse' : 'row',
|
||||
flexDirection:
|
||||
(props?.imagePosition ?? 'left') === 'left' ? 'row-reverse' : 'row',
|
||||
marginBottom: 20,
|
||||
'@mdDown': {
|
||||
width: '100%',
|
||||
|
|
@ -40,7 +41,7 @@ export function LandingSection(props: LandingSectionProps): JSX.Element {
|
|||
as="h2"
|
||||
css={{
|
||||
fontWeight: '700',
|
||||
color: '#3D3D3D',
|
||||
color: '#FFFFFF',
|
||||
lineHeight: 1.25,
|
||||
'@mdDown': {
|
||||
fontSize: 24,
|
||||
|
|
@ -58,7 +59,7 @@ export function LandingSection(props: LandingSectionProps): JSX.Element {
|
|||
<Box
|
||||
as="p"
|
||||
css={{
|
||||
color: '#666',
|
||||
color: '#898989',
|
||||
}}
|
||||
>
|
||||
{props.descriptionText}
|
||||
|
|
|
|||
|
|
@ -15,23 +15,7 @@ import Link from 'next/link'
|
|||
|
||||
export function GetStartedButton(props: { lang: 'en' | 'zh' }): JSX.Element {
|
||||
return (
|
||||
<Button
|
||||
as={Link}
|
||||
href="/login"
|
||||
style="ctaDarkYellow"
|
||||
css={{
|
||||
borderRadius: 4,
|
||||
background: '$omnivoreCtaYellow',
|
||||
padding: '12px 25px',
|
||||
color: '#3D3D3D',
|
||||
fontWeight: '600',
|
||||
textDecoration: 'none',
|
||||
transition: 'background-color ease-out 50ms',
|
||||
'&:hover': {
|
||||
backgroundColor: '$omnivoreYellow',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Button as={Link} href="/login" style="landingCta">
|
||||
{props.lang == 'zh' ? `免费注册` : `Sign Up for Free`}
|
||||
</Button>
|
||||
)
|
||||
|
|
@ -43,8 +27,6 @@ const containerStyles = {
|
|||
pb: 100,
|
||||
width: '100%',
|
||||
maxWidth: '1224px',
|
||||
background:
|
||||
'linear-gradient(0deg, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.2)), linear-gradient(0deg, rgba(253, 250, 236, 0.7), rgba(253, 250, 236, 0.7))',
|
||||
'@mdDown': {
|
||||
pt: 50,
|
||||
},
|
||||
|
|
@ -64,7 +46,7 @@ const sections = [
|
|||
{
|
||||
en: {
|
||||
titleText: `Save it now. Read it later.`,
|
||||
descriptionText: `Save articles, PDFs, and Twitter threads as you come across them
|
||||
descriptionText: `Save articles and PDFs as you come across them
|
||||
using Omnivore's mobile apps and browser extensions. Read them
|
||||
later using our distraction free reader.`,
|
||||
},
|
||||
|
|
@ -77,7 +59,7 @@ const sections = [
|
|||
},
|
||||
{
|
||||
en: {
|
||||
titleText: `Get all your newsletters in one place.`,
|
||||
titleText: `Get all your RSS feeds and newsletters in one place.`,
|
||||
descriptionText: `Send newsletters directly to your Omnivore library rather than
|
||||
scattered across multiple inboxes. Read them on your own time, away
|
||||
from the constant distractions and interruptions of your email.`,
|
||||
|
|
@ -93,7 +75,7 @@ const sections = [
|
|||
en: {
|
||||
titleText: `Keep your reading organized, whatever that means to you.`,
|
||||
descriptionText: `Keep your reading organized and easily available with labels,
|
||||
filters, rules, and fully indexed text searches. We're not here
|
||||
filters, rules, and ful text searches. We're not here
|
||||
to tell you how to stay organized — our job is to give you the tools
|
||||
to build a system that works for you.`,
|
||||
},
|
||||
|
|
@ -107,8 +89,7 @@ const sections = [
|
|||
{
|
||||
en: {
|
||||
titleText: `Add highlights and notes.`,
|
||||
descriptionText: `Become a better reader — engage your brain and improve retention by
|
||||
reading actively, not passively. Highlight key sections and add
|
||||
descriptionText: `Highlight key sections and add
|
||||
notes as you read. You can access your highlights and notes any time
|
||||
— they stay with your articles forever.`,
|
||||
},
|
||||
|
|
@ -123,7 +104,7 @@ const sections = [
|
|||
en: {
|
||||
titleText: `Sync with your second brain.`,
|
||||
descriptionText: `Omnivore syncs with popular Personal Knowledge Management systems
|
||||
including Logseq and Obsidian, so you can pull all your saved
|
||||
including Logseq, Obsidian, and Notion, so you can pull all your saved
|
||||
reading, highlights, and notes into your second brain.`,
|
||||
},
|
||||
zh: {
|
||||
|
|
@ -137,7 +118,7 @@ const sections = [
|
|||
en: {
|
||||
titleText: `Listen to your reading with text-to-speech.`,
|
||||
descriptionText: `Work through your to-be-read list and give your eyes a break with
|
||||
TTS, exclusively in the Omnivore app for iOS. Realistic,
|
||||
text-to-speech, exclusively in the Omnivore app for iOS. Realistic,
|
||||
natural-sounding AI voices will read any saved article aloud.`,
|
||||
},
|
||||
zh: {
|
||||
|
|
@ -209,41 +190,6 @@ export function LandingSectionsContainer(
|
|||
/>
|
||||
)
|
||||
})}
|
||||
|
||||
<VStack
|
||||
alignment="center"
|
||||
css={{
|
||||
width: '100vw',
|
||||
backgroundColor: '#fff',
|
||||
paddingBottom: '40px',
|
||||
marginTop: '40px',
|
||||
borderTop: '1px solid var(--colors-omnivoreYellow)',
|
||||
borderBottom: '1px solid var(--colors-omnivoreYellow)',
|
||||
'@md': {
|
||||
marginTop: 0,
|
||||
},
|
||||
}}
|
||||
>
|
||||
{props.lang == 'en' && (
|
||||
<Box
|
||||
as="p"
|
||||
css={{
|
||||
color: '#3D3D3D',
|
||||
fontWeight: '700',
|
||||
fontSize: '2.5rem',
|
||||
lineHeight: '1.25',
|
||||
textAlign: 'center',
|
||||
marginBottom: '40px',
|
||||
'@mdDown': {
|
||||
fontSize: '2rem',
|
||||
},
|
||||
}}
|
||||
>
|
||||
Get Started With Omnivore Today
|
||||
</Box>
|
||||
)}
|
||||
<GetStartedButton lang={props.lang} />
|
||||
</VStack>
|
||||
</VStack>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ export const NavMenuFooter = (props: NavMenuFooterProps): JSX.Element => {
|
|||
position: 'fixed',
|
||||
bottom: '0%',
|
||||
alignItems: 'center',
|
||||
|
||||
backgroundColor: '$thBackground2',
|
||||
width: LIBRARY_LEFT_MENU_WIDTH,
|
||||
overflowY: 'auto',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { ReactNode, useEffect, useMemo, useRef, useState } from "react"
|
||||
import { ReactNode, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { StyledText } from '../../elements/StyledText'
|
||||
import { Box, HStack, SpanBox, VStack } from '../../elements/LayoutPrimitives'
|
||||
import { Button } from '../../elements/Button'
|
||||
|
|
@ -30,8 +30,8 @@ import { OutlinedLabelChip } from '../../elements/OutlinedLabelChip'
|
|||
import { NewsletterIcon } from '../../elements/icons/NewsletterIcon'
|
||||
import { Dropdown, DropdownOption } from '../../elements/DropdownElements'
|
||||
import { useRouter } from 'next/router'
|
||||
import { DiscoverIcon } from "../../elements/icons/DiscoverIcon"
|
||||
import { escapeQuotes } from "../../../utils/helper"
|
||||
import { DiscoverIcon } from '../../elements/icons/DiscoverIcon'
|
||||
import { escapeQuotes } from '../../../utils/helper'
|
||||
|
||||
export const LIBRARY_LEFT_MENU_WIDTH = '275px'
|
||||
|
||||
|
|
@ -158,9 +158,6 @@ export function LibraryFilterMenu(props: LibraryFilterMenuProps): JSX.Element {
|
|||
</Box>
|
||||
<LibraryNav {...props} />
|
||||
<Shortcuts {...props} />
|
||||
{/* <SavedSearches {...props} savedSearches={savedSearches} />
|
||||
<Subscriptions {...props} subscriptions={subscriptions} />
|
||||
<Labels {...props} labels={labels} /> */}
|
||||
<NavMenuFooter {...props} />
|
||||
<Box css={{ height: '250px ' }} />
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ export const { styled, css, theme, getCssText, globalCss, keyframes, config } =
|
|||
// Brand Colors
|
||||
omnivoreRed: '#FA5E4A;',
|
||||
omnivoreGray: '#3D3D3D',
|
||||
omnivoreYellow: 'rgb(255, 234, 159)',
|
||||
omnivoreYellow: '#FFEAA0',
|
||||
omnivoreLightGray: 'rgb(125, 125, 125)',
|
||||
omnivoreCtaYellow: 'rgb(255, 210, 52)',
|
||||
searchActiveOutline: 'rgb(255, 210, 52)',
|
||||
|
|
|
|||
|
|
@ -12,24 +12,21 @@ export type RequestContext = {
|
|||
}
|
||||
}
|
||||
|
||||
type RequestHeaders = {
|
||||
authorization?: string
|
||||
pendingUserAuth?: string
|
||||
}
|
||||
|
||||
function requestHeaders(): RequestHeaders {
|
||||
function requestHeaders(): Record<string, string> {
|
||||
const authToken = window?.localStorage.getItem('authToken') || undefined
|
||||
const pendingAuthToken =
|
||||
window?.localStorage.getItem('pendingUserAuth') || undefined
|
||||
|
||||
if (authToken) {
|
||||
return {
|
||||
'X-OmnivoreClient': 'web',
|
||||
authorization: authToken,
|
||||
}
|
||||
}
|
||||
|
||||
if (pendingAuthToken) {
|
||||
return {
|
||||
'X-OmnivoreClient': 'web',
|
||||
pendingUserAuth: pendingAuthToken,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { useRouter } from 'next/router'
|
||||
import Script from 'next/script'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { LoginLayout } from './../components/templates/LoginLayout'
|
||||
import { parseErrorCodes } from '../lib/queryParamParser'
|
||||
|
|
@ -8,8 +7,9 @@ import { formatMessage } from '../locales/en/messages'
|
|||
|
||||
export default function Login(): JSX.Element {
|
||||
const router = useRouter()
|
||||
const [errorMessage, setErrorMessage] =
|
||||
useState<string | undefined>(undefined)
|
||||
const [errorMessage, setErrorMessage] = useState<string | undefined>(
|
||||
undefined
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (!router.isReady) return
|
||||
|
|
@ -30,10 +30,6 @@ export default function Login(): JSX.Element {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Script
|
||||
src="https://accounts.google.com/gsi/client"
|
||||
strategy="afterInteractive"
|
||||
/>
|
||||
<PageMetaData
|
||||
title="Welcome to Omnivore"
|
||||
path="/login"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,24 @@
|
|||
import React from 'react'
|
||||
import { SettingsLayout } from '../../../components/templates/SettingsLayout'
|
||||
import MobileInstallHelp from '../../../components/elements/MobileInstallHelp'
|
||||
import IOSInstallHelp from '../../../components/elements/IOSInstallHelp'
|
||||
import ExtensionInstallHelp from '../../../components/elements/ExtensionsInstallHelp'
|
||||
import { Box } from '../../../components/elements/LayoutPrimitives'
|
||||
import AndroidInstallHelp from '../../../components/elements/AndroidInstallHelp'
|
||||
|
||||
const Divider = (): JSX.Element => {
|
||||
return (
|
||||
<Box
|
||||
css={{
|
||||
my: '$2',
|
||||
'@lg': {
|
||||
my: '12px',
|
||||
height: '1px',
|
||||
backgroundColor: '$grayBorder',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default function Installation(): JSX.Element {
|
||||
return (
|
||||
|
|
@ -22,17 +38,10 @@ export default function Installation(): JSX.Element {
|
|||
},
|
||||
}}
|
||||
>
|
||||
<MobileInstallHelp />
|
||||
<Box
|
||||
css={{
|
||||
my: '$2',
|
||||
'@lg': {
|
||||
my: '12px',
|
||||
height: '1px',
|
||||
backgroundColor: '$grayBorder',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<IOSInstallHelp />
|
||||
<Divider />
|
||||
<AndroidInstallHelp />
|
||||
<Divider />
|
||||
<ExtensionInstallHelp />
|
||||
</Box>
|
||||
</SettingsLayout>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import React from 'react'
|
||||
import { SettingsLayout } from '../../../components/templates/SettingsLayout'
|
||||
import MobileInstallHelp from '../../../components/elements/MobileInstallHelp'
|
||||
import IOSInstallHelp from '../../../components/elements/IOSInstallHelp'
|
||||
|
||||
export default function Mobile(): JSX.Element {
|
||||
return (
|
||||
<SettingsLayout title="Mobile Installation">
|
||||
<MobileInstallHelp />
|
||||
<IOSInstallHelp />
|
||||
</SettingsLayout>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 200 KiB After Width: | Height: | Size: 597 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 400 KiB |
|
|
@ -1,19 +1,20 @@
|
|||
import { ComponentStory, ComponentMeta } from '@storybook/react'
|
||||
import MobileInstallHelp from '../components/elements/MobileInstallHelp'
|
||||
import IOSInstallHelp from '../components/elements/IOSInstallHelp'
|
||||
import { Box } from '../components/elements/LayoutPrimitives'
|
||||
|
||||
export default {
|
||||
title: 'Components/MobileInstallHelp',
|
||||
component: MobileInstallHelp,
|
||||
component: IOSInstallHelp,
|
||||
argTypes: {
|
||||
onboarding: {
|
||||
description: 'Changes the appearence of the component to match onboarding page designs.',
|
||||
description:
|
||||
'Changes the appearence of the component to match onboarding page designs.',
|
||||
control: { type: 'boolean' },
|
||||
},
|
||||
},
|
||||
} as ComponentMeta<typeof MobileInstallHelp>
|
||||
} as ComponentMeta<typeof IOSInstallHelp>
|
||||
|
||||
const Template: ComponentStory<typeof MobileInstallHelp> = (args) => (
|
||||
const Template: ComponentStory<typeof IOSInstallHelp> = (args) => (
|
||||
<Box
|
||||
css={{
|
||||
maxWidth: '50rem',
|
||||
|
|
@ -25,7 +26,7 @@ const Template: ComponentStory<typeof MobileInstallHelp> = (args) => (
|
|||
boxShadow: '0px 3px 11px 0px #201F1D0A',
|
||||
}}
|
||||
>
|
||||
<MobileInstallHelp {...args} />
|
||||
<IOSInstallHelp {...args} />
|
||||
</Box>
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue