From 7b2ba6988c7c7d20bb91e7622ec5a82c4fc8d8df Mon Sep 17 00:00:00 2001 From: ItsFlash10 Date: Fri, 30 Aug 2024 07:15:01 +0530 Subject: [PATCH 1/2] feat-602: Added leagacy mode button on Blog Page --- .prettierrc | 7 +- apps/web/app/pdf/[...pdfId]/page.tsx | 32 +-- apps/web/app/tracks/[...trackIds]/page.tsx | 1 + apps/web/components/Blog.tsx | 45 +++- apps/web/components/BlogAppbar.tsx | 280 ++++++++++++++------- apps/web/components/CustomPagination.tsx | 78 ++++++ apps/web/components/LessonView.tsx | 13 +- apps/web/components/ModeToggle.tsx | 30 ++- apps/web/components/NotionRenderer.tsx | 59 ++--- apps/web/components/PageToggle.tsx | 21 +- apps/web/components/TrackTools.tsx | 13 +- apps/web/package.json | 1 + apps/web/tailwind.config.js | 10 +- packages/store/src/atoms/index.ts | 3 +- packages/store/src/atoms/view.ts | 6 + yarn.lock | 5 + 16 files changed, 405 insertions(+), 199 deletions(-) create mode 100644 apps/web/components/CustomPagination.tsx create mode 100644 packages/store/src/atoms/view.ts diff --git a/.prettierrc b/.prettierrc index e1e9ab71..a11c097b 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,8 +1,9 @@ { "singleQuote": false, - "printWidth":120, + "printWidth": 120, "bracketSpacing": true, "tabWidth": 2, "trailingComma": "es5", - "semi": true -} \ No newline at end of file + "semi": true, + "plugins": ["prettier-plugin-tailwindcss"] +} diff --git a/apps/web/app/pdf/[...pdfId]/page.tsx b/apps/web/app/pdf/[...pdfId]/page.tsx index 70372042..eeb03a1b 100644 --- a/apps/web/app/pdf/[...pdfId]/page.tsx +++ b/apps/web/app/pdf/[...pdfId]/page.tsx @@ -26,7 +26,9 @@ export default async function TrackComponent({ params }: { params: { pdfId: stri if (problemDetails?.notionDocId && trackDetails?.problems) { // notionRecordMaps = await notion.getPage(problemDetails.notionDocId); notionRecordMaps = await Promise.all( - trackDetails.problems.map(async (problem: any) => await notion.getPage((await getProblem(problem.id))?.notionDocId!)) + trackDetails.problems.map( + async (problem: any) => await notion.getPage((await getProblem(problem.id))?.notionDocId!) + ) ); } @@ -36,20 +38,20 @@ export default async function TrackComponent({ params }: { params: { pdfId: stri } if (trackDetails && problemDetails) { return ( -
- {trackDetails?.problems.map((problem: any, i: number) => ( - - ))} - -
+
+ {trackDetails?.problems.map((problem: any, i: number) => ( + + ))} + +
); } } diff --git a/apps/web/app/tracks/[...trackIds]/page.tsx b/apps/web/app/tracks/[...trackIds]/page.tsx index 7a085911..9edb7656 100644 --- a/apps/web/app/tracks/[...trackIds]/page.tsx +++ b/apps/web/app/tracks/[...trackIds]/page.tsx @@ -87,6 +87,7 @@ export default async function TrackComponent({ params }: { params: { trackIds: s return ( { const mounted = useMountStatus(); + const isLegacyMode = useRecoilValue(isLegacyViewMode); if (isPdfRequested == undefined || !isPdfRequested) { if (!mounted) { @@ -25,16 +34,28 @@ export const Blog = ({ } } - return ( -
- -
- + const renderBlog = () => + isLegacyMode ? ( +
+ {showAppBar && } + + {showPagination && ( +
+ +
+ )}
-
- + ) : ( +
+ +
+ +
+
+ +
-
- ); + ); + + return renderBlog(); }; - \ No newline at end of file diff --git a/apps/web/components/BlogAppbar.tsx b/apps/web/components/BlogAppbar.tsx index d75a43e2..65e2b0f1 100644 --- a/apps/web/components/BlogAppbar.tsx +++ b/apps/web/components/BlogAppbar.tsx @@ -1,17 +1,23 @@ "use client"; -import { Problem, Track } from "@prisma/client"; import { useEffect, useState } from "react"; import Link from "next/link"; import { useParams, useRouter } from "next/navigation"; -import { Button, Card, CardContent, Separator } from "@repo/ui"; -import { ModeToggle } from "./ModeToggle"; import { signIn } from "next-auth/react"; import { useSession } from "next-auth/react"; -import UserAccountDropDown from "./UserAccountDropDown"; import Image from "next/image"; +import { useRecoilState } from "recoil"; +import { Download, Menu, RefreshCcwDot, User, X } from "lucide-react"; import { AnimatePresence, motion } from "framer-motion"; -import { Download, Menu, User, X } from "lucide-react"; +import { DownloadIcon } from "@radix-ui/react-icons"; + +import { Problem, Track } from "@prisma/client"; +import { isLegacyViewMode } from "@repo/store"; +import { Button, Card, CardContent, Separator } from "@repo/ui"; + +import { ModeToggle } from "./ModeToggle"; +import UserAccountDropDown from "./UserAccountDropDown"; +import CustomPagination from "./CustomPagination"; export const BlogAppbar = ({ track, @@ -25,6 +31,8 @@ export const BlogAppbar = ({ const session = useSession(); const user = session.data?.user; + const [isLegacyMode, setIsLegacyMode] = useRecoilState(isLegacyViewMode); + const { trackIds }: { trackIds?: string[] } = useParams(); const currentTrack = trackIds ? trackIds.join("/") : ""; @@ -34,6 +42,31 @@ export const BlogAppbar = ({ }); const [visible, setVisible] = useState(true); const [lastScrollY, setLastScrollY] = useState(0); + const [scrollingDown, setScrollingDown] = useState(false); + const [prevScrollPos, setPrevScrollPos] = useState(0); + + const toggleViewMode = () => { + const newViewMode = !isLegacyMode ? "legacy" : "new"; + setIsLegacyMode(!isLegacyMode); + localStorage.setItem("viewMode", newViewMode); + }; + + const debounce = (func: any, delay: any) => { + let timeoutId: any; + return (...args: any) => { + clearTimeout(timeoutId); + timeoutId = setTimeout(() => { + func(...args); + }, delay); + }; + }; + + const debouncedHandleScroll = debounce(() => { + const currentScrollPos = window.scrollY; + setVisible(prevScrollPos > currentScrollPos || currentScrollPos < 50); + setScrollingDown(prevScrollPos < currentScrollPos); + setPrevScrollPos(currentScrollPos); + }, 90); const handleScroll = () => { if (typeof window !== "undefined") { @@ -60,7 +93,7 @@ export const BlogAppbar = ({ transition={{ duration: 0.3 }} className={`${visible ? "translate-y-0" : "-translate-y-full"} px-6`} > - + {track?.problems?.map((problem: { id: string; title: string }, index: number) => { const isDisabled = currentTrack === `${track.id}/${problem.id}`; return ( @@ -68,7 +101,7 @@ export const BlogAppbar = ({ isDisabled && e.preventDefault()} > @@ -83,6 +116,147 @@ export const BlogAppbar = ({ ); }; + const renderUIModeToggleButton = () => ( + + ); + + const renderBlogAppbar = () => + isLegacyMode ? ( +
+
+
+ DailyCode +
+ +

+ {track.title} ({problemIndex + 1} / {track.problems.length}) +

+
+ + + + + + + {renderUIModeToggleButton()} + +
+
+ +

+ {track.title} ({problemIndex + 1} / {track.problems.length}) +

+
+ ) : ( + <> + +
+ {/* menu */} +
setIsOpen(!isOpen)} + className="text-primary border-primary/10 flex cursor-pointer items-center gap-4 rounded-lg border bg-black/10 p-3 backdrop-blur-lg" + > + {isOpen ? : } +
+ {/* track title */} + +
+ + Logo + + + +

+ {track.title} + + {problemIndex + 1} of {track.problems.length} + +

+
+
+
+ + +
+ {!user ? ( + + ) : ( + + )} + + + + + {renderUIModeToggleButton()} +
+
+
+ {isOpen && renderTopics()} + + ); + + useEffect(() => { + window.addEventListener("scroll", isLegacyMode ? debouncedHandleScroll : handleScroll); + return () => { + window.removeEventListener("scroll", isLegacyMode ? debouncedHandleScroll : handleScroll); + }; + }, [prevScrollPos, debouncedHandleScroll, lastScrollY]); + useEffect(() => { window.addEventListener("scroll", handleScroll); return () => { @@ -90,6 +264,12 @@ export const BlogAppbar = ({ }; }, [lastScrollY]); + useEffect(() => { + const savedView = localStorage.getItem("viewMode"); + console.log({ savedView, check: savedView === "legacy" }); + setIsLegacyMode(savedView === "legacy"); + }, []); + useEffect(() => { const handleKeyPress = (event: KeyboardEvent) => { if (event.key === "ArrowRight") { @@ -109,89 +289,5 @@ export const BlogAppbar = ({ }; }, [problemIndex, router, track]); - return ( - <> - -
- {/* menu */} -
setIsOpen(!isOpen)} - className="cursor-pointer flex gap-4 p-3 text-primary bg-black/10 backdrop-blur-lg rounded-lg border border-primary/10 items-center" - > - {isOpen ? : } -
- {/* track title */} - -
- - Logo - - - -

- {track.title} - - {problemIndex + 1} of {track.problems.length} - -

-
-
-
- - -
- {!user ? ( - - ) : ( - - )} - - - - -
-
-
- {isOpen && renderTopics()} - - ); + return renderBlogAppbar(); }; diff --git a/apps/web/components/CustomPagination.tsx b/apps/web/components/CustomPagination.tsx new file mode 100644 index 00000000..0e175a6e --- /dev/null +++ b/apps/web/components/CustomPagination.tsx @@ -0,0 +1,78 @@ +import { Track, Problem } from "@prisma/client"; +import { PageToggle } from "./PageToggle"; +import Link from "next/link"; +import { Button } from "@repo/ui"; +import { ChevronLeftIcon, ChevronRightIcon } from "@radix-ui/react-icons"; + +const CustomPagination = ({ + allProblems, + track, + problemIndex, +}: { + allProblems: Problem[]; + track: Track & { problems: Problem[] }; + problemIndex: number; +}) => { + return ( +
+ + + + + + + + + + +
+ ); +}; + +export default CustomPagination; diff --git a/apps/web/components/LessonView.tsx b/apps/web/components/LessonView.tsx index d683c55d..5bc5d737 100644 --- a/apps/web/components/LessonView.tsx +++ b/apps/web/components/LessonView.tsx @@ -10,12 +10,14 @@ export const LessonView = async ({ problem, track, showAppBar, + showPagination = false, isPdfRequested, }: { problem: Problem & { notionRecordMap: any }; track: Track & { problems: Problem[] }; - showAppBar?: Boolean; - isPdfRequested?: Boolean; + showAppBar?: boolean; + showPagination?: boolean; + isPdfRequested?: boolean; }) => { const session = await getServerSession(authOptions); const problemIndex = track.problems.findIndex((p) => p.id === problem.id); @@ -39,11 +41,12 @@ export const LessonView = async ({ if (problem.type === "Blog") { return ( ); } diff --git a/apps/web/components/ModeToggle.tsx b/apps/web/components/ModeToggle.tsx index cc0b7a0b..e66154d9 100644 --- a/apps/web/components/ModeToggle.tsx +++ b/apps/web/components/ModeToggle.tsx @@ -2,13 +2,18 @@ import * as React from "react"; import { Moon, Sun } from "lucide-react"; +import { useRecoilValue } from "recoil"; import { useTheme } from "next-themes"; -import { Switch } from "@repo/ui"; + +import { Button, Switch } from "@repo/ui"; +import { isLegacyViewMode } from "@repo/store"; export function ModeToggle() { const { theme, setTheme } = useTheme(); const [mounted, setMounted] = React.useState(false); + const isLegacyMode = useRecoilValue(isLegacyViewMode); + React.useEffect(() => { setMounted(true); }, []); @@ -18,11 +23,20 @@ export function ModeToggle() { const isDarkMode = theme === "dark" || (theme === "system" && window.matchMedia("(prefers-color-scheme: dark)").matches); - return ( -
- - setTheme(checked ? "dark" : "light")} /> - -
- ); + const renderToggle = () => + isLegacyMode ? ( + + ) : ( +
+ + setTheme(checked ? "dark" : "light")} /> + +
+ ); + + return renderToggle(); } diff --git a/apps/web/components/NotionRenderer.tsx b/apps/web/components/NotionRenderer.tsx index 55d453c7..5ec17197 100644 --- a/apps/web/components/NotionRenderer.tsx +++ b/apps/web/components/NotionRenderer.tsx @@ -2,6 +2,9 @@ import { useMemo } from "react"; import { NotionRenderer as NotionRendererLib } from "react-notion-x"; import { useTheme } from "next-themes"; +import { useRecoilValue } from "recoil"; + +import { isLegacyViewMode } from "@repo/store"; import CodeBlock from "./CodeBlock"; @@ -10,6 +13,8 @@ export const NotionRenderer = ({ recordMap }: { recordMap: any }) => { const { resolvedTheme } = useTheme(); const isDarkMode = resolvedTheme === "dark"; + const isLegacyMode = useRecoilValue(isLegacyViewMode); + const components = useMemo( () => ({ Code: CodeBlock, @@ -19,50 +24,14 @@ export const NotionRenderer = ({ recordMap }: { recordMap: any }) => { ); return ( -
- -
- -
-
+ ); }; diff --git a/apps/web/components/PageToggle.tsx b/apps/web/components/PageToggle.tsx index d6660923..e5d42d5e 100644 --- a/apps/web/components/PageToggle.tsx +++ b/apps/web/components/PageToggle.tsx @@ -1,29 +1,38 @@ import { useParams } from "next/navigation"; -import { cn } from "@repo/ui/utils"; -import { Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@repo/ui"; -import { Track, Problem } from "@prisma/client"; import Link from "next/link"; +import { useRecoilValue } from "recoil"; import { ArrowUpRight } from "lucide-react"; +import { Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@repo/ui"; +import { Track, Problem } from "@prisma/client"; +import { isLegacyViewMode } from "@repo/store"; +import { cn } from "@repo/ui/utils"; + export function PageToggle({ allProblems, track }: { allProblems: Problem[]; track: Track & { problems: Problem[] } }) { const { trackIds }: { trackIds?: string[] } = useParams(); const currentTrack = trackIds ? trackIds.join("/") : ""; + const isLegacyMode = useRecoilValue(isLegacyViewMode); + return ( - - + {allProblems.map((problem: { id: string; title: string }, index: number) => ( {index + 1} - {problem.title} diff --git a/apps/web/components/TrackTools.tsx b/apps/web/components/TrackTools.tsx index aaa41231..078271bb 100644 --- a/apps/web/components/TrackTools.tsx +++ b/apps/web/components/TrackTools.tsx @@ -22,12 +22,11 @@ const TrackTools = ({ initial={{ y: 20, opacity: 0 }} animate={{ y: 0, opacity: 1 }} transition={{ duration: 0.5, ease: "easeInOut", type: "spring", damping: 10 }} - className="flex gap-2 justify-between w-full items-center p-6" + className="flex w-full items-center justify-between gap-2 p-6" > -
- - @@ -38,7 +37,7 @@ const TrackTools = ({ style={{ cursor: problemIndex !== 0 ? "pointer" : "not-allowed" }} >