diff --git a/app/astro.config.mjs b/app/astro.config.mjs index bfe9230..8247250 100644 --- a/app/astro.config.mjs +++ b/app/astro.config.mjs @@ -1,9 +1,14 @@ +import { readFileSync } from "node:fs"; import { defineConfig } from "astro/config"; + +const siteConfig = JSON.parse( + readFileSync(new URL("./src/config/site.json", import.meta.url)), +); import mdx from "@astrojs/mdx"; import tailwindcss from "@tailwindcss/vite"; const site = - process.env.SITE_URL || process.env.PUBLIC_SITE_URL || "https://comiida.com"; + process.env.SITE_URL || process.env.PUBLIC_SITE_URL || siteConfig.url; export default defineConfig({ site, diff --git a/app/src/components/Footer.astro b/app/src/components/Footer.astro index 3a5d6de..fb7b857 100644 --- a/app/src/components/Footer.astro +++ b/app/src/components/Footer.astro @@ -14,7 +14,7 @@ const { flush = false } = Astro.props;

- +
diff --git a/app/src/config/site.json b/app/src/config/site.json new file mode 100644 index 0000000..0f6ba33 --- /dev/null +++ b/app/src/config/site.json @@ -0,0 +1,20 @@ +{ + "name": "SeedProject Site", + "url": "https://example.com", + "description": "A short one-line description of this site, used for SEO and social sharing.", + "tagline": "A starter site built on SeedProject", + "language": "en", + "author": { + "slug": "site-author", + "name": "Site Author", + "bio": "One-line author bio — who runs this site.", + "longBio": "A longer author biography paragraph describing who runs this site and their background.", + "avatar": "/avatar-placeholder.png", + "jobTitle": "Founder & Editor", + "knowsAbout": [], + "sameAs": [] + }, + "social": { + "twitter": "" + } +} diff --git a/app/src/content/blog/welcome/cover.png b/app/src/content/blog/welcome/cover.png new file mode 100644 index 0000000..9554827 Binary files /dev/null and b/app/src/content/blog/welcome/cover.png differ diff --git a/app/src/content/blog/welcome/index.mdx b/app/src/content/blog/welcome/index.mdx new file mode 100644 index 0000000..cf93ca4 --- /dev/null +++ b/app/src/content/blog/welcome/index.mdx @@ -0,0 +1,22 @@ +--- +title: "Welcome to your new site" +excerpt: "A sample post so your blog builds out of the box. Edit or delete it once you add real content." +date: 2026-01-01 +readingTime: 2 +category: "guides" +author: "site-author" +thumbnail: "./cover.png" +featured: true +--- + +This is a sample post included with the **SeedProject base**. It exists so the +blog, homepage, RSS feed, and sitemap all build before you've written anything. + +## Getting started + +1. Edit `site.config.json` at the repo root with your site's name, URL, and author. +2. Run `node scripts/configure.mjs` to stamp that identity across the theme and engines. +3. Replace this post with your own content under `app/src/content/blog/`. + +Each post is a folder with an `index.mdx` file and a `cover` image, using the +frontmatter fields defined in `app/src/content.config.js`. diff --git a/app/src/lib/blog-data.js b/app/src/lib/blog-data.js index 255fff6..ccd1ea7 100644 --- a/app/src/lib/blog-data.js +++ b/app/src/lib/blog-data.js @@ -1,33 +1,22 @@ import { getCollection } from "astro:content"; +import siteConfig from "../config/site.json"; const siteUrl = ( import.meta.env.SITE_URL || import.meta.env.PUBLIC_SITE_URL || - "https://quietpages-eta.vercel.app" + siteConfig.url ).replace(/\/$/, ""); export const authors = [ { - slug: "carlos-arias", - name: "Carlos Arias", - bio: "AI engineer and digital strategist with 25+ years building software and AI systems; founder of CarlosArias&Co and engineer behind Medellín.co.", - longBio: - "Carlos Arias is an AI engineer and strategist with over two decades across software engineering, digital marketing, and AI. He is the founder of CarlosArias&Co and Snoopi.io, and an engineer and strategist behind the Medellín.co city guide. Based between South Florida and Latin America, he builds AI-driven systems for local visibility and revenue-tracked growth. Comiida's articles are researched from public sources and AI-assisted under his editorial oversight.", - avatar: "https://carlosarias.com/wp-content/uploads/2023/02/cropped-clos.jpg", - jobTitle: "Founder & Editor, Comiida", - knowsAbout: [ - "Medellín restaurants", - "Colombian cuisine", - "dining guides", - "local SEO", - ], - sameAs: [ - "https://x.com/hicarlosarias", - "https://www.linkedin.com/in/hicarlosarias/", - "https://www.instagram.com/carlosarias.co", - "https://www.facebook.com/hicarlosarias", - "https://carlosarias.com", - ], + slug: siteConfig.author.slug, + name: siteConfig.author.name, + bio: siteConfig.author.bio, + longBio: siteConfig.author.longBio, + avatar: siteConfig.author.avatar, + jobTitle: siteConfig.author.jobTitle, + knowsAbout: siteConfig.author.knowsAbout || [], + sameAs: siteConfig.author.sameAs || [], }, ]; @@ -38,45 +27,7 @@ export const categories = [ { slug: "neighborhoods", name: "Neighborhoods" }, ]; -export const tags = [ - { slug: "food-guide", name: "Food Guide" }, - { slug: "ciudad-del-rio", name: "Ciudad Del Rio" }, - { slug: "things-to-do", name: "Things To Do" }, - { slug: "terminal-del-sur", name: "Terminal Del Sur" }, - { slug: "specialty-coffee", name: "Specialty Coffee" }, - { slug: "craft-beer", name: "Craft Beer" }, - { slug: "rionegro", name: "Rionegro" }, - { slug: "antioquia", name: "Antioquia" }, - { slug: "day-trip", name: "Day Trip" }, - { slug: "oriente-antioqueno", name: "Oriente Antioqueno" }, - { slug: "food-festival", name: "Food Festival" }, - { slug: "marinilla", name: "Marinilla" }, - { slug: "wake-medellin", name: "Wake Medellin" }, - { slug: "peruvian-cuisine", name: "Peruvian Cuisine" }, - { slug: "steakhouse", name: "Steakhouse" }, - { slug: "gastronomy", name: "Gastronomy" }, - { slug: "time-out", name: "Time Out" }, - { slug: "food-ranking", name: "Food Ranking" }, - { slug: "chef", name: "Chef" }, - { slug: "colombian-cuisine", name: "Colombian Cuisine" }, - { slug: "new-restaurant", name: "New Restaurant" }, - { slug: "legal-news", name: "Legal News" }, - { slug: "fine-dining", name: "Fine Dining" }, - { slug: "hidden-kitchen", name: "Hidden Kitchen" }, - { slug: "chefs-table", name: "Chefs Table" }, - { slug: "tasting-menu", name: "Tasting Menu" }, - { slug: "new-openings", name: "New Openings" }, - { slug: "restaurant-news", name: "Restaurant News" }, - { slug: "restaurants", name: "Restaurants" }, - { slug: "coffee", name: "Coffee" }, - { slug: "el-poblado", name: "El Poblado" }, - { slug: "brunch", name: "Brunch" }, - { slug: "expats", name: "Expats" }, - { slug: "food-safety", name: "Food Safety" }, - { slug: "street-food", name: "Street Food" }, - { slug: "medellin", name: "Medellín" }, - { slug: "travel", name: "Travel" }, -]; +export const tags = []; export const imageSrc = (image) => (typeof image === "string" ? image : image?.src); @@ -136,9 +87,9 @@ export const formatDate = (iso) => }); export const SITE = { - name: "Comiida", - description: - "Medellín's restaurant scene for English-speaking expats, nomads, and travelers — guides, news, and data-driven dining picks.", + name: siteConfig.name, + description: siteConfig.description, + tagline: siteConfig.tagline, url: siteUrl, }; diff --git a/app/src/pages/index.astro b/app/src/pages/index.astro index 9602e5b..062d053 100644 --- a/app/src/pages/index.astro +++ b/app/src/pages/index.astro @@ -28,7 +28,7 @@ const jsonLd = { --- Watercolor painting of Medellín's green Andean mountains and valley - {featuredAuthor.name} diff --git a/astroagent.config.json b/astroagent.config.json index abd7098..87bfa83 100644 --- a/astroagent.config.json +++ b/astroagent.config.json @@ -1,6 +1,6 @@ { - "name": "comiida", - "url": "https://comiida.com", + "name": "seedproject-site", + "url": "https://example.com", "appDir": "app", "outDir": "public", "buildCommand": "npm run build", diff --git a/content-pipeline/config.json b/content-pipeline/config.json index 490130f..fe32e19 100644 --- a/content-pipeline/config.json +++ b/content-pipeline/config.json @@ -1,9 +1,9 @@ { "site": { - "url": "https://comiida.com", - "name": "Comiida", - "topic": "the restaurant industry in Medellin, Colombia", - "audience": "English-speaking expats, digital nomads, and tourists in Medellin", + "url": "https://example.com", + "name": "SeedProject Site", + "topic": "your subject area", + "audience": "your target audience", "language": "en" }, "paths": { @@ -36,8 +36,8 @@ "maxPerScan": 8 }, "author": { - "slug": "carlos-arias", - "name": "Carlos Arias" + "slug": "site-author", + "name": "Site Author" }, "image": { "provider": "higgsfield", @@ -46,27 +46,42 @@ "outputFormat": "jpg", "credit": { "caption": "Illustrative cover image. Not a photograph of any specific establishment.", - "author": "Comiida" + "author": "SeedProject Site" } }, "editorial": { "calendarDays": 90, "refillThreshold": 7, "refillCount": 14, - "timezone": "America/Bogota", + "timezone": "America/New_York", "contentMix": { - "guide": 0.30, + "guide": 0.3, "list": 0.25, - "news-roundup": 0.20, + "news-roundup": 0.2, "trend": 0.15, - "review-summary": 0.10 + "review-summary": 0.1 }, "wordCounts": { - "news-roundup": [600, 900], - "trend": [800, 1200], - "review-summary": [900, 1300], - "list": [1000, 1500], - "guide": [1200, 1800] + "news-roundup": [ + 600, + 900 + ], + "trend": [ + 800, + 1200 + ], + "review-summary": [ + 900, + 1300 + ], + "list": [ + 1000, + 1500 + ], + "guide": [ + 1200, + 1800 + ] } } } diff --git a/scripts/configure.mjs b/scripts/configure.mjs new file mode 100644 index 0000000..12da949 --- /dev/null +++ b/scripts/configure.mjs @@ -0,0 +1,59 @@ +#!/usr/bin/env node +/** + * configure.mjs — stamp site.config.json (the single source of identity) into + * every engine config. Run after editing site.config.json: + * + * node scripts/configure.mjs + * + * Writes: + * - app/src/config/site.json (Astro theme reads this) + * - content-pipeline/config.json (site identity + author + timezone) + * - astroagent.config.json (name + url) + */ +import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs"; +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +const root = resolve(dirname(fileURLToPath(import.meta.url)), ".."); +const read = (p) => JSON.parse(readFileSync(resolve(root, p), "utf8")); +const write = (p, obj) => { + const full = resolve(root, p); + mkdirSync(dirname(full), { recursive: true }); + writeFileSync(full, JSON.stringify(obj, null, 2) + "\n"); + console.log(" wrote", p); +}; +const slug = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, ""); + +const site = read("site.config.json"); +console.log(`Configuring site: ${site.name} <${site.url}>`); + +// 1) Astro theme +write("app/src/config/site.json", { + name: site.name, + url: site.url, + description: site.description, + tagline: site.tagline, + language: site.language, + author: site.author, + social: site.social, +}); + +// 2) content-pipeline +if (existsSync(resolve(root, "content-pipeline/config.json"))) { + const cp = read("content-pipeline/config.json"); + cp.site = { ...cp.site, url: site.url, name: site.name, topic: site.topic, audience: site.audience, language: site.language }; + cp.author = { ...(cp.author || {}), slug: site.author.slug, name: site.author.name }; + if (cp.editorial) cp.editorial.timezone = site.timezone; + if (cp.image && cp.image.credit) cp.image.credit.author = site.name; + write("content-pipeline/config.json", cp); +} + +// 3) astroagent +if (existsSync(resolve(root, "astroagent.config.json"))) { + const aa = read("astroagent.config.json"); + aa.name = slug(site.name); + aa.url = site.url; + write("astroagent.config.json", aa); +} + +console.log("Done. Rebuild the site: (cd app && npm run build)"); diff --git a/site.config.json b/site.config.json new file mode 100644 index 0000000..3d0c86a --- /dev/null +++ b/site.config.json @@ -0,0 +1,23 @@ +{ + "name": "SeedProject Site", + "url": "https://example.com", + "description": "A short one-line description of this site, used for SEO and social sharing.", + "tagline": "A starter site built on SeedProject", + "language": "en", + "timezone": "America/New_York", + "topic": "your subject area", + "audience": "your target audience", + "author": { + "slug": "site-author", + "name": "Site Author", + "bio": "One-line author bio — who runs this site.", + "longBio": "A longer author biography paragraph describing who runs this site and their background.", + "avatar": "/avatar-placeholder.png", + "jobTitle": "Founder & Editor", + "knowsAbout": [], + "sameAs": [] + }, + "social": { + "twitter": "" + } +}