Skip to content

Commit 1714667

Browse files
committed
feat: Add share CTA component to blog and neuromorphic pages
1 parent 61291b0 commit 1714667

File tree

8 files changed

+51
-145
lines changed

8 files changed

+51
-145
lines changed

assets/images/og-image.png

-625 KB
Binary file not shown.

layouts/blog/single.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@
1414
<div class="content mb-10">
1515
{{ .Content }}
1616
</div>
17-
{{ partial "components/share-cta.html" . }}
17+
1818
{{ partial "components/author-bios.html" . }}
1919

20+
{{ partial "components/share-cta.html" . }}
2021
</article>
2122

2223
{{ partial "components/sidebar-toc-shared.html" . }}
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<div class="share-cta-section mt-12 pt-8">
1+
<div class="share-cta-section mt-12 pt-8 border-t border-border dark:border-darkmode-border">
22
<div class="text-center">
33
<h2 class="text-3xl font-bold mb-4">Enjoy this content? Share it!</h2>
44
<p class="max-w-2xl mx-auto mb-8 text-lg text-gray-600 dark:text-gray-400">
@@ -7,4 +7,8 @@ <h2 class="text-3xl font-bold mb-4">Enjoy this content? Share it!</h2>
77
</div>
88

99
{{ partial "components/og-preview.html" . }}
10+
11+
<p class="text-center mt-6 text-sm text-gray-500">
12+
Hover over the image to reveal sharing options.
13+
</p>
1014
</div>

scripts/collectOgData.js

Lines changed: 29 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// scripts/collectOgData.js
2-
const { join, dirname, basename } = require('path'); // Ensure basename is imported
2+
const { join, dirname, basename } = require('path');
33
const { readdir, readFile, stat, mkdir, writeFile } = require('fs/promises');
44
const toml = require('toml');
55
const mimeTypes = require('mime-types');
@@ -49,19 +49,6 @@ async function ensureDir(dirPath) {
4949
catch (err) { if (err.code !== 'EEXIST') throw err; debugLog(`Directory already exists: ${dirPath}`); }
5050
}
5151

52-
// slugify is kept in case it's needed elsewhere, but not for OG image name from content pages
53-
function slugify(text) {
54-
if (!text) return 'untitled';
55-
return text
56-
.toString()
57-
.toLowerCase()
58-
.replace(/\s+/g, '-')
59-
.replace(/[^\w-]+/g, '')
60-
.replace(/--+/g, '-')
61-
.replace(/^-+/, '')
62-
.replace(/-+$/, '');
63-
}
64-
6552
async function findMarkdownFiles(dir) {
6653
let entries;
6754
try { entries = await readdir(dir); } catch (err) { console.warn(`Could not read directory ${dir}: ${err.message}`); return []; }
@@ -89,7 +76,6 @@ function extractFrontMatter(content) {
8976
const excludeMatch = fm.match(/^exclude_sitemap:\s*(true)\s*$/im);
9077
const imageMatch = fm.match(/^(?:image|Image):\s*"?([^"#\n]+)"?\s*$/m);
9178

92-
9379
if (titleMatch) title = titleMatch[1].split('#')[0].trim().replace(/^['"]|['"]$/g, '').replace(/\\"/g, '"').replace(/\\'/g, "'").trim();
9480
if (descMatch) {
9581
let raw = descMatch[1].replace(/\\"/g, '"').replace(/\\'/g, "'");
@@ -125,26 +111,18 @@ async function getHugoSiteConfig() {
125111
let paramsConfig = {};
126112

127113
try {
128-
debugLog(`Reading Hugo config from: ${HUGO_CONFIG_PATH}`);
129114
if (await pathExists(HUGO_CONFIG_PATH)) {
130115
const hugoContent = await readFile(HUGO_CONFIG_PATH, 'utf8');
131116
siteConfig = toml.parse(hugoContent);
132-
debugLog(`Hugo config parsed.`);
133-
} else {
134-
console.warn(`⚠️ Hugo config file not found at ${HUGO_CONFIG_PATH}`);
135117
}
136118
} catch (err) {
137119
console.error(`❌ Error parsing ${HUGO_CONFIG_PATH}: ${err.message}`);
138120
}
139121

140122
try {
141-
debugLog(`Reading params config from: ${PARAMS_CONFIG_PATH}`);
142123
if (await pathExists(PARAMS_CONFIG_PATH)) {
143124
const paramsContent = await readFile(PARAMS_CONFIG_PATH, 'utf8');
144125
paramsConfig = toml.parse(paramsContent);
145-
debugLog(`Params config parsed.`);
146-
} else {
147-
console.warn(`⚠️ Params config file not found at ${PARAMS_CONFIG_PATH}`);
148126
}
149127
} catch (err) {
150128
console.error(`❌ Error parsing ${PARAMS_CONFIG_PATH}: ${err.message}`);
@@ -161,35 +139,19 @@ async function getHugoSiteConfig() {
161139
async function getPaletteFromScss() {
162140
const palette = { ...DEFAULT_COLORS };
163141
try {
164-
debugLog(`Attempting to read SCSS variables from: ${CUSTOM_SCSS_PATH}`);
165142
if (!(await pathExists(CUSTOM_SCSS_PATH))) {
166143
console.warn(`⚠️ Custom SCSS file not found at ${CUSTOM_SCSS_PATH}. Using default colors.`);
167144
return palette;
168145
}
169146
const scssContent = await readFile(CUSTOM_SCSS_PATH, 'utf8');
170147

171-
let foundColorsCount = 0;
172148
CSS_VARS_TO_EXTRACT.forEach(cssVarName => {
173149
const regex = new RegExp(`--${cssVarName}\\s*:\\s*([^;]+);`, 'm');
174150
const match = scssContent.match(regex);
175151
if (match && match[1]) {
176-
const colorValue = match[1].trim();
177-
if (palette[cssVarName] !== colorValue || !DEFAULT_COLORS.hasOwnProperty(cssVarName)) {
178-
if (palette[cssVarName] !== colorValue && DEFAULT_COLORS.hasOwnProperty(cssVarName) ) {
179-
debugLog(`Updated CSS variable --${cssVarName} from SCSS: ${colorValue} (was ${palette[cssVarName]})`);
180-
} else if (!DEFAULT_COLORS.hasOwnProperty(cssVarName)) {
181-
debugLog(`Found new CSS variable --${cssVarName} from SCSS: ${colorValue}`);
182-
}
183-
foundColorsCount++;
184-
} else {
185-
debugLog(`CSS variable --${cssVarName} found in SCSS but value (${colorValue}) is same as default.`);
186-
}
187-
palette[cssVarName] = colorValue;
188-
} else {
189-
debugLog(`CSS variable --${cssVarName} not found or not in expected format in ${CUSTOM_SCSS_PATH}. Will use default: ${palette[cssVarName]}`);
152+
palette[cssVarName] = match[1].trim();
190153
}
191154
});
192-
console.log(`🎨 Extracted/Updated ${foundColorsCount} colors from SCSS. Total in palette: ${Object.keys(palette).length}`);
193155
return palette;
194156
} catch (err) {
195157
console.error(`❌ Error reading or parsing SCSS file ${CUSTOM_SCSS_PATH}: ${err.message}`);
@@ -204,42 +166,35 @@ async function collectData() {
204166
const hugoConfig = await getHugoSiteConfig();
205167
const colorPalette = await getPaletteFromScss();
206168

207-
let absoluteLogoPath = '';
208-
if (hugoConfig.logoPath) {
209-
debugLog(`Logo path from config: ${hugoConfig.logoPath}`);
210-
if (hugoConfig.logoPath.startsWith('/')) {
211-
absoluteLogoPath = join(STATIC_DIR, hugoConfig.logoPath.substring(1));
212-
debugLog(`Trying static logo path (absolute): ${absoluteLogoPath}`);
213-
} else {
169+
// --- MODIFIED LOGO LOGIC ---
170+
// Explicitly use assets/images/ONM-logo.png as the primary logo for OG images.
171+
let absoluteLogoPath = join(ASSETS_DIR, 'images', 'ONM-logo.png');
172+
173+
if (!(await pathExists(absoluteLogoPath))) {
174+
console.warn(`⚠️ Preferred OG logo not found at ${absoluteLogoPath}. Falling back to config logo.`);
175+
// Fallback to the logo from hugo config if the primary one is missing
176+
if (hugoConfig.logoPath) {
214177
const pathInAssets = join(ASSETS_DIR, hugoConfig.logoPath);
215178
const pathInStatic = join(STATIC_DIR, hugoConfig.logoPath);
216-
217179
if (await pathExists(pathInAssets)) {
218180
absoluteLogoPath = pathInAssets;
219-
debugLog(`Found logo in assets: ${absoluteLogoPath}`);
220181
} else if (await pathExists(pathInStatic)) {
221182
absoluteLogoPath = pathInStatic;
222-
debugLog(`Found logo in static: ${absoluteLogoPath}`);
223183
} else {
224-
console.warn(`⚠️ Logo path specified (${hugoConfig.logoPath}) but file not found in assets or static directory.`);
225184
absoluteLogoPath = '';
226185
}
186+
} else {
187+
absoluteLogoPath = '';
227188
}
228-
} else {
229-
console.warn(`⚠️ No logo path specified in params.toml.`);
230189
}
231-
190+
// --- END MODIFIED LOGO LOGIC ---
191+
232192
const logoDataUri = await getImageDataUri(absoluteLogoPath);
233193
if (!logoDataUri) {
234-
if (hugoConfig.logoPath && absoluteLogoPath) {
235-
console.warn(`⚠️ Logo data URI could not be generated. Attempted path: ${absoluteLogoPath}`);
236-
} else if (!hugoConfig.logoPath) {
237-
console.warn(`⚠️ No logo path in config, so no logo data URI generated.`);
238-
} else {
239-
console.warn(`⚠️ Logo path ${hugoConfig.logoPath} did not resolve to an existing file, no logo data URI generated.`);
240-
}
194+
console.error("❌ Could not generate a data URI for the logo. OG images will not have a logo.");
241195
}
242196

197+
243198
const outputData = {
244199
siteNameForDisplay: hugoConfig.siteName,
245200
logoDataUri: logoDataUri,
@@ -250,26 +205,23 @@ async function collectData() {
250205
// 1. Add Homepage Data
251206
console.log('🏠 Processing Homepage...');
252207
if (hugoConfig.siteName && hugoConfig.siteDescription) {
253-
const homepageOgDir = join(STATIC_DIR, 'images'); // OG images for homepage go to static/images
208+
const homepageOgDir = join(STATIC_DIR, 'images');
254209
await ensureDir(homepageOgDir);
255210
outputData.pages.push({
256211
type: 'homepage',
257212
title: hugoConfig.siteName,
258213
description: hugoConfig.siteDescription,
259-
outputPath: join(homepageOgDir, `og-image.${OUTPUT_FORMAT}`), // Consistent name for homepage OG
214+
outputPath: join(homepageOgDir, `og-image.${OUTPUT_FORMAT}`),
260215
tempHtmlPath: join(TMP_DIR, `homepage-temp-og.html`),
261-
pageSpecificLogoUri: null // Homepage uses the global logo
216+
pageSpecificLogoUri: null
262217
});
263218
debugLog('Added homepage data.');
264-
} else {
265-
console.warn('⚠️ Missing siteName or siteDescription for homepage OG image.');
266219
}
267220

268221
// 2. Process Content Pages
269222
console.log('📄 Processing content pages...');
270223
const markdownFiles = await findMarkdownFiles(CONTENT_ROOT_DIR);
271-
let processedCount = 0;
272-
let skippedCount = 0;
224+
let processedCount = 0, skippedCount = 0;
273225

274226
for (const mdFile of markdownFiles) {
275227
const pageDirectory = dirname(mdFile);
@@ -280,53 +232,39 @@ async function collectData() {
280232
const { title, description, isDraft, excludeSitemap, image: pageImage } = extractFrontMatter(mdContent);
281233

282234
if (isDraft || excludeSitemap || !title || !description) {
283-
debugLog(`Skipping ${relativeMdPath} (Draft: ${isDraft}, Exclude: ${excludeSitemap}, NoTitle: ${!title}, NoDesc: ${!description})`);
284235
skippedCount++;
285236
continue;
286237
}
287238

288239
let pageSpecificLogoUri = null;
289240
if (pageImage) {
290241
let imageFullPath = join(pageDirectory, pageImage); // Check in bundle first
291-
if (! (await pathExists(imageFullPath))) {
242+
if (!(await pathExists(imageFullPath))) {
292243
const staticImageCand = join(STATIC_DIR, pageImage.startsWith('/') ? pageImage.substring(1) : pageImage);
293-
const assetImageCand = join(ASSETS_DIR, pageImage.startsWith('/') ? pageImage.substring(1) : pageImage);
294-
if(await pathExists(staticImageCand)) {
244+
if (await pathExists(staticImageCand)) {
295245
imageFullPath = staticImageCand;
296-
debugLog(`Found page image in static: ${imageFullPath}`);
297-
} else if(await pathExists(assetImageCand)) {
298-
imageFullPath = assetImageCand;
299-
debugLog(`Found page image in assets: ${imageFullPath}`);
300246
} else {
301-
debugLog(`Page specific image ${pageImage} for ${relativeMdPath} not found in bundle, static, or assets. Will use global logo if available, or no logo.`);
302247
imageFullPath = null;
303248
}
304-
} else {
305-
debugLog(`Found page image in bundle: ${imageFullPath}`);
306249
}
307-
308-
if(imageFullPath) {
250+
if (imageFullPath) {
309251
pageSpecificLogoUri = await getImageDataUri(imageFullPath);
310-
if(pageSpecificLogoUri) debugLog(`Using page specific image for ${relativeMdPath}: ${pageImage}`);
311-
else debugLog(`Failed to get Data URI for page image: ${imageFullPath}`);
312252
}
313253
}
314254

315-
// MODIFICATION: Use parent directory name as the slug for OG image
316255
const parentDirName = basename(pageDirectory);
317-
const ogImageFilename = `${parentDirName}-og.${OUTPUT_FORMAT}`; // Use parentDirName as the slug
256+
const ogImageFilename = `${parentDirName}-og.${OUTPUT_FORMAT}`;
318257

319258
outputData.pages.push({
320259
type: 'content',
321260
sourceMdPath: mdFile,
322261
title: title,
323262
description: description,
324-
outputPath: join(pageDirectory, ogImageFilename), // Image saved in the page's bundle
325-
tempHtmlPath: join(TMP_DIR, `${parentDirName}-${Date.now()}-temp-og.html`), // Temp HTML uses parentDirName
263+
outputPath: join(pageDirectory, ogImageFilename),
264+
tempHtmlPath: join(TMP_DIR, `${parentDirName}-${Date.now()}-temp-og.html`),
326265
pageSpecificLogoUri: pageSpecificLogoUri
327266
});
328267
processedCount++;
329-
debugLog(`Added data for: ${relativeMdPath}, OG image: ${ogImageFilename} (slug from dir: ${parentDirName})`);
330268

331269
} catch (err) {
332270
console.error(`❌ Error processing ${relativeMdPath}: ${err.message}`);
@@ -336,17 +274,11 @@ async function collectData() {
336274

337275
// 3. Write JSON Output
338276
console.log(`💾 Writing data for ${outputData.pages.length} pages to ${OUTPUT_JSON_PATH}...`);
339-
try {
340-
await writeFile(OUTPUT_JSON_PATH, JSON.stringify(outputData, null, 2));
341-
console.log('✅ Data collection complete.');
342-
console.log(`📊 Processed ${processedCount} content pages, skipped ${skippedCount}.`);
343-
} catch (err) {
344-
console.error(`❌ Error writing JSON output: ${err.message}`);
345-
process.exit(1);
346-
}
277+
await writeFile(OUTPUT_JSON_PATH, JSON.stringify(outputData, null, 2));
278+
console.log('✅ Data collection complete.');
279+
console.log(`📊 Processed ${processedCount} content pages, skipped ${skippedCount}.`);
347280
}
348281

349-
// --- Execution ---
350282
(async () => {
351283
try {
352284
await collectData();

0 commit comments

Comments
 (0)