feat(playground): add session management and folder open icon in PlaygroundSidebar component
This commit is contained in:
parent
08831481b8
commit
20d790c5e0
@ -22,6 +22,7 @@
|
|||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cross-fetch": "^4.0.0",
|
"cross-fetch": "^4.0.0",
|
||||||
|
"devicons-react": "^1.4.0",
|
||||||
"gitea-js": "^1.22.0",
|
"gitea-js": "^1.22.0",
|
||||||
"jotai": "^2.10.3",
|
"jotai": "^2.10.3",
|
||||||
"lucide-react": "^0.468.0",
|
"lucide-react": "^0.468.0",
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
"use server";
|
||||||
|
|
||||||
import api from "@/lib/gitea";
|
import api from "@/lib/gitea";
|
||||||
import { GitEntry, APIError } from "gitea-js";
|
import { GitEntry, APIError } from "gitea-js";
|
||||||
|
|
@ -1,4 +1,5 @@
|
|||||||
import { auth } from "@/auth";
|
"use client";
|
||||||
|
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import {
|
import {
|
||||||
Sidebar,
|
Sidebar,
|
||||||
@ -18,8 +19,10 @@ import {
|
|||||||
CollapsibleContent,
|
CollapsibleContent,
|
||||||
CollapsibleTrigger,
|
CollapsibleTrigger,
|
||||||
} from "@/components/ui/collapsible";
|
} from "@/components/ui/collapsible";
|
||||||
import { retrieveTreeStructure } from "@/app/actions";
|
import { useSession } from "next-auth/react";
|
||||||
import { ChevronRight, File, Folder } from "lucide-react";
|
import { retrieveTreeStructure } from "@/actions";
|
||||||
|
import { COriginal, JavaOriginal } from "devicons-react";
|
||||||
|
import { ChevronRight, File, Folder, FolderOpen } from "lucide-react";
|
||||||
|
|
||||||
interface FileTree {
|
interface FileTree {
|
||||||
name: string;
|
name: string;
|
||||||
@ -69,20 +72,32 @@ export function buildFileTree(tree: GitEntry[]): FileTree {
|
|||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function PlaygroundSidebar({
|
export function PlaygroundSidebar({
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof Sidebar>) {
|
}: React.ComponentProps<typeof Sidebar>) {
|
||||||
const session = await auth();
|
const { data: session } = useSession();
|
||||||
|
const [fileTree, setFileTree] = React.useState<FileTree>({
|
||||||
|
name: "",
|
||||||
|
type: "tree",
|
||||||
|
children: {},
|
||||||
|
});
|
||||||
|
|
||||||
const username = session?.user?.name ?? "";
|
const username = session?.user?.name ?? "";
|
||||||
let fileTree: FileTree = { name: "", type: "tree", children: {} };
|
|
||||||
if (username) {
|
React.useEffect(() => {
|
||||||
const tree: GitEntry[] = await retrieveTreeStructure(
|
async function fetchFileTree() {
|
||||||
username,
|
if (username) {
|
||||||
"playground",
|
const tree: GitEntry[] = await retrieveTreeStructure(
|
||||||
"main"
|
username,
|
||||||
);
|
"playground",
|
||||||
fileTree = buildFileTree(tree);
|
"main"
|
||||||
}
|
);
|
||||||
|
const newFileTree = buildFileTree(tree);
|
||||||
|
setFileTree(newFileTree);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fetchFileTree();
|
||||||
|
}, [username]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Sidebar {...props}>
|
<Sidebar {...props}>
|
||||||
@ -106,10 +121,22 @@ export async function PlaygroundSidebar({
|
|||||||
|
|
||||||
function Tree({ item }: { item: FileTree }) {
|
function Tree({ item }: { item: FileTree }) {
|
||||||
const { name, type, children } = item;
|
const { name, type, children } = item;
|
||||||
|
const fileExtension = name.split(".").pop();
|
||||||
|
|
||||||
|
let fileIcon = <File />;
|
||||||
|
|
||||||
|
if (fileExtension === "c") {
|
||||||
|
fileIcon = <COriginal />;
|
||||||
|
} else if (fileExtension === "java") {
|
||||||
|
fileIcon = <JavaOriginal />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [isOpen, setIsOpen] = React.useState(false);
|
||||||
|
|
||||||
if (type === "blob") {
|
if (type === "blob") {
|
||||||
return (
|
return (
|
||||||
<SidebarMenuButton className="data-[active=true]:bg-transparent">
|
<SidebarMenuButton className="data-[active=true]:bg-transparent">
|
||||||
<File />
|
{fileIcon}
|
||||||
{name}
|
{name}
|
||||||
</SidebarMenuButton>
|
</SidebarMenuButton>
|
||||||
);
|
);
|
||||||
@ -117,11 +144,15 @@ function Tree({ item }: { item: FileTree }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SidebarMenuItem>
|
<SidebarMenuItem>
|
||||||
<Collapsible className="group/collapsible [&[data-state=open]>button>svg:first-child]:rotate-90">
|
<Collapsible
|
||||||
|
open={isOpen}
|
||||||
|
onOpenChange={setIsOpen}
|
||||||
|
className="group/collapsible [&[data-state=open]>button>svg:first-child]:rotate-90"
|
||||||
|
>
|
||||||
<CollapsibleTrigger asChild>
|
<CollapsibleTrigger asChild>
|
||||||
<SidebarMenuButton>
|
<SidebarMenuButton>
|
||||||
<ChevronRight className="transition-transform" />
|
<ChevronRight className="transition-transform" />
|
||||||
<Folder />
|
{isOpen ? <FolderOpen /> : <Folder />}
|
||||||
{name}
|
{name}
|
||||||
</SidebarMenuButton>
|
</SidebarMenuButton>
|
||||||
</CollapsibleTrigger>
|
</CollapsibleTrigger>
|
||||||
|
@ -9,6 +9,7 @@ import {
|
|||||||
BreadcrumbList,
|
BreadcrumbList,
|
||||||
BreadcrumbPage,
|
BreadcrumbPage,
|
||||||
} from "@/components/ui/breadcrumb";
|
} from "@/components/ui/breadcrumb";
|
||||||
|
import { SessionProvider } from "next-auth/react";
|
||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
import { ModeSwitcher } from "@/components/mode-switcher";
|
import { ModeSwitcher } from "@/components/mode-switcher";
|
||||||
import LanguageSwitcher from "@/components/language-switcher";
|
import LanguageSwitcher from "@/components/language-switcher";
|
||||||
@ -18,30 +19,32 @@ export default function PlaygroundLayout({
|
|||||||
children,
|
children,
|
||||||
}: Readonly<{ children: React.ReactNode }>) {
|
}: Readonly<{ children: React.ReactNode }>) {
|
||||||
return (
|
return (
|
||||||
<SidebarProvider>
|
<SessionProvider>
|
||||||
<PlaygroundSidebar />
|
<SidebarProvider>
|
||||||
<SidebarInset>
|
<PlaygroundSidebar />
|
||||||
<header className="flex h-14 shrink-0 items-center gap-2">
|
<SidebarInset>
|
||||||
<div className="flex flex-1 items-center gap-2 px-3">
|
<header className="flex h-14 shrink-0 items-center gap-2">
|
||||||
<SidebarTrigger />
|
<div className="flex flex-1 items-center gap-2 px-3">
|
||||||
<ModeSwitcher />
|
<SidebarTrigger />
|
||||||
<Separator orientation="vertical" className="mr-2 h-4" />
|
<ModeSwitcher />
|
||||||
<Breadcrumb>
|
<Separator orientation="vertical" className="mr-2 h-4" />
|
||||||
<BreadcrumbList>
|
<Breadcrumb>
|
||||||
<BreadcrumbItem>
|
<BreadcrumbList>
|
||||||
<BreadcrumbPage className="line-clamp-1">
|
<BreadcrumbItem>
|
||||||
Project Management & Task Tracking
|
<BreadcrumbPage className="line-clamp-1">
|
||||||
</BreadcrumbPage>
|
Project Management & Task Tracking
|
||||||
</BreadcrumbItem>
|
</BreadcrumbPage>
|
||||||
</BreadcrumbList>
|
</BreadcrumbItem>
|
||||||
</Breadcrumb>
|
</BreadcrumbList>
|
||||||
</div>
|
</Breadcrumb>
|
||||||
<div className="ml-auto px-3">
|
</div>
|
||||||
<LanguageSwitcher />
|
<div className="ml-auto px-3">
|
||||||
</div>
|
<LanguageSwitcher />
|
||||||
</header>
|
</div>
|
||||||
{children}
|
</header>
|
||||||
</SidebarInset>
|
{children}
|
||||||
</SidebarProvider>
|
</SidebarInset>
|
||||||
|
</SidebarProvider>
|
||||||
|
</SessionProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user