project urls

This commit is contained in:
Chris Wanstrath 2025-07-28 11:21:48 -07:00
parent ed7e1349b5
commit ae6d191b91
2 changed files with 42 additions and 5 deletions

View File

@ -1,12 +1,14 @@
import { marked } from "marked"
import { type ProjectMetadata } from "../server"
interface ProjectProps {
name: string
project: ProjectMetadata
readme: string
files: string[]
}
export function Project({ name, readme, files }: ProjectProps) {
export function Project({ project, readme, files }: ProjectProps) {
const name = project.name
return (
<>
<p><a href="/">« Back</a></p>
@ -15,6 +17,13 @@ export function Project({ name, readme, files }: ProjectProps) {
<p dangerouslySetInnerHTML={{ __html: marked.parse(readme) }} />
</div>
<div class="side-content">
<h2>Links</h2>
<ul class="file-list">
<li><a href={project.github}>GitHub</a></li>
{project.url && (
<li><a href={project.url}>{project.url.replace(`https://`, "")}</a></li>
)}
</ul>
{files.length > 0 && (
<>
<h2>Files</h2>

View File

@ -9,10 +9,19 @@ 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"
export const REPO_URL = "https://github.com/probablycorey/the-workshop"
export const PROJECTS_DIR = ".."
const WORKSHOP_APP_DOMAIN = "theworkshop.cc"
const CUBBY_DIR = "./cubby"
export type ProjectMetadata = {
name: string
mtime: Date
status: "recent" | "active" | "inactive",
github: string,
url: string | null,
}
// ----------------------------------------------------------------------------
// Setup
// ----------------------------------------------------------------------------
@ -51,6 +60,9 @@ app.get("/", async (c) => {
app.get("/p/:name", async (c) => {
const name = c.req.param("name").replace("..", "")
const project = await projectsWithMetadata().then(projects => projects.find(p => p.name === name))
if (!project) return c.json({ error: 'Project not found' }, 404)
const readme = await Bun.file(`${PROJECTS_DIR}/${name}/README.md`).text()
const cubbyPath = join(CUBBY_DIR, `project_${name}`)
let files: string[] = []
@ -63,7 +75,7 @@ app.get("/p/:name", async (c) => {
}
}
return c.html(tsx(<Project name={name} readme={readme} files={files} />))
return c.html(tsx(<Project project={project} readme={readme} files={files} />))
})
app.get('/p/:id/:filename', async c => {
@ -133,6 +145,22 @@ async function projects(): Promise<string[]> {
return subdirs
}
async function projectsWithMetadata(): Promise<ProjectMetadata[]> {
const projects = await projectsWithDates()
return Promise.all(projects.map(async project => ({
name: project.name,
mtime: project.mtime,
status: project.status,
github: `${REPO_URL}/tree/main/packages/${project.name}`,
url: await isWorkshopApp(project.name) ? `https://${project.name}.${WORKSHOP_APP_DOMAIN}` : null,
})))
}
async function isWorkshopApp(projectName: string): Promise<boolean> {
const json = await Bun.file(`${PROJECTS_DIR}/${projectName}/package.json`).json()
return json.scripts && json.scripts["subdomain:start"] !== undefined
}
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 => {