diff --git a/public/keepsimple_/assets/longevity/diet/diet-mobile-bg.webp b/public/keepsimple_/assets/longevity/diet/diet-mobile-bg.webp new file mode 100644 index 0000000..92a7fb2 Binary files /dev/null and b/public/keepsimple_/assets/longevity/diet/diet-mobile-bg.webp differ diff --git a/public/keepsimple_/assets/longevity/sleep/supplements-icons/Stress.png b/public/keepsimple_/assets/longevity/sleep/supplements-icons/Stress.png new file mode 100644 index 0000000..c87606c Binary files /dev/null and b/public/keepsimple_/assets/longevity/sleep/supplements-icons/Stress.png differ diff --git a/public/keepsimple_/assets/longevity/star-glow.png b/public/keepsimple_/assets/longevity/star-glow.png new file mode 100644 index 0000000..fe9fc3f Binary files /dev/null and b/public/keepsimple_/assets/longevity/star-glow.png differ diff --git a/src/api/longevity/workout.ts b/src/api/longevity/workout.ts index 4b82336..ae14f41 100644 --- a/src/api/longevity/workout.ts +++ b/src/api/longevity/workout.ts @@ -5,7 +5,7 @@ export async function getWorkout(locale: string) { next: { revalidate: 3600 }, }); - if (!res.ok) throw new Error('Failed to fetch contributor'); + if (!res.ok) throw new Error('Failed to fetch workout data'); const json = await res.json(); const attrs = json?.data?.attributes ?? {}; diff --git a/src/components/Header/Header.module.scss b/src/components/Header/Header.module.scss index f61a15c..c299080 100644 --- a/src/components/Header/Header.module.scss +++ b/src/components/Header/Header.module.scss @@ -19,6 +19,7 @@ .logo { margin-top: 3px !important; cursor: pointer; + object-fit: contain; } .actions { @@ -214,7 +215,7 @@ padding: 0 1.4rem; height: 82px; background-color: #fff; - z-index: 5; + z-index: 6; align-items: center; justify-content: center; diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index e0309f1..580bb28 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -73,8 +73,8 @@ const Header: FC = () => { }} src={ isDarkTheme - ? '/keepsimple_/assets/logos/keepsimpleNewYearDark.svg' - : '/keepsimple_/assets/logos/keepsimpleNewYear.svg' + ? '/keepsimple_/assets/logos/keepsimpleDark.svg' + : '/keepsimple_/assets/logos/keepsimple.svg' } alt="keepsimple logo" width={130.61} diff --git a/src/components/longevity/FlipCard/FlipCard.module.scss b/src/components/longevity/FlipCard/FlipCard.module.scss index 48a63a1..320e1d5 100644 --- a/src/components/longevity/FlipCard/FlipCard.module.scss +++ b/src/components/longevity/FlipCard/FlipCard.module.scss @@ -10,14 +10,6 @@ flex-direction: column; margin-bottom: 30px; - .pageSwitcherFlip { - position: absolute; - bottom: 20px; - z-index: 55; - cursor: pointer; - right: 12px; - } - .headline { padding-bottom: 12px; justify-content: center !important; diff --git a/src/components/longevity/FlipCard/FlipCard.tsx b/src/components/longevity/FlipCard/FlipCard.tsx index be30698..89a3f11 100644 --- a/src/components/longevity/FlipCard/FlipCard.tsx +++ b/src/components/longevity/FlipCard/FlipCard.tsx @@ -16,8 +16,6 @@ const FlipCard: FC = ({ hacksQuote, quoteAuthor, isHacks, - setSwitchPage, - switchPage, chartWidth, }) => { return ( @@ -26,14 +24,6 @@ const FlipCard: FC = ({ [styles.hacksFlipCard]: isHacks, })} > - {'Page setSwitchPage && setSwitchPage(!switchPage)} - /> {isHacks ? (
void; - switchPage?: boolean; chartWidth?: number; }; diff --git a/src/components/longevity/HTMLClamp/HTMLClamp.module.scss b/src/components/longevity/HTMLClamp/HTMLClamp.module.scss new file mode 100644 index 0000000..ed63b70 --- /dev/null +++ b/src/components/longevity/HTMLClamp/HTMLClamp.module.scss @@ -0,0 +1,57 @@ +@import '@styles/_variables.scss'; + +.description { + @extend .longevityList; + overflow-y: auto; + max-height: 367px; + + &::-webkit-scrollbar { + width: 8px; + } + + &::-webkit-scrollbar-track { + box-shadow: inset 0 0 5px #dddddd; + background-color: #dddddd; + border-radius: 8px; + opacity: 1; + } + + &::-webkit-scrollbar-thumb { + background: #333131; + border-radius: 8px; + } + + &::-webkit-scrollbar-thumb:hover { + background: #333131; + } + + .htmlContent { + padding-right: 15px; + line-height: 1.5; + + p { + margin: 0; + } + + a { + color: #000000d9; + } + } +} + +.clamped { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 9; + overflow: hidden; +} + +.showMoreBtn { + background: none; + border: none; + padding: 0; + margin-top: 6px; + cursor: pointer; + font-size: 14px; + font-weight: 700; +} diff --git a/src/components/longevity/HTMLClamp/HTMLClamp.tsx b/src/components/longevity/HTMLClamp/HTMLClamp.tsx new file mode 100644 index 0000000..ffb0e3e --- /dev/null +++ b/src/components/longevity/HTMLClamp/HTMLClamp.tsx @@ -0,0 +1,70 @@ +import React, { FC, useEffect, useRef, useState } from 'react'; +import cn from 'classnames'; + +import { HTMLClampTypes } from '@components/longevity/HTMLClamp/HTMLClamp.types'; + +import styles from './HTMLClamp.module.scss'; + +const HtmlClamp: FC = ({ html, lines = 9, className }) => { + const shouldClamp = true; + + const contentRef = useRef(null); + const [expanded, setExpanded] = useState(false); + const [hasOverflow, setHasOverflow] = useState(false); + + useEffect(() => { + const el = contentRef.current; + if (!el) return; + + const measure = () => { + if (!shouldClamp) { + setHasOverflow(false); + return; + } + + if (!expanded) { + setHasOverflow(el.scrollHeight > el.clientHeight + 1); + } else { + setExpanded(false); + requestAnimationFrame(() => { + const el2 = contentRef.current; + if (el2) setHasOverflow(el2.scrollHeight > el2.clientHeight + 1); + setExpanded(true); + }); + } + }; + + measure(); + + const ro = new ResizeObserver(measure); + ro.observe(el); + + return () => ro.disconnect(); + }, [html, lines, shouldClamp]); + + return ( +
+
+
+ {hasOverflow && ( + + )} +
+
+ ); +}; + +export default HtmlClamp; diff --git a/src/components/longevity/HTMLClamp/HTMLClamp.types.ts b/src/components/longevity/HTMLClamp/HTMLClamp.types.ts new file mode 100644 index 0000000..d51138f --- /dev/null +++ b/src/components/longevity/HTMLClamp/HTMLClamp.types.ts @@ -0,0 +1,6 @@ +export type HTMLClampTypes = { + html: string; + lines?: number; + onlyMobile?: boolean; + className?: string; +}; diff --git a/src/components/longevity/HTMLClamp/index.ts b/src/components/longevity/HTMLClamp/index.ts new file mode 100644 index 0000000..c0ea982 --- /dev/null +++ b/src/components/longevity/HTMLClamp/index.ts @@ -0,0 +1,3 @@ +import HtmlClamp from './HTMLClamp'; + +export default HtmlClamp; diff --git a/src/components/longevity/LongevitySubSection/LongevitySubSection.module.scss b/src/components/longevity/LongevitySubSection/LongevitySubSection.module.scss index 3e18d53..44be819 100644 --- a/src/components/longevity/LongevitySubSection/LongevitySubSection.module.scss +++ b/src/components/longevity/LongevitySubSection/LongevitySubSection.module.scss @@ -97,13 +97,22 @@ margin: 0; li { + list-style: none; + position: relative; + padding-left: 25px; padding-bottom: 20px; - padding-left: 12px; line-height: 1.5; @include text-body; - &::marker { - content: url('/keepsimple_/assets/longevity/habits/marker.svg'); + &::before { + content: ''; + position: absolute; + left: 0; + top: 0.35em; + width: 12px; + height: 12px; + background: url('/keepsimple_/assets/longevity/habits/marker.svg') + no-repeat center / contain; } } } @@ -156,7 +165,7 @@ } .habitTooltip { - font-size: 16px; + font-size: 14px; } .backgroundImg { @@ -171,4 +180,10 @@ } } } + .whyDoThisMobileModal { + display: flex; + flex-direction: column; + height: 100%; + justify-content: space-between; + } } diff --git a/src/components/longevity/LongevitySubSection/LongevitySubSection.tsx b/src/components/longevity/LongevitySubSection/LongevitySubSection.tsx index f06243e..914c253 100644 --- a/src/components/longevity/LongevitySubSection/LongevitySubSection.tsx +++ b/src/components/longevity/LongevitySubSection/LongevitySubSection.tsx @@ -6,6 +6,7 @@ import { Tooltip as ReactTooltip } from 'react-tooltip'; import WhyDoThisTooltip from '@components/longevity/WhyDoThisTooltip'; import Modal from '@components/Modal'; import Heading from '@components/Heading'; +import BorderedPill from '@components/longevity/BorderedPill'; import { useIsWidthLessThan } from '@hooks/useScreenSize'; @@ -24,6 +25,7 @@ const LongevitySubSection: FC = ({ children, date, isHacks, + damageTypeHeadline, }) => { const { habitTooltipTitle } = longevityData[locale]; const isMobile = useIsWidthLessThan(956); @@ -70,7 +72,11 @@ const LongevitySubSection: FC = ({ place={'bottom'} className={cn(styles.tooltip, {})} > - + )}
@@ -99,7 +105,17 @@ const LongevitySubSection: FC = ({ } onClick={() => setOpenMobileModal(false)} > - +
+ + setOpenMobileModal(false)} + /> +
)} diff --git a/src/components/longevity/LongevitySubSection/LongevitySubSection.types.ts b/src/components/longevity/LongevitySubSection/LongevitySubSection.types.ts index bc0d3f2..8a4a519 100644 --- a/src/components/longevity/LongevitySubSection/LongevitySubSection.types.ts +++ b/src/components/longevity/LongevitySubSection/LongevitySubSection.types.ts @@ -7,4 +7,5 @@ export type LongevitySubSectionProps = { children?: React.ReactNode; date?: string; isHacks?: boolean; + damageTypeHeadline?: string; }; diff --git a/src/components/longevity/MainInfoSection/MainInfoSection.module.scss b/src/components/longevity/MainInfoSection/MainInfoSection.module.scss index 494da01..cb29084 100644 --- a/src/components/longevity/MainInfoSection/MainInfoSection.module.scss +++ b/src/components/longevity/MainInfoSection/MainInfoSection.module.scss @@ -39,7 +39,7 @@ letter-spacing: -5px; color: #ce2128; margin-left: 60px; - z-index: 555; + z-index: 5; } } diff --git a/src/components/longevity/MobileNavigation/MobileNavigation.module.scss b/src/components/longevity/MobileNavigation/MobileNavigation.module.scss index 22b9cba..8ee58bf 100644 --- a/src/components/longevity/MobileNavigation/MobileNavigation.module.scss +++ b/src/components/longevity/MobileNavigation/MobileNavigation.module.scss @@ -199,19 +199,15 @@ .nextButton { margin-left: 16px; - .nextLink { - text-decoration: unset; - - .nextStaticTxt { - color: #484848; - font-size: 16px; - font-weight: 400; - } + .nextStaticTxt { + color: #484848; + font-size: 16px; + font-weight: 400; + } - .nextPage { - font-weight: 600; - color: #000; - } + .nextPage { + font-weight: 600; + color: #000; } span { diff --git a/src/components/longevity/MobileNavigation/MobileNavigation.tsx b/src/components/longevity/MobileNavigation/MobileNavigation.tsx index 6f6a3bc..2a83c24 100644 --- a/src/components/longevity/MobileNavigation/MobileNavigation.tsx +++ b/src/components/longevity/MobileNavigation/MobileNavigation.tsx @@ -228,11 +228,12 @@ const MobileNavigation: FC = () => { ))} - - - Next:{' '} - {nextPathname.name} - + nextPathname && router.push(nextPathname.path)} + > + Next:{' '} + {nextPathname.name} ); diff --git a/src/components/longevity/Navigation/Navigation.module.scss b/src/components/longevity/Navigation/Navigation.module.scss index 880206a..76f9c43 100644 --- a/src/components/longevity/Navigation/Navigation.module.scss +++ b/src/components/longevity/Navigation/Navigation.module.scss @@ -96,6 +96,12 @@ } } +.link { + svg:first-child { + margin-top: -5px; + } +} + .subNav { position: relative; overflow: hidden; diff --git a/src/components/longevity/ShinyStars/ShinyStars.module.scss b/src/components/longevity/ShinyStars/ShinyStars.module.scss new file mode 100644 index 0000000..aaeccaa --- /dev/null +++ b/src/components/longevity/ShinyStars/ShinyStars.module.scss @@ -0,0 +1,22 @@ +.starWrap { + position: absolute; + z-index: 10; + animation: fadeInAndOut 2s linear infinite; + will-change: opacity; +} + +.starImg { + display: block; +} + +@keyframes fadeInAndOut { + 0% { + opacity: 0; + } + 50% { + opacity: 1; + } + 100% { + opacity: 0; + } +} diff --git a/src/components/longevity/ShinyStars/ShinyStars.tsx b/src/components/longevity/ShinyStars/ShinyStars.tsx new file mode 100644 index 0000000..0bcd4ea --- /dev/null +++ b/src/components/longevity/ShinyStars/ShinyStars.tsx @@ -0,0 +1,66 @@ +import Image from 'next/image'; +import { useState } from 'react'; +import styles from './ShinyStars.module.scss'; + +const rand = (min: number, max: number) => Math.random() * (max - min) + min; + +type Star = { + id: number; + left: string; + bottom: string; + delay: string; + duration: string; +}; + +const STAR_COUNT = 4; + +const makeStar = (id: number): Star => ({ + id, + left: `${rand(2, 98).toFixed(2)}%`, + bottom: `${rand(2, 85).toFixed(2)}%`, + delay: `${rand(0, 1.5).toFixed(2)}s`, // stagger a bit + duration: `${rand(1.8, 3.0).toFixed(2)}s`, // slight variety +}); + +export default function ShinyStars() { + const [stars, setStars] = useState(() => + Array.from({ length: STAR_COUNT }, (_, i) => makeStar(i)), + ); + + const teleportStar = (id: number) => { + setStars(prev => + prev.map(s => + s.id === id + ? { ...s, left: makeStar(id).left, bottom: makeStar(id).bottom } + : s, + ), + ); + }; + + return ( + <> + {stars.map(s => ( + teleportStar(s.id)} + > + star + + ))} + + ); +} diff --git a/src/components/longevity/ShinyStars/index.ts b/src/components/longevity/ShinyStars/index.ts new file mode 100644 index 0000000..d7bd3b0 --- /dev/null +++ b/src/components/longevity/ShinyStars/index.ts @@ -0,0 +1,3 @@ +import ShinyStars from './ShinyStars'; + +export default ShinyStars; diff --git a/src/components/longevity/StrengthAndTimeCompression/StrengthAndTimeCompression.module.scss b/src/components/longevity/StrengthAndTimeCompression/StrengthAndTimeCompression.module.scss index edf853c..ba2a333 100644 --- a/src/components/longevity/StrengthAndTimeCompression/StrengthAndTimeCompression.module.scss +++ b/src/components/longevity/StrengthAndTimeCompression/StrengthAndTimeCompression.module.scss @@ -48,6 +48,22 @@ .staticSmallText { font-size: 18px; } + + .orangeResult { + .totalMins, + .staticBigText, + .staticSmallText { + color: #ffae01; + } + } + + .greenResult { + .totalMins, + .staticBigText, + .staticSmallText { + color: #4d8539; + } + } } .result { diff --git a/src/components/longevity/StrengthAndTimeCompression/StrengthAndTimeCompression.tsx b/src/components/longevity/StrengthAndTimeCompression/StrengthAndTimeCompression.tsx index 54093b0..2ec9b2c 100644 --- a/src/components/longevity/StrengthAndTimeCompression/StrengthAndTimeCompression.tsx +++ b/src/components/longevity/StrengthAndTimeCompression/StrengthAndTimeCompression.tsx @@ -1,4 +1,5 @@ import React, { FC, useMemo, useState } from 'react'; +import cn from 'classnames'; import Heading from '@components/Heading'; import ProgressBar from '@components/longevity/ProgressBar'; @@ -42,7 +43,13 @@ const StrengthAndTimeCompression: FC = () => { setStopIndex={setSelectedIndex} stopIndex={selectedIndex} /> -
+
{selectedLevel.totalMinutesPerWeek} diff --git a/src/components/longevity/StudySection/StudySection.module.scss b/src/components/longevity/StudySection/StudySection.module.scss index c5e3d4f..6d4d1ff 100644 --- a/src/components/longevity/StudySection/StudySection.module.scss +++ b/src/components/longevity/StudySection/StudySection.module.scss @@ -31,7 +31,7 @@ .showFlipCard { animation: showFlipCardAndScaleUp 0.6s forwards; - z-index: 33; + z-index: 15; } .hideFlipCard { @@ -120,7 +120,10 @@ position: absolute; bottom: 20px; right: 12px; + z-index: 15; cursor: pointer; + animation-delay: 2s; + animation: pulse-shadow-animation 2s infinite; } @media (max-width: 1190px) { @@ -205,3 +208,15 @@ transform: scale(1); } } + +@keyframes pulse-shadow-animation { + 0% { + filter: drop-shadow(0px 0px 18px rgba(53, 35, 13, 0.2)); + } + 70% { + filter: drop-shadow(0px 0px 18px rgba(10, 10, 12, 0.58)); + } + 100% { + filter: drop-shadow(0px 0px 18px rgba(53, 35, 13, 0.2)); + } +} diff --git a/src/components/longevity/StudySection/StudySection.tsx b/src/components/longevity/StudySection/StudySection.tsx index 44695a1..804abb3 100644 --- a/src/components/longevity/StudySection/StudySection.tsx +++ b/src/components/longevity/StudySection/StudySection.tsx @@ -9,6 +9,7 @@ import { StudySectionProps } from './StudySection.types'; import FlipCard from '@components/longevity/FlipCard'; import { useIsWidthLessThan } from '@hooks/useScreenSize'; import Modal from '@components/Modal'; +import HtmlClamp from '@components/longevity/HTMLClamp'; import { BorderedPill } from '@components/longevity/BorderedPill/BorderedPill'; import LearnMoreIcon from '@icons/longevity/LearnMoreIcon'; @@ -40,7 +41,7 @@ const StudySection: FC = ({ const headlineBg = isHacks ? '/keepsimple_/assets/longevity/study/hacks.png' : '/keepsimple_/assets/longevity/study-headline-bg.png'; - //explain to learn doesn't have it + return ( <>
@@ -72,10 +73,18 @@ const StudySection: FC = ({ />
-
+ {isMobile ? ( + + ) : ( +
+ )} {isMobile && flippedCardChart && (
= ({ />
)} - {flippedCardChart && ( - {'Page { - setSwitchPage(!switchPage); - }} - /> - )}
{!isMobile && ( @@ -115,13 +112,25 @@ const StudySection: FC = ({ isHacks={isHacks} hacksQuote={hacksQuote} quoteAuthor={quoteAuthor} - switchPage={switchPage} - setSwitchPage={setSwitchPage} chartWidth={chartWidth} />
)}
+ {flippedCardChart && ( +
+ {'Page { + setSwitchPage(!switchPage); + }} + /> +
+ )} {isMobile && openModal && ( = ({ name, description, categories }) => { alt={category.attributes.title} width={24} height={24} + unoptimized /> {category.attributes.title} diff --git a/src/components/longevity/WeeklyWorkout/WeeklyWorkout.module.scss b/src/components/longevity/WeeklyWorkout/WeeklyWorkout.module.scss index 6ed9c82..db628c6 100644 --- a/src/components/longevity/WeeklyWorkout/WeeklyWorkout.module.scss +++ b/src/components/longevity/WeeklyWorkout/WeeklyWorkout.module.scss @@ -29,6 +29,12 @@ text-transform: uppercase; font-weight: 600; } + .orangeMinutes { + color: #ffae01; + } + .greenMinutes { + color: #4d8539; + } } .divider { @@ -78,6 +84,13 @@ color: #ce2128; font-weight: 700; } + .orangeRisk { + color: #ffae01; + } + + .greenRisk { + color: #4d8539; + } } } diff --git a/src/components/longevity/WeeklyWorkout/WeeklyWorkout.tsx b/src/components/longevity/WeeklyWorkout/WeeklyWorkout.tsx index 877292a..9557eaf 100644 --- a/src/components/longevity/WeeklyWorkout/WeeklyWorkout.tsx +++ b/src/components/longevity/WeeklyWorkout/WeeklyWorkout.tsx @@ -83,7 +83,15 @@ const WeeklyWorkout: FC = () => { showRightIcon={false} className={styles.heading} /> - {selectedMinutes} min + + {selectedMinutes} min +

{

- Risk of Dying Early {summary.riskOfDyingEarly} + Risk of Dying Early{' '} + + {summary.riskOfDyingEarly} +


Estimated ↓ Cognitive Decline / Dementia Risk - {summary.cognitiveDecline} + + {' '} + {summary.cognitiveDecline} +


Brain Aging Trajectory - {summary.brainAgingActive} + + {summary.brainAgingActive} +

diff --git a/src/components/longevity/WhatToEatOrAvoid/AboutTheProduct/AboutTheProduct.module.scss b/src/components/longevity/WhatToEatOrAvoid/AboutTheProduct/AboutTheProduct.module.scss index b0b37ea..833bb01 100644 --- a/src/components/longevity/WhatToEatOrAvoid/AboutTheProduct/AboutTheProduct.module.scss +++ b/src/components/longevity/WhatToEatOrAvoid/AboutTheProduct/AboutTheProduct.module.scss @@ -43,7 +43,7 @@ @media (max-width: 965px) { .aboutProduct { padding: 16px; - background-image: url('/keepsimple_/assets/longevity/diet/tooltip-bg.png'); + background-image: unset; background-repeat: no-repeat; background-size: cover; display: flex; @@ -53,11 +53,17 @@ z-index: 10; max-width: 500px; + .content { + padding-top: 20px; + } .tooltipHeading { h5 { font-size: 18px !important; } } + .divider { + width: -webkit-fill-available; + } .subText { font-size: 16px; diff --git a/src/components/longevity/WhatToEatOrAvoid/AboutTheProduct/AboutTheProduct.tsx b/src/components/longevity/WhatToEatOrAvoid/AboutTheProduct/AboutTheProduct.tsx index 7916c46..bbe59a9 100644 --- a/src/components/longevity/WhatToEatOrAvoid/AboutTheProduct/AboutTheProduct.tsx +++ b/src/components/longevity/WhatToEatOrAvoid/AboutTheProduct/AboutTheProduct.tsx @@ -23,6 +23,7 @@ const AboutTheProduct: FC = ({ title, content }) => { alt={'info'} width={459} height={2} + className={styles.divider} />
= ({
{tooltipContent && ( -
+
+ {!isMobile && } {title} = ({ whatDamagesText, + headline, locale, }) => { - const { whatDamagesTitle } = longevityData[locale]; - return (
- + {headline && ( + + )}
= ({ locale, data }) => { basicStats={data?.basicStats} locale={locale} japaneseText={data?.['japanese title'] ? data?.['japanese title'] : ''} - backgroundImageUrl={`${process.env.NEXT_PUBLIC_STRAPI}${data?.['image']?.data?.attributes.url}`} + backgroundImageUrl={`${process.env.NEXT_PUBLIC_STRAPI}${data?.['image']?.data?.attributes?.url}`} /> = ({ locale, data }) => { key={index} description={item.explanation} name={item.title} - iconUrl={`${strapiURl}${item.icon.data.attributes.url}`} + iconUrl={`${strapiURl}${item?.icon?.data?.attributes?.url}`} /> ))} diff --git a/src/layouts/HabitsLayout/HabitsLayout.tsx b/src/layouts/HabitsLayout/HabitsLayout.tsx index 1f40279..77524aa 100644 --- a/src/layouts/HabitsLayout/HabitsLayout.tsx +++ b/src/layouts/HabitsLayout/HabitsLayout.tsx @@ -1,9 +1,12 @@ -import { HabitsLayoutProps } from '@layouts/HabitsLayout/HabitsLayout.types'; import { FC } from 'react'; -import styles from '@layouts/LongevityLayouts/WhatIsThisLayout.module.scss'; + import MainInfoSection from '@components/longevity/MainInfoSection'; import LongevitySubSection from '@components/longevity/LongevitySubSection'; +import { HabitsLayoutProps } from '@layouts/HabitsLayout/HabitsLayout.types'; + +import styles from '@layouts/LongevityLayouts/WhatIsThisLayout.module.scss'; + const HabitsLayout: FC = ({ data, locale }) => { const imgPath = '/keepsimple_/assets/longevity/habits/'; @@ -24,6 +27,7 @@ const HabitsLayout: FC = ({ data, locale }) => { description={data?.routine?.description || ''} headlineBackgroundImageUrl={`${imgPath}routine.png`} whatDamages={data?.routine?.['damage type']} + damageTypeHeadline={data?.routine?.['damage type headline']} /> = ({ data, locale }) => { description={data?.['daily movement']?.description} headlineBackgroundImageUrl={`${imgPath}daily-movement.png`} whatDamages={data?.['daily movement']?.['damage type']} + damageTypeHeadline={ + data?.['daily movement']?.['damage type headline'] + } /> = ({ data, locale }) => { description={data?.['substance junk']?.description} headlineBackgroundImageUrl={`${imgPath}substance-junk.png`} whatDamages={data?.['substance junk']?.['damage type']} + damageTypeHeadline={ + data?.['substance junk']?.['damage type headline'] + } /> = ({ data, locale }) => { description={data?.['informational junk']?.description} headlineBackgroundImageUrl={`${imgPath}informational-junk.png`} whatDamages={data?.['informational junk']?.['damage type']} + damageTypeHeadline={ + data?.['informational junk']?.['damage type headline'] + } /> = ({ data, locale }) => { description={data?.['cold environment']?.description} headlineBackgroundImageUrl={`${imgPath}cold-environment.png`} whatDamages={data?.['cold environment']?.['damage type']} + damageTypeHeadline={ + data?.['cold environment']?.['damage type headline'] + } /> = ({ data, locale }) => { description={data?.['mental load management']?.description} headlineBackgroundImageUrl={`${imgPath}mental-load.png`} whatDamages={data?.['mental load management']?.['damage type']} + damageTypeHeadline={ + data?.['mental load management']?.['damage type headline'] + } />{' '} = ({ data, locale }) => { description={data?.['weekend protocol']?.description} headlineBackgroundImageUrl={`${imgPath}informational-junk.png`} whatDamages={data?.['weekend protocol']?.['damage type']} + damageTypeHeadline={ + data?.['weekend protocol']?.['damage type headline'] + } /> = ({ data, locale }) => { description={data?.['weekly Lan Party']?.description} headlineBackgroundImageUrl={`${imgPath}informational-junk.png`} whatDamages={data?.['weekly Lan Party']?.['damage type']} + damageTypeHeadline={ + data?.['weekly Lan Party']?.['damage type headline'] + } /> diff --git a/src/layouts/Layout.module.scss b/src/layouts/Layout.module.scss index ad46971..cfdcdf6 100644 --- a/src/layouts/Layout.module.scss +++ b/src/layouts/Layout.module.scss @@ -37,24 +37,41 @@ } } -.canvas { - opacity: 1; -} - .canvasTransitionOn { transition: opacity 350ms ease; will-change: opacity; } +.canvasTransitionOff { + transition: none; +} + +.canvasOn { + animation: smooth-fadeIn 350ms ease; + will-change: opacity; +} + +.canvasOff { + opacity: 80%; +} + @media (max-width: 965px) { .longevityMain { .section { gap: 0; } - .videoWrapper, .canvas { display: none; } } } + +@keyframes smooth-fadeIn { + from { + opacity: 80%; + } + to { + opacity: 100%; + } +} diff --git a/src/layouts/SleepLayout/SleepLayout.tsx b/src/layouts/SleepLayout/SleepLayout.tsx index 6afbd72..55e631b 100644 --- a/src/layouts/SleepLayout/SleepLayout.tsx +++ b/src/layouts/SleepLayout/SleepLayout.tsx @@ -1,6 +1,6 @@ -import { FC, useState } from 'react'; +import { FC, useRef, useState } from 'react'; import Image from 'next/image'; - +import html2canvas from 'html2canvas'; import Modal from '@components/Modal'; import Table from '@components/longevity/Table'; import Supplement from '@components/longevity/Supplement'; @@ -17,12 +17,9 @@ const SleepLayout: FC = ({ locale, data, supplements }) => { const isMobile = useIsWidthLessThan(1140); // TODO: move to constants const imgPath = '/keepsimple_/assets/longevity/sleep/'; - + const tableRef = useRef(null); const [open, setOpen] = useState(false); - - const handleOpen = async () => { - setOpen(true); - }; + const [imgSrc, setImgSrc] = useState(''); // TODO: move to constants const tableKeys = [ @@ -32,6 +29,34 @@ const SleepLayout: FC = ({ locale, data, supplements }) => { 'fully optimized', ]; + const makeTableImage = async () => { + if (!tableRef.current) return; + + await new Promise(r => setTimeout(r, 50)); + + const targetWidth = 900; + + const canvas = await html2canvas(tableRef.current, { + backgroundColor: '#fff', + useCORS: true, + + scale: 2, + + windowWidth: targetWidth, + width: targetWidth, + + scrollX: 0, + scrollY: 0, + }); + + setImgSrc(canvas.toDataURL('image/png')); + }; + + const handleOpen = async () => { + setOpen(true); + await makeTableImage(); + }; + return ( <> = ({ locale, data, supplements }) => { title={data['supplement headline']} headlineBackgroundImageUrl={`${imgPath}supplements-header.png`} > + {isMobile && ( +
+
+ + + + )} {supplements.map((supplementItem, index) => ( = ({ locale, data, supplements }) => { {open && ( - setOpen(false)} fullSizeMobile> -
setOpen(false)}> + )} diff --git a/src/pages/tools/longevity-protocol/about-project.tsx b/src/pages/tools/longevity-protocol/about-project.tsx index f3dc0e5..0f47f01 100644 --- a/src/pages/tools/longevity-protocol/about-project.tsx +++ b/src/pages/tools/longevity-protocol/about-project.tsx @@ -1,5 +1,4 @@ import { GetServerSideProps } from 'next'; -import { useRouter } from 'next/router'; import { getWhatIsThis } from '@api/longevity/what-is-this'; import SeoGenerator from '@components/SeoGenerator'; @@ -7,21 +6,15 @@ import SeoGenerator from '@components/SeoGenerator'; import WhatIsThisLayout from '@layouts/LongevityLayouts'; const AboutProject = ({ aboutTheProject }) => { - const router = useRouter(); - const { locale } = router; - const currentLocale = locale === 'ru' ? 'ru' : 'en'; - const OGTags = { - ogDescription: aboutTheProject[currentLocale]?.ogDescription || '', - ogTitle: aboutTheProject[currentLocale]?.ogTitle || '', - ogType: aboutTheProject[currentLocale]?.ogType || '', - ogImageAlt: aboutTheProject[currentLocale]?.ogImageAlt || '', + ogDescription: aboutTheProject['en']?.ogDescription || '', + ogTitle: aboutTheProject['en']?.ogTitle || '', + ogType: aboutTheProject['en']?.ogType || '', + ogImageAlt: aboutTheProject['en']?.ogImageAlt || '', ogImage: { data: { attributes: { - url: - aboutTheProject[currentLocale]?.ogImage?.data?.attributes?.url || - '', + url: aboutTheProject['en']?.ogImage?.data?.attributes?.url || '', }, }, }, @@ -31,19 +24,18 @@ const AboutProject = ({ aboutTheProject }) => { <> ); diff --git a/src/pages/tools/longevity-protocol/environment.tsx b/src/pages/tools/longevity-protocol/environment.tsx index 81889fc..077af30 100644 --- a/src/pages/tools/longevity-protocol/environment.tsx +++ b/src/pages/tools/longevity-protocol/environment.tsx @@ -12,14 +12,14 @@ const Environment = ({ environment }) => { const currentLocale = locale === 'ru' ? 'ru' : 'en'; const OGTags = { - ogDescription: environment[currentLocale]?.ogDescription || '', - ogTitle: environment[currentLocale]?.ogTitle || '', - ogType: environment[currentLocale]?.ogType || '', - ogImageAlt: environment[currentLocale]?.ogImageAlt || '', + ogDescription: environment['en']?.ogDescription || '', + ogTitle: environment['en']?.ogTitle || '', + ogType: environment['en']?.ogType || '', + ogImageAlt: environment['en']?.ogImageAlt || '', ogImage: { data: { attributes: { - url: environment[currentLocale]?.ogImage?.data?.attributes?.url || '', + url: environment['en']?.ogImage?.data?.attributes?.url || '', }, }, }, @@ -29,10 +29,10 @@ const Environment = ({ environment }) => { <> { - const router = useRouter(); - const { locale } = router; - const currentLocale = locale === 'ru' ? 'ru' : 'en'; - const OGTags = { - ogDescription: dietData[currentLocale]?.ogDescription || '', - ogTitle: dietData[currentLocale]?.ogTitle || '', - ogType: dietData[currentLocale]?.ogType || '', - ogImageAlt: dietData[currentLocale]?.ogImageAlt || '', + ogDescription: dietData['en']?.ogDescription || '', + ogTitle: dietData['en']?.ogTitle || '', + ogType: dietData['en']?.ogType || '', + ogImageAlt: dietData['en']?.ogImageAlt || '', ogImage: { data: { attributes: { - url: dietData[currentLocale]?.ogImage?.data?.attributes?.url || '', + url: dietData['en']?.ogImage?.data?.attributes?.url || '', }, }, }, @@ -29,19 +24,16 @@ const Diet = ({ dietData }) => { <> - + ); }; diff --git a/src/pages/tools/longevity-protocol/habits/lifestyle.tsx b/src/pages/tools/longevity-protocol/habits/lifestyle.tsx index 40e502e..7733385 100644 --- a/src/pages/tools/longevity-protocol/habits/lifestyle.tsx +++ b/src/pages/tools/longevity-protocol/habits/lifestyle.tsx @@ -1,5 +1,4 @@ import { GetStaticProps } from 'next'; -import { useRouter } from 'next/router'; import HabitsLayout from '@layouts/HabitsLayout/HabitsLayout'; @@ -7,19 +6,15 @@ import { getHabitsProtocol } from '@api/longevity/habits-protocol'; import SeoGenerator from '@components/SeoGenerator'; const Lifestyle = ({ habitsData }) => { - const router = useRouter(); - const { locale } = router; - const currentLocale = locale === 'ru' ? 'ru' : 'en'; - const OGTags = { - ogDescription: habitsData[currentLocale]?.ogDescription || '', - ogTitle: habitsData[currentLocale]?.ogTitle || '', - ogType: habitsData[currentLocale]?.ogType || '', - ogImageAlt: habitsData[currentLocale]?.ogImageAlt || '', + ogDescription: habitsData['en']?.ogDescription || '', + ogTitle: habitsData['en']?.ogTitle || '', + ogType: habitsData['en']?.ogType || '', + ogImageAlt: habitsData['en']?.ogImageAlt || '', ogImage: { data: { attributes: { - url: habitsData[currentLocale]?.ogImage?.data?.attributes?.url || '', + url: habitsData['en']?.ogImage?.data?.attributes?.url || '', }, }, }, @@ -29,19 +24,16 @@ const Lifestyle = ({ habitsData }) => { <> - + ); }; diff --git a/src/pages/tools/longevity-protocol/habits/sleep.tsx b/src/pages/tools/longevity-protocol/habits/sleep.tsx index 5b07d3d..b281428 100644 --- a/src/pages/tools/longevity-protocol/habits/sleep.tsx +++ b/src/pages/tools/longevity-protocol/habits/sleep.tsx @@ -1,4 +1,3 @@ -import { useRouter } from 'next/router'; import { GetStaticProps } from 'next'; import { getSleep } from '@api/longevity/sleep'; @@ -8,19 +7,15 @@ import SleepLayout from '@layouts/SleepLayout/SleepLayout'; import SeoGenerator from '@components/SeoGenerator'; const Sleep = ({ sleepData, sleepSupplements }) => { - const router = useRouter(); - const { locale } = router; - const currentLocale = locale === 'ru' ? 'ru' : 'en'; - const OGTags = { - ogDescription: sleepData[currentLocale]?.ogDescription || '', - ogTitle: sleepData[currentLocale]?.ogTitle || '', - ogType: sleepData[currentLocale]?.ogType || '', - ogImageAlt: sleepData[currentLocale]?.ogImageAlt || '', + ogDescription: sleepData['en']?.ogDescription || '', + ogTitle: sleepData['en']?.ogTitle || '', + ogType: sleepData['en']?.ogType || '', + ogImageAlt: sleepData['en']?.ogImageAlt || '', ogImage: { data: { attributes: { - url: sleepData[currentLocale]?.ogImage?.data?.attributes?.url || '', + url: sleepData['en']?.ogImage?.data?.attributes?.url || '', }, }, }, @@ -30,18 +25,18 @@ const Sleep = ({ sleepData, sleepSupplements }) => { <> diff --git a/src/pages/tools/longevity-protocol/habits/study.tsx b/src/pages/tools/longevity-protocol/habits/study.tsx index 979928b..4dab0bb 100644 --- a/src/pages/tools/longevity-protocol/habits/study.tsx +++ b/src/pages/tools/longevity-protocol/habits/study.tsx @@ -1,5 +1,4 @@ import { GetStaticProps } from 'next'; -import { useRouter } from 'next/router'; import StudyLayout from '@layouts/StudyLayout'; @@ -7,19 +6,15 @@ import { getStudy } from '@api/longevity/study'; import SeoGenerator from '@components/SeoGenerator'; const Study = ({ studyData }) => { - const router = useRouter(); - const { locale } = router; - const currentLocale = locale === 'ru' ? 'ru' : 'en'; - const OGTags = { - ogDescription: studyData[currentLocale]?.ogDescription || '', - ogTitle: studyData[currentLocale]?.ogTitle || '', - ogType: studyData[currentLocale]?.ogType || '', - ogImageAlt: studyData[currentLocale]?.ogImageAlt || '', + ogDescription: studyData['en']?.ogDescription || '', + ogTitle: studyData['en']?.ogTitle || '', + ogType: studyData['en']?.ogType || '', + ogImageAlt: studyData['en']?.ogImageAlt || '', ogImage: { data: { attributes: { - url: studyData[currentLocale]?.ogImage?.data?.attributes?.url || '', + url: studyData['en']?.ogImage?.data?.attributes?.url || '', }, }, }, @@ -29,19 +24,16 @@ const Study = ({ studyData }) => { <> - + ); }; diff --git a/src/pages/tools/longevity-protocol/habits/supplements.tsx b/src/pages/tools/longevity-protocol/habits/supplements.tsx index 496267e..88aac4b 100644 --- a/src/pages/tools/longevity-protocol/habits/supplements.tsx +++ b/src/pages/tools/longevity-protocol/habits/supplements.tsx @@ -1,5 +1,4 @@ import { GetStaticProps } from 'next'; -import { useRouter } from 'next/router'; import SupplementsLayout from '@layouts/Supplements'; @@ -7,19 +6,15 @@ import { getSupplements } from '@api/longevity/supplements'; import SeoGenerator from '@components/SeoGenerator'; const Supplements = ({ supplements }) => { - const router = useRouter(); - const { locale } = router; - const currentLocale = locale === 'ru' ? 'ru' : 'en'; - const OGTags = { - ogDescription: supplements[currentLocale]?.ogDescription || '', - ogTitle: supplements[currentLocale]?.ogTitle || '', - ogType: supplements[currentLocale]?.ogType || '', - ogImageAlt: supplements[currentLocale]?.ogImageAlt || '', + ogDescription: supplements['en']?.ogDescription || '', + ogTitle: supplements['en']?.ogTitle || '', + ogType: supplements['en']?.ogType || '', + ogImageAlt: supplements['en']?.ogImageAlt || '', ogImage: { data: { attributes: { - url: supplements[currentLocale]?.ogImage?.data?.attributes?.url || '', + url: supplements['en']?.ogImage?.data?.attributes?.url || '', }, }, }, @@ -29,18 +24,18 @@ const Supplements = ({ supplements }) => { <> ); diff --git a/src/pages/tools/longevity-protocol/habits/workout.tsx b/src/pages/tools/longevity-protocol/habits/workout.tsx index f6c399f..a80bdd5 100644 --- a/src/pages/tools/longevity-protocol/habits/workout.tsx +++ b/src/pages/tools/longevity-protocol/habits/workout.tsx @@ -1,5 +1,4 @@ import { GetStaticProps } from 'next'; -import { useRouter } from 'next/router'; import WorkoutLayout from '@layouts/WorkoutLayout/WorkoutLayout'; @@ -7,19 +6,15 @@ import { getWorkout } from '@api/longevity/workout'; import SeoGenerator from '@components/SeoGenerator'; const Workout = ({ workoutData }) => { - const router = useRouter(); - const { locale } = router; - const currentLocale = locale === 'ru' ? 'ru' : 'en'; - const OGTags = { - ogDescription: workoutData[currentLocale]?.ogDescription || '', - ogTitle: workoutData[currentLocale]?.ogTitle || '', - ogType: workoutData[currentLocale]?.ogType || '', - ogImageAlt: workoutData[currentLocale]?.ogImageAlt || '', + ogDescription: workoutData['en']?.ogDescription || '', + ogTitle: workoutData['en']?.ogTitle || '', + ogType: workoutData['en']?.ogType || '', + ogImageAlt: workoutData['en']?.ogImageAlt || '', ogImage: { data: { attributes: { - url: workoutData[currentLocale]?.ogImage?.data?.attributes?.url || '', + url: workoutData['en']?.ogImage?.data?.attributes?.url || '', }, }, }, @@ -29,18 +24,18 @@ const Workout = ({ workoutData }) => { <> ); diff --git a/src/pages/tools/longevity-protocol/results.tsx b/src/pages/tools/longevity-protocol/results.tsx index 4c44969..d63b720 100644 --- a/src/pages/tools/longevity-protocol/results.tsx +++ b/src/pages/tools/longevity-protocol/results.tsx @@ -1,5 +1,4 @@ import { GetServerSideProps } from 'next'; -import { useRouter } from 'next/router'; import ResultsLayout from '@layouts/ResultsLayout'; @@ -7,20 +6,15 @@ import { getLongevityResults } from '@api/longevity/results'; import SeoGenerator from '@components/SeoGenerator'; const Results = ({ yearlyResults }) => { - const router = useRouter(); - const { locale } = router; - const currentLocale = locale === 'ru' ? 'ru' : 'en'; - const OGTags = { - ogDescription: yearlyResults[currentLocale]?.ogDescription || '', - ogTitle: yearlyResults[currentLocale]?.ogTitle || '', - ogType: yearlyResults[currentLocale]?.ogType || '', - ogImageAlt: yearlyResults[currentLocale]?.ogImageAlt || '', + ogDescription: yearlyResults['en']?.ogDescription || '', + ogTitle: yearlyResults['en']?.ogTitle || '', + ogType: yearlyResults['en']?.ogType || '', + ogImageAlt: yearlyResults['en']?.ogImageAlt || '', ogImage: { data: { attributes: { - url: - yearlyResults[currentLocale]?.ogImage?.data?.attributes?.url || '', + url: yearlyResults['en']?.ogImage?.data?.attributes?.url || '', }, }, }, @@ -30,18 +24,18 @@ const Results = ({ yearlyResults }) => { <> );