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
+
+ {projects.map(project => -
+
+ {project.status === "recent" ? "🟢" : project.status === "active" ? "🟡" : "🔴"}
+
+
+ {project.name}
+
+
)}
+
+
+ )
+}
\ 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
-
- {names.map(name => - {name}
)}
-
-
- ))
+ 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})
}