Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions site/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules/
dist/
79 changes: 79 additions & 0 deletions site/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# devloop site

Minimal static marketing site for the `devloop` CLI. Single page, monochrome
teletype aesthetic, violet accent matching the CLI brand. No runtime
dependencies: Tailwind compiled to static CSS, IBM Plex Mono self-hosted from
`fonts/` (OFL, weights 400 + 700), used across the whole page.

## Develop

```sh
pnpm install
pnpm dev # tailwind watch -> dist/styles.css
pnpm preview # build + serve dist/ at http://localhost:4178
```

## Build

```sh
pnpm build # writes dist/index.html + dist/styles.css
```

`build.mjs` clears `dist/`, compiles `src/input.css` with the Tailwind CLI to
`dist/styles.css`, then copies `index.html` and `fonts/` into `dist/`. The
output is fully static (HTML, CSS, woff2) with no runtime dependency. Deploy the
`dist/` directory to any static host.

## Deploy to Cloudflare Pages

### Option A: Git integration (recommended)

In the Cloudflare dashboard, Workers & Pages > Create > Pages > Connect to Git,
pick this repo, and set:

- Production branch: `main`
- Root directory: `site`
- Build command: `pnpm build`
- Build output directory: `dist` (relative to the root directory, i.e. `site/dist`)

Every push to `main` then rebuilds and deploys. Preview deployments are created
for other branches automatically.

### Option B: Direct upload with Wrangler

```sh
cd site
pnpm install
pnpm build
npx wrangler pages deploy dist --project-name devloop
```

### Custom domain (devloop.sh)

The install command on the page is `curl -fsSL https://devloop.sh/install | bash`,
so deployment is only complete once two things are true:

1. `devloop.sh` points at this Pages project (Pages project > Custom domains >
add `devloop.sh`; Cloudflare provisions the TLS cert).
2. `https://devloop.sh/install` serves the install script as `text/plain`. Until
the real installer exists, either drop an `install` file into the deployed
output or add a redirect to the raw `install.sh` in the CLI repo. With Pages,
a `dist/_redirects` line like `/install https://raw.githubusercontent.com/satyaborg/devloop/main/install.sh 200`
proxies it.

## Other static hosts

`dist/` is plain static files, so it also drops onto Vercel, Netlify, GitHub
Pages, or S3/CloudFront. Set the build command to `pnpm build` and the publish
directory to `site/dist`.

## Structure

```
site/
index.html source page
src/input.css tailwind entry + theme tokens + @font-face
build.mjs build script (tailwind compile + copy html/fonts)
fonts/ IBM Plex Mono woff2 (400, 700)
dist/ build output (gitignored)
```
19 changes: 19 additions & 0 deletions site/build.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { execFileSync } from "node:child_process";
import { cpSync, mkdirSync, rmSync } from "node:fs";

const root = new URL(".", import.meta.url).pathname;
const dist = `${root}dist`;

rmSync(dist, { recursive: true, force: true });
mkdirSync(dist, { recursive: true });

execFileSync(
"npx",
["tailwindcss", "-i", "./src/input.css", "-o", "./dist/styles.css", "--minify"],
{ cwd: root, stdio: "inherit" },
);

cpSync(`${root}index.html`, `${dist}/index.html`);
cpSync(`${root}fonts`, `${dist}/fonts`, { recursive: true });

console.log("built -> dist/");
42 changes: 42 additions & 0 deletions site/dev.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { spawn } from "node:child_process";
import { copyFileSync, cpSync, mkdirSync, rmSync, watch } from "node:fs";

const root = new URL(".", import.meta.url).pathname;
const dist = `${root}dist`;
const port = process.env.PORT ?? "4178";

rmSync(dist, { recursive: true, force: true });
mkdirSync(dist, { recursive: true });
copyFileSync(`${root}index.html`, `${dist}/index.html`);
cpSync(`${root}fonts`, `${dist}/fonts`, { recursive: true });

const child = (cmd, args) =>
spawn(cmd, args, { cwd: root, stdio: "inherit" });

child("npx", [
"tailwindcss",
"-i", "./src/input.css",
"-o", "./dist/styles.css",
"--watch",
]);

let pending;
watch(`${root}index.html`, () => {
clearTimeout(pending);
pending = setTimeout(() => {
try {
copyFileSync(`${root}index.html`, `${dist}/index.html`);
} catch (err) {
console.error(`[dev] index.html copy skipped: ${err.message}`);
}
}, 50);
});

child("npx", [
"browser-sync",
"start",
"--server", "dist",
"--files", "dist",
"--port", port,
"--no-notify",
]);
Binary file added site/fonts/JetBrainsMono-400.woff2
Binary file not shown.
Binary file added site/fonts/JetBrainsMono-700.woff2
Binary file not shown.
Loading