diff --git a/_data/cvPageConfig.js b/_data/cvPageConfig.js
new file mode 100644
index 0000000..456b388
--- /dev/null
+++ b/_data/cvPageConfig.js
@@ -0,0 +1,29 @@
+/**
+ * CV Page Configuration Data
+ * Reads config from indiekit-endpoint-cv plugin CV page builder.
+ * Falls back to null — cv.njk then uses the default hardcoded layout.
+ *
+ * The CV plugin writes a .indiekit/cv-page.json file that Eleventy watches.
+ * On change, a rebuild picks up the new config, allowing layout changes
+ * without a Docker rebuild.
+ */
+
+import { readFileSync } from "node:fs";
+import { resolve, dirname } from "node:path";
+import { fileURLToPath } from "node:url";
+
+const __dirname = dirname(fileURLToPath(import.meta.url));
+
+export default function () {
+ try {
+ // Resolve via the content/ symlink relative to the Eleventy project
+ const configPath = resolve(__dirname, "..", "content", ".indiekit", "cv-page.json");
+ const raw = readFileSync(configPath, "utf8");
+ const config = JSON.parse(raw);
+ console.log("[cvPageConfig] Loaded CV page builder config");
+ return config;
+ } catch {
+ // No CV page builder config — fall back to hardcoded layout in cv.njk
+ return null;
+ }
+}
diff --git a/_includes/components/cv-builder.njk b/_includes/components/cv-builder.njk
new file mode 100644
index 0000000..4af77bf
--- /dev/null
+++ b/_includes/components/cv-builder.njk
@@ -0,0 +1,121 @@
+{#
+ CV Page Builder - renders configured layout, sections, and sidebar
+ from cvPageConfig (written by indiekit-endpoint-cv plugin)
+#}
+
+{% set layout = cvPageConfig.layout or "single-column" %}
+{% set hasSidebar = cvPageConfig.sidebar and cvPageConfig.sidebar.length %}
+
+{# Hero — rendered at top when enabled (default: true) #}
+{% if cvPageConfig.hero.enabled != false %}
+
+ {{ site.author.title }}
+
+ {{ site.author.bio }}
+
+
+ {{ site.author.name }}
+
+ {% if site.author.title %}
+
+ Last updated: {{ cv.lastUpdated | date("PPP") }} +
+{% endif %} + +{# Footer — rendered after the main layout, full width #} +{% include "components/cv-footer.njk" %} diff --git a/_includes/components/cv-footer.njk b/_includes/components/cv-footer.njk new file mode 100644 index 0000000..c86957e --- /dev/null +++ b/_includes/components/cv-footer.njk @@ -0,0 +1,26 @@ +{# CV Page Builder Footer — renders footer items in a responsive 3-column grid #} +{% if cvPageConfig.footer and cvPageConfig.footer.length %} + +{% endif %} diff --git a/_includes/components/cv-sidebar.njk b/_includes/components/cv-sidebar.njk new file mode 100644 index 0000000..ff83e8e --- /dev/null +++ b/_includes/components/cv-sidebar.njk @@ -0,0 +1,45 @@ +{# CV Page Builder Sidebar — renders widgets from cvPageConfig.sidebar #} +{% if cvPageConfig.sidebar and cvPageConfig.sidebar.length %} + {% for widget in cvPageConfig.sidebar %} + {% if widget.type == "author-card" %} + {% include "components/widgets/author-card.njk" %} + {% elif widget.type == "social-activity" %} + {% include "components/widgets/social-activity.njk" %} + {% elif widget.type == "github-repos" %} + {% include "components/widgets/github-repos.njk" %} + {% elif widget.type == "funkwhale" %} + {% include "components/widgets/funkwhale.njk" %} + {% elif widget.type == "recent-posts" %} + {% include "components/widgets/recent-posts.njk" %} + {% elif widget.type == "blogroll" %} + {% include "components/widgets/blogroll.njk" %} + {% elif widget.type == "feedland" %} + {% include "components/widgets/feedland.njk" %} + {% elif widget.type == "categories" %} + {% include "components/widgets/categories.njk" %} + {% elif widget.type == "search" %} + + {% elif widget.type == "webmentions" %} + {% include "components/widgets/webmentions.njk" %} + {% elif widget.type == "custom-html" %} + {# Custom content widget #} + {% set wConfig = widget.config or {} %} + + {% else %} + + {% endif %} + {% endfor %} +{% endif %} diff --git a/cv.njk b/cv.njk index 2c4f7fb..e55d789 100644 --- a/cv.njk +++ b/cv.njk @@ -6,7 +6,7 @@ permalink: /cv/ pagefindIgnore: true --- -{# Standalone CV page — renders all CV sections using the same partials as the homepage builder #} +{# CV page — uses configurable layout when cvPageConfig exists, falls back to hardcoded layout #} {% set hasCvData = (cv.experience and cv.experience.length) or (cv.projects and cv.projects.length) or @@ -14,75 +14,84 @@ pagefindIgnore: true {% if hasCvData %} -{# Hero / intro #} -- {{ site.author.title }} -
- {% endif %} - {% if site.author.bio %} -- {{ site.author.bio }} -
- {% endif %} -+ {{ site.author.title }} +
+ {% endif %} + {% if site.author.bio %} ++ {{ site.author.bio }} +
+ {% endif %} +- Last updated: {% if cv.lastUpdated %}{{ cv.lastUpdated | date("PPP") }}{% endif %} -
-{% endif %} + {# Last Updated #} + {% if cv.lastUpdated %} ++ Last updated: {{ cv.lastUpdated | date("PPP") }} +
+ {% endif %} + + {% endif %} {% else %}