commit 0ed5909289be57b4c25f5537429b8ad20902dd75 Author: Stephen Donahue Date: Sat Mar 28 04:10:09 2026 +0000 scaffold unprompted site: eleventy, templates, gitea CI diff --git a/.eleventy.js b/.eleventy.js new file mode 100644 index 0000000..41c9b82 --- /dev/null +++ b/.eleventy.js @@ -0,0 +1,35 @@ +module.exports = function (eleventyConfig) { + eleventyConfig.addPassthroughCopy("css"); + + eleventyConfig.addCollection("columns", function (collectionApi) { + return collectionApi + .getFilteredByGlob("columns/**/*.md") + .sort((a, b) => b.date - a.date); + }); + + eleventyConfig.addFilter("year", function (date) { + return new Date(date).getFullYear(); + }); + + eleventyConfig.addFilter("isoDate", function (date) { + return new Date(date).toISOString().split("T")[0]; + }); + + eleventyConfig.addFilter("readableDate", function (date) { + return new Date(date).toLocaleDateString("en-US", { + year: "numeric", + month: "long", + day: "numeric", + }); + }); + + return { + dir: { + input: ".", + includes: "_includes", + output: "_site", + }, + markdownTemplateEngine: "njk", + htmlTemplateEngine: "njk", + }; +}; diff --git a/.gitea/workflows/deploy.yaml b/.gitea/workflows/deploy.yaml new file mode 100644 index 0000000..b3b2ffb --- /dev/null +++ b/.gitea/workflows/deploy.yaml @@ -0,0 +1,41 @@ +name: Deploy to S3 + +on: + push: + branches: [main] + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Build + run: yarn build + + - name: Deploy to S3 + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + run: | + pip install awscli + aws s3 sync _site/ s3://${{ vars.S3_BUCKET }} --delete + + - name: Invalidate CloudFront + if: vars.CF_DISTRIBUTION_ID != '' + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + run: | + aws cloudfront create-invalidation \ + --distribution-id ${{ vars.CF_DISTRIBUTION_ID }} \ + --paths "/*" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3a799fb --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +_site/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..51931ec --- /dev/null +++ b/Dockerfile @@ -0,0 +1,10 @@ +FROM node:22-alpine AS build +WORKDIR /app +COPY package.json yarn.lock* ./ +RUN yarn install --frozen-lockfile 2>/dev/null || yarn install +COPY . . +RUN yarn build + +FROM alpine:3.20 +RUN apk add --no-cache aws-cli +COPY --from=build /app/_site /site diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9568461 --- /dev/null +++ b/Makefile @@ -0,0 +1,27 @@ +S3_BUCKET ?= s3://donny.nyc +CF_DISTRIBUTION_ID ?= + +.PHONY: build dev deploy invalidate + +build: + docker build -t unprompted . + +dev: + docker run --rm -v $$(pwd):/app -w /app -p 8080:8080 node:22-alpine sh -c "yarn install && yarn dev --port 8080" + +deploy: build + docker run --rm \ + -e AWS_ACCESS_KEY_ID \ + -e AWS_SECRET_ACCESS_KEY \ + -e AWS_DEFAULT_REGION \ + unprompted \ + aws s3 sync /site $(S3_BUCKET) --delete + +invalidate: +ifdef CF_DISTRIBUTION_ID + aws cloudfront create-invalidation \ + --distribution-id $(CF_DISTRIBUTION_ID) \ + --paths "/*" +else + @echo "CF_DISTRIBUTION_ID not set, skipping invalidation" +endif diff --git a/_includes/base.njk b/_includes/base.njk new file mode 100644 index 0000000..b316991 --- /dev/null +++ b/_includes/base.njk @@ -0,0 +1,29 @@ + + + + + + {% if title %}{{ title }} — un:prompted{% else %}un:prompted{% endif %} + + + + + +
+
+ {{ content | safe }} +
+ + {% include "sidebar.njk" %} +
+ + + + diff --git a/_includes/column.njk b/_includes/column.njk new file mode 100644 index 0000000..cb1c611 --- /dev/null +++ b/_includes/column.njk @@ -0,0 +1,37 @@ + + + + + + {{ title }} — un:prompted + + + + + +
+
+
+
+

{{ title }}

+ +
+
+ {{ content | safe }} +
+
+
+ + {% include "sidebar.njk" %} +
+ + + + diff --git a/_includes/sidebar.njk b/_includes/sidebar.njk new file mode 100644 index 0000000..c105c21 --- /dev/null +++ b/_includes/sidebar.njk @@ -0,0 +1,21 @@ + diff --git a/columns/2026-03-28-hello-world.md b/columns/2026-03-28-hello-world.md new file mode 100644 index 0000000..cace7a9 --- /dev/null +++ b/columns/2026-03-28-hello-world.md @@ -0,0 +1,9 @@ +--- +title: Hello, world +date: 2026-03-28 +layout: column.njk +tags: column +permalink: /columns/2026/hello-world/ +--- + +This is the first entry. diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..abf212d --- /dev/null +++ b/css/style.css @@ -0,0 +1,216 @@ +*, +*::before, +*::after { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +:root { + --font-body: Georgia, "Times New Roman", serif; + --font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif; + --color-bg: #fdfdfd; + --color-text: #1a1a1a; + --color-muted: #6b6b6b; + --color-border: #e0e0e0; + --color-link: #1a1a1a; + --color-link-hover: #555; + --max-width: 960px; + --sidebar-width: 200px; +} + +html { + font-size: 18px; + line-height: 1.6; +} + +body { + font-family: var(--font-body); + color: var(--color-text); + background: var(--color-bg); + max-width: var(--max-width); + margin: 0 auto; + padding: 2rem 1.5rem; +} + +a { + color: var(--color-link); + text-decoration: none; + border-bottom: 1px solid var(--color-border); +} + +a:hover { + color: var(--color-link-hover); + border-bottom-color: var(--color-muted); +} + +/* header */ + +.site-header { + margin-bottom: 2rem; +} + +.site-title { + font-family: var(--font-ui); + font-size: 1rem; + font-weight: 600; + letter-spacing: 0.02em; + border-bottom: none; +} + +/* layout */ + +.site-layout { + display: grid; + grid-template-columns: 1fr var(--sidebar-width); + gap: 3rem; +} + +/* main content */ + +.content h1 { + font-size: 1.6rem; + line-height: 1.25; + margin-bottom: 0.25rem; +} + +.column-header time { + font-family: var(--font-ui); + font-size: 0.8rem; + color: var(--color-muted); +} + +.column-body { + margin-top: 1.5rem; +} + +.column-body h2 { + font-size: 1.2rem; + margin-top: 2rem; + margin-bottom: 0.5rem; +} + +.column-body h3 { + font-size: 1rem; + margin-top: 1.5rem; + margin-bottom: 0.5rem; +} + +.column-body p { + margin-bottom: 1rem; +} + +.column-body blockquote { + border-left: 3px solid var(--color-border); + padding-left: 1rem; + color: var(--color-muted); + margin-bottom: 1rem; +} + +.column-body ul, +.column-body ol { + margin-bottom: 1rem; + padding-left: 1.5rem; +} + +.column-body pre { + background: #f5f5f5; + padding: 1rem; + overflow-x: auto; + margin-bottom: 1rem; + font-size: 0.85rem; + line-height: 1.5; +} + +.column-body code { + font-size: 0.85em; +} + +.column-body hr { + border: none; + border-top: 1px solid var(--color-border); + margin: 2rem 0; +} + +/* sidebar */ + +.sidebar { + font-family: var(--font-ui); + font-size: 0.8rem; +} + +.sidebar h2 { + font-size: 0.75rem; + text-transform: uppercase; + letter-spacing: 0.08em; + color: var(--color-muted); + margin-bottom: 0.75rem; +} + +.sidebar .year-label { + font-size: 0.75rem; + font-weight: 600; + color: var(--color-muted); + margin-top: 0.75rem; + margin-bottom: 0.25rem; +} + +.sidebar ul { + list-style: none; +} + +.sidebar li { + margin-bottom: 0.3rem; +} + +.sidebar a { + border-bottom: none; + color: var(--color-muted); +} + +.sidebar a:hover { + color: var(--color-text); +} + +/* footer */ + +.site-footer { + margin-top: 3rem; + padding-top: 1.5rem; + border-top: 1px solid var(--color-border); +} + +.footer-nav { + font-family: var(--font-ui); + font-size: 0.8rem; + display: flex; + gap: 1.5rem; +} + +.footer-nav a { + color: var(--color-muted); + border-bottom: none; +} + +.footer-nav a:hover { + color: var(--color-text); +} + +/* responsive */ + +@media (max-width: 640px) { + html { + font-size: 16px; + } + + .site-layout { + grid-template-columns: 1fr; + gap: 2rem; + } + + .sidebar { + order: 1; + border-top: 1px solid var(--color-border); + padding-top: 1.5rem; + } +} diff --git a/index.njk b/index.njk new file mode 100644 index 0000000..b3e610e --- /dev/null +++ b/index.njk @@ -0,0 +1,18 @@ +--- +layout: base.njk +--- + +{%- set latest = collections.columns | first -%} +{%- if latest %} +
+
+

{{ latest.data.title }}

+ +
+
+ {{ latest.content | safe }} +
+
+{%- else %} +

Nothing here yet.

+{%- endif %} diff --git a/package.json b/package.json new file mode 100644 index 0000000..a7688d4 --- /dev/null +++ b/package.json @@ -0,0 +1,12 @@ +{ + "name": "unprompted", + "version": "1.0.0", + "private": true, + "scripts": { + "build": "eleventy", + "dev": "eleventy --serve --watch" + }, + "dependencies": { + "@11ty/eleventy": "^3.0.0" + } +} diff --git a/pages/about.md b/pages/about.md new file mode 100644 index 0000000..518c51b --- /dev/null +++ b/pages/about.md @@ -0,0 +1,7 @@ +--- +title: About +layout: base.njk +permalink: /about/ +--- + +About page. diff --git a/pages/code.md b/pages/code.md new file mode 100644 index 0000000..ba6bb7d --- /dev/null +++ b/pages/code.md @@ -0,0 +1,7 @@ +--- +title: Code +layout: base.njk +permalink: /code/ +--- + +Code and projects.