diff options
Diffstat (limited to '')
-rw-r--r-- | src/views/Landing/FeaturesSection.jsx | 139 | ||||
-rw-r--r-- | src/views/Landing/HomeHero.jsx | 186 | ||||
-rw-r--r-- | src/views/Landing/Landing.jsx | 32 | ||||
-rw-r--r-- | src/views/Landing/PricingSection.jsx | 179 |
4 files changed, 536 insertions, 0 deletions
diff --git a/src/views/Landing/FeaturesSection.jsx b/src/views/Landing/FeaturesSection.jsx new file mode 100644 index 0000000..a7da1f0 --- /dev/null +++ b/src/views/Landing/FeaturesSection.jsx @@ -0,0 +1,139 @@ +import { + AutoAwesomeMosaicOutlined, + AutoAwesomeRounded, + CodeRounded, + GroupRounded, + HistoryRounded, + Webhook, +} from '@mui/icons-material' +import Card from '@mui/joy/Card' +import Container from '@mui/joy/Container' +import Typography from '@mui/joy/Typography' +import { styled } from '@mui/system' + +const FeatureIcon = styled('div')({ + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + backgroundColor: '#f0f0f0', // Adjust the background color as needed + borderRadius: '50%', + minWidth: '60px', + height: '60px', + marginRight: '16px', +}) + +const CardData = [ + { + title: 'Open Source & Transparent', + headline: 'Built for the Community', + description: + 'Donetick is a community-driven, open-source project. Contribute, customize, and make task management truly yours.', + icon: CodeRounded, + }, + { + title: 'Circles: Your Task Hub', + headline: 'Share & Conquer Together', + description: + 'Create circles for your family, friends, or team. Easily share tasks and track progress within each group.', + icon: GroupRounded, + }, + { + title: 'Track Your Progress', + headline: "See Who's Done What", + description: + 'View a history of task completion for each member of your circles. Celebrate successes and stay on top of your goals.', + icon: HistoryRounded, + }, + { + title: 'Automated Chore Scheduling', + headline: 'Fully Customizable Recurring Tasks', + description: + 'Set up chores to repeat daily, weekly, or monthly. Donetick will automatically assign and track each task for you.', + icon: AutoAwesomeMosaicOutlined, + }, + { + title: 'Automated Task Assignment', + headline: 'Share Responsibilities Equally', + description: + 'can automatically assigns tasks to each member of your circle. Randomly or based on past completion.', + icon: AutoAwesomeRounded, + }, + { + title: 'Integrations & Webhooks', + headline: 'API & 3rd Party Integrations', + description: + 'Connect Donetick with your favorite apps and services. Trigger tasks based on events from other platforms.', + icon: Webhook, + }, +] + +function Feature2({ icon: Icon, title, headline, description, index }) { + return ( + <Card + variant='plain' + sx={{ textAlign: 'left', p: 2 }} + data-aos-delay={100 * index} + data-aos-anchor='[data-aos-id-features2-blocks]' + data-aos='fade-up' + > + <div style={{ display: 'flex', alignItems: 'center' }}> + <FeatureIcon> + <Icon + color='primary' + style={{ Width: '30px', height: '30px' }} + stroke={1.5} + /> + </FeatureIcon> + <div> + {/* Changes are within this div */} + <Typography level='h4' mt={1} mb={0.5}> + {title} + </Typography> + <Typography level='body-sm' color='neutral' lineHeight={1.4}> + {headline} + </Typography> + </div> + </div> + <Typography level='body-md' color='neutral' lineHeight={1.6}> + {description} + </Typography> + </Card> + ) +} + +function FeaturesSection() { + const features = CardData.map((feature, index) => ( + <Feature2 + icon={feature.icon} + title={feature.title} + headline={feature.headline} + description={feature.description} + index={index} + key={index} + /> + )) + + return ( + <Container sx={{ textAlign: 'center' }}> + <Typography level='h4' mt={2} mb={4}> + Donetick + </Typography> + + <Container maxWidth={'lg'} sx={{ mb: 8 }}> + <Typography level='body-md' color='neutral'> + Navigate personal growth with genuine insights, thoughtful privacy, + and actionable steps tailored just for you. + </Typography> + </Container> + + <div + className='align-center mt-8 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3' + data-aos-id-features2-blocks + > + {features} + </div> + </Container> + ) +} + +export default FeaturesSection diff --git a/src/views/Landing/HomeHero.jsx b/src/views/Landing/HomeHero.jsx new file mode 100644 index 0000000..a96374a --- /dev/null +++ b/src/views/Landing/HomeHero.jsx @@ -0,0 +1,186 @@ +/* eslint-disable tailwindcss/no-custom-classname */ +// import { StyledButton } from '@/components/styled-button' +import { Button } from '@mui/joy' +import Typography from '@mui/joy/Typography' +import Box from '@mui/material/Box' +import Grid from '@mui/material/Grid' +import React from 'react' +import { useNavigate } from 'react-router-dom' + +import Logo from '@/assets/logo.svg' +import screenShotMyChore from '@/assets/screenshot-my-chore.png' +import { GitHub } from '@mui/icons-material' + +const HomeHero = () => { + const navigate = useNavigate() + const HERO_TEXT_THAT = [ + // 'Donetick simplifies the entire process, from scheduling and reminders to automatic task assignment and progress tracking.', + // 'Donetick is the intuitive task and chore management app designed for groups. Take charge of shared responsibilities, automate your workflow, and achieve more together.', + 'An open-source, user-friendly app for managing tasks and chores, featuring customizable options to help you and others stay organized', + ] + + const [heroTextIndex, setHeroTextIndex] = React.useState(0) + + React.useEffect(() => { + // const intervalId = setInterval( + // () => setHeroTextIndex(index => index + 1), + // 4000, // every 4 seconds + // ) + // return () => clearTimeout(intervalId) + }, []) + + const Title = () => ( + <Box + sx={{ + textAlign: 'center', + display: 'flex', + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'center', + }} + > + <img src={Logo} width={'100px'} /> + <Typography level='h1' fontSize={58} fontWeight={800}> + <span + data-aos-delay={50 * 1} + data-aos-anchor='[data-aos-id-hero]' + data-aos='fade-up' + > + Done + </span> + <span + data-aos-delay={100 * 3} + data-aos-anchor='[data-aos-id-hero]' + data-aos='fade-up' + style={{ + color: '#06b6d4', + }} + > + tick + </span> + </Typography> + </Box> + ) + + const Subtitle = () => ( + <Typography + level='h2' + fontWeight={500} + textAlign={'center'} + className='opacity-70' + data-aos-delay={100 * 5} + data-aos-anchor='[data-aos-id-hero]' + data-aos='zoom-in' + > + Simplify Tasks & Chores, Together. + </Typography> + ) + + const CTAButton = () => ( + <Button + data-aos-delay={100 * 2} + data-aos-anchor='[data-aos-id-hero]' + data-aos='fade-up' + variant='solid' + size='lg' + sx={{ + py: 1.25, + px: 5, + fontSize: 20, + mt: 2, + borderWidth: 3, + // boxShadow: '0px 0px 24px rgba(81, 230, 221, 0.5)', + transition: 'all 0.20s', + }} + className='hover:scale-105' + onClick={() => { + // if the url is donetick.com then navigate to app.donetick.com/my/chores + // else navigate to /my/chores + if (window.location.hostname === 'donetick.com') { + window.location.href = 'https://app.donetick.com/my/chores' + } else { + navigate('/my/chores') + } + }} + > + Get started + </Button> + ) + + return ( + // <Box + // id='hero' + // className='grid min-h-[90vh] w-full place-items-center px-4 py-12' + // data-aos-id-hero + // > + <Grid container spacing={16} sx={{ py: 12 }}> + <Grid item xs={12} md={7}> + <Title /> + <div className='flex flex-col gap-6'> + <Subtitle /> + + <Typography + level='title-lg' + textAlign={'center'} + fontSize={28} + // textColor={'#06b6d4'} + color='primary' + data-aos-delay={100 * 1} + data-aos-anchor='[data-aos-id-hero]' + data-aos='fade-up' + > + {`"${HERO_TEXT_THAT[heroTextIndex % HERO_TEXT_THAT.length]}"`} + </Typography> + + <Box className='flex w-full justify-center'> + <CTAButton /> + <Button + data-aos-delay={100 * 2.5} + data-aos-anchor='[data-aos-id-hero]' + data-aos='fade-up' + variant='soft' + size='lg' + sx={{ + py: 1.25, + px: 5, + ml: 2, + fontSize: 20, + mt: 2, + borderWidth: 3, + // boxShadow: '0px 0px 24px rgba(81, 230, 221, 0.5)', + transition: 'all 0.20s', + }} + className='hover:scale-105' + onClick={() => { + // new window open to https://github.com/Donetick: + window.open('https://github.com/donetick', '_blank') + }} + startDecorator={<GitHub />} + > + Github + </Button> + </Box> + </div> + </Grid> + + <Grid item xs={12} md={5}> + <div className='flex justify-center'> + <img + src={screenShotMyChore} + width={'100%'} + style={{ + maxWidth: 300, + }} + height={'auto'} + alt='Hero img' + data-aos-delay={100 * 2} + data-aos-anchor='[data-aos-id-hero]' + data-aos='fade-left' + /> + </div> + </Grid> + </Grid> + ) +} + +export default HomeHero diff --git a/src/views/Landing/Landing.jsx b/src/views/Landing/Landing.jsx new file mode 100644 index 0000000..2041e42 --- /dev/null +++ b/src/views/Landing/Landing.jsx @@ -0,0 +1,32 @@ +import { Container } from '@mui/joy' +import AOS from 'aos' +import 'aos/dist/aos.css' +import { useEffect, useState } from 'react' +import { useNavigate } from 'react-router-dom' +import FeaturesSection from './FeaturesSection' +import HomeHero from './HomeHero' +import PricingSection from './PricingSection' +const Landing = () => { + const Navigate = useNavigate() + const getCurrentUser = () => { + return JSON.parse(localStorage.getItem('user')) + } + const [users, setUsers] = useState([]) + const [currentUser, setCurrentUser] = useState(getCurrentUser()) + + useEffect(() => { + AOS.init({ + once: false, // whether animation should happen only once - while scrolling down + }) + }, []) + + return ( + <Container className='flex h-full items-center justify-center'> + <HomeHero /> + <FeaturesSection /> + <PricingSection /> + </Container> + ) +} + +export default Landing diff --git a/src/views/Landing/PricingSection.jsx b/src/views/Landing/PricingSection.jsx new file mode 100644 index 0000000..634cf7d --- /dev/null +++ b/src/views/Landing/PricingSection.jsx @@ -0,0 +1,179 @@ +/* eslint-disable react/jsx-key */ +import { CheckRounded } from '@mui/icons-material' +import { Box, Button, Card, Container, Typography } from '@mui/joy' +import React from 'react' +import { useNavigate } from 'react-router-dom' + +const PricingSection = () => { + const navigate = useNavigate() + const FEATURES_FREE = [ + ['Create Tasks and Chores', <CheckRounded color='primary' />], + ['Limited Task History', <CheckRounded color='primary' />], + ['Circle up to two members', <CheckRounded color='primary' />], + ] + const FEATURES_PREMIUM = [ + ['All Basic Features', <CheckRounded color='primary' />], + ['Hosted on DoneTick servers', <CheckRounded color='primary' />], + ['Up to 8 Circle Members', <CheckRounded color='primary' />], + [ + 'Notification through Telegram (Discord coming soon)', + <CheckRounded color='primary' />, + ], + ['Unlimited History', <CheckRounded color='primary' />], + [ + 'All circle members get the same features as the owner', + <CheckRounded color='primary' />, + ], + ] + const FEATURES_YEARLY = [ + // ['All Basic Features', <CheckRounded color='primary' />], + // ['Up to 8 Circle Members', <CheckRounded color='primary' />], + ['Notification through Telegram bot', <CheckRounded color='primary' />], + ['Custom Webhook/API Integration', <CheckRounded color='primary' />], + ['Unlimited History', <CheckRounded color='primary' />], + + ['Priority Support', <CheckRounded color='primary' />], + ] + const PRICEITEMS = [ + { + title: 'Basic', + description: + 'Hosted on Donetick servers, supports up to 2 circle members and includes all the features of the free plan.', + price: 0, + previousPrice: 0, + interval: 'month', + discount: false, + features: FEATURES_FREE, + }, + + { + title: 'Plus', + description: + // 'Supports up to 8 circle members and includes all the features of the Basic plan.', + 'Hosted on Donetick servers, supports up to 8 circle members and includes all the features of the Basic plan.', + price: 30.0, + // previousPrice: 76.89, + interval: 'year', + // discount: true, + features: FEATURES_YEARLY, + }, + ] + return ( + <Container + sx={{ textAlign: 'center', mb: 2 }} + maxWidth={'lg'} + id='pricing-tiers' + > + <Typography level='h4' mt={2} mb={2}> + Pricing + </Typography> + + <Container maxWidth={'sm'} sx={{ mb: 8 }}> + <Typography level='body-md' color='neutral'> + Choose the plan that works best for you. + </Typography> + </Container> + + <div + className='mt-8 grid grid-cols-1 gap-2 sm:grid-cols-1 lg:grid-cols-2' + data-aos-id-pricing + > + {PRICEITEMS.map((pi, index) => ( + <Card + key={index} + data-aos-delay={50 * (1 + index)} + data-aos-anchor='[data-aos-id-pricing]' + data-aos='fade-up' + className='hover:bg-white dark:hover:bg-teal-900' + sx={{ + textAlign: 'center', + p: 5, + minHeight: 400, + // maxWidth: 400, + display: 'flex', + flexDirection: 'column', + justifyContent: 'space-between', + // when top reach the top change the background color: + '&:hover': { + // backgroundColor: '#FFFFFF', + boxShadow: '0px 0px 20px rgba(0, 0, 0, 0.1)', + }, + }} + > + <Box + display='flex' + flexDirection='column' + justifyContent='flex-start' // Updated property + alignItems='center' + > + <Typography level='h2'>{pi.title}</Typography> + <Typography level='body-md'>{pi.description}</Typography> + </Box> + <Box + display='flex' + flexDirection='column' + justifyContent='center' + alignItems='center' + > + <Box + display='flex' + flexDirection='row' + alignItems='baseline' + sx={{ my: 4 }} + > + {pi.discount && ( + <Typography + level='h3' + component='span' + sx={{ textDecoration: 'line-through', opacity: 0.5 }} + > + ${pi.previousPrice} + </Typography> + )} + <Typography level='h2' component='span'> + ${pi.price} + </Typography> + <Typography level='body-md' component='span'> + / {pi.interval} + </Typography> + </Box> + + <Typography level='title-md'>Features</Typography> + {pi.features.map(feature => ( + <Typography + startDecorator={feature[1]} + level='body-md' + color='neutral' + lineHeight={1.6} + > + {feature[0]} + </Typography> + ))} + + {/* Here start the test */} + <div style={{ marginTop: 'auto' }}> + <Button + sx={{ mt: 5 }} + onClick={() => { + navigate('/settings#account') + }} + > + Get Started + </Button> + <Typography + level='body-md' + color='neutral' + lineHeight={1.6} + ></Typography> + </div> + </Box> + </Card> + ))} + </div> + + {/* Here start the test */} + </Container> + ) +} + +export default PricingSection |