Initial Roux Hugo site — fashion journal for roux.pivoine.art
100-post fashion journal generated from ~/projects/ginger content: - Hugo Extended static site with TailwindCSS v4 - WebP image pipeline (thumb/card/og/full sizes via Hugo image processing) - Full SEO: sitemap (501 URLs), OpenGraph with per-post images, Twitter cards - Async page transitions via View Transitions API - Deep-linked URLs: /posts/[slug]/, /categories/[cat]/, /tags/[tag]/, /issues/ - Lightbox with keyboard/swipe nav, thumbnail strip, inverted search index - Issues archive with quarterly release structure - Multi-stage Dockerfile (Tailwind → Hugo → nginx:alpine) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Import posts from ~/projects/ginger/posts.csv into Hugo content.
|
||||
Only imports posts whose generated_image exists in the selected images folder.
|
||||
Run from the site root: python3 scripts/import-posts.py
|
||||
"""
|
||||
import csv
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
GINGER = Path.home() / "projects" / "ginger"
|
||||
CSV_PATH = GINGER / "posts.csv"
|
||||
IMG_DIR = GINGER / "images" / "final" / "selected"
|
||||
SITE = Path(__file__).parent.parent
|
||||
CONTENT = SITE / "content" / "posts"
|
||||
DATA_DIR = SITE / "data"
|
||||
|
||||
CONTENT.mkdir(parents=True, exist_ok=True)
|
||||
DATA_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Collect available images
|
||||
available = {f.name for f in IMG_DIR.iterdir() if f.is_file()}
|
||||
|
||||
matched = []
|
||||
with open(CSV_PATH, newline="", encoding="utf-8") as f:
|
||||
reader = csv.DictReader(f)
|
||||
for row in reader:
|
||||
gen = row.get("generated_image", "").strip()
|
||||
if gen and gen in available:
|
||||
matched.append(row)
|
||||
|
||||
print(f"Matched {len(matched)} posts out of {len(available)} available images")
|
||||
|
||||
# Sort deterministically by generated_image filename for stable plate numbers
|
||||
matched.sort(key=lambda r: r["generated_image"])
|
||||
|
||||
for idx, row in enumerate(matched, start=1):
|
||||
plate = f"{idx:03d}"
|
||||
gen_img = row["generated_image"].strip()
|
||||
slug = gen_img.replace(".png", "")
|
||||
title = row["title"].strip()
|
||||
desc = row["description"].strip().replace('"', '\\"')
|
||||
raw_cat = row.get("category", "").strip()
|
||||
raw_tags = row.get("tags", "").strip()
|
||||
|
||||
cats = [c.strip() for c in raw_cat.split(",") if c.strip()]
|
||||
tags = [t.strip() for t in raw_tags.split(",") if t.strip()]
|
||||
|
||||
cats_yaml = "\n".join(f' - "{c}"' for c in cats)
|
||||
tags_yaml = "\n".join(f' - "{t}"' for t in tags) if tags else ' []'
|
||||
|
||||
bundle = CONTENT / slug
|
||||
bundle.mkdir(exist_ok=True)
|
||||
|
||||
src_img = IMG_DIR / gen_img
|
||||
dst_img = bundle / gen_img
|
||||
if not dst_img.exists():
|
||||
shutil.copy2(src_img, dst_img)
|
||||
|
||||
md = f"""---
|
||||
title: "{title.replace('"', '\\"')}"
|
||||
description: "{desc}"
|
||||
plate: "{plate}"
|
||||
slug: "{slug}"
|
||||
image: "{gen_img}"
|
||||
weight: {idx}
|
||||
categories:
|
||||
{cats_yaml}
|
||||
tags:
|
||||
{tags_yaml}
|
||||
---
|
||||
"""
|
||||
(bundle / "index.md").write_text(md, encoding="utf-8")
|
||||
|
||||
print(f"Created {len(matched)} page bundles in {CONTENT}")
|
||||
|
||||
# Write data/issues.json
|
||||
issues = [
|
||||
{
|
||||
"id": "01",
|
||||
"number": "№ 01",
|
||||
"title": "Fabric, Light & Gesture",
|
||||
"season": "Spring MMXXVI",
|
||||
"publishedAt": "2026-03-21",
|
||||
"blurb": "The inaugural plates — one hundred photographs gathered across ateliers, streets, and quiet hotel corridors.",
|
||||
"status": "current"
|
||||
},
|
||||
{
|
||||
"id": "02",
|
||||
"number": "№ 02",
|
||||
"title": "The Glasshouse",
|
||||
"season": "Summer MMXXVI",
|
||||
"publishedAt": "2026-06-21",
|
||||
"blurb": "Forthcoming — a study in transparency, condensation, and the long late light of June.",
|
||||
"status": "forthcoming"
|
||||
},
|
||||
{
|
||||
"id": "03",
|
||||
"number": "№ 03",
|
||||
"title": "Atelier After Hours",
|
||||
"season": "Autumn MMXXVI",
|
||||
"publishedAt": "2026-09-22",
|
||||
"blurb": "Forthcoming — the slow work of cloth and thread, photographed when the studio is half-empty.",
|
||||
"status": "forthcoming"
|
||||
}
|
||||
]
|
||||
(DATA_DIR / "issues.json").write_text(json.dumps(issues, indent=2), encoding="utf-8")
|
||||
print("Wrote data/issues.json")
|
||||
Reference in New Issue
Block a user