diff --git a/packages/cubby/src/components/Projects.tsx b/packages/cubby/src/components/Projects.tsx new file mode 100644 index 0000000..b5eecce --- /dev/null +++ b/packages/cubby/src/components/Projects.tsx @@ -0,0 +1,38 @@ +interface ProjectData { + name: string + mtime: Date + status: "recent" | "active" | "inactive" +} + +interface ProjectsProps { + projects: ProjectData[] +} + +export function Projects({ projects }: ProjectsProps) { + const statusText = (status: "recent" | "active" | "inactive") => { + switch (status) { + case "recent": return "Modified in the last 2 weeks" + case "active": return "Modified in the last month" + case "inactive": return "Modified over a month ago" + } + } + + return ( +
+

Projects

+ +
+ ) +} \ No newline at end of file diff --git a/packages/cubby/src/server.tsx b/packages/cubby/src/server.tsx index 20acae0..f930239 100644 --- a/packages/cubby/src/server.tsx +++ b/packages/cubby/src/server.tsx @@ -1,12 +1,13 @@ import { Hono } from "hono" import { serveStatic } from "hono/bun" import { render } from "preact-render-to-string" -import { marked } from "marked" +import { $ } from "bun" import { readdirSync } from "fs" import { mkdir, readdir } from 'node:fs/promises' import { basename, join } from 'path' import { Layout } from "./components/Layout" import { Project } from "./components/Project" +import { Projects } from "./components/Projects" const PROJECTS_DIR = ".." const WORKSHOP_REPO = "https://github.com/probablycorey/the-workshop" @@ -28,7 +29,7 @@ app.use("*", async (c, next) => { const start = Date.now() await next() const end = Date.now() - console.log(`${c.req.method} ${c.req.url} - ${c.res.status} (${end - start}ms)`) + console.log(`${c.res.status} ${c.req.method} ${c.req.url} (${end - start}ms)`) }) // ---------------------------------------------------------------------------- @@ -36,8 +37,7 @@ app.use("*", async (c, next) => { // ---------------------------------------------------------------------------- api.get('/projects', async c => { - const names = await projects() - return c.json(names) + return c.json(await projectsWithDates()) }) // ---------------------------------------------------------------------------- @@ -45,15 +45,8 @@ api.get('/projects', async c => { // ---------------------------------------------------------------------------- app.get("/", async (c) => { - const names = await projects() - return c.html(tsx( -
-

Projects

- -
- )) + const projects = await projectsWithDates() + return c.html(tsx()) }) app.get("/p/:name", async (c) => { @@ -140,6 +133,24 @@ async function projects(): Promise { return subdirs } +async function projectsWithDates(): Promise<{ name: string, mtime: Date, status: "recent" | "active" | "inactive" }[]> { + const names = await projects() + const projectsWithDates = await Promise.all(names.map(async name => { + const lastModified = await mtime(name) + const daysSince = (Date.now() - lastModified.getTime()) / (24 * 60 * 60 * 1000) + const status: "recent" | "active" | "inactive" = daysSince <= 14 ? "recent" : daysSince <= 30 ? "active" : "inactive" + return { name, mtime: lastModified, status } + })) + const sorted = projectsWithDates.sort((a, b) => b.mtime.getTime() - a.mtime.getTime()) + return sorted +} + +async function mtime(project: string): Promise { + const proc = await $`cd ${PROJECTS_DIR} && git log -1 --format=%ct -- ${project}`.quiet() + if (proc.exitCode !== 0) return new Date(0) + return new Date(parseInt(proc.stdout.toString().trim()) * 1000) +} + function tsx(node: any) { return "" + render({node}) }