From 0e2ec7a54c0d4d0c3d8ea82f1356e907d72f7adc Mon Sep 17 00:00:00 2001 From: Sumit Jain Date: Fri, 7 Mar 2025 22:59:14 +0530 Subject: [PATCH 01/48] feat: refactor data fetching for commit documentation and add custom hooks --- .../features/LandingPage/DocsLandingPage.tsx | 15 ++--- .../LandingPage/useGetCommitDocsDetails.ts | 66 +++++++++++++++++++ 2 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 docs/src/pages/features/LandingPage/useGetCommitDocsDetails.ts diff --git a/docs/src/pages/features/LandingPage/DocsLandingPage.tsx b/docs/src/pages/features/LandingPage/DocsLandingPage.tsx index 8d0a2eb..6f8188d 100644 --- a/docs/src/pages/features/LandingPage/DocsLandingPage.tsx +++ b/docs/src/pages/features/LandingPage/DocsLandingPage.tsx @@ -1,20 +1,13 @@ import { ErrorBanner } from "@/components/common/ErrorBanner/ErrorBanner"; -import { CommitDocs } from "@/types/commit/CommitDocs"; -import { useFrappeGetCall } from "frappe-react-sdk"; import { FullPageLoader } from "@/components/common/FullPageLoader/FullPageLoader"; import { ShootingStars } from "./ShootingStars"; import HeroSection from "./HeroSection"; import DocsList from "./DocsList"; +import { useGetCommitDocsList } from "./useGetCommitDocsDetails"; const DocsLandingPage = () => { - const { data, error, isLoading } = useFrappeGetCall<{ message: CommitDocs[] }>( - 'commit.commit.doctype.commit_docs.commit_docs.get_commit_docs_list', {}, undefined, { - revalidateOnFocus: false, - revalidateIfStale: false, - revalidateOnReconnect: false, - } - ); + const { data, isLoading, error } = useGetCommitDocsList(); if (error) { return ; @@ -23,7 +16,7 @@ const DocsLandingPage = () => { if (isLoading) { return ; } - if (data && data?.message) { + if (data && data) { return (
@@ -43,7 +36,7 @@ const DocsLandingPage = () => {
- +
diff --git a/docs/src/pages/features/LandingPage/useGetCommitDocsDetails.ts b/docs/src/pages/features/LandingPage/useGetCommitDocsDetails.ts new file mode 100644 index 0000000..1bf9279 --- /dev/null +++ b/docs/src/pages/features/LandingPage/useGetCommitDocsDetails.ts @@ -0,0 +1,66 @@ +import { useMemo } from 'react'; +import { useFrappeGetCall } from 'frappe-react-sdk'; +import { Docs } from '@/pages/features/docs/docs'; + +export const useGetCommitDocsDetails = (ID: string) => { + // First, check if the data is already available in window.frappe.boot + const bootCommitDocsDetails: Docs = useMemo(() => { + // @ts-expect-error + return window?.frappe?.boot?.get_all_commit_docs_detail?.[ID] || null; + }, [ID]); + + // Use the API call hook with conditional fetching + const { + data: apiCommitDocsDetails, + error, + isLoading + } = useFrappeGetCall<{ message: Docs }>( + 'commit.commit.doctype.commit_docs.commit_docs.get_commit_docs_details', + { + route: ID, + }, + bootCommitDocsDetails === null ? 'get_commit_docs_details' : null, + { + // Only fetch if boot data is not available + revalidateOnFocus: false, + revalidateIfStale: false, + revalidateOnReconnect: false, + } + ); + + // Return the data from boot if available, otherwise from the API call + const data = bootCommitDocsDetails || apiCommitDocsDetails?.message; + + return { data, error, isLoading }; +}; + +export const useGetCommitDocsList = () => { + + // First check if the data is already available in window.frappe.boot + const bootCommitDocsList = useMemo(() => { + // @ts-expect-error + return window?.frappe?.boot?.get_commit_docs_list || null; + }, []); + + // Use the API call hook with conditional fetching + const { + data: apiCommitDocsList, + error, + isLoading + } = useFrappeGetCall<{ message: Docs[] }>( + 'commit.commit.doctype.commit_docs.commit_docs.get_commit_docs_list', + {}, + bootCommitDocsList === null ? 'get_commit_docs_list' : null, + { + // Only fetch if boot data is not available + revalidateOnFocus: false, + revalidateIfStale: false, + revalidateOnReconnect: false, + } + ); + + // Return the data from boot if available, otherwise from the API call + const data = bootCommitDocsList || apiCommitDocsList?.message; + + return { data, error, isLoading }; +}; \ No newline at end of file From 5e03cbbe13f8fb8191ea8e4111ceaa64db5b83f3 Mon Sep 17 00:00:00 2001 From: Sumit Jain Date: Sat, 8 Mar 2025 01:04:14 +0530 Subject: [PATCH 02/48] feat: remove unused DocsLandingPage, DocsList, HeroSection, and ShootingStars components --- .../docs/LandingPage/DocsLandingPage.tsx | 56 ------- .../features/docs/LandingPage/DocsList.tsx | 55 ------- .../features/docs/LandingPage/HeroSection.tsx | 31 ---- .../docs/LandingPage/ShootingStars.tsx | 154 ------------------ 4 files changed, 296 deletions(-) delete mode 100644 dashboard/src/pages/features/docs/LandingPage/DocsLandingPage.tsx delete mode 100644 dashboard/src/pages/features/docs/LandingPage/DocsList.tsx delete mode 100644 dashboard/src/pages/features/docs/LandingPage/HeroSection.tsx delete mode 100644 dashboard/src/pages/features/docs/LandingPage/ShootingStars.tsx diff --git a/dashboard/src/pages/features/docs/LandingPage/DocsLandingPage.tsx b/dashboard/src/pages/features/docs/LandingPage/DocsLandingPage.tsx deleted file mode 100644 index 4ca7b90..0000000 --- a/dashboard/src/pages/features/docs/LandingPage/DocsLandingPage.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { ErrorBanner } from "@/components/common/ErrorBanner/ErrorBanner"; -import { CommitDocs } from "@/types/commit/CommitDocs"; -import { useFrappeGetCall } from "frappe-react-sdk"; -import { FullPageLoader } from "@/components/common/FullPageLoader/FullPageLoader"; -import { ShootingStars } from "./ShootingStars"; -import HeroSection from "./HeroSection"; -import DocsList from "./DocsList"; - -const DocsLandingPage = () => { - - const { data, error, isLoading } = useFrappeGetCall<{ message: CommitDocs[] }>( - 'commit.commit.doctype.commit_docs.commit_docs.get_commit_docs_list', {}, undefined, { - revalidateOnFocus: false, - revalidateIfStale: false, - revalidateOnReconnect: false, - } - ); - - if (error) { - return ; - } - - if (isLoading) { - return ; - } - if (data && data?.message) { - return ( -
-
-
- -
- -
-
-
- -
-
-
- ); - } - - return null; -}; - -export default DocsLandingPage; diff --git a/dashboard/src/pages/features/docs/LandingPage/DocsList.tsx b/dashboard/src/pages/features/docs/LandingPage/DocsList.tsx deleted file mode 100644 index f83918f..0000000 --- a/dashboard/src/pages/features/docs/LandingPage/DocsList.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" -import { CommitDocs } from "@/types/commit/CommitDocs" -import { ArrowUpRight } from "lucide-react"; -import { useMemo } from "react" - -const DocsList = ({ data }: { data: CommitDocs[] }) => { - return ( -
- {data.map((item, idx) => ( - - ))} -
- ) -} - -export default DocsList - -const DocCard = ({ data }: { data: CommitDocs }) => { - - const appNameInitials = useMemo(() => { - return data.header[0].toUpperCase() - }, [data]) - - return ( -
-
-
- - - - {appNameInitials} - - -
- {data.header} -
- - - -
- {data.published == 1 &&
-
-
} -
-
- {data.description} -
- -
- ) -} \ No newline at end of file diff --git a/dashboard/src/pages/features/docs/LandingPage/HeroSection.tsx b/dashboard/src/pages/features/docs/LandingPage/HeroSection.tsx deleted file mode 100644 index d103bc0..0000000 --- a/dashboard/src/pages/features/docs/LandingPage/HeroSection.tsx +++ /dev/null @@ -1,31 +0,0 @@ - -import { Button } from "@/components/ui/button"; - -const HeroSection = () => { - return ( -
-
-
- Boring docs? Not on our watch! -
-
- Meet Commit Docs, built with Frappe Framework, it is the modern standard for public-facing documentation. Beautiful out of the box, easy to maintain, and Open Source ✨. -
-
- -
-
- {/*
- ManDoodle. -
*/} -
- ) -} - -export default HeroSection \ No newline at end of file diff --git a/dashboard/src/pages/features/docs/LandingPage/ShootingStars.tsx b/dashboard/src/pages/features/docs/LandingPage/ShootingStars.tsx deleted file mode 100644 index 18a6c8e..0000000 --- a/dashboard/src/pages/features/docs/LandingPage/ShootingStars.tsx +++ /dev/null @@ -1,154 +0,0 @@ -import { cn } from "@/lib/utils"; -import React, { useEffect, useState, useRef } from "react"; - -interface ShootingStar { - id: number; - x: number; - y: number; - angle: number; - scale: number; - speed: number; - distance: number; -} - -interface ShootingStarsProps { - minSpeed?: number; - maxSpeed?: number; - minDelay?: number; - maxDelay?: number; - starColor?: string; - trailColor?: string; - starWidth?: number; - starHeight?: number; - className?: string; - maxStars?: number; -} - -const getRandomStartPoint = () => { - const side = Math.floor(Math.random() * 4); - const offset = Math.random() * window.innerWidth; - - switch (side) { - case 0: - return { x: offset, y: 0, angle: 45 }; - case 1: - return { x: window.innerWidth, y: offset, angle: 135 }; - case 2: - return { x: offset, y: window.innerHeight, angle: 225 }; - case 3: - return { x: 0, y: offset, angle: 315 }; - default: - return { x: 0, y: 0, angle: 45 }; - } -}; - -export const ShootingStars: React.FC = ({ - minSpeed = 10, - maxSpeed = 30, - minDelay = 1200, - maxDelay = 4200, - starColor = "#9E00FF", - trailColor = "#2EB9DF", - starWidth = 10, - starHeight = 1, - className, - maxStars = 5, // Maximum stars on the screen -}) => { - const [stars, setStars] = useState([]); - const svgRef = useRef(null); - - useEffect(() => { - const createStar = () => { - if (stars.length >= maxStars) return; // Ensure we don't exceed maxStars - - const { x, y, angle } = getRandomStartPoint(); - const newStar: ShootingStar = { - id: Date.now() + Math.random(), // Unique ID - x, - y, - angle, - scale: 1, - speed: Math.random() * (maxSpeed - minSpeed) + minSpeed, - distance: 0, - }; - - setStars((prevStars) => [...prevStars, newStar]); - - const randomDelay = Math.random() * (maxDelay - minDelay) + minDelay; - setTimeout(createStar, randomDelay); - }; - - const timeoutId = setTimeout(createStar, minDelay); - - return () => clearTimeout(timeoutId); - }, [stars.length, minSpeed, maxSpeed, minDelay, maxDelay, maxStars]); - - useEffect(() => { - const moveStars = () => { - setStars((prevStars) => - prevStars - .map((star) => { - const newX = - star.x + star.speed * Math.cos((star.angle * Math.PI) / 180); - const newY = - star.y + star.speed * Math.sin((star.angle * Math.PI) / 180); - const newDistance = star.distance + star.speed; - const newScale = 1 + newDistance / 100; - - // Remove stars that go out of bounds - if ( - newX < -50 || - newX > window.innerWidth + 50 || - newY < -50 || - newY > window.innerHeight + 50 - ) { - return null; - } - - return { - ...star, - x: newX, - y: newY, - distance: newDistance, - scale: newScale, - }; - }) - .filter((star) => star !== null) as ShootingStar[] // Remove null values - ); - - requestAnimationFrame(moveStars); - }; - - const animationFrame = requestAnimationFrame(moveStars); - return () => cancelAnimationFrame(animationFrame); - }, []); - - return ( - - {stars.map((star) => ( - - ))} - - - - - - - - ); -}; From f9fa7f2c0c8fc1883958f49204425eef7bb1ce71 Mon Sep 17 00:00:00 2001 From: Sumit Jain Date: Sat, 8 Mar 2025 01:04:58 +0530 Subject: [PATCH 03/48] feat: enhance commit documentation retrieval and update routing for docs --- .../commit/doctype/commit_docs/commit_docs.py | 2 +- commit/www/commit.py | 4 +- dashboard/src/App.tsx | 48 ++++++++++--------- .../meta_apps/useGetCommitDocsDetails.ts | 32 +++++++++++++ dashboard/src/components/ui/card.tsx | 14 +++--- 5 files changed, 69 insertions(+), 31 deletions(-) diff --git a/commit/commit/doctype/commit_docs/commit_docs.py b/commit/commit/doctype/commit_docs/commit_docs.py index 3616512..c47f403 100644 --- a/commit/commit/doctype/commit_docs/commit_docs.py +++ b/commit/commit/doctype/commit_docs/commit_docs.py @@ -345,7 +345,7 @@ def get_commit_docs_list(): commit_docs_list = frappe.get_all('Commit Docs', filters=filters, - fields=["header", "light_mode_logo", "route", "published", "description"], + fields=["header", "light_mode_logo", "route", "published", "description","name"], ) return commit_docs_list \ No newline at end of file diff --git a/commit/www/commit.py b/commit/www/commit.py index 6dcf343..58ba352 100644 --- a/commit/www/commit.py +++ b/commit/www/commit.py @@ -3,7 +3,8 @@ import frappe.sessions import re from commit.api.meta_data import get_installed_apps -from commit.commit.doctype.commit_docs.commit_docs import get_all_commit_docs_detail +from commit.commit.doctype.commit_docs.commit_docs import get_all_commit_docs_detail, get_commit_docs_list + no_cache = 1 SCRIPT_TAG_PATTERN = re.compile(r"\") @@ -40,6 +41,7 @@ def get_boot(): boot["commit_docs_header_image_url"] = commit_settings.commit_docs_header_image_url boot["get_installed_apps"] = get_installed_apps() boot["get_all_commit_docs_detail"] = get_all_commit_docs_detail() + boot["get_commit_docs_list"] = get_commit_docs_list() boot_json = frappe.as_json(boot, indent=None, separators=(",", ":")) boot_json = SCRIPT_TAG_PATTERN.sub("", boot_json) diff --git a/dashboard/src/App.tsx b/dashboard/src/App.tsx index 02d10dd..64fbe6e 100644 --- a/dashboard/src/App.tsx +++ b/dashboard/src/App.tsx @@ -1,10 +1,8 @@ import { FrappeProvider } from 'frappe-react-sdk' -import { BrowserRouter, Route, Routes } from 'react-router-dom' +import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom' import PageNotFound from './components/common/PageNotFound/PageNotFound' import APIViewerContainer from './pages/features/api_viewer/APIViewer' import AppAPIViewerContainer from './pages/features/api_viewer/AppAPIViewer' -import DocsPage from './pages/features/docs/DocsPage' -import DocsLandingPage from './pages/features/docs/LandingPage/DocsLandingPage' import PageContent from './pages/features/docs/PageContent' import ViewDocs from './pages/features/docs/ViewDocs' import ERDViewer from './pages/features/erd/ERDViewer' @@ -28,26 +26,32 @@ function App() { {/* */} - - {/** Public Routes */} - {/* } /> */} + + {/** Public Routes */} + {/* } /> */} - {/** Private Routes */} - {/* } /> */} - {/* default route on '/' */} - } /> - {/*TODO: Need to Change below route */} - } /> - } /> - } /> - } /> - } /> - } /> - } > - } /> - } /> - - } /> + {/** Private Routes */} + {/* } /> */} + {/* default route on '/' */} + } /> + {/*TODO: Need to Change below route */} + } /> + } /> + } /> + } /> + } /> + } /> + } > + Hello} /> + } /> + } /> + } /> + } /> + } /> + } /> + {/* } /> */} + + } /> {/* */} diff --git a/dashboard/src/components/features/meta_apps/useGetCommitDocsDetails.ts b/dashboard/src/components/features/meta_apps/useGetCommitDocsDetails.ts index cb79be9..693ce1e 100644 --- a/dashboard/src/components/features/meta_apps/useGetCommitDocsDetails.ts +++ b/dashboard/src/components/features/meta_apps/useGetCommitDocsDetails.ts @@ -1,6 +1,7 @@ import { useMemo } from 'react'; import { useFrappeGetCall } from 'frappe-react-sdk'; import { Docs } from '@/pages/features/docs/docs'; +import { CommitDocs } from '@/types/commit/CommitDocs'; export const useGetCommitDocsDetails = (ID: string) => { // First, check if the data is already available in window.frappe.boot @@ -31,5 +32,36 @@ export const useGetCommitDocsDetails = (ID: string) => { // Return the data from boot if available, otherwise from the API call const data = bootCommitDocsDetails || apiCommitDocsDetails?.message; + return { data, error, isLoading }; +}; + +export const useGetCommitDocsList = () => { + + // First check if the data is already available in window.frappe.boot + const bootCommitDocsList = useMemo(() => { + // @ts-expect-error + return window?.frappe?.boot?.get_commit_docs_list || null; + }, []); + + // Use the API call hook with conditional fetching + const { + data: apiCommitDocsList, + error, + isLoading, + } = useFrappeGetCall<{ message: CommitDocs[] }>( + 'commit.commit.doctype.commit_docs.commit_docs.get_commit_docs_list', + {}, + bootCommitDocsList === null ? 'get_commit_docs_list' : null, + { + // Only fetch if boot data is not available + revalidateOnFocus: false, + revalidateIfStale: false, + revalidateOnReconnect: false, + } + ); + + // Return the data from boot if available, otherwise from the API call + const data: CommitDocs[] = bootCommitDocsList || apiCommitDocsList?.message; + return { data, error, isLoading }; }; \ No newline at end of file diff --git a/dashboard/src/components/ui/card.tsx b/dashboard/src/components/ui/card.tsx index 9f7e608..cabfbfc 100644 --- a/dashboard/src/components/ui/card.tsx +++ b/dashboard/src/components/ui/card.tsx @@ -30,10 +30,10 @@ const CardHeader = React.forwardRef< CardHeader.displayName = "CardHeader" const CardTitle = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes + HTMLDivElement, + React.HTMLAttributes >(({ className, ...props }, ref) => ( -

+ HTMLDivElement, + React.HTMLAttributes >(({ className, ...props }, ref) => ( -

(({ className, ...props }, ref) => (

)) From c0eb9c300d17f0f942e29a0ac87f8f71e01a5246 Mon Sep 17 00:00:00 2001 From: Sumit Jain Date: Sat, 8 Mar 2025 01:05:48 +0530 Subject: [PATCH 04/48] feat: Docs tab and list of docs --- .../features/docs/LandingPage/DocsCard.tsx | 99 +++++++++++++++++++ dashboard/src/pages/overview/Overview.tsx | 27 +++-- 2 files changed, 116 insertions(+), 10 deletions(-) create mode 100644 dashboard/src/pages/features/docs/LandingPage/DocsCard.tsx diff --git a/dashboard/src/pages/features/docs/LandingPage/DocsCard.tsx b/dashboard/src/pages/features/docs/LandingPage/DocsCard.tsx new file mode 100644 index 0000000..4b29565 --- /dev/null +++ b/dashboard/src/pages/features/docs/LandingPage/DocsCard.tsx @@ -0,0 +1,99 @@ +import { Button } from "@/components/ui/button"; +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import { useCallback, useMemo, useState } from "react"; +import { Pencil, SquareArrowOutUpRight, Trash } from "lucide-react"; +import { CommitDocs } from "@/types/commit/CommitDocs"; +import { useNavigate } from "react-router-dom"; +import { useFrappeDeleteDoc } from "frappe-react-sdk"; +import { toast } from "@/components/ui/use-toast"; +import { AlertDialog, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from '@/components/ui/alert-dialog' + + +const DocsListCard = ({ data }: { data: CommitDocs }) => { + + const appNameInitials = useMemo(() => { + return data.header[0].toUpperCase() + }, [data]) + + const [openDeleteDialogModal, setOpenDeleteDialogModal] = useState(false) + + const navigate = useNavigate() + + const onNavigate = useCallback(() => { + navigate({ + pathname: `/docs/${data.name}` + }) + }, [navigate]) + + return ( +
+
+ + + + {appNameInitials} + + +
+
{data.header}
+
+ {data.description} +
+
+
+
+ + + +
+ {openDeleteDialogModal && ( + + + + )} +
+ ); +} + +const DeleteProjectModal = ({data}: {data: CommitDocs}) => { + + const { deleteDoc, reset } = useFrappeDeleteDoc() + + const handleProjectDelete = () => { + + deleteDoc("Commit Docs", `${data.name}`) + .then(() => { + reset() + }).then(() => toast({ + description: `Commit Docs ${data.name} deleted successfully`, + duration: 1500 + })) + } + return ( + + + Delete Docs {data.header} + + + This will delete {data.header} docs and it's related files. + + + + Cancel + + + + ) +} + +export default DocsListCard; diff --git a/dashboard/src/pages/overview/Overview.tsx b/dashboard/src/pages/overview/Overview.tsx index 7be224a..20b1a3b 100644 --- a/dashboard/src/pages/overview/Overview.tsx +++ b/dashboard/src/pages/overview/Overview.tsx @@ -1,35 +1,42 @@ import { FullPageLoader } from "@/components/common/FullPageLoader/FullPageLoader" import { Header } from "@/components/common/Header" import { TabsContent, TabsList, TabsTrigger, Tabs } from "@/components/ui/tabs" -import { isSystemAppAvailable } from "@/utils/roles" +import { isSystemAppAvailable, isSystemManager } from "@/utils/roles" import { lazy, Suspense } from "react" +import CommitDocsList from "../features/docs/LandingPage/CommitDocsList" const Projects = lazy(() => import('@/components/features/projects/Projects')) const YourApps = lazy(() => import('@/components/features/meta_apps/YourApps')) const Overview = () => { const areAppsAvailable = isSystemAppAvailable() + const isCreateAccess = isSystemManager(); + return (
- {areAppsAvailable ? - - Projects - Site Apps + + + Projects + {areAppsAvailable && Site Apps} + {isCreateAccess && Docs} }> - + {areAppsAvailable && }> - - : }> - - } + } + {isCreateAccess && + }> + + + } +
) } From f911f3b640353cffd07229af5b59c793171a5558 Mon Sep 17 00:00:00 2001 From: Sumit Jain Date: Sat, 8 Mar 2025 01:06:00 +0530 Subject: [PATCH 05/48] feat: add CommitDocsList component for displaying commit documentation --- .../docs/LandingPage/CommitDocsList.tsx | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 dashboard/src/pages/features/docs/LandingPage/CommitDocsList.tsx diff --git a/dashboard/src/pages/features/docs/LandingPage/CommitDocsList.tsx b/dashboard/src/pages/features/docs/LandingPage/CommitDocsList.tsx new file mode 100644 index 0000000..fffbee6 --- /dev/null +++ b/dashboard/src/pages/features/docs/LandingPage/CommitDocsList.tsx @@ -0,0 +1,42 @@ +import { ErrorBanner } from "@/components/common/ErrorBanner/ErrorBanner"; +import { FullPageLoader } from "@/components/common/FullPageLoader/FullPageLoader"; +import { useGetCommitDocsList } from "@/components/features/meta_apps/useGetCommitDocsDetails"; +import { Plus } from "lucide-react" + +import { Button } from "@/components/ui/button" +import DocsListCard from "./DocsCard"; + +const CommitDocsList = () => { + + const { data, isLoading, error } = useGetCommitDocsList(); + + if (error) { + return ; + } + + if (isLoading) { + return ; + } + if (data) { + return ( +
+
+
Commit Docs
+ +
+
+ {data.map((item, index) => ( + + ))} +
+
+ ); + } + + return null; +}; + +export default CommitDocsList; From 82b0a71978a278b59789107d1046f585384355d9 Mon Sep 17 00:00:00 2001 From: Sumit Jain Date: Sat, 8 Mar 2025 01:06:37 +0530 Subject: [PATCH 06/48] feat: Docs dashboard Sidebar --- dashboard/src/pages/features/docs/Sidebar.tsx | 284 ++++-------------- .../src/pages/features/docs/ViewDocs.tsx | 30 +- 2 files changed, 74 insertions(+), 240 deletions(-) diff --git a/dashboard/src/pages/features/docs/Sidebar.tsx b/dashboard/src/pages/features/docs/Sidebar.tsx index 9f110f5..53cfa9b 100644 --- a/dashboard/src/pages/features/docs/Sidebar.tsx +++ b/dashboard/src/pages/features/docs/Sidebar.tsx @@ -1,238 +1,80 @@ -import { CommitDocs } from "@/types/commit/CommitDocs"; -import { DocsSidebarItem } from "./docs"; -import DynamicIcon from "@/components/common/DynamicIconImport/IconComponent"; -import { Badge } from "@/components/ui/badge"; -import { useCallback, useEffect, useState } from "react"; -import { cn } from "@/lib/utils"; -import { ChevronDown, ChevronRight } from "lucide-react"; -import { Link, useParams } from "react-router-dom"; +import { FilePenLine, House, PanelBottom, PanelLeft, PanelLeftOpen, PanelRightOpen, PanelTop, Settings } from "lucide-react"; +import { Link, useLocation } from "react-router-dom"; import { useGetCommitDocsDetails } from "@/components/features/meta_apps/useGetCommitDocsDetails"; -import { useFrappePrefetchCall } from "frappe-react-sdk"; +import { Button } from "@/components/ui/button"; -export const Sidebar = ({ ID }: { ID: string }) => { - - const { data, isLoading } = useGetCommitDocsDetails(ID); - - if (data) { - const commit_docs: CommitDocs = data.commit_docs; - const sidebar_items = data.sidebar_items; - return ( -
-
- {/* Header */} -
- {commit_docs.light_mode_logo && ( - logo - )} - {commit_docs.header &&
{commit_docs.header}
} - {commit_docs.published == 0 && ( - - Draft - - )} -
- {/* Sidebar Items */} - {Object.keys(sidebar_items).map((key) => ( - - ))} -
-
- ); - } - if (isLoading) { - return ; - } -}; - -const SidebarGroup = ({ groupName, items }: { groupName: string, items: DocsSidebarItem[] }) => { - const [isExpanded, setIsExpanded] = useState(true); - - return ( -
-
setIsExpanded(!isExpanded)}> -
{groupName}
- {isExpanded ? : } -
- {isExpanded && items.length > 0 && ( -
    - {items.map((item) => ( - - ))} -
- )} -
- ) +export interface SidebarItem { + title: string; + route: string; + icon?: JSX.Element; } -const SidebarItem = ({ item, className, level = 1 }: { item: DocsSidebarItem, className?: string, level?: number }) => { - const { pageID } = useParams(); +const SidebarItems: SidebarItem[] = [ + { title: "Overview", route: "overview", icon: }, + { title: "Editor", route: "editor", icon: }, + { title: "Sidebar", route: "sidebar", icon: }, + { title: "Navbar", route: "navbar", icon: }, + { title: "Footer", route: "footer", icon: }, + { title: "Settings", route: "settings", icon: }, +]; - // Check if the current route is in the item's hierarchy - const isRouteMatch = (item: DocsSidebarItem): boolean => { - if (item.route === pageID) return true; - if (item.group_items) { - return item.group_items.some(isRouteMatch); - } - return false; - }; - - const [isExpanded, setIsExpanded] = useState(() => isRouteMatch(item)); +export const Sidebar = ({ ID, isCollapsed, setIsCollapsed }: { ID: string, isCollapsed: boolean, setIsCollapsed: React.Dispatch> }) => { - if (item.is_group_page && item.group_items?.length) { - return ( -
  • - - {isExpanded && item.group_items.length && -
      - {item.group_items.map((groupItem) => ( - - ))} -
    - } -
  • - ) - } - - return ( -
  • - -
  • - ) -} - -const BadgeClassMap = { - blue: 'bg-blue-500 hover:bg-blue-600', - red: 'bg-red-500 hover:bg-red-600', - green: 'bg-green-500 hover:bg-green-600', - yellow: 'bg-yellow-500 hover:bg-yellow-600', - purple: 'bg-purple-500 hover:bg-purple-600', - pink: 'bg-pink-500 hover:bg-pink-600', - indigo: 'bg-indigo-500 hover:bg-indigo-600', - cyan: 'bg-cyan-500 hover:bg-cyan-600', - teal: 'bg-teal-500 hover:bg-teal-600', - lime: 'bg-lime-500 hover:bg-lime-600', - orange: 'bg-orange-500 hover:bg-orange-600', - 'blue-gray': 'bg-blue-gray-500 hover:bg-blue-gray-600', - gray: 'bg-gray-500 hover:bg-gray-600', - 'true-gray': 'bg-true-gray-500 hover:bg-true-gray-600', - 'warm-gray': 'bg-warm-gray-500 hover:bg-warm-gray-600', - 'cool-gray': 'bg-cool-gray-500 hover:bg-cool-gray-600', -} + const { data } = useGetCommitDocsDetails(ID); -const SidebarTitle = ({ item, className, isExpanded, setIsExpanded }: { item: DocsSidebarItem, className?: string, isExpanded?: boolean, setIsExpanded?: (isExpanded: boolean) => void }) => { - const { pageID } = useParams(); - const isSelected = item.route === pageID; + const location = useLocation(); + const pathSegments = location.pathname.split('/').filter(Boolean); - const BADGE_COLOR = BadgeClassMap[item.badge_color as keyof typeof BadgeClassMap ?? 'gray']; + const last = pathSegments[pathSegments.length - 1] + const selectedClassName = "text-blue-600 dark:text-blue-500 hover:bg-blue-600/5 dark:hover:bg-blue-500/5"; + const notSelectedClassName = "text-gray-700 dark:text-gray-400 hover:bg-gray-200 dark:hover:bg-gray-700/10"; - const handleClick = () => { - if (item.is_group_page && setIsExpanded) { - setIsExpanded(!isExpanded); - } + const toggleCollapse = () => { + setIsCollapsed(!isCollapsed); }; - const [isHovered, setIsHovered] = useState(false); - const preload = useFrappePrefetchCall('commit.commit.doctype.commit_docs_page.commit_docs_page.get_commit_docs_page', { - name: item.route - }) - - useEffect(() => { - let timeout: NodeJS.Timeout | null - if (isHovered) { - timeout = setTimeout(() => { - preload() - }, 250) - } - - return () => { - if (timeout) { - clearTimeout(timeout) - } - } - - }, [isHovered]) - - const onMouseEnter = useCallback(() => { - setIsHovered(true) - }, []) - - const onMouseLeave = useCallback(() => { - setIsHovered(false) - }, []) - - const content = ( -
    -
    - {item.icon && } - {item.badge && {item.badge}} -
    - {item.title} -
    -
    -
    - {item.published === 0 && Draft} - {item.is_group_page && item.group_items?.length ? {isExpanded ? : } : null} -
    -
    - ); - - return item.is_group_page ? ( -
    - {content} -
    - ) : ( - - {content} - - ); -}; - -const SidebarSkeleton = () => { - return ( -
    -
    - {/* Header Skeleton */} -
    -
    -
    -
    - {/* Sidebar Groups Skeleton */} - {[...Array(5)].map((_, groupIndex) => ( -
    -
    -
    - -
    -
      - {[...Array(3 + Math.floor(Math.random() * 2))].map((_, itemIndex) => ( -
      -
    • + if (data) { + return ( +
    +
    +
    + +
    +
    +
    +
    + +
    +
    - ))}

    - ); + ); + } + + return null }; \ No newline at end of file diff --git a/dashboard/src/pages/features/docs/ViewDocs.tsx b/dashboard/src/pages/features/docs/ViewDocs.tsx index 46dcd1c..483cbcf 100644 --- a/dashboard/src/pages/features/docs/ViewDocs.tsx +++ b/dashboard/src/pages/features/docs/ViewDocs.tsx @@ -1,7 +1,6 @@ import { Outlet, useParams } from "react-router-dom"; import { Sidebar } from "./Sidebar"; -import { Navbar } from "./Navbar"; -import { Footer } from "./Footer"; +import { useState } from "react"; const ViewDocs = () => { const { ID } = useParams(); @@ -13,30 +12,23 @@ const ViewDocs = () => { }; const ViewDocsDetails = ({ ID }: { ID: string }) => { - + const [isCollapsed, setIsCollapsed] = useState(false); return (
    -
    - -
    - {/* Sidebar */} - - {/* Main Content */} -
    -
    - + +
    +
    +
    +
    + +
    +
    -
    +
    -