This commit is contained in:
Concept Agent
2026-05-07 11:45:16 +02:00
parent 4860391e99
commit 9907a2ab7d
47 changed files with 8317 additions and 0 deletions
+116
View File
@@ -0,0 +1,116 @@
#!/usr/bin/env python3
"""
build_locations.py — Location page generator for floorithardwoodfloors.com
Reads data/locations.json + locations/_template.html
Outputs flat .html files: locations/{slug}.html
Usage:
python3 build_locations.py
python3 build_locations.py --slug buffalo # rebuild one city only
python3 build_locations.py --list # list all cities in database
"""
import json
import os
import sys
import argparse
from pathlib import Path
from datetime import datetime
SITE_ROOT = Path(__file__).parent
DATA_FILE = SITE_ROOT / "data" / "locations.json"
TEMPLATE_FILE = SITE_ROOT / "locations" / "_template.html"
OUTPUT_DIR = SITE_ROOT / "locations"
def build_faq_html(faqs: list) -> str:
"""Render FAQ list to HTML accordion items."""
items = []
for faq in faqs:
items.append(f""" <div class="faq-item">
<div class="faq-question">
<h4>{faq['q']}</h4>
<div class="faq-icon" aria-hidden="true"></div>
</div>
<div class="faq-answer">
<div class="faq-answer-inner">{faq['a']}</div>
</div>
</div>""")
return "\n".join(items)
def render_page(location: dict, template: str) -> str:
"""Stamp all {{variable}} placeholders in template with location data."""
html = template
# Render complex fields first
html = html.replace("{{faq_items}}", build_faq_html(location.get("faqs", [])))
# Stamp all scalar fields
for key, value in location.items():
if isinstance(value, str):
html = html.replace(f"{{{{{key}}}}}", value)
return html
def build_one(location: dict, template: str, verbose: bool = True) -> Path:
"""Generate one location page. Returns output path."""
slug = location["slug"]
city = location.get("city", slug)
output_path = OUTPUT_DIR / f"{slug}.html"
html = render_page(location, template)
output_path.write_text(html, encoding="utf-8")
if verbose:
print(f" Built: locations/{slug}.html ({city}, {location.get('state','NY')})")
return output_path
def main():
parser = argparse.ArgumentParser(description="Build flat location HTML pages from JSON database.")
parser.add_argument("--slug", help="Build a single city by slug (e.g. buffalo)")
parser.add_argument("--list", action="store_true", help="List all cities in database")
args = parser.parse_args()
# Validate paths
if not DATA_FILE.exists():
print(f"ERROR: data file not found: {DATA_FILE}")
sys.exit(1)
if not TEMPLATE_FILE.exists():
print(f"ERROR: template not found: {TEMPLATE_FILE}")
sys.exit(1)
locations = json.loads(DATA_FILE.read_text(encoding="utf-8"))
template = TEMPLATE_FILE.read_text(encoding="utf-8")
if args.list:
print(f"\nLocations in database ({len(locations)} total):")
for loc in locations:
print(f" {loc['slug']:20s} {loc.get('city','')}, {loc.get('state','NY')}")
return
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
if args.slug:
matches = [l for l in locations if l["slug"] == args.slug]
if not matches:
print(f"ERROR: slug '{args.slug}' not found in database.")
sys.exit(1)
print(f"\nBuilding single location: {args.slug}")
build_one(matches[0], template)
else:
print(f"\nBuilding {len(locations)} location pages...")
built = []
for loc in locations:
path = build_one(loc, template)
built.append(path)
print(f"\nDone. {len(built)} pages written to locations/")
print(f"Completed at {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
if __name__ == "__main__":
main()