diff --git a/packages/api/src/utils/usernamePolicy.ts b/packages/api/src/utils/usernamePolicy.ts index 20bd5fe32..853be928a 100644 --- a/packages/api/src/utils/usernamePolicy.ts +++ b/packages/api/src/utils/usernamePolicy.ts @@ -82,6 +82,7 @@ const RESERVED_NAMES = new Set([ 'jobs', 'join', 'json', + 'landing', 'language', 'languages', 'lists', diff --git a/packages/web/components/elements/images/CurvedUnderlineIcon.tsx b/packages/web/components/elements/images/CurvedUnderlineIcon.tsx new file mode 100644 index 000000000..32e42e4a2 --- /dev/null +++ b/packages/web/components/elements/images/CurvedUnderlineIcon.tsx @@ -0,0 +1,25 @@ +type CurvedUnderlineIconProps = { + size?: string + fillColor?: string + } + + export function CurvedUnderlineIcon({ + fillColor = '#FF9B3E', + size, + }: CurvedUnderlineIconProps): JSX.Element { + return ( + + + + ) + } + \ No newline at end of file diff --git a/packages/web/components/templates/landing/LandingFooter.tsx b/packages/web/components/templates/landing/LandingFooter.tsx new file mode 100644 index 000000000..9d0e87422 --- /dev/null +++ b/packages/web/components/templates/landing/LandingFooter.tsx @@ -0,0 +1,136 @@ +import { OmnivoreNameLogo } from '../../elements/images/OmnivoreNameLogo'; +import Link from 'next/link' +import Image from 'next/image' +import { Box, HStack } from '../../elements/LayoutPrimitives'; +import { GithubLogo, DiscordLogo, TwitterLogo } from 'phosphor-react' + +const containerStyles = { + padding: '5vw', + background: '#252525', + py: 60, + pb: 105, + width: '100%', + '@md': { + paddingLeft: '6vw', + }, + '@xl': { + paddingLeft: '140px', + } +} + +const titleStyles = { + maxWidth: 330, + fontWeight: 'normal', + fontSize: 18, + lineHeight: '27px', + color: '#FFFFFF', + mb: 45, + '@mdDown': { + fontSize: '3vw' + } +} + +const socialsContainerStyles = { + maxWidth: 140, + marginBottom: 79 +} + +const copyrightStyles = { + maxWidth: 330, + fontWeight: 'normal', + fontSize: 18, + lineHeight: '27px', + color: '#5F5E58' +} + +const sectionOne = { + width: '60%' +} +const sectionTwo = { + width: '40%', + pt: 10 +} + +const contactStyles = { + fontWeight: '700', + fontSize: 36, + lineHeight: '39px', + color: 'white', + '@mdDown': { + fontSize: 26, + } +} +const supportStyles = { + fontSize: 24, + lineHeight: '36px', + color: 'white', + '@mdDown': { + fontSize: '3vw' + } +} + +const imageStyles = { + maxWidth: 190, + width: '100%', +} + +const socialIconContainerStyles = { + maxWidth: 32, + maxHeight: 32, +} + +export function LandingFooter(): JSX.Element { + return ( + + + Everything you read. Safe, organized, and easy to share. + + + + + + + + + + + + + + + + + + + + + + + + © 2022 Omnivore + + + + + + Download on the App Store + + + {/* + + + app-store + + + */} + + + Contact + + + support@omnivore.app + + + + ) +} diff --git a/packages/web/components/templates/landing/LandingHeader.tsx b/packages/web/components/templates/landing/LandingHeader.tsx new file mode 100644 index 000000000..54da7fa1a --- /dev/null +++ b/packages/web/components/templates/landing/LandingHeader.tsx @@ -0,0 +1,50 @@ +import Link from 'next/link' +import { Box, SpanBox } from '../../elements/LayoutPrimitives' +import { OmnivoreNameLogo } from '../../elements/images/OmnivoreNameLogo' + +const containerStyles = { + position: 'absolute', + top: 0, + left: 0, + p: '0px 15px 0px 15px', + height: '68px', + minHeight: '68px', + display: 'flex', + alignItems: 'center', + '@md': { width: '50%' }, + '@xsDown': { height: '48px' }, + justifyContent: 'space-between', + width: '100%', +} + +const linkStyles = { + marginLeft: 'auto', + verticalAlign: 'middle', + cursor: 'pointer', + lineHeight: '100%', +} + +const textStyles = { + pt: '5px', + pr: '6px', + fontSize: 24, + lineHeight: '24px', + fontWeight: 'normal' +} + +export function LandingHeader(): JSX.Element { + return ( + + + + + + + Log in + + + + + + ) +} diff --git a/packages/web/components/templates/landing/LandingSection.tsx b/packages/web/components/templates/landing/LandingSection.tsx new file mode 100644 index 000000000..02ed69d70 --- /dev/null +++ b/packages/web/components/templates/landing/LandingSection.tsx @@ -0,0 +1,90 @@ +import { HStack, VStack, Box } from '../../elements/LayoutPrimitives' +import { CSS, styled } from '@stitches/react' + +type LandingSectionProps = { + titleText: string, + descriptionText: string, + icon: React.ReactElement, + image: React.ReactElement, + containerStyles?: CSS, +} + +const MainContainer = styled(HStack, { + width: '100%', +}) + +const titleTextStyles = { + fontWeight: '700', + color: '#3D3D3D', + lineHeight: '53px', + '@mdDown': { + fontSize: 24, + }, + '@md': { + fontSize: '$5', + }, + '@xl': { + fontSize: 45, + } +} + +const descriptionTextStyles = { + color: 'rgb(125, 125, 125)', +} + +const iconContainerStyles = { + width: 56, + height: 56, + background: 'white', + border: '1px solid rgba(61, 61, 61, 0.08)', + boxSizing: 'border-box', + borderRadius: '50%', + '@mdDown': { + width: 32, + height: 32, + padding: 5, + }, +} + +const imageContainerStyles = { + width: '50%', + '@mdDown': { + width: 0, + display: 'none', + } +} + +const layoutStyles = { + width: '50%', + padding: 10, + '@mdDown': { + width: '100%', + } +} + +const innerLayoutStyles = { + maxWidth: 480, + alignSelf: 'center', + '@mdDown': { + alignItems: 'center', + }, +} + +export function LandingSection(props: LandingSectionProps): JSX.Element { + return ( + + + + + {props.icon} + + {props.titleText} + {props.descriptionText} + + + + {props.image} + + + ) +} diff --git a/packages/web/components/templates/landing/LandingSectionsContainer.tsx b/packages/web/components/templates/landing/LandingSectionsContainer.tsx new file mode 100644 index 000000000..6fd01529b --- /dev/null +++ b/packages/web/components/templates/landing/LandingSectionsContainer.tsx @@ -0,0 +1,210 @@ +import Link from 'next/link' +import { VStack, Box, SpanBox } from '../../elements/LayoutPrimitives' +import { CurvedUnderlineIcon } from '../../elements/images/CurvedUnderlineIcon' +import { Button } from '../../elements/Button' +import { MagnifyingGlass, Palette, MegaphoneSimple, Binoculars, ArrowRight } from 'phosphor-react' +import { LandingSection } from './LandingSection' + +const buttonStyles = { + display: 'flex', + borderRadius: 4, + px: 30, + background: 'rgb(255, 210, 52)', + color: '#3D3D3D' +} + +const arrowStyles = { + marginLeft: 10, + padding: 2, +} + +export function GetStartedButton(): JSX.Element { + return ( + + ) +} + +const containerStyles = { + px: '2vw', + pt: 100, + pb: 100, + width: '100%', + 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, + }, + '@md': { + px: '6vw', + }, + '@xl': { + px: '100px', + } +} + +const titleStyles = { + fontWeight: '600', + fontSize: '24', + textAlign: 'center', + lineHeight: '36px', + color: '#FF9B3E', + '@mdDown': { + fontSize: 16, + letterSpacing: '0.02em' + } +} + +const subTitleText = { + fontSize: 64, + maxWidth: 590, + fontWeight: '700', + textAlign: 'center', + lineHeight: '70px', + mb: 30, + '@mdDown': { + maxWidth: 295, + fontSize: 32, + lineHeight: '40px', + } +} + +const reversedSectionStyles = { + flexDirection: 'row-reverse', + marginBottom: 20 +} + +const callToActionStyles = { + background: 'white', + borderRadius: '24px', + boxSizing: 'border-box', + border: '1px solid #D8D7D5', + boxShadow: '0px 7px 8px rgba(32, 31, 29, 0.03), 0px 18px 24px rgba(32, 31, 29, 0.03)', + padding: 40, + height: 330, + '@mdDown': { + display: 'none', + }, + '@md': { + width: '100%', + }, + '@xl': { + width: '95%', + }, +} + +const callToActionText = { + color: '#3D3D3D', + fontWeight: '700', + fontSize: 64, + lineHeight: '70px', + textAlign: 'center', + maxWidth: 500 +} + +const underlineIconStyles = { + height: '5px', + alignSelf: 'normal', + position: 'relative', + bottom: 20, +} + +type LandingSectionsContainerProps = { + hideFirst?: boolean, + hideSecond?: boolean, + hideThird?: boolean, + hideFourth?: boolean, +} + +export function LandingSectionsContainer({ + hideFirst = false, + hideSecond = false, + hideThird = true, + hideFourth = true, +}: LandingSectionsContainerProps): JSX.Element { + const iconColor = 'rgb(255, 210, 52)' + return ( + + + + This is Omnivore + + + + + + + Collect and share the best of the web + + {!hideFirst && ( + + } + icon={} + /> + )} + {!hideSecond && ( + + } + icon={} + containerStyles={reversedSectionStyles} + /> + )} + {!hideThird && ( + + } + icon={} + /> + )} + {!hideFourth && ( + + } + icon={} + containerStyles={reversedSectionStyles} + /> + )} + + + Get started with Omnivore today + + + + + ) +} diff --git a/packages/web/pages/landing.tsx b/packages/web/pages/landing.tsx new file mode 100644 index 000000000..a7cb1bcbb --- /dev/null +++ b/packages/web/pages/landing.tsx @@ -0,0 +1,51 @@ +import { VStack, Box } from './../components/elements/LayoutPrimitives' +import { LandingSectionsContainer, GetStartedButton } from '../components/templates/landing/LandingSectionsContainer' +import { LandingHeader } from '../components/templates/landing/LandingHeader' +import { LandingFooter } from '../components/templates/landing/LandingFooter' + +const mobileContainerStyles = { + maxWidth: 430, + alignSelf: 'center', + px: 10, + display: 'none', + marginTop: 60, + '@mdDown': { + display: 'flex', + } +} + +const headingStyles = { + fontWeight: '700', + fontSize: 42, + lineHeight: '46px', + mb: 16 +} + +const subHeadingStyles = { + fontWeight: '700', + fontSize: 24, + lineHeight: '36px', + color: '#5F5E58', + mb: 32, +} + +export default function LandingPage(): JSX.Element { + return ( + <> + + + + Collect and share the best of the web + + Everything you read. Safe, organized, and easy to share. + + + + + + + + + + ) +} diff --git a/packages/web/public/static/landing/landing-1.png b/packages/web/public/static/landing/landing-1.png new file mode 100644 index 000000000..f199bf765 Binary files /dev/null and b/packages/web/public/static/landing/landing-1.png differ diff --git a/packages/web/public/static/landing/landing-1@2x.png b/packages/web/public/static/landing/landing-1@2x.png new file mode 100644 index 000000000..299ab5d2e Binary files /dev/null and b/packages/web/public/static/landing/landing-1@2x.png differ diff --git a/packages/web/public/static/landing/landing-2.png b/packages/web/public/static/landing/landing-2.png new file mode 100644 index 000000000..b602ca09b Binary files /dev/null and b/packages/web/public/static/landing/landing-2.png differ diff --git a/packages/web/public/static/landing/landing-2@2x.png b/packages/web/public/static/landing/landing-2@2x.png new file mode 100644 index 000000000..2247052f0 Binary files /dev/null and b/packages/web/public/static/landing/landing-2@2x.png differ diff --git a/packages/web/public/static/landing/landing-3.png b/packages/web/public/static/landing/landing-3.png new file mode 100644 index 000000000..62c71adbf Binary files /dev/null and b/packages/web/public/static/landing/landing-3.png differ diff --git a/packages/web/public/static/landing/landing-3@2x.png b/packages/web/public/static/landing/landing-3@2x.png new file mode 100644 index 000000000..07cf79bea Binary files /dev/null and b/packages/web/public/static/landing/landing-3@2x.png differ diff --git a/packages/web/public/static/landing/landing-4.png b/packages/web/public/static/landing/landing-4.png new file mode 100644 index 000000000..3032d15b4 Binary files /dev/null and b/packages/web/public/static/landing/landing-4.png differ diff --git a/packages/web/public/static/landing/landing-4@2x.png b/packages/web/public/static/landing/landing-4@2x.png new file mode 100644 index 000000000..f8d86f031 Binary files /dev/null and b/packages/web/public/static/landing/landing-4@2x.png differ diff --git a/packages/web/public/static/media/googlePlayBadge.png b/packages/web/public/static/media/googlePlayBadge.png new file mode 100644 index 000000000..a18b1b88b Binary files /dev/null and b/packages/web/public/static/media/googlePlayBadge.png differ