~repos /website
git clone https://pyrossh.dev/repos/website.git
木 Personal website of pyrossh. Built with astrojs, shiki, vite.
src/components/RecursiveList.astro
---import { Icon } from "astro-icon/components";import allIcons from "@iconify-json/vscode-icons/icons.json" assert { type: "json" };import prettyBytes from "pretty-bytes";import { resolveFileIcon } from "@/utils/files";
interface FileNode { name: string; path: string; isDirectory: boolean; size: number; ext: string; absolutePath: string; children?: FileNode[];}
interface Props { items: FileNode[]; repoId: string; depth?: number;}
const { items, repoId, depth = 0 } = Astro.props;---
{ items.map((item) => { if (item.isDirectory && item.children) { return ( <li class="folder" style={`padding-left: ${depth * 1}rem;`}> <details> <summary> <Icon name="mdi:folder" size="24px" color="hsl(45deg 75.37% 60%)" /> <span>{item.name}</span> </summary> <ul> <Astro.self items={item.children} repoId={repoId} depth={depth + 1} /> </ul> </details> </li> ); } else { const iconName = resolveFileIcon(item.name, item.ext); const fileType = allIcons.icons[`file-type-${iconName}`] ? `file-type-${iconName}` : "default-file"; return ( <li class="file" style={`padding-left: ${depth * 1}rem;`}> <div class="file-content"> <div class="file-name"> <Icon name={`vscode-icons:${fileType}`} size="18px" /> <a href={`/repos/${repoId}/files/${item.path}`} rel="nofollow"> {item.name} </a> </div> {item.size && ( <div class="file-size"> <span>{prettyBytes(item.size).replace(" ", "")}</span> </div> )} </div> </li> ); } })}
<style> svg[data-icon] { margin-right: 0.3rem; }
.folder { margin: 0; details { margin: 0.25rem 0; } summary { display: flex; align-items: center; cursor: pointer; padding: 0.4rem; background-color: var(--color-box-bg); } ul { padding: 0; margin: 0.25rem 0 0.5rem 1rem; } }
.file { margin: 0.25rem 0; .file-content { display: flex; padding: 0.4rem; background-color: var(--color-box-bg); }
.file-name { flex: 1; display: flex; align-items: center;
a { text-decoration: none;
&:hover { /* color: var(--color-link); */ text-decoration: underline; text-underline-offset: 3px; } } }
.file-size { margin-left: auto; padding-left: 1rem; opacity: 0.7; } }</style>