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