Quellcode durchsuchen

calendar UI

master
kj1352 vor 4 Jahren
Ursprung
Commit
e72e954117
8 geänderte Dateien mit 412 neuen und 9 gelöschten Zeilen
  1. +5
    -0
      package-lock.json
  2. +1
    -0
      package.json
  3. +2
    -0
      src/App.tsx
  4. +207
    -0
      src/components/calendar/Calendar.module.scss
  5. +173
    -0
      src/components/calendar/Calendar.tsx
  6. +4
    -4
      src/components/home/Home.tsx
  7. +3
    -5
      src/components/revise/Revise.tsx
  8. +17
    -0
      src/structure/schedule.ts

+ 5
- 0
package-lock.json Datei anzeigen

@@ -10601,6 +10601,11 @@
"minimist": "^1.2.5"
}
},
"moment": {
"version": "2.29.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
},
"move-concurrently": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",


+ 1
- 0
package.json Datei anzeigen

@@ -10,6 +10,7 @@
"@types/node": "^12.20.15",
"@types/react": "^17.0.13",
"@types/react-dom": "^17.0.8",
"moment": "^2.29.1",
"node-sass": "^6.0.1",
"query-string": "^7.0.1",
"react": "^17.0.2",


+ 2
- 0
src/App.tsx Datei anzeigen

@@ -17,6 +17,7 @@ import { ReactComponent as TimeIcon } from './assets/icons/time.svg';
import { IProfile } from "./structure/profile";
import { ALL_WORDS } from "./data/all-words";
import { WordDetails } from "./components/word-details/WordDetails";
import { Calendar } from "./components/calendar/Calendar";


export var userProfileData : IProfile = {
@@ -78,6 +79,7 @@ function App() {
<Route path="/shelf-details/" component={ShelfDetails} />
<Route path="/word-details/" component={WordDetails} />
<Route path="/revise" component={Revise} />
<Route path="/calendar" component={Calendar} />
<Redirect from="/" to="/home" />
</Switch>
<Tabs />


+ 207
- 0
src/components/calendar/Calendar.module.scss Datei anzeigen

@@ -0,0 +1,207 @@
.navHeader {
background-color: transparent;
text-align: center;
position: relative;
display: flex;
justify-content: flex-start;
align-items: center;
padding: 1rem 1.5rem;

button {
width: 4rem;
text-align: center;
background-color: transparent;
border: 0;
display: flex;
align-items: center;
justify-content: flex-start;

svg {
width: 1rem;
color: var(--black);
}
}
}


.todayHeader {
padding: 0 2rem;
margin-top: 2rem;

h4 {
font-size: 2rem;
color: var(--black);
}

p {
font-size: 1.2rem;
color: var(--light-grey);
letter-spacing: 0.5px;
font-weight: 300;
}

h5 {
margin-top: 3rem;
font-size: 1.6rem;
font-weight: 400;
color: var(--black);
padding-bottom: 0.5rem;
}
}

.currentWeek {
padding: 0.5rem;
list-style: none;
display: grid;
grid-template-columns: repeat(7, 1fr);
background-color: var(--creamy-white);
z-index: 1;
position: sticky;
top: 0;
box-shadow: 0px 5px 5px -8px var(--light-grey);

li {
text-align: center;
padding: 0.5rem 0;

&:last-child {
label, span {
color: var(--red);
}
}

&.active {
background-color: var(--teal);
border-radius: 1rem;

label, span {
color: white;
}
}
}

label {
display: block;
font-size: 1.2rem;
color: var(--light-grey);
}

span {
display: block;
font-size: 1.2rem;
font-weight: 600;
color: var(--black);
}
}

.currentDayDetails {
padding: 1rem;
list-style: none;

li {
min-height: 4rem;
position: relative;

&:nth-child(4n - 2) .task::before {
background-color: var(--orange);
}

&:nth-child(4n - 1) .task::before {
background-color: var(--blue);
}

&:nth-child(4n - 3) .task::before {
background-color: var(--red);
}

&:nth-child(4n - 4) .task::before {
background-color: var(--teal);
}

&.cycle {
label {
display: flex;
align-items: center;
justify-content: flex-start;
&::after {
content: '';
flex-grow: 1;
height: 2px;
border-bottom: 2px dashed var(--light-grey);
margin-left: 2rem;
transform: scaleY(0.4);
}
}
}

label {
font-size: 1.4rem;
color: var(--light-grey);
text-align: left;
opacity: 0.8;
}
}

.task {
width: calc(100% - 6rem);
display: block;
margin-left: auto;
padding: 1rem 2rem;
border-radius: 2.5rem;
position: relative;
overflow: visible;
line-height: 1.7;

&.completed {
opacity: 0.5;
}

&::before {
content: '';
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: var(--orange);
opacity: 0.5;
border-radius: inherit;
}

&>* {
position: relative;
}

h5 {
font-size: 1.6rem;
color: var(--black);
}

p {
font-size: 1.1rem;
color: var(--grey);
}

.indicator {
position: absolute;
left: -2rem;
top: calc(50% - 0.8rem);
width: 1.6rem;
height: 1.6rem;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
color: white;

&.overTime {
background-color: var(--red);
}

&.completed {
background-color: var(--teal);
}
}
}
}

+ 173
- 0
src/components/calendar/Calendar.tsx Datei anzeigen

@@ -0,0 +1,173 @@
import React, { useState } from 'react';
import styles from './Calendar.module.scss';
import { ReactComponent as ChevronLeft } from '../../assets/icons/chevron-left.svg';
import moment from 'moment';
import { ISchedule } from '../../structure/schedule';
import { NavLink } from 'react-router-dom';


const SCHEDULE: Array<ISchedule> = [{
calendar_date: {
date: moment().format('DD'),
month: moment().format('MM'),
year: moment().format('YYYY'),
time: {
hours: 8,
minutes: 0
}
},
title: 'Vocabulary: All Words',
description: 'Revision of "All Words" in Vocabulary shelf',
revision_link: '/revise',
external_link: '',
duration_in_min: 10,
isCompleted: true
}, {
calendar_date: {
date: moment().format('DD'),
month: moment().format('MM'),
year: moment().format('YYYY'),
time: {
hours: 10,
minutes: 0
}
},
title: 'Revision Test: All Shelves',
description: '',
revision_link: '/revise',
external_link: '',
duration_in_min: 30,
isCompleted: false
}, {
calendar_date: {
date: moment().format('DD'),
month: moment().format('MM'),
year: moment().format('YYYY'),
time: {
hours: 17,
minutes: 30
}
},
title: 'Books: Sapiens',
description: 'Revision of "Sapiens" in Books shelf',
revision_link: '/revise',
external_link: '',
duration_in_min: 30,
isCompleted: false
}, ];

function getCurrentWeek() {
let currentDate = moment();

let weekStart = currentDate.clone().startOf('isoWeek');
let days = [];

for (let i = 0; i <= 6; i++) {
days.push({
date: moment(weekStart).add(i, 'days').format("DD"),
day: moment(weekStart).add(i, 'days').format("ddd"),
month_name: moment(weekStart).add(i, 'days').format("MMMM"),
month: moment(weekStart).add(i, 'days').format("MM"),
year: moment().format('YYYY')
});
}

return days;
}

export const Calendar: React.FC = () => {
const today = {
date: moment().format('DD'),
day: moment().format('ddd'),
month_name: moment().format('MMMM'),
month: moment().format('MM'),
year: moment().format('YYYY')
};

const currentTime = {
hours: Number(moment().format('HH')),
minutes: Number(moment().format('mm'))
}

let current_week = getCurrentWeek();

const [selectedDate, setSelectedDate] = useState<{
date: string,
month: string,
year: string
}>({
date: today.date,
month: today.month,
year: today.year
});

let hours = [];

for (let i = 0; i < 24; i += 1) {
hours.push(i);
}

return <section className="modalPage">
<header className={styles.navHeader}>
<button onClick={() => window.history.back()}>
<ChevronLeft />
</button>
</header>
<header className={styles.todayHeader}>
<h4> Today </h4>
<p> Productive day, Neymar </p>

<h5> { today.month_name }, { today.year } </h5>
</header>

<ul className={styles.currentWeek}>
{ current_week.map((week, index) => {
return <li key={index} className={week.date === selectedDate.date && week.month === selectedDate.month ? styles.active : ''}
onClick={() => setSelectedDate({
date: week.date,
month: week.month,
year: week.year
})}>
<label> { week.day } </label>
<span> { week.date } </span>
</li>
}) }
</ul>

<ul className={styles.currentDayDetails}>
{ hours.map((hours, index) => {
return <li key={index} className={(hours % 4 === 0) ? styles.cycle : ''}>
<label> { hours.toString().padStart(2, '0') }:00 </label>

{ SCHEDULE.map((schedule, schedule_index) => {
if (schedule.calendar_date.date === selectedDate.date &&
schedule.calendar_date.month === selectedDate.month &&
schedule.calendar_date.year === selectedDate.year &&
schedule.calendar_date.time.hours === hours) {
return <NavLink to={schedule.revision_link} key={schedule_index}
className={styles.task + ' ' + (schedule.isCompleted ? styles.completed: '')}
onClick={() => schedule.isCompleted = true}>
{ currentTime.hours >= schedule.calendar_date.time.hours &&
currentTime.minutes >= schedule.calendar_date.time.minutes &&
!schedule.isCompleted && <div className={styles.indicator + ' ' + styles.overTime}>
!
</div> }

{ schedule.isCompleted && <div className={styles.indicator + ' ' + styles.completed}>
&#10003;
</div> }

<h5> { schedule.title } </h5>
<p> { schedule.description } </p>
<p> { schedule.duration_in_min } minutes practice </p>
</NavLink>
}
}) }
</li>
}) }
</ul>
</section>
}

+ 4
- 4
src/components/home/Home.tsx Datei anzeigen

@@ -68,9 +68,9 @@ export const Home: React.FC = () => {
<BookIcon />
Revisions
</h4>
<button>
<NavLink to="/calendar">
<CalendarIcon />
</button>
</NavLink>
</header>
<ul>
<li>
@@ -134,9 +134,9 @@ export const Home: React.FC = () => {
<span className={styles.text}> { shelf.words.length > 0 ? (shelf.revisedWords.length * 100/ shelf.words.length) : 0 }% </span>
</div>
<h5> { category.name } </h5>
<p> { shelf.name } </p>
<h5> { shelf.name } </h5>
<p> { shelf.words.length } words </p>
<p> { category.name } </p>
</li>
})
}) }


+ 3
- 5
src/components/revise/Revise.tsx Datei anzeigen

@@ -21,11 +21,9 @@ export const Revise: React.FC = () => {
{ progressState === 'END' && <div>
<Summary />

<NavLink to={'/home'}>
<button className={styles.finishButton}>
Done
</button>
</NavLink>
<button className={styles.finishButton} onClick={() => window.history.back()}>
Done
</button>
</div> }
</section>
}

+ 17
- 0
src/structure/schedule.ts Datei anzeigen

@@ -0,0 +1,17 @@
export type ISchedule = {
calendar_date: {
date: string,
month: string,
year: string,
time: {
hours: number,
minutes: number,
}
},
title: string,
description: string,
revision_link: string,
external_link: string,
duration_in_min: number,
isCompleted: boolean,
};

Laden…
Abbrechen
Speichern