feat: Add notification types and enhance color management
- Introduced NOTIFICATION_TYPE constants for pre-due, due date, and post-due notifications in Colors.jsx. - Updated HistoryCard.jsx to utilize TASK_COLOR for chip colors based on task status. - Created DemoCalendar.jsx to showcase a visual task calendar with sample chore data. - Enhanced DemoMyChore.jsx to include status for demo tasks. - Added DemoNotificationTemplate.jsx for demonstrating smart notification scheduling. - Revamped FeaturesSection.jsx to reflect updated feature descriptions and icons. - Updated Footer.jsx to link to the correct API reference documentation. - Improved GettingStarted.jsx with new mobile app download options and enhanced layout. - Integrated TabletInstallationSection into Landing.jsx for better user guidance.
This commit is contained in:
@@ -13,6 +13,7 @@ import Option from '@mui/joy/Option'
|
||||
import Select from '@mui/joy/Select'
|
||||
import Typography from '@mui/joy/Typography'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { NOTIFICATION_TYPE, TASK_COLOR } from '../utils/Colors'
|
||||
|
||||
const timeUnits = [
|
||||
{ label: 'Mins', value: 'm' },
|
||||
@@ -307,8 +308,10 @@ const NotificationTemplate = ({
|
||||
flexDirection: 'column',
|
||||
position: 'relative',
|
||||
height: 90,
|
||||
bgcolor: 'background.level1',
|
||||
bgcolor: 'background.surface',
|
||||
borderRadius: 'md',
|
||||
border: '1px solid',
|
||||
borderColor: 'neutral.outlinedBorder',
|
||||
p: 2,
|
||||
transition: 'height 0.3s ease',
|
||||
// '&:hover': {
|
||||
@@ -368,11 +371,11 @@ const NotificationTemplate = ({
|
||||
left: `${percent}%`,
|
||||
transform: 'translateX(-50%)',
|
||||
color:
|
||||
Number(n.value) < 0
|
||||
? 'primary.600'
|
||||
: Number(n.value) === 0
|
||||
? 'warning.600'
|
||||
: 'success.600',
|
||||
convertToMinutes(n.value, n.unit) < 0
|
||||
? TASK_COLOR.SCHEDULED
|
||||
: convertToMinutes(n.value, n.unit) === 0
|
||||
? TASK_COLOR.TODAY
|
||||
: TASK_COLOR.LATE,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
@@ -399,13 +402,6 @@ const NotificationTemplate = ({
|
||||
}
|
||||
size={'sm'}
|
||||
variant={'solid'}
|
||||
color={
|
||||
Number(n.value) < 0
|
||||
? 'success'
|
||||
: Number(n.value) === 0
|
||||
? 'warning'
|
||||
: 'danger'
|
||||
}
|
||||
sx={{
|
||||
'--Badge-paddingX': '4px',
|
||||
'--Badge-minHeight': '16px',
|
||||
@@ -413,6 +409,15 @@ const NotificationTemplate = ({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
'& .MuiBadge-badge': {
|
||||
background:
|
||||
convertToMinutes(n.value, n.unit) < 0
|
||||
? NOTIFICATION_TYPE.PREDUE
|
||||
: convertToMinutes(n.value, n.unit) === 0
|
||||
? NOTIFICATION_TYPE.DUE_DATE
|
||||
: NOTIFICATION_TYPE.POSTDUE,
|
||||
color: 'white',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<NotificationsIcon
|
||||
@@ -433,36 +438,7 @@ const NotificationTemplate = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={
|
||||
{
|
||||
// border: '1px solid',
|
||||
// borderColor: 'neutral.outlinedBorder',
|
||||
// borderRadius: 2,
|
||||
// p: 3,
|
||||
// maxWidth: 500,
|
||||
// bgcolor: 'background.body',
|
||||
// boxShadow: 'sm',
|
||||
}
|
||||
}
|
||||
>
|
||||
{/* <Typography level={'h4'} sx={{ mb: 2 }}>
|
||||
Schedule Name
|
||||
</Typography> */}
|
||||
|
||||
{/* Template Name Field */}
|
||||
{/* <Box sx={{ mb: 3 }}>
|
||||
<Typography level={'body2'} sx={{ mb: 1, fontWeight: 'md' }}>
|
||||
Template Name
|
||||
</Typography>
|
||||
<Input
|
||||
value={templateName}
|
||||
onChange={handleNameChange}
|
||||
placeholder='Enter template name'
|
||||
sx={{ width: '100%' }}
|
||||
/>
|
||||
</Box> */}
|
||||
|
||||
<Box>
|
||||
{error && (
|
||||
<Alert
|
||||
variant='soft'
|
||||
@@ -486,42 +462,117 @@ const NotificationTemplate = ({
|
||||
const badgeNumber = notificationIndexMap[idx]
|
||||
const uiRep = getUIRepresentation(n)
|
||||
|
||||
const getNotificationColors = value => {
|
||||
if (Number(value) < 0) {
|
||||
return {
|
||||
bgColor: NOTIFICATION_TYPE.PREDUE,
|
||||
lightBg: `${NOTIFICATION_TYPE.PREDUE}20`,
|
||||
borderColor: `${NOTIFICATION_TYPE.PREDUE}40`,
|
||||
textColor: NOTIFICATION_TYPE.PREDUE,
|
||||
}
|
||||
} else if (Number(value) === 0) {
|
||||
return {
|
||||
bgColor: NOTIFICATION_TYPE.DUE_DATE,
|
||||
lightBg: `${NOTIFICATION_TYPE.DUE_DATE}20`,
|
||||
borderColor: `${NOTIFICATION_TYPE.DUE_DATE}40`,
|
||||
textColor: NOTIFICATION_TYPE.DUE_DATE,
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
bgColor: NOTIFICATION_TYPE.POSTDUE,
|
||||
lightBg: `${NOTIFICATION_TYPE.POSTDUE}20`,
|
||||
borderColor: `${NOTIFICATION_TYPE.POSTDUE}40`,
|
||||
textColor: NOTIFICATION_TYPE.POSTDUE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const colors = getNotificationColors(n.value)
|
||||
|
||||
return (
|
||||
<Box
|
||||
key={idx}
|
||||
sx={{ display: 'flex', alignItems: 'center', mb: 1 }}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
mb: 1.5,
|
||||
p: 2,
|
||||
borderRadius: 8,
|
||||
border: '1px solid',
|
||||
borderColor: 'neutral.outlinedBorder',
|
||||
background: 'background.surface',
|
||||
transition: 'all 0.2s ease',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'start',
|
||||
width: 18,
|
||||
gap: 1.5,
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
className='notification-icon'
|
||||
sx={{
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: 32,
|
||||
height: 32,
|
||||
borderRadius: 6,
|
||||
background: `${colors.bgColor}15`,
|
||||
color: colors.textColor,
|
||||
position: 'relative',
|
||||
flexShrink: 0,
|
||||
'& svg': {
|
||||
fontSize: 16,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Badge
|
||||
badgeContent={badgeNumber}
|
||||
size={'sm'}
|
||||
sx={{
|
||||
'--Badge-minHeight': '20px',
|
||||
'--Badge-fontSize': '0.75rem',
|
||||
'--Badge-minHeight': '16px',
|
||||
'--Badge-fontSize': '0.7rem',
|
||||
'--Badge-paddingX': '5px',
|
||||
position: 'absolute',
|
||||
top: -6,
|
||||
right: -6,
|
||||
'& .MuiBadge-badge': {
|
||||
background: colors.bgColor,
|
||||
color: 'white',
|
||||
},
|
||||
}}
|
||||
color={
|
||||
Number(n.value) < 0
|
||||
? 'success'
|
||||
: Number(n.value) === 0
|
||||
? 'warning'
|
||||
: 'danger'
|
||||
}
|
||||
>
|
||||
{/* Empty box to attach badge to */}
|
||||
</Badge>
|
||||
/>
|
||||
<NotificationsIcon />
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
minWidth: 0,
|
||||
flex: '1',
|
||||
display: { xs: 'none', md: 'flex' }, // Show only on md and up
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
level='body-sm'
|
||||
sx={{
|
||||
fontWeight: 600,
|
||||
color: 'text.primary',
|
||||
fontSize: 14,
|
||||
}}
|
||||
>
|
||||
{getRelativeLabel(n)}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 1,
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
<Select
|
||||
value={uiRep.timing}
|
||||
onChange={(_, value) => handleChange(idx, 'timing', value)}
|
||||
sx={{ mr: 1, minWidth: 100 }}
|
||||
sx={{ minWidth: 80 }}
|
||||
size={'sm'}
|
||||
>
|
||||
{timingOptions.map(opt => (
|
||||
@@ -539,8 +590,7 @@ const NotificationTemplate = ({
|
||||
handleChange(idx, 'displayValue', e.target.value)
|
||||
}
|
||||
sx={{
|
||||
width: 80,
|
||||
mr: 1,
|
||||
width: 60,
|
||||
opacity: uiRep.timing === 'ondue' ? 0.6 : 1,
|
||||
}}
|
||||
size={'sm'}
|
||||
@@ -551,8 +601,7 @@ const NotificationTemplate = ({
|
||||
disabled={uiRep.timing === 'ondue'}
|
||||
onChange={(_, value) => handleChange(idx, 'unit', value)}
|
||||
sx={{
|
||||
mr: 1,
|
||||
minWidth: 80,
|
||||
minWidth: 70,
|
||||
opacity: uiRep.timing === 'ondue' ? 0.6 : 1,
|
||||
}}
|
||||
size={'sm'}
|
||||
@@ -568,22 +617,45 @@ const NotificationTemplate = ({
|
||||
disabled={notifications.length === 1}
|
||||
color={'danger'}
|
||||
size={'sm'}
|
||||
sx={{ mr: 1 }}
|
||||
variant={'soft'}
|
||||
sx={{
|
||||
transition: 'all 0.2s ease',
|
||||
'&:hover': {
|
||||
transform: 'scale(1.1)',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<DeleteIcon fontSize={'small'} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
<Box sx={{ display: 'flex', gap: 1, mt: 1, mb: 2, flexWrap: 'wrap' }}>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
gap: 1.5,
|
||||
mt: 1,
|
||||
mb: 2,
|
||||
flexWrap: 'wrap',
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
onClick={() => addSmartNotification('reminder')}
|
||||
disabled={notifications.length >= maxNotifications}
|
||||
startDecorator={<AddIcon />}
|
||||
size={'sm'}
|
||||
variant={'outlined'}
|
||||
color={'primary'}
|
||||
sx={{
|
||||
borderRadius: 6,
|
||||
fontWeight: 500,
|
||||
borderColor: `${TASK_COLOR.SCHEDULED}60`,
|
||||
color: TASK_COLOR.SCHEDULED,
|
||||
'&:hover': {
|
||||
borderColor: TASK_COLOR.SCHEDULED,
|
||||
background: `${TASK_COLOR.SCHEDULED}10`,
|
||||
},
|
||||
}}
|
||||
>
|
||||
Reminder
|
||||
</Button>
|
||||
@@ -596,7 +668,16 @@ const NotificationTemplate = ({
|
||||
startDecorator={<AddIcon />}
|
||||
size={'sm'}
|
||||
variant={'outlined'}
|
||||
color={'warning'}
|
||||
sx={{
|
||||
borderRadius: 6,
|
||||
fontWeight: 500,
|
||||
borderColor: `${NOTIFICATION_TYPE.DUE_DATE}60`,
|
||||
color: NOTIFICATION_TYPE.DUE_DATE,
|
||||
'&:hover': {
|
||||
borderColor: NOTIFICATION_TYPE.DUE_DATE,
|
||||
background: `${NOTIFICATION_TYPE.DUE_DATE}10`,
|
||||
},
|
||||
}}
|
||||
>
|
||||
Due Alert
|
||||
</Button>
|
||||
@@ -606,18 +687,34 @@ const NotificationTemplate = ({
|
||||
startDecorator={<AddIcon />}
|
||||
size={'sm'}
|
||||
variant={'outlined'}
|
||||
color={'danger'}
|
||||
sx={{
|
||||
borderRadius: 6,
|
||||
fontWeight: 500,
|
||||
borderColor: `${NOTIFICATION_TYPE.POSTDUE}60`,
|
||||
color: NOTIFICATION_TYPE.POSTDUE,
|
||||
'&:hover': {
|
||||
borderColor: NOTIFICATION_TYPE.POSTDUE,
|
||||
background: `${NOTIFICATION_TYPE.POSTDUE}10`,
|
||||
},
|
||||
}}
|
||||
>
|
||||
Follow-up
|
||||
</Button>
|
||||
</Box>
|
||||
{showSaveDefault && (
|
||||
<Box sx={{ mt: 1, display: 'flex', justifyContent: 'center' }}>
|
||||
<Button
|
||||
variant='outlined'
|
||||
size='sm'
|
||||
color='neutral'
|
||||
// sx={{ ml: 'auto', mt: 0.5 }}
|
||||
startDecorator={<Save />}
|
||||
sx={{
|
||||
borderRadius: 6,
|
||||
fontWeight: 500,
|
||||
'&:hover': {
|
||||
background: 'neutral.softHoverBg',
|
||||
},
|
||||
}}
|
||||
onClick={() => {
|
||||
localStorage.setItem(
|
||||
'defaultNotificationTemplate',
|
||||
@@ -626,8 +723,9 @@ const NotificationTemplate = ({
|
||||
setShowSaveDefault(false)
|
||||
}}
|
||||
>
|
||||
Save as Default for Future Tasks
|
||||
Save as Default
|
||||
</Button>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{showTimeline && renderTimeline()}
|
||||
|
||||
@@ -53,6 +53,11 @@ export const COLORS = {
|
||||
sand: '#d7ccc8',
|
||||
white: '#FFFFFF',
|
||||
}
|
||||
export const NOTIFICATION_TYPE = {
|
||||
PREDUE: '#4ec1a2',
|
||||
DUE_DATE: '#f6ad55',
|
||||
POSTDUE: '#F03A47',
|
||||
}
|
||||
|
||||
export const TASK_COLOR = {
|
||||
COMPLETED: '#4ec1a2',
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
Typography,
|
||||
} from '@mui/joy'
|
||||
import moment from 'moment'
|
||||
import { TASK_COLOR } from '../../utils/Colors.jsx'
|
||||
|
||||
const getCompletedChip = historyEntry => {
|
||||
if (historyEntry.status === 0) {
|
||||
@@ -49,7 +50,7 @@ const getCompletedChip = historyEntry => {
|
||||
<Chip
|
||||
size='sm'
|
||||
variant='solid'
|
||||
color='success'
|
||||
sx={{ backgroundColor: TASK_COLOR.COMPLETED, color: 'white' }}
|
||||
startDecorator={<Check />}
|
||||
>
|
||||
On Time
|
||||
@@ -57,7 +58,12 @@ const getCompletedChip = historyEntry => {
|
||||
)
|
||||
} else if (performedAt.isBefore(dueDate)) {
|
||||
return (
|
||||
<Chip size='sm' variant='soft' color='primary' startDecorator={<Check />}>
|
||||
<Chip
|
||||
size='sm'
|
||||
variant='soft'
|
||||
sx={{ backgroundColor: TASK_COLOR.SCHEDULED, color: 'white' }}
|
||||
startDecorator={<Check />}
|
||||
>
|
||||
Early
|
||||
</Chip>
|
||||
)
|
||||
@@ -66,7 +72,7 @@ const getCompletedChip = historyEntry => {
|
||||
<Chip
|
||||
size='sm'
|
||||
variant='solid'
|
||||
color='warning'
|
||||
sx={{ backgroundColor: TASK_COLOR.LATE, color: 'white' }}
|
||||
startDecorator={<Timelapse />}
|
||||
>
|
||||
Late
|
||||
|
||||
155
src/views/Landing/DemoCalendar.jsx
Normal file
155
src/views/Landing/DemoCalendar.jsx
Normal file
@@ -0,0 +1,155 @@
|
||||
import { Card, Grid, Typography } from '@mui/joy'
|
||||
import moment from 'moment'
|
||||
import CalendarView from '../components/CalendarView'
|
||||
|
||||
const DemoCalendar = () => {
|
||||
// Generate sample chore data across different dates
|
||||
const generateSampleChores = () => {
|
||||
const today = moment()
|
||||
const chores = []
|
||||
|
||||
// High priority tasks
|
||||
chores.push({
|
||||
id: 1,
|
||||
name: '🧹 Deep Clean Living Room',
|
||||
priority: 1,
|
||||
nextDueDate: today.clone().add(2, 'days').hour(10).minute(0).toISOString(),
|
||||
assignedTo: 1,
|
||||
})
|
||||
|
||||
chores.push({
|
||||
id: 2,
|
||||
name: '🚗 Car Maintenance Check',
|
||||
priority: 1,
|
||||
nextDueDate: today.clone().add(5, 'days').hour(14).minute(30).toISOString(),
|
||||
assignedTo: 1,
|
||||
})
|
||||
|
||||
// Medium priority tasks
|
||||
chores.push({
|
||||
id: 3,
|
||||
name: '🌱 Water Indoor Plants',
|
||||
priority: 2,
|
||||
nextDueDate: today.clone().add(1, 'days').hour(8).minute(0).toISOString(),
|
||||
assignedTo: 1,
|
||||
})
|
||||
|
||||
chores.push({
|
||||
id: 4,
|
||||
name: '🛒 Weekly Grocery Shopping',
|
||||
priority: 2,
|
||||
nextDueDate: today.clone().add(3, 'days').hour(16).minute(0).toISOString(),
|
||||
assignedTo: 1,
|
||||
})
|
||||
|
||||
chores.push({
|
||||
id: 5,
|
||||
name: '📧 Organize Email Inbox',
|
||||
priority: 2,
|
||||
nextDueDate: today.clone().add(7, 'days').hour(11).minute(0).toISOString(),
|
||||
assignedTo: 1,
|
||||
})
|
||||
|
||||
// Low priority tasks
|
||||
chores.push({
|
||||
id: 6,
|
||||
name: '📚 Organize Bookshelf',
|
||||
priority: 3,
|
||||
nextDueDate: today.clone().add(4, 'days').hour(15).minute(0).toISOString(),
|
||||
assignedTo: 1,
|
||||
})
|
||||
|
||||
chores.push({
|
||||
id: 7,
|
||||
name: '🎨 Paint Bedroom Wall',
|
||||
priority: 3,
|
||||
nextDueDate: today.clone().add(10, 'days').hour(9).minute(0).toISOString(),
|
||||
assignedTo: 1,
|
||||
})
|
||||
|
||||
// Tasks for today
|
||||
chores.push({
|
||||
id: 8,
|
||||
name: '🍽️ Do Dishes',
|
||||
priority: 2,
|
||||
nextDueDate: today.clone().hour(19).minute(0).toISOString(),
|
||||
assignedTo: 1,
|
||||
})
|
||||
|
||||
chores.push({
|
||||
id: 9,
|
||||
name: '🗑️ Take Out Trash',
|
||||
priority: 1,
|
||||
nextDueDate: today.clone().hour(7).minute(30).toISOString(),
|
||||
assignedTo: 1,
|
||||
})
|
||||
|
||||
// Tasks with no priority
|
||||
chores.push({
|
||||
id: 10,
|
||||
name: '🎵 Practice Guitar',
|
||||
priority: null,
|
||||
nextDueDate: today.clone().add(6, 'days').hour(18).minute(0).toISOString(),
|
||||
assignedTo: 1,
|
||||
})
|
||||
|
||||
// Multiple tasks on same day
|
||||
chores.push({
|
||||
id: 11,
|
||||
name: '🧺 Do Laundry',
|
||||
priority: 2,
|
||||
nextDueDate: today.clone().add(2, 'days').hour(12).minute(0).toISOString(),
|
||||
assignedTo: 1,
|
||||
})
|
||||
|
||||
chores.push({
|
||||
id: 12,
|
||||
name: '🏃 Morning Jog',
|
||||
priority: 3,
|
||||
nextDueDate: today.clone().add(2, 'days').hour(6).minute(30).toISOString(),
|
||||
assignedTo: 1,
|
||||
})
|
||||
|
||||
return chores
|
||||
}
|
||||
|
||||
const sampleChores = generateSampleChores()
|
||||
|
||||
return (
|
||||
<>
|
||||
<Grid item xs={12} sm={7} data-aos-calendar-demo-section>
|
||||
<div
|
||||
data-aos-delay={100}
|
||||
data-aos-anchor='[data-aos-calendar-demo-section]'
|
||||
data-aos='fade-up'
|
||||
>
|
||||
<CalendarView chores={sampleChores} />
|
||||
</div>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={5} data-aos-calendar-description>
|
||||
<Card
|
||||
sx={{
|
||||
p: 4,
|
||||
py: 6,
|
||||
height: 'fit-content',
|
||||
}}
|
||||
data-aos-delay={200}
|
||||
data-aos-anchor='[data-aos-calendar-description]'
|
||||
data-aos='fade-left'
|
||||
>
|
||||
<Typography level='h3' textAlign='center' sx={{ mt: 2, mb: 4 }}>
|
||||
Visual Task Calendar
|
||||
</Typography>
|
||||
<Typography level='body-lg' textAlign='center' sx={{ mb: 4 }}>
|
||||
Get a bird's-eye view of all your tasks with the interactive calendar.
|
||||
See priority-coded dots for each day, click to view detailed task lists,
|
||||
and easily track your upcoming responsibilities. The color-coded priority
|
||||
system helps you focus on what matters most.
|
||||
</Typography>
|
||||
</Card>
|
||||
</Grid>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default DemoCalendar
|
||||
@@ -14,6 +14,7 @@ const DemoMyChore = () => {
|
||||
nextDueDate: moment().add(1, 'days').hour(8).minute(0).toISOString(),
|
||||
isRolling: false,
|
||||
assignedTo: 1,
|
||||
status: 0,
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
@@ -24,6 +25,7 @@ const DemoMyChore = () => {
|
||||
nextDueDate: moment().subtract(7, 'day').toISOString(),
|
||||
isRolling: false,
|
||||
assignedTo: 1,
|
||||
status: 0,
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
|
||||
57
src/views/Landing/DemoNotificationTemplate.jsx
Normal file
57
src/views/Landing/DemoNotificationTemplate.jsx
Normal file
@@ -0,0 +1,57 @@
|
||||
import { Card, Grid, Typography } from '@mui/joy'
|
||||
import NotificationTemplate from '../../components/NotificationTemplate'
|
||||
|
||||
const DemoNotificationTemplate = () => {
|
||||
const demoNotifications = [
|
||||
{ value: -3, unit: 'd' }, // 3 days before
|
||||
{ value: 0, unit: 'm' }, // On due
|
||||
{ value: 1, unit: 'd' }, // 1 day after
|
||||
]
|
||||
|
||||
const handleNotificationChange = data => {
|
||||
// Demo handler - doesn't need to do anything
|
||||
console.log('Demo notification change:', data)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Grid item xs={12} sm={7} data-aos-notification-template-list>
|
||||
<div
|
||||
data-aos-delay={100}
|
||||
data-aos-anchor='[data-aos-notification-template-list]'
|
||||
data-aos='fade-up'
|
||||
>
|
||||
<NotificationTemplate
|
||||
value={{ templates: demoNotifications }}
|
||||
onChange={handleNotificationChange}
|
||||
maxNotifications={5}
|
||||
showTimeline={false}
|
||||
/>
|
||||
</div>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={5} data-aos-notification-demo-section>
|
||||
<Card
|
||||
sx={{
|
||||
p: 4,
|
||||
py: 6,
|
||||
height: 'fit-content',
|
||||
}}
|
||||
data-aos-delay={200}
|
||||
data-aos-anchor='[data-aos-notification-demo-section]'
|
||||
data-aos='fade-left'
|
||||
>
|
||||
<Typography level='h3' textAlign='center' sx={{ mt: 2, mb: 4 }}>
|
||||
Smart Notification Scheduling
|
||||
</Typography>
|
||||
<Typography level='body-lg' textAlign='center' sx={{ mb: 4 }}>
|
||||
Set up intelligent reminders for your tasks with flexible timing
|
||||
options. Get notified before, on, or after due dates with
|
||||
customizable intervals.
|
||||
</Typography>
|
||||
</Card>
|
||||
</Grid>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default DemoNotificationTemplate
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
Psychology,
|
||||
Schedule,
|
||||
Security,
|
||||
Settings,
|
||||
Timer,
|
||||
} from '@mui/icons-material'
|
||||
import { Box, Card, Container, Grid, Typography, useTheme } from '@mui/joy'
|
||||
@@ -19,10 +20,10 @@ const FeaturesSection = () => {
|
||||
|
||||
const features = [
|
||||
{
|
||||
icon: <Schedule />,
|
||||
title: 'Smart Scheduling',
|
||||
icon: <Psychology />,
|
||||
title: 'Natural Language Input',
|
||||
description:
|
||||
'Flexible recurring tasks: daily, weekly, monthly, or custom intervals. Choose rolling or fixed schedules and set completion windows to fit any routine.',
|
||||
'Add tasks just by typing. Donetick understands dates, priorities, labels. you can have quickest way to add tasks.',
|
||||
},
|
||||
{
|
||||
icon: <Groups />,
|
||||
@@ -32,9 +33,21 @@ const FeaturesSection = () => {
|
||||
},
|
||||
{
|
||||
icon: <EmojiEvents />,
|
||||
title: 'Motivating Gamification',
|
||||
title: 'Gamification and Points',
|
||||
description:
|
||||
'Earn points, climb leaderboards, and unlock achievements for completing tasks. Make productivity fun and rewarding.',
|
||||
'Earn points, climb leaderboards for completing tasks. You can even require admin approval for points!',
|
||||
},
|
||||
{
|
||||
icon: <CalendarMonth />,
|
||||
title: 'Visual Calendar View',
|
||||
description:
|
||||
'See all your tasks in a color-coded calendar. Filter by assignee, view daily agendas, and plan with ease.',
|
||||
},
|
||||
{
|
||||
icon: <Schedule />,
|
||||
title: 'Smart Scheduling',
|
||||
description:
|
||||
'Flexible recurring tasks: daily, weekly, monthly, or custom intervals. Choose rolling or fixed schedules and set completion windows to fit any routine.',
|
||||
},
|
||||
{
|
||||
icon: <Assignment />,
|
||||
@@ -42,36 +55,6 @@ const FeaturesSection = () => {
|
||||
description:
|
||||
'Distribute tasks fairly using smart algorithms: round-robin, least busy, random, or custom rules. No more manual juggling.',
|
||||
},
|
||||
{
|
||||
icon: <Analytics />,
|
||||
title: 'Insightful Analytics',
|
||||
description:
|
||||
'Track progress, view completion history, and spot trends with clear reports and visualizations. Understand your productivity at a glance.',
|
||||
},
|
||||
{
|
||||
icon: <AutoAwesome />,
|
||||
title: 'Advanced Organization',
|
||||
description:
|
||||
'Break down tasks with subtasks, set priorities, add labels and tags, and use templates for quick setup. Stay organized your way.',
|
||||
},
|
||||
{
|
||||
icon: <Notifications />,
|
||||
title: 'Smart Notifications',
|
||||
description:
|
||||
'Get timely reminders via email, Telegram, push, or webhooks. Customize alerts so you never miss what matters.',
|
||||
},
|
||||
{
|
||||
icon: <Api />,
|
||||
title: 'Seamless Integrations',
|
||||
description:
|
||||
'Connect with REST API, webhooks, and automation tools. Import, export, and trigger actions to fit your workflow.',
|
||||
},
|
||||
{
|
||||
icon: <Security />,
|
||||
title: 'Privacy & Security',
|
||||
description:
|
||||
'Open-source and secure by design. Choose cloud or self-hosting for full control over your data.',
|
||||
},
|
||||
{
|
||||
icon: <Timer />,
|
||||
title: 'Built-in Time Tracking',
|
||||
@@ -79,16 +62,40 @@ const FeaturesSection = () => {
|
||||
'Track work sessions with a timer, review detailed logs, and analyze productivity patterns for every task.',
|
||||
},
|
||||
{
|
||||
icon: <Psychology />,
|
||||
title: 'Natural Language Input',
|
||||
icon: <AutoAwesome />,
|
||||
title: 'Advanced Organization',
|
||||
description:
|
||||
'Add tasks just by typing. Our AI understands dates, priorities, labels, and more—no forms needed.',
|
||||
'Break down tasks with subtasks, set priorities, add labels and tags, and use templates for quick setup.',
|
||||
},
|
||||
{
|
||||
icon: <CalendarMonth />,
|
||||
title: 'Visual Calendar View',
|
||||
icon: <Settings />,
|
||||
title: 'Advanced Task Settings',
|
||||
description:
|
||||
'See all your tasks in a color-coded calendar. Filter by assignee, view daily agendas, and plan with ease.',
|
||||
'Configure task-specific settings like completion windows, custom point values, and require admin approval for tasks.',
|
||||
},
|
||||
{
|
||||
icon: <Analytics />,
|
||||
title: 'Insightful Analytics',
|
||||
description:
|
||||
'Track progress, view completion history, and spot trends with clear reports and visualizations.',
|
||||
},
|
||||
{
|
||||
icon: <Notifications />,
|
||||
title: 'Smart Notifications',
|
||||
description:
|
||||
'Get timely reminders via Donetick app or other way like Telegram, push, or webhooks.',
|
||||
},
|
||||
{
|
||||
icon: <Api />,
|
||||
title: 'Seamless Integrations',
|
||||
description:
|
||||
'Connect with REST API, webhooks, and automation tools. Import, export, and trigger actions to fit your workflows.',
|
||||
},
|
||||
{
|
||||
icon: <Security />,
|
||||
title: 'Privacy & Security',
|
||||
description:
|
||||
'Open-source and transparent. For security, you can secure your account with 2FA.',
|
||||
},
|
||||
]
|
||||
|
||||
@@ -179,33 +186,6 @@ const FeaturesSection = () => {
|
||||
transition: 'opacity 0.4s ease',
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
'&:hover': {
|
||||
transform: { xs: 'translateY(-4px)', sm: 'translateY(-8px)' },
|
||||
boxShadow: {
|
||||
xs: '0 15px 30px rgba(0, 0, 0, 0.08)',
|
||||
sm: '0 25px 50px rgba(0, 0, 0, 0.1)',
|
||||
},
|
||||
borderColor: 'primary.200',
|
||||
'&::before': {
|
||||
transform: 'scaleX(1)',
|
||||
},
|
||||
'&::after': {
|
||||
opacity: 1,
|
||||
},
|
||||
'& .feature-icon': {
|
||||
transform: {
|
||||
xs: 'scale(1.05)',
|
||||
sm: 'scale(1.1) rotate(5deg)',
|
||||
},
|
||||
background:
|
||||
'linear-gradient(135deg, var(--joy-palette-primary-500) 0%, var(--joy-palette-primary-600) 100%)',
|
||||
color: 'primary.50',
|
||||
boxShadow: '0 8px 20px rgba(6, 182, 212, 0.3)',
|
||||
},
|
||||
'& .feature-title': {
|
||||
color: 'primary.600',
|
||||
},
|
||||
},
|
||||
'@media (max-width: 600px)': {
|
||||
'&:active': {
|
||||
transform: 'scale(0.98)',
|
||||
@@ -286,62 +266,7 @@ const FeaturesSection = () => {
|
||||
mt={{ xs: 8, sm: 10, md: 12 }}
|
||||
data-aos='fade-up'
|
||||
data-aos-duration='800'
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
p: { xs: 4, sm: 5, md: 6 },
|
||||
borderRadius: { xs: 20, md: 24 },
|
||||
background:
|
||||
'linear-gradient(135deg, rgba(6, 182, 212, 0.05) 0%, rgba(8, 145, 178, 0.08) 100%)',
|
||||
border: '1px solid rgba(6, 182, 212, 0.15)',
|
||||
maxWidth: { xs: '100%', sm: 550, md: 600 },
|
||||
mx: 'auto',
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
'&::before': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
background:
|
||||
'radial-gradient(circle at 50% 50%, rgba(6, 182, 212, 0.1) 0%, transparent 70%)',
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
level='h3'
|
||||
sx={{
|
||||
fontSize: { xs: 22, sm: 26, md: 28 },
|
||||
fontWeight: 700,
|
||||
mb: { xs: 1.5, sm: 2 },
|
||||
color: 'text.primary',
|
||||
lineHeight: 1.2,
|
||||
position: 'relative',
|
||||
zIndex: 1,
|
||||
}}
|
||||
>
|
||||
Ready to Transform Your Task Management?
|
||||
</Typography>
|
||||
<Typography
|
||||
level='body-lg'
|
||||
sx={{
|
||||
color: 'text.secondary',
|
||||
mb: { xs: 3, sm: 4 },
|
||||
lineHeight: 1.6,
|
||||
fontSize: { xs: 15, sm: 16 },
|
||||
position: 'relative',
|
||||
zIndex: 1,
|
||||
px: { xs: 0, sm: 2 },
|
||||
}}
|
||||
>
|
||||
Join thousands who have streamlined their workflows with Donetick's
|
||||
powerful features
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
></Box>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -21,11 +21,13 @@ const Footer = () => {
|
||||
{ label: 'Features', href: '#features' },
|
||||
{ label: 'Demo', href: '#demo' },
|
||||
{ label: 'Getting Started', href: '#getting-started' },
|
||||
{ label: 'Pricing', href: '/pricing' },
|
||||
],
|
||||
resources: [
|
||||
{ label: 'Documentation', href: 'https://docs.donetick.com/' },
|
||||
{ label: 'API Reference', href: 'https://docs.donetick.com/api' },
|
||||
{
|
||||
label: 'API Reference',
|
||||
href: 'https://docs.donetick.com/advance-settings/api',
|
||||
},
|
||||
{
|
||||
label: 'Discussions',
|
||||
href: 'https://github.com/donetick/donetick/discussions',
|
||||
|
||||
@@ -1,66 +1,132 @@
|
||||
import {
|
||||
AddHome,
|
||||
Android,
|
||||
Apple,
|
||||
AutoAwesome,
|
||||
Cloud,
|
||||
GitHub,
|
||||
InstallMobile,
|
||||
Storage,
|
||||
} from '@mui/icons-material'
|
||||
import { Box, Button, Card, Grid, styled, Typography } from '@mui/joy'
|
||||
import { Box, Button, Card, Container, Grid, Typography } from '@mui/joy'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
const IconContainer = styled('div')({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: '50%',
|
||||
minWidth: '60px',
|
||||
height: '60px',
|
||||
marginRight: '16px',
|
||||
})
|
||||
|
||||
const ButtonContainer = styled('div')({
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
marginTop: 'auto',
|
||||
})
|
||||
|
||||
function StartOptionCard({ icon: Icon, title, description, button, index }) {
|
||||
return (
|
||||
<Card
|
||||
variant='plain'
|
||||
data-aos='fade-up'
|
||||
data-aos-delay={index * 100}
|
||||
data-aos-duration='800'
|
||||
variant='outlined'
|
||||
sx={{
|
||||
p: 2,
|
||||
p: { xs: 3, sm: 4, md: 4 },
|
||||
height: '100%',
|
||||
borderRadius: { xs: 16, md: 20 },
|
||||
border: '1px solid',
|
||||
borderColor: 'divider',
|
||||
background: 'background.surface',
|
||||
transition: 'all 0.4s cubic-bezier(0.4, 0, 0.2, 1)',
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
cursor: 'pointer',
|
||||
minHeight: { xs: 300, sm: 320 },
|
||||
display: 'flex',
|
||||
minHeight: '300px',
|
||||
py: 4,
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'space-between',
|
||||
'&::before': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: '4px',
|
||||
background:
|
||||
'linear-gradient(90deg, var(--joy-palette-primary-400) 0%, var(--joy-palette-primary-600) 100%)',
|
||||
transform: 'scaleX(0)',
|
||||
transformOrigin: 'left',
|
||||
transition: 'transform 0.4s ease',
|
||||
},
|
||||
'&::after': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
background:
|
||||
'linear-gradient(135deg, rgba(6, 182, 212, 0.02) 0%, rgba(8, 145, 178, 0.04) 100%)',
|
||||
opacity: 0,
|
||||
transition: 'opacity 0.4s ease',
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
'@media (max-width: 600px)': {
|
||||
'&:active': {
|
||||
transform: 'scale(0.98)',
|
||||
},
|
||||
},
|
||||
}}
|
||||
data-aos-delay={100 * index}
|
||||
data-aos-anchor='[data-aos-id-getting-started-container]'
|
||||
data-aos='fade-up'
|
||||
>
|
||||
{/* Changes are within this div */}
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'column',
|
||||
textAlign: 'center',
|
||||
mb: 3,
|
||||
}}
|
||||
>
|
||||
<IconContainer>{Icon}</IconContainer>
|
||||
<Box
|
||||
className='option-icon'
|
||||
sx={{
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: { xs: 60, sm: 80 },
|
||||
height: { xs: 60, sm: 80 },
|
||||
borderRadius: { xs: 16, sm: 20 },
|
||||
background:
|
||||
'linear-gradient(135deg, var(--joy-palette-primary-50) 0%, var(--joy-palette-primary-100) 100%)',
|
||||
color: 'primary.500',
|
||||
mb: 3,
|
||||
transition: 'all 0.4s cubic-bezier(0.4, 0, 0.2, 1)',
|
||||
'& svg': {
|
||||
fontSize: { xs: 32, sm: 40 },
|
||||
},
|
||||
}}
|
||||
>
|
||||
{Icon}
|
||||
</Box>
|
||||
|
||||
<Typography level='h4' textAlign={'center'}>
|
||||
<Typography
|
||||
className='option-title'
|
||||
level='title-lg'
|
||||
sx={{
|
||||
fontSize: { xs: 20, sm: 24 },
|
||||
fontWeight: 700,
|
||||
color: 'text.primary',
|
||||
lineHeight: 1.3,
|
||||
transition: 'color 0.3s ease',
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Typography level='body-md' color='neutral' lineHeight={1.6}>
|
||||
<Typography
|
||||
level='body-md'
|
||||
sx={{
|
||||
color: 'text.secondary',
|
||||
lineHeight: 1.6,
|
||||
fontSize: { xs: 14, sm: 15 },
|
||||
textAlign: 'center',
|
||||
mb: 3,
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
{description}
|
||||
</Typography>
|
||||
|
||||
<ButtonContainer>{button}</ButtonContainer>
|
||||
<Box sx={{ mt: 'auto' }}>{button}</Box>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -70,7 +136,7 @@ const GettingStarted = () => {
|
||||
const information = [
|
||||
{
|
||||
title: 'Donetick Web',
|
||||
icon: <Cloud style={{ fontSize: '48px' }} />,
|
||||
icon: <Cloud />,
|
||||
description:
|
||||
'The easiest way! Just create account and start using Donetick',
|
||||
button: (
|
||||
@@ -88,7 +154,7 @@ const GettingStarted = () => {
|
||||
},
|
||||
{
|
||||
title: 'Selfhosted',
|
||||
icon: <Storage style={{ fontSize: '48px' }} />,
|
||||
icon: <Storage />,
|
||||
description: 'Download the binary and manage your own Donetick instance',
|
||||
button: (
|
||||
<Button
|
||||
@@ -108,7 +174,7 @@ const GettingStarted = () => {
|
||||
},
|
||||
{
|
||||
title: 'Hassio Addon',
|
||||
icon: <AddHome style={{ fontSize: '48px' }} />,
|
||||
icon: <AddHome />,
|
||||
description:
|
||||
'Have Home Assistant? Install Donetick as a Home Assistant Addon with single click',
|
||||
button: (
|
||||
@@ -127,30 +193,259 @@ const GettingStarted = () => {
|
||||
),
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<Box
|
||||
<Container maxWidth='xl' sx={{ py: { xs: 6, sm: 8, md: 12 } }}>
|
||||
{/* Section Header */}
|
||||
<Box textAlign='center' mb={{ xs: 6, md: 8 }} data-aos='fade-up'>
|
||||
<Typography
|
||||
level='h2'
|
||||
sx={{
|
||||
alignContent: 'center',
|
||||
fontSize: { xs: 28, sm: 36, md: 42, lg: 48 },
|
||||
fontWeight: 700,
|
||||
mb: { xs: 2, md: 3 },
|
||||
color: 'text.primary',
|
||||
lineHeight: { xs: 1.2, md: 1.1 },
|
||||
background:
|
||||
'linear-gradient(135deg, var(--joy-palette-primary-500) 0%, var(--joy-palette-primary-600) 100%)',
|
||||
backgroundClip: 'text',
|
||||
WebkitBackgroundClip: 'text',
|
||||
WebkitTextFillColor: 'transparent',
|
||||
textAlign: 'center',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
mt: 2,
|
||||
}}
|
||||
>
|
||||
<Typography level='h4' mt={2} mb={4}>
|
||||
Getting Started
|
||||
Get Started Today
|
||||
</Typography>
|
||||
<Typography
|
||||
level='body-lg'
|
||||
sx={{
|
||||
fontSize: { xs: 16, sm: 17, md: 18, lg: 19 },
|
||||
color: 'text.secondary',
|
||||
maxWidth: { xs: '100%', sm: 600, md: 700 },
|
||||
mx: 'auto',
|
||||
lineHeight: 1.6,
|
||||
px: { xs: 1, sm: 0 },
|
||||
}}
|
||||
>
|
||||
Ready to transform your household management? Start with our mobile
|
||||
app for the best experience, or choose from our other convenient
|
||||
options.
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
{/* Mobile App CTA Section - Primary */}
|
||||
<Box
|
||||
textAlign='center'
|
||||
mb={{ xs: 8, sm: 10, md: 12 }}
|
||||
data-aos='fade-up'
|
||||
data-aos-duration='800'
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
p: { xs: 5, sm: 6, md: 7 },
|
||||
borderRadius: { xs: 20, md: 24 },
|
||||
background:
|
||||
'linear-gradient(135deg, rgba(6, 182, 212, 0.08) 0%, rgba(8, 145, 178, 0.12) 100%)',
|
||||
border: '2px solid rgba(6, 182, 212, 0.2)',
|
||||
maxWidth: { xs: '100%', sm: 650, md: 700 },
|
||||
mx: 'auto',
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
boxShadow: '0 20px 40px rgba(0, 0, 0, 0.1)',
|
||||
'&::before': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
level='body-lg'
|
||||
sx={{
|
||||
color: 'text.secondary',
|
||||
mb: { xs: 4, sm: 5 },
|
||||
lineHeight: 1.6,
|
||||
fontSize: { xs: 16, sm: 17 },
|
||||
position: 'relative',
|
||||
zIndex: 1,
|
||||
px: { xs: 0, sm: 2 },
|
||||
maxWidth: 500,
|
||||
mx: 'auto',
|
||||
}}
|
||||
>
|
||||
Get the full Donetick experience with notifications, realtime
|
||||
updates, and seamless task management on the go
|
||||
</Typography>
|
||||
|
||||
<Box maxWidth={'lg'} sx={{ mb: 8 }}>
|
||||
<Typography level='body-md' color='neutral'>
|
||||
You can start using Donetick in multiple ways, the easiest of which is
|
||||
to use Donetick Web so you can get started in seconds, or if you are
|
||||
into selfhosting you can download the binary and run it on your own
|
||||
server, or if you are using Home Assistant you can install Donetick as
|
||||
a Home Assistant Addon
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: { xs: 'column', sm: 'row' },
|
||||
gap: { xs: 3, sm: 4 },
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
position: 'relative',
|
||||
zIndex: 1,
|
||||
}}
|
||||
>
|
||||
{/* App Store Badge */}
|
||||
<Box
|
||||
onClick={() => {
|
||||
window.open(
|
||||
'https://apps.apple.com/app/apple-store/id6742807441?pt=127258663&ct=website&mt=8',
|
||||
'_blank',
|
||||
)
|
||||
}}
|
||||
sx={{
|
||||
cursor: 'pointer',
|
||||
transition: 'all 0.3s ease',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
background: '#000000',
|
||||
borderRadius: '12px',
|
||||
padding: '12px 24px',
|
||||
minWidth: { xs: 200, sm: 180 },
|
||||
height: 60,
|
||||
border: '1px solid #333',
|
||||
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',
|
||||
}}
|
||||
>
|
||||
<Apple sx={{ color: 'white', fontSize: 40, mr: 2 }} />
|
||||
<Box>
|
||||
<Typography
|
||||
level='body-xs'
|
||||
sx={{
|
||||
color: 'white',
|
||||
fontSize: 11,
|
||||
lineHeight: 1,
|
||||
mb: 0.5,
|
||||
fontWeight: 400,
|
||||
}}
|
||||
>
|
||||
Download on the
|
||||
</Typography>
|
||||
<div data-aos-id-getting-started-container>
|
||||
<Grid container spacing={4} mt={4}>
|
||||
<Typography
|
||||
level='title-md'
|
||||
sx={{
|
||||
color: 'white',
|
||||
fontSize: 18,
|
||||
lineHeight: 1,
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
App Store
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Google Play Badge */}
|
||||
<Box
|
||||
onClick={() => {
|
||||
window.open(
|
||||
'https://github.com/donetick/donetick/releases',
|
||||
'_blank',
|
||||
)
|
||||
}}
|
||||
sx={{
|
||||
cursor: 'pointer',
|
||||
transition: 'all 0.3s ease',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
background:
|
||||
'linear-gradient(135deg, #000000 0%, #1a1a1a 100%)',
|
||||
borderRadius: '12px',
|
||||
padding: '12px 24px',
|
||||
minWidth: { xs: 200, sm: 180 },
|
||||
height: 60,
|
||||
border: '1px solid #333',
|
||||
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
mr: 2,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: 32,
|
||||
height: 32,
|
||||
}}
|
||||
>
|
||||
<Android sx={{ color: 'white', fontSize: 40 }} />
|
||||
</Box>
|
||||
<Box>
|
||||
<Typography
|
||||
level='body-xs'
|
||||
sx={{
|
||||
color: 'white',
|
||||
fontSize: 11,
|
||||
lineHeight: 1,
|
||||
mb: 0.5,
|
||||
fontWeight: 400,
|
||||
}}
|
||||
>
|
||||
Download for
|
||||
</Typography>
|
||||
<Typography
|
||||
level='title-md'
|
||||
sx={{
|
||||
color: 'white',
|
||||
fontSize: 18,
|
||||
lineHeight: 1,
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
Android
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Alternative Options Section */}
|
||||
<Box textAlign='center' mb={{ xs: 4, md: 6 }} data-aos='fade-up'>
|
||||
<Typography
|
||||
level='h4'
|
||||
sx={{
|
||||
fontSize: { xs: 20, sm: 22, md: 24 },
|
||||
fontWeight: 600,
|
||||
mb: { xs: 1, md: 1.5 },
|
||||
color: 'text.primary',
|
||||
}}
|
||||
>
|
||||
Other Ways to Get Started
|
||||
</Typography>
|
||||
<Typography
|
||||
level='body-md'
|
||||
sx={{
|
||||
color: 'text.secondary',
|
||||
maxWidth: 500,
|
||||
mx: 'auto',
|
||||
fontSize: { xs: 14, sm: 15 },
|
||||
}}
|
||||
>
|
||||
Prefer a different setup? Choose from these alternatives
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
{/* Options Grid */}
|
||||
<Grid container spacing={{ xs: 3, sm: 4, md: 4 }}>
|
||||
{information.map((info, index) => (
|
||||
<Grid item xs={12} md={4} key={index}>
|
||||
<StartOptionCard
|
||||
@@ -158,13 +453,12 @@ const GettingStarted = () => {
|
||||
title={info.title}
|
||||
description={info.description}
|
||||
button={info.button}
|
||||
index={index}
|
||||
/>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</div>
|
||||
</Box>
|
||||
</Box>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,11 +7,13 @@ import CookiePermissionSnackbar from './CookiePermissionSnackbar'
|
||||
import DemoAssignee from './DemoAssignee'
|
||||
import DemoHistory from './DemoHistory'
|
||||
import DemoMyChore from './DemoMyChore'
|
||||
import DemoNotificationTemplate from './DemoNotificationTemplate'
|
||||
import DemoScheduler from './DemoScheduler'
|
||||
import FeaturesSection from './FeaturesSection'
|
||||
import Footer from './Footer'
|
||||
import GettingStarted from './GettingStarted'
|
||||
import HomeHero from './HomeHero'
|
||||
import TabletInstallationSection from './TabletInstallationSection'
|
||||
const Landing = () => {
|
||||
const Navigate = useNavigate()
|
||||
useEffect(() => {
|
||||
@@ -37,13 +39,13 @@ const Landing = () => {
|
||||
<DemoMyChore />
|
||||
<DemoAssignee />
|
||||
<DemoScheduler />
|
||||
<DemoNotificationTemplate />
|
||||
|
||||
<DemoHistory />
|
||||
</Grid>
|
||||
<FeaturesSection />
|
||||
<TabletInstallationSection />
|
||||
<GettingStarted />
|
||||
|
||||
{/* <PricingSection /> */}
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
|
||||
Reference in New Issue
Block a user