using astro
Some checks are pending
/ deploy (push) Waiting to run

This commit is contained in:
Loyyd 2026-06-11 08:29:29 +02:00
parent 8e40b8599b
commit 830585e2ba
15 changed files with 5371 additions and 15 deletions

4
.gitignore vendored
View file

@ -11,3 +11,7 @@ Thumbs.db
npm-debug.log*
yarn-debug.log*
yarn-error.log*
node_modules/
dist/
.astro/

View file

@ -6,8 +6,8 @@ explicitly says a change must preserve a URL.
## What This Is
This is a plain static website made from HTML, CSS, JavaScript, images, PDFs,
and other static assets.
This is an Astro-built static website. The current source content is exported
HTML plus CSS, JavaScript, images, PDFs, and other static assets.
## Working Rules
@ -27,8 +27,11 @@ and other static assets.
| `website/index.html` | Home page |
| `website/about.html` | About page |
| `website/contact.html` | Contact page with the form |
| `website/*.html` | All other static pages, archives, categories, tags, and posts |
| `website/PAGES.md` | Map from old folder paths to new flat filenames |
| `website/` | Source HTML pages, blog posts, speech archives, categories, and tags |
| `website/PAGES.md` | Map from old folder paths to current HTML paths |
| `src/pages/` | Astro endpoints that generate static output from `website/` |
| `src/components/` | Astro components for shared layout migration |
| `dist/` | Generated static output from `npm run build` |
| `css/` | Site-level stylesheets |
| `js/` | Site-level scripts |
| `assets/` | Images, PDFs, fonts, theme files, uploads, and static vendor files |
@ -36,6 +39,18 @@ and other static assets.
## Local Preview
For Astro development:
```bash
npm run dev
```
For the Nginx preview:
```bash
npm run build
```
```bash
docker compose up
```

View file

@ -1,10 +1,13 @@
# familyfedie-website
Local static website files.
Local static website files built with Astro.
## Project Structure
- `website/` - top-level static pages
- `src/pages/` - Astro endpoints that generate static HTML from `website/`
- `src/components/` - Astro components for the shared layout migration path
- `dist/` - generated static output from `npm run build`
- `website/index.html` - homepage
- `website/about.html` - about page
- `website/contact.html` - contact page with the form
@ -23,6 +26,12 @@ Local static website files.
## Maintenance
Run Astro locally while editing:
```bash
npm run dev
```
After changing shared navigation, sidebar, or footer markup in
`scripts/components.mjs`, run:
@ -32,6 +41,14 @@ npm run render:layout
## Local Preview
Build the Astro output first:
```bash
npm run build
```
Then serve `dist/` with Docker:
```bash
docker compose up
```

9
astro.config.mjs Normal file
View file

@ -0,0 +1,9 @@
import { defineConfig } from "astro/config";
export default defineConfig({
output: "static",
outDir: "dist",
build: {
format: "file",
},
});

View file

@ -3,7 +3,7 @@ server {
listen [::]:80;
server_name _;
root /usr/share/nginx/html/website;
root /usr/share/nginx/html/dist;
index index.html;
location ~ /\. {
@ -15,17 +15,17 @@ server {
}
location /assets/ {
alias /usr/share/nginx/html/assets/;
alias /usr/share/nginx/html/dist/assets/;
try_files $uri =404;
}
location /css/ {
alias /usr/share/nginx/html/css/;
alias /usr/share/nginx/html/dist/css/;
try_files $uri =404;
}
location /js/ {
alias /usr/share/nginx/html/js/;
alias /usr/share/nginx/html/dist/js/;
try_files $uri =404;
}
}

View file

@ -1,7 +1,7 @@
# Site Structure
This is a local static site. Top-level pages are kept in `website/`, while blog
posts and speech archive pages are grouped into dedicated folders.
This is a local static site built with Astro. The current exported HTML source
is kept in `website/`, while Astro emits the served site into `dist/`.
## Root
@ -16,6 +16,11 @@ posts and speech archive pages are grouped into dedicated folders.
- `website/speeches/rev-dr-sun-myung-moon/*.html` - yearly speech archive pages
- `website/speeches/categories/*.html` - speech category archive pages
- `website/PAGES.md` - map of old folder paths to current HTML paths
- `src/pages/index.html.ts` - Astro endpoint for the home page
- `src/pages/[...route].ts` - Astro endpoint for all other existing HTML pages
- `src/lib/static-pages.ts` - maps `website/` files to Astro static routes
- `src/components/` - Astro shared layout components for ongoing migration
- `dist/` - generated site output, ignored by git
- `css/` - site-level stylesheets
- `js/` - site-level scripts
- `assets/` - images, PDFs, fonts, theme files, uploads, and vendor files
@ -23,14 +28,19 @@ posts and speech archive pages are grouped into dedicated folders.
- `scripts/components.mjs` - shared nav/sidebar/footer components
- `scripts/render-shared-layout.mjs` - renders shared layout components into pages
- `scripts/organize-content.mjs` - organizes exported blog and speech pages
- `scripts/copy-static-assets.mjs` - copies `assets/`, `css/`, and `js/` into `dist/`
- `docker/` and `compose.yaml` - local static server preview
- `.forgejo/` - deployment automation
## Shared Layout
The site remains static HTML, but common navigation, sidebar, and footer markup
is generated from `scripts/components.mjs`. Run `npm run render:layout` after
editing those components.
The current source pages remain static HTML, but common navigation, sidebar, and
footer markup is generated from `scripts/components.mjs`. Run
`npm run render:layout` after editing those components.
Astro components in `src/components/` are available for the next migration step:
converting individual pages from exported HTML into `.astro` or Markdown content
while reusing the same layout structure.
## Asset Layout
@ -45,6 +55,19 @@ editing those components.
Run:
```bash
npm run dev
```
Then open Astro's local URL, usually:
```text
http://localhost:4321
```
For the Nginx preview, build first:
```bash
npm run build
docker compose up
```

5083
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -2,6 +2,12 @@
"scripts": {
"organize": "node scripts/organize-content.mjs",
"render:layout": "node scripts/render-shared-layout.mjs",
"build": "npm run organize && npm run render:layout"
"prepare:source": "npm run organize && npm run render:layout",
"dev": "npm run prepare:source && astro dev --host 0.0.0.0",
"build": "npm run prepare:source && astro build && node scripts/copy-static-assets.mjs",
"preview": "astro preview --host 0.0.0.0"
},
"devDependencies": {
"astro": "^6.4.6"
}
}

View file

@ -0,0 +1,18 @@
import fs from "node:fs";
import path from "node:path";
const repoRoot = process.cwd();
const distRoot = path.join(repoRoot, "dist");
const staticDirs = ["assets", "css", "js"];
function copyDir(source, destination) {
fs.rmSync(destination, { recursive: true, force: true });
fs.mkdirSync(path.dirname(destination), { recursive: true });
fs.cpSync(source, destination, { recursive: true });
}
for (const dir of staticDirs) {
copyDir(path.join(repoRoot, dir), path.join(distRoot, dir));
}
console.log(`Copied ${staticDirs.join(", ")} into dist/.`);

View file

@ -0,0 +1,18 @@
<footer id="footer" role="contentinfo">
<div id="colophon"></div>
<div id="footer2">
<div id="footer2-inner">
<div id="site-copyright">
<b>Family Federation for World Peace and Unification (FFWPU) Ireland</b>
<br />
Charity no. CHY 6071 All Rights Reserved 2013
<br />
<a href="/speeches/" target="_blank">Speeches</a>
</div>
<div style="text-align:center;padding:5px 0 2px;text-transform:uppercase;font-size:12px;margin:1em auto 0;">
Family Federation for World Peace and Unification Ireland
</div>
</div>
</div>
</footer>

View file

@ -0,0 +1,70 @@
---
const { pathname = "/" } = Astro.props;
const navItems = [
{ href: "/index.html", label: "Home", match: ["/index.html", "/"] },
{
href: "/about.html",
label: "About Us",
match: ["/about.html", "/the-founders.html", "/about-us-organizations.html"],
children: [
{ href: "/the-founders.html", label: "The Founders" },
{ href: "/about-us-organizations.html", label: "Organizations" },
],
},
{ href: "/videos.html", label: "Videos", match: ["/videos.html"] },
{
href: "/events.html",
label: "Events",
match: ["/events.html", "/services.html"],
children: [{ href: "/services.html", label: "Sunday Services" }],
},
{ href: "/speeches/", label: "Speeches", match: ["/speeches/"] },
{ href: "/contact.html", label: "Contact", match: ["/contact.html"] },
];
function isCurrent(item) {
return item.match.some((match) => {
if (match === "/") {
return pathname === "/";
}
if (match.endsWith("/")) {
return pathname.startsWith(match);
}
return pathname === match;
});
}
---
<nav id="access" class="jssafe" role="navigation">
<div class="skip-link screen-reader-text"><a href="#content" title="Skip to content">Skip to content</a></div>
<div class="menu">
<ul id="prime_nav" class="menu">
{
navItems.map((item, index) => {
const current = isCurrent(item);
return (
<li class:list={["menu-item", item.children && "menu-item-has-children", current && "current-menu-item current_page_item", `menu-item-${index + 1}`]}>
<a href={item.href} aria-current={current ? "page" : undefined}>
<span>{item.label}</span>
</a>
{
item.children && (
<ul class="sub-menu">
{item.children.map((child, childIndex) => (
<li class={`menu-item menu-item-${index + 1}-${childIndex + 1}`}>
<a href={child.href}>
<span>{child.label}</span>
</a>
</li>
))}
</ul>
)
}
</li>
);
})
}
</ul>
</div>
</nav>

View file

@ -0,0 +1,26 @@
---
const sidebarItems = [
{ href: "/the-founders.html", label: "The Founders" },
{ href: "/services.html", label: "Sunday Services" },
{ href: "/contact.html", label: "Contact" },
{ href: "/speeches/", label: "Speeches" },
];
---
<div id="secondary" class="widget-area sidey" role="complementary">
<ul class="xoxo">
<li id="nav_menu-2" class="widget-container widget_nav_menu">
<div class="menu-menu-3-side-bar-menu-container">
<ul id="menu-menu-3-side-bar-menu" class="menu">
{
sidebarItems.map((item, index) => (
<li class={`menu-item menu-item-${index + 1}`}>
<a href={item.href}>{item.label}</a>
</li>
))
}
</ul>
</div>
</li>
</ul>
</div>

32
src/lib/static-pages.ts Normal file
View file

@ -0,0 +1,32 @@
import fs from "node:fs";
import path from "node:path";
export const repoRoot = process.cwd();
export const websiteRoot = path.join(repoRoot, "website");
export function walkHtmlFiles(dir = websiteRoot): string[] {
return fs.readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
return walkHtmlFiles(fullPath);
}
return entry.isFile() && entry.name.endsWith(".html") ? [fullPath] : [];
});
}
export function relativeWebsitePath(filePath: string): string {
return path.relative(websiteRoot, filePath).split(path.sep).join("/");
}
export function routeFromRelativePath(relativePath: string): string {
if (relativePath === "index.html") {
return "";
}
return relativePath;
}
export function sourcePathFromRoute(route = ""): string {
const relativePath = route === "" ? "index.html" : route.endsWith(".html") ? route : `${route}/index.html`;
return path.join(websiteRoot, relativePath);
}

23
src/pages/[...route].ts Normal file
View file

@ -0,0 +1,23 @@
import fs from "node:fs/promises";
import { relativeWebsitePath, routeFromRelativePath, sourcePathFromRoute, walkHtmlFiles } from "../lib/static-pages";
export function getStaticPaths() {
return walkHtmlFiles()
.map(relativeWebsitePath)
.filter((relativePath) => relativePath !== "index.html")
.map((relativePath) => ({
params: {
route: routeFromRelativePath(relativePath),
},
}));
}
export async function GET({ params }: { params: { route?: string } }) {
const html = await fs.readFile(sourcePathFromRoute(params.route), "utf8");
return new Response(html, {
headers: {
"content-type": "text/html; charset=utf-8",
},
});
}

12
src/pages/index.html.ts Normal file
View file

@ -0,0 +1,12 @@
import fs from "node:fs/promises";
import { sourcePathFromRoute } from "../lib/static-pages";
export async function GET() {
const html = await fs.readFile(sourcePathFromRoute(), "utf8");
return new Response(html, {
headers: {
"content-type": "text/html; charset=utf-8",
},
});
}