feat(playground): add session management and folder open icon in PlaygroundSidebar component

This commit is contained in:
ngc2207 2024-12-14 18:49:35 +08:00
parent 08831481b8
commit 20d790c5e0
4 changed files with 79 additions and 42 deletions

View File

@ -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",

View File

@ -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";

View File

@ -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: {} };
React.useEffect(() => {
async function fetchFileTree() {
if (username) { if (username) {
const tree: GitEntry[] = await retrieveTreeStructure( const tree: GitEntry[] = await retrieveTreeStructure(
username, username,
"playground", "playground",
"main" "main"
); );
fileTree = buildFileTree(tree); 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>

View File

@ -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,6 +19,7 @@ export default function PlaygroundLayout({
children, children,
}: Readonly<{ children: React.ReactNode }>) { }: Readonly<{ children: React.ReactNode }>) {
return ( return (
<SessionProvider>
<SidebarProvider> <SidebarProvider>
<PlaygroundSidebar /> <PlaygroundSidebar />
<SidebarInset> <SidebarInset>
@ -43,5 +45,6 @@ export default function PlaygroundLayout({
{children} {children}
</SidebarInset> </SidebarInset>
</SidebarProvider> </SidebarProvider>
</SessionProvider>
); );
} }