scaffold unprompted site: eleventy, templates, gitea CI
Some checks failed
Deploy to S3 / deploy (push) Failing after 1m26s
Some checks failed
Deploy to S3 / deploy (push) Failing after 1m26s
This commit is contained in:
35
.eleventy.js
Normal file
35
.eleventy.js
Normal file
@@ -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",
|
||||||
|
};
|
||||||
|
};
|
||||||
41
.gitea/workflows/deploy.yaml
Normal file
41
.gitea/workflows/deploy.yaml
Normal file
@@ -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 "/*"
|
||||||
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
node_modules/
|
||||||
|
_site/
|
||||||
10
Dockerfile
Normal file
10
Dockerfile
Normal file
@@ -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
|
||||||
27
Makefile
Normal file
27
Makefile
Normal file
@@ -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
|
||||||
29
_includes/base.njk
Normal file
29
_includes/base.njk
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>{% if title %}{{ title }} — un:prompted{% else %}un:prompted{% endif %}</title>
|
||||||
|
<link rel="stylesheet" href="/css/style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header class="site-header">
|
||||||
|
<a href="/" class="site-title">un:prompted</a>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="site-layout">
|
||||||
|
<main class="content">
|
||||||
|
{{ content | safe }}
|
||||||
|
</main>
|
||||||
|
|
||||||
|
{% include "sidebar.njk" %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="site-footer">
|
||||||
|
<nav class="footer-nav">
|
||||||
|
<a href="/about/">about</a>
|
||||||
|
<a href="/code/">code</a>
|
||||||
|
</nav>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
37
_includes/column.njk
Normal file
37
_includes/column.njk
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>{{ title }} — un:prompted</title>
|
||||||
|
<link rel="stylesheet" href="/css/style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header class="site-header">
|
||||||
|
<a href="/" class="site-title">un:prompted</a>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="site-layout">
|
||||||
|
<main class="content">
|
||||||
|
<article class="column-entry">
|
||||||
|
<header class="column-header">
|
||||||
|
<h1>{{ title }}</h1>
|
||||||
|
<time datetime="{{ date | isoDate }}">{{ date | readableDate }}</time>
|
||||||
|
</header>
|
||||||
|
<div class="column-body">
|
||||||
|
{{ content | safe }}
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
{% include "sidebar.njk" %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="site-footer">
|
||||||
|
<nav class="footer-nav">
|
||||||
|
<a href="/about/">about</a>
|
||||||
|
<a href="/code/">code</a>
|
||||||
|
</nav>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
21
_includes/sidebar.njk
Normal file
21
_includes/sidebar.njk
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<aside class="sidebar">
|
||||||
|
<nav class="sidebar-nav">
|
||||||
|
<h2>archive</h2>
|
||||||
|
{%- set currentYear = null -%}
|
||||||
|
{%- for column in collections.columns %}
|
||||||
|
{%- set colYear = column.date | year -%}
|
||||||
|
{%- if colYear != currentYear %}
|
||||||
|
{%- if currentYear != null %}
|
||||||
|
</ul>
|
||||||
|
{%- endif %}
|
||||||
|
{%- set currentYear = colYear %}
|
||||||
|
<h3 class="year-label">{{ colYear }}</h3>
|
||||||
|
<ul>
|
||||||
|
{%- endif %}
|
||||||
|
<li><a href="{{ column.url }}">{{ column.data.title }}</a></li>
|
||||||
|
{%- endfor %}
|
||||||
|
{%- if currentYear != null %}
|
||||||
|
</ul>
|
||||||
|
{%- endif %}
|
||||||
|
</nav>
|
||||||
|
</aside>
|
||||||
9
columns/2026-03-28-hello-world.md
Normal file
9
columns/2026-03-28-hello-world.md
Normal file
@@ -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.
|
||||||
216
css/style.css
Normal file
216
css/style.css
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
18
index.njk
Normal file
18
index.njk
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
layout: base.njk
|
||||||
|
---
|
||||||
|
|
||||||
|
{%- set latest = collections.columns | first -%}
|
||||||
|
{%- if latest %}
|
||||||
|
<article class="column-entry">
|
||||||
|
<header class="column-header">
|
||||||
|
<h1><a href="{{ latest.url }}">{{ latest.data.title }}</a></h1>
|
||||||
|
<time datetime="{{ latest.date | isoDate }}">{{ latest.date | readableDate }}</time>
|
||||||
|
</header>
|
||||||
|
<div class="column-body">
|
||||||
|
{{ latest.content | safe }}
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
{%- else %}
|
||||||
|
<p>Nothing here yet.</p>
|
||||||
|
{%- endif %}
|
||||||
12
package.json
Normal file
12
package.json
Normal file
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
7
pages/about.md
Normal file
7
pages/about.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
title: About
|
||||||
|
layout: base.njk
|
||||||
|
permalink: /about/
|
||||||
|
---
|
||||||
|
|
||||||
|
About page.
|
||||||
7
pages/code.md
Normal file
7
pages/code.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
title: Code
|
||||||
|
layout: base.njk
|
||||||
|
permalink: /code/
|
||||||
|
---
|
||||||
|
|
||||||
|
Code and projects.
|
||||||
Reference in New Issue
Block a user