feat: preload apng leo, page moons, logic of transitions between pages breath and compatibility, fix navbar footer, fix energy values

This commit is contained in:
gofnnp 2023-09-28 02:22:13 +04:00
parent 8b78a612fb
commit 864eb9ee4b
12 changed files with 170 additions and 64 deletions

View File

@ -1,4 +1,4 @@
import { useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { import {
Routes, Routes,
Route, Route,
@ -42,16 +42,42 @@ import HomePage from "../HomePage";
import UserCallbacksPage from "../UserCallbacksPage"; import UserCallbacksPage from "../UserCallbacksPage";
import NavbarFooter, { INavbarHomeItems } from "../NavbarFooter"; import NavbarFooter, { INavbarHomeItems } from "../NavbarFooter";
import { EPathsFromHome } from "@/store/siteConfig"; import { EPathsFromHome } from "@/store/siteConfig";
import parseAPNG, { APNG } from "apng-js";
import { useApi, useApiCall } from "@/api";
import { Asset } from "@/api/resources/Assets";
function App(): JSX.Element { function App(): JSX.Element {
const [isSpecialOfferOpen, setIsSpecialOfferOpen] = useState<boolean>(false); const [isSpecialOfferOpen, setIsSpecialOfferOpen] = useState<boolean>(false);
const [leoApng, setLeoApng] = useState<Error | APNG>(Error);
const navigate = useNavigate(); const navigate = useNavigate();
const api = useApi();
const closeSpecialOfferAttention = () => { const closeSpecialOfferAttention = () => {
setIsSpecialOfferOpen(false); setIsSpecialOfferOpen(false);
navigate(routes.client.emailEnter()); navigate(routes.client.emailEnter());
}; };
const assetsData = useCallback(async () => {
const { assets } = await api.getAssets({
category: String("au"),
});
return assets;
}, [api]);
const { data } = useApiCall<Asset[]>(assetsData);
useEffect(() => {
async function getApng() {
if (!data) return;
const response = await fetch(
data.find((item) => item.key === "au.apng.leo")?.url || ""
);
const arrayBuffer = await response.arrayBuffer();
setLeoApng(parseAPNG(arrayBuffer));
}
getApng();
}, [data]);
return ( return (
<Routes> <Routes>
<Route element={<Layout setIsSpecialOfferOpen={setIsSpecialOfferOpen} />}> <Route element={<Layout setIsSpecialOfferOpen={setIsSpecialOfferOpen} />}>
@ -84,7 +110,10 @@ function App(): JSX.Element {
path={routes.client.compatibilityResult()} path={routes.client.compatibilityResult()}
element={<CompatResultPage />} element={<CompatResultPage />}
/> />
<Route path={routes.client.breath()} element={<BreathPage />} /> <Route
path={routes.client.breath()}
element={<BreathPage leoApng={leoApng} />}
/>
<Route path={routes.client.priceList()} element={<PriceListPage />} /> <Route path={routes.client.priceList()} element={<PriceListPage />} />
<Route path={routes.client.home()} element={<HomePage />} /> <Route path={routes.client.home()} element={<HomePage />} />
<Route <Route
@ -127,7 +156,7 @@ function Layout({ setIsSpecialOfferOpen }: LayoutProps): JSX.Element {
dispatch( dispatch(
actions.siteConfig.update({ actions.siteConfig.update({
home: { home: {
pathFromHome: EPathsFromHome.compatibility, pathFromHome: EPathsFromHome.navbar,
isShowNavbar: showNavbarFooter, isShowNavbar: showNavbarFooter,
}, },
}) })
@ -138,7 +167,7 @@ function Layout({ setIsSpecialOfferOpen }: LayoutProps): JSX.Element {
dispatch( dispatch(
actions.siteConfig.update({ actions.siteConfig.update({
home: { home: {
pathFromHome: EPathsFromHome.breath, pathFromHome: EPathsFromHome.navbar,
isShowNavbar: showNavbarFooter, isShowNavbar: showNavbarFooter,
}, },
}) })
@ -150,12 +179,14 @@ function Layout({ setIsSpecialOfferOpen }: LayoutProps): JSX.Element {
{ {
title: "Breathing", title: "Breathing",
path: routes.client.breath(), path: routes.client.breath(),
paths: [routes.client.breath(), routes.client.breathResult()],
image: "Breath.svg", image: "Breath.svg",
onClick: handleBreath, onClick: handleBreath,
}, },
{ {
title: "Aura", title: "Aura",
path: routes.client.home(), path: routes.client.home(),
paths: [routes.client.home()],
image: "Aura.svg", image: "Aura.svg",
active: true, active: true,
onClick: () => null, onClick: () => null,
@ -163,12 +194,17 @@ function Layout({ setIsSpecialOfferOpen }: LayoutProps): JSX.Element {
{ {
title: "Compatibility", title: "Compatibility",
path: routes.client.compatibility(), path: routes.client.compatibility(),
paths: [
routes.client.compatibility(),
routes.client.compatibilityResult(),
],
image: "Compatibility.svg", image: "Compatibility.svg",
onClick: handleCompatibility, onClick: handleCompatibility,
}, },
{ {
title: "My Moon", title: "My Moon",
path: routes.client.wallpaper(), path: routes.client.wallpaper(),
paths: [routes.client.wallpaper()],
image: "moon.svg", image: "moon.svg",
onClick: () => null, onClick: () => null,
}, },
@ -221,7 +257,7 @@ function MainPage(): JSX.Element {
function ProtectWallpaperPage(): JSX.Element { function ProtectWallpaperPage(): JSX.Element {
const status = useSelector(selectors.selectStatus); const status = useSelector(selectors.selectStatus);
return (<WallpaperPage />); return <WallpaperPage />;
return status === "subscribed" ? ( return status === "subscribed" ? (
<WallpaperPage /> <WallpaperPage />
) : ( ) : (

View File

@ -1,7 +1,6 @@
import styles from "./styles.module.css"; import styles from "./styles.module.css";
import { useCallback, useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useRef, useState } from "react";
import { UserCallbacks, useApi, useApiCall } from "@/api"; import { UserCallbacks, useApi, useApiCall } from "@/api";
import { Asset } from "@/api/resources/Assets";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { actions, selectors } from "@/store"; import { actions, selectors } from "@/store";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@ -10,13 +9,17 @@ import StartBreathModalChild from "../StartBreathModalChild";
import Title from "../Title"; import Title from "../Title";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import routes from "@/routes"; import routes from "@/routes";
import parseAPNG from "apng-js"; import { APNG } from "apng-js";
import Player from "apng-js/types/library/player"; import Player from "apng-js/types/library/player";
import { EPathsFromHome } from "@/store/siteConfig"; import { EPathsFromHome } from "@/store/siteConfig";
let apngPlayer: Player | null = null; let apngPlayer: Player | null = null;
function BreathPage(): JSX.Element { interface BreathPageProps {
leoApng: Error | APNG;
}
function BreathPage({ leoApng }: BreathPageProps): JSX.Element {
const { t } = useTranslation(); const { t } = useTranslation();
const [isOpenModal, setIsOpenModal] = useState<boolean>(true); const [isOpenModal, setIsOpenModal] = useState<boolean>(true);
const [isShowPreview, setIsShowPreview] = useState<boolean>(true); const [isShowPreview, setIsShowPreview] = useState<boolean>(true);
@ -28,15 +31,6 @@ function BreathPage(): JSX.Element {
const homeConfig = useSelector(selectors.selectHome); const homeConfig = useSelector(selectors.selectHome);
const showNavbarFooter = homeConfig.isShowNavbar; const showNavbarFooter = homeConfig.isShowNavbar;
const assetsData = useCallback(async () => {
const { assets } = await api.getAssets({
category: String("au"),
});
return assets;
}, [api]);
const { data } = useApiCall<Asset[]>(assetsData);
useEffect(() => { useEffect(() => {
if (isOpenModal) return; if (isOpenModal) return;
const previewTimeOut = setTimeout(() => { const previewTimeOut = setTimeout(() => {
@ -55,26 +49,20 @@ function BreathPage(): JSX.Element {
}, [navigate, isOpenModal]); }, [navigate, isOpenModal]);
useEffect(() => { useEffect(() => {
async function getApng() { async function getApngPlayer() {
if (!data) return;
const response = await fetch(
data.find((item) => item.key === "au.apng.leo")?.url || ""
);
const arrayBuffer = await response.arrayBuffer();
const apng = parseAPNG(arrayBuffer);
const context = leoCanvasRef.current?.getContext("2d"); const context = leoCanvasRef.current?.getContext("2d");
if (context && !(apng instanceof Error)) { if (context && !(leoApng instanceof Error)) {
context.canvas.height = apng.height; context.canvas.height = leoApng.height;
context.canvas.width = apng.width; context.canvas.width = leoApng.width;
const _apngPlayer = await apng.getPlayer(context); const _apngPlayer = await leoApng.getPlayer(context);
apngPlayer = _apngPlayer; apngPlayer = _apngPlayer;
if (apngPlayer) { if (apngPlayer) {
apngPlayer.stop(); apngPlayer.stop();
} }
} }
} }
getApng(); getApngPlayer();
}, [data]); }, [leoApng]);
const beginBreath = () => { const beginBreath = () => {
setIsOpenModal(false); setIsOpenModal(false);
@ -168,7 +156,10 @@ function BreathPage(): JSX.Element {
</div> </div>
)} )}
<FullScreenModal isOpen={isOpenModal}> <FullScreenModal isOpen={isOpenModal}>
<StartBreathModalChild handleBegin={beginBreath} isShowNavbar={showNavbarFooter} /> <StartBreathModalChild
handleBegin={beginBreath}
isShowNavbar={showNavbarFooter}
/>
</FullScreenModal> </FullScreenModal>
{!isOpenModal && !isShowPreview && ( {!isOpenModal && !isShowPreview && (
<div className={styles["text-container"]}> <div className={styles["text-container"]}>

View File

@ -25,6 +25,8 @@ function CompatResultPage(): JSX.Element {
const showNavbarFooter = homeConfig.isShowNavbar; const showNavbarFooter = homeConfig.isShowNavbar;
const [text, setText] = useState("Loading..."); const [text, setText] = useState("Loading...");
const [isOpenModal, setIsOpenModal] = useState(true); const [isOpenModal, setIsOpenModal] = useState(true);
const [isVisualLoading, setIsVisualLoading] = useState(true);
const [isDataLoading, setIsDataLoading] = useState(true);
const handleNext = () => { const handleNext = () => {
if (homeConfig.pathFromHome === EPathsFromHome.breath) { if (homeConfig.pathFromHome === EPathsFromHome.breath) {
@ -68,10 +70,14 @@ function CompatResultPage(): JSX.Element {
setTimeout(loadAIRequest, 3000); setTimeout(loadAIRequest, 3000);
} }
setText(aIRequest?.ai_request?.response?.body || "Loading..."); setText(aIRequest?.ai_request?.response?.body || "Loading...");
setIsDataLoading(false);
checkLoading();
return aIRequest.ai_request; return aIRequest.ai_request;
}; };
return await loadAIRequest(); return await loadAIRequest();
} }
setIsDataLoading(false);
checkLoading();
setText(aICompat?.compat?.body || "Loading..."); setText(aICompat?.compat?.body || "Loading...");
return aICompat.compat; return aICompat.compat;
@ -91,6 +97,14 @@ function CompatResultPage(): JSX.Element {
return "108px"; return "108px";
}; };
function checkLoading() {
if (isVisualLoading || isDataLoading) {
setIsOpenModal(true);
} else {
setIsOpenModal(false);
}
}
return ( return (
<section <section
className={`${styles.page} page`} className={`${styles.page} page`}
@ -100,7 +114,8 @@ function CompatResultPage(): JSX.Element {
<CompatibilityLoading <CompatibilityLoading
secondPerson={rightUser.name} secondPerson={rightUser.name}
onEndLoading={() => { onEndLoading={() => {
setIsOpenModal(false); setIsVisualLoading(false);
checkLoading();
}} }}
/> />
</FullScreenModal> </FullScreenModal>

View File

@ -14,7 +14,7 @@ const colors: Record<string, string> = {
} }
const valueFormatter = (value: number) => { const valueFormatter = (value: number) => {
return `${(value).toFixed()}%` return `${(value * 10).toFixed(1)}%`
} }
function EnergyValues({ className, values }: IEnergyValues): JSX.Element { function EnergyValues({ className, values }: IEnergyValues): JSX.Element {

View File

@ -134,7 +134,7 @@ function HomePage(): JSX.Element {
</div> </div>
</div> </div>
<div className={styles.content} style={{ marginTop: isShowNavbar ? "calc(100vh - 570px)" : "calc(100vh - 500px)"}}> <div className={styles.content} style={{ marginTop: isShowNavbar ? "calc(100vh - 570px)" : "calc(100vh - 500px)"}}>
<div className={styles["content__buttons"]}> {<div className={`${styles["content__buttons"]} ${isShowNavbar ? styles["content__buttons--hidden"] : ""}`}>
<BlurringSubstrate <BlurringSubstrate
style={{ color: "#fa71ea" }} style={{ color: "#fa71ea" }}
className={styles["content__buttons-item"]} className={styles["content__buttons-item"]}
@ -149,7 +149,7 @@ function HomePage(): JSX.Element {
> >
{buttonTextFormatter(t("aura-10_breath-button"))} {buttonTextFormatter(t("aura-10_breath-button"))}
</BlurringSubstrate> </BlurringSubstrate>
</div> </div>}
<div className={styles["content__daily-forecast"]}> <div className={styles["content__daily-forecast"]}>
{dailyForecast && {dailyForecast &&
dailyForecast.forecasts.map((forecast, index) => ( dailyForecast.forecasts.map((forecast, index) => (

View File

@ -131,6 +131,11 @@
/* margin-left: 13px; */ /* margin-left: 13px; */
} }
.content__buttons--hidden {
opacity: 0;
pointer-events: none;
}
@keyframes pulse { @keyframes pulse {
0% { 0% {
transform: scale(0.9); transform: scale(0.9);

View File

@ -3,8 +3,9 @@ import styles from "./styles.module.css";
export interface INavbarHomeItems { export interface INavbarHomeItems {
title: string; title: string;
path: string; paths: string[];
image: string; image: string;
path: string;
active?: boolean; active?: boolean;
onClick?: () => void; onClick?: () => void;
} }
@ -32,9 +33,9 @@ function NavbarFooter({ items }: INavbarHomeProps): JSX.Element {
className={styles["navbar-item__image-container"]} className={styles["navbar-item__image-container"]}
style={{ style={{
backgroundColor: backgroundColor:
item.path === location.pathname ? "#ff2c57" : "#fff", item.paths.includes(location.pathname) ? "#ff2c57" : "#fff",
mask: `url('./navbar-icons/${item.image}')`, mask: `url('/navbar-icons/${item.image}')`,
WebkitMask: `url('./navbar-icons/${item.image}')`, WebkitMask: `url('/navbar-icons/${item.image}')`,
WebkitMaskSize: "contain", WebkitMaskSize: "contain",
WebkitMaskRepeat: "no-repeat", WebkitMaskRepeat: "no-repeat",
WebkitMaskPosition: "center", WebkitMaskPosition: "center",
@ -49,7 +50,7 @@ function NavbarFooter({ items }: INavbarHomeProps): JSX.Element {
</div> </div>
<p <p
style={{ style={{
color: item.path === location.pathname ? "#ff2c57" : "#fff", color: item.paths.includes(location.pathname) ? "#ff2c57" : "#fff",
}} }}
> >
{item.title} {item.title}

View File

@ -12,8 +12,6 @@ function StartBreathModalChild({
isShowNavbar=false isShowNavbar=false
}: IStartBreathModalChildProps): JSX.Element { }: IStartBreathModalChildProps): JSX.Element {
const { t } = useTranslation(); const { t } = useTranslation();
console.log(isShowNavbar);
return ( return (
<section className={`${styles["start-breath"]} page ${isShowNavbar ? styles["show-navbar"] : ""}`}> <section className={`${styles["start-breath"]} page ${isShowNavbar ? styles["show-navbar"] : ""}`}>

View File

@ -28,20 +28,27 @@ function UserCallbacksPage(): JSX.Element {
if (homeConfig.pathFromHome === EPathsFromHome.breath) { if (homeConfig.pathFromHome === EPathsFromHome.breath) {
return navigate(routes.client.compatibility()); return navigate(routes.client.compatibility());
} }
if (homeConfig.pathFromHome === EPathsFromHome.navbar) {
return navigate(routes.client.breath());
}
}; };
const getPaddingBottomPage = () => { const getPaddingBottomPage = () => {
if (homeConfig.pathFromHome === EPathsFromHome.compatibility && showNavbarFooter) return "246px"; if (
homeConfig.pathFromHome === EPathsFromHome.compatibility &&
showNavbarFooter
)
return "246px";
if (showNavbarFooter) return "164px"; if (showNavbarFooter) return "164px";
return "108px"; return "108px";
} };
return ( return (
<section <section
className={`${styles.page} page`} className={`${styles.page} page`}
style={{ paddingBottom: getPaddingBottomPage() }} style={{ paddingBottom: getPaddingBottomPage() }}
> >
{!showNavbarFooter && <div className={styles.cross} onClick={handleNext}></div>} {<div className={styles.cross} onClick={handleNext}></div>}
<div className={styles["title-container"]}> <div className={styles["title-container"]}>
<Title variant="h3" className={styles.percent}> <Title variant="h3" className={styles.percent}>
<> <>

View File

@ -11,7 +11,7 @@ import {
getCategoryIdByZodiacSign, getCategoryIdByZodiacSign,
getZodiacSignByDate, getZodiacSignByDate,
} from "@/services/zodiac-sign"; } from "@/services/zodiac-sign";
import { Zodiac } from "@/api/resources/Zodiacs"; import { Zodiac, ZodiacParagraph } from "@/api/resources/Zodiacs";
type Forecasts = DailyForecasts.Forecast[]; type Forecasts = DailyForecasts.Forecast[];
type PersonalAssets = Assets.Asset[]; type PersonalAssets = Assets.Asset[];
@ -21,9 +21,42 @@ interface WallpaperData {
zodiac: Zodiac; zodiac: Zodiac;
} }
function getZodiacParagraphs(
paragraphs: ZodiacParagraph[],
depth = 0
): JSX.Element[] {
depth++;
if (!paragraphs) {
return [];
}
function getTypeOfContent(content: string[] | ZodiacParagraph[]) {
if (Array.isArray(content) && content.length > 0) {
return typeof content[0];
}
}
return paragraphs.map((paragraph, index) => {
const Headline = `h${depth}` as keyof JSX.IntrinsicElements;
return (
<div className={styles["wallpaper-paragraph"]} key={index}>
<Headline
className={`${styles["wallpaper-paragraph__title"]} ${
depth % 2 === 0 ? styles["wallpaper-paragraph__title--white"] : ""
}`}
>
{paragraph.title}
</Headline>
{getTypeOfContent(paragraph.content) === "string"
? paragraph.content.map((content, _index) => <p key={_index}>{content as string}</p>)
: getZodiacParagraphs(paragraph.content as ZodiacParagraph[], depth)}
</div>
);
});
}
function WallpaperPage(): JSX.Element { function WallpaperPage(): JSX.Element {
const api = useApi(); const api = useApi();
const { t, i18n } = useTranslation(); const { i18n } = useTranslation();
const locale = i18n.language; const locale = i18n.language;
const token = const token =
"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOjIzNjEyLCJpYXQiOjE2OTM0MTg5MTAsImV4cCI6MTcwMjA1ODkxMCwianRpIjoiNzg5MjkwYWItODg0YS00MGUyLTkyNjEtOWI2OGEyNjkwNmE0IiwiZW1haWwiOiJvdGhlckBleGFtcGxlLmNvbSIsInN0YXRlIjoicHJvdmVuIiwibG9jIjoiZW4iLCJ0eiI6LTI4ODAwLCJ0eXBlIjoiZW1haWwiLCJpc3MiOiJjb20ubGlmZS5hdXJhIn0.J2ocWIv5jKzuKMcwMgWMiNMyGg5qLlMAeln-bQm_9lw"; "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOjIzNjEyLCJpYXQiOjE2OTM0MTg5MTAsImV4cCI6MTcwMjA1ODkxMCwianRpIjoiNzg5MjkwYWItODg0YS00MGUyLTkyNjEtOWI2OGEyNjkwNmE0IiwiZW1haWwiOiJvdGhlckBleGFtcGxlLmNvbSIsInN0YXRlIjoicHJvdmVuIiwibG9jIjoiZW4iLCJ0eiI6LTI4ODAwLCJ0eXBlIjoiZW1haWwiLCJpc3MiOiJjb20ubGlmZS5hdXJhIn0.J2ocWIv5jKzuKMcwMgWMiNMyGg5qLlMAeln-bQm_9lw";
@ -50,7 +83,6 @@ function WallpaperPage(): JSX.Element {
})); }));
}, [api, token, locale, zodiacSign]); }, [api, token, locale, zodiacSign]);
const { data, isPending } = useApiCall<WallpaperData>(loadData); const { data, isPending } = useApiCall<WallpaperData>(loadData);
const forecasts = data ? data.forecasts : [];
const asset = data ? data.assets.at(0) : null; const asset = data ? data.assets.at(0) : null;
const zodiacInfo = data ? data.zodiac : null; const zodiacInfo = data ? data.zodiac : null;
@ -64,14 +96,6 @@ function WallpaperPage(): JSX.Element {
className={styles["wallpaper-image"]} className={styles["wallpaper-image"]}
style={{ backgroundImage: `url(${asset?.url})` }} style={{ backgroundImage: `url(${asset?.url})` }}
> >
<div className={styles["zodiac-metas"]}>
{zodiacInfo?.metas.map((meta, index) => (
<div key={index} className={styles["zodiac-meta"]}>
<p className={styles["zodiac-meta-label"]}>{meta.label}</p>
<p className={styles["zodiac-meta-value"]}>{meta.value}</p>
</div>
))}
</div>
{asset ? ( {asset ? (
<div className={styles["btn-download"]} onClick={handleClick} /> <div className={styles["btn-download"]} onClick={handleClick} />
) : null} ) : null}
@ -80,10 +104,18 @@ function WallpaperPage(): JSX.Element {
<div className={styles["wallpaper-content"]}> <div className={styles["wallpaper-content"]}>
{isPending ? null : ( {isPending ? null : (
<> <>
<h1 className={styles["wallpaper-title"]}> <div className={styles["zodiac-metas"]}>
{zodiacInfo?.metas.map((meta, index) => (
<div key={index} className={styles["zodiac-meta"]}>
<p className={styles["zodiac-meta-label"]}>{meta.label}</p>
<p className={styles["zodiac-meta-value"]}>{meta.value}</p>
</div>
))}
</div>
{/* <h1 className={styles["wallpaper-title"]}>
{t("analysis_background")} {t("analysis_background")}
</h1> </h1> */}
{forecasts.map((forecast) => ( {/* {forecasts.map((forecast) => (
<div <div
key={forecast.category_name} key={forecast.category_name}
className={styles["wallpaper-forecast"]} className={styles["wallpaper-forecast"]}
@ -93,7 +125,10 @@ function WallpaperPage(): JSX.Element {
</h2> </h2>
<p className={styles["wallpaper-text"]}>{forecast.body}</p> <p className={styles["wallpaper-text"]}>{forecast.body}</p>
</div> </div>
))} ))} */}
<div className={styles["wallpaper-forecast"]}>
{getZodiacParagraphs(zodiacInfo?.paragraphs || [])}
</div>
</> </>
)} )}
</div> </div>

View File

@ -33,7 +33,7 @@
} }
.wallpaper-content::before { .wallpaper-content::before {
content: ''; content: "";
display: block; display: block;
position: absolute; position: absolute;
top: -30px; top: -30px;
@ -72,7 +72,8 @@
} }
.zodiac-metas { .zodiac-metas {
width: 100%; width: calc(100% - 64px);
margin: -80px auto 16px;
height: fit-content; height: fit-content;
padding: 16px; padding: 16px;
background-color: #5d5d5d; background-color: #5d5d5d;
@ -97,4 +98,20 @@
.zodiac-meta-value { .zodiac-meta-value {
font-weight: 700; font-weight: 700;
} }
.wallpaper-paragraph {
margin-bottom: 32px;
}
.wallpaper-paragraph__title {
color: #ea445a;
margin-bottom: 16px;
}
.wallpaper-paragraph__title--white {
margin-bottom: 0;
color: #fff;
font-size: 22px;
font-weight: 700;
}

View File

@ -3,7 +3,8 @@ import type { PayloadAction } from "@reduxjs/toolkit";
export enum EPathsFromHome { export enum EPathsFromHome {
compatibility, compatibility,
breath breath,
navbar
} }
interface ISiteConfig { interface ISiteConfig {