diff --git a/_config/date.js b/_config/date.js index 531f79c..6887f0e 100644 --- a/_config/date.js +++ b/_config/date.js @@ -1,31 +1,40 @@ const { DateTime } = require("luxon"); module.exports = function (eleventyConfig, { TIME_ZONE }) { - eleventyConfig.addDateParsing(function (dateValue) { - // i know this is a deranged solution. sorry LOL - let localDate; - try { - if (dateValue instanceof Date && !isNaN(dateValue)) { - // handle filename dates (ie 2025-10-18-post.md) - localDate = DateTime.fromJSDate(dateValue, { zone: "utc" }) - .setZone(TIME_ZONE) - .startOf("day"); // Set to midnight in America/Santiago - } else if (typeof dateValue === "string" && dateValue) { - // handle string dates (ie from front matter, if used) - localDate = DateTime.fromISO(dateValue, { zone: TIME_ZONE }).startOf("day"); - } else { - // handle invalid input - console.warn(`Invalid date value: ${dateValue} for ${this.page.inputPath}`); - localDate = DateTime.now().setZone(TIME_ZONE).startOf("day"); - } - if (!localDate || localDate.isValid === false) { - throw new Error(`Invalid date value (${dateValue}) for ${this.page.inputPath}: ${localDate?.invalidReason || "Unknown"}`); - } - return localDate.toJSDate(); - } catch (error) { - console.error(`Date parsing error for ${this.page.inputPath}:`, error.message); - // fallback to current date in TIME_ZONE - return DateTime.now().setZone(TIME_ZONE).startOf("day").toJSDate(); - } - }); + eleventyConfig.addDateParsing(function (dateValue) { + // i know this is a deranged solution. sorry LOL + let localDate; + try { + if (dateValue instanceof Date && !isNaN(dateValue)) { + // handle filename dates (ie 2025-10-18-post.md) + localDate = DateTime.fromJSDate(dateValue, { zone: "utc" }) + .setZone(TIME_ZONE) + .startOf("day"); // Set to midnight in America/Santiago + } else if (typeof dateValue === "string" && dateValue) { + // handle string dates (ie from front matter, if used) + localDate = DateTime.fromISO(dateValue, { zone: TIME_ZONE }).startOf( + "day", + ); + } else { + // handle invalid input + console.warn( + `Invalid date value: ${dateValue} for ${this.page.inputPath}`, + ); + localDate = DateTime.now().setZone(TIME_ZONE).startOf("day"); + } + if (!localDate || localDate.isValid === false) { + throw new Error( + `Invalid date value (${dateValue}) for ${this.page.inputPath}: ${localDate?.invalidReason || "Unknown"}`, + ); + } + return localDate.toJSDate(); + } catch (error) { + console.error( + `Date parsing error for ${this.page.inputPath}:`, + error.message, + ); + // fallback to current date in TIME_ZONE + return DateTime.now().setZone(TIME_ZONE).startOf("day").toJSDate(); + } + }); }; diff --git a/_config/filters.js b/_config/filters.js index da669b8..c738e1e 100644 --- a/_config/filters.js +++ b/_config/filters.js @@ -1,158 +1,230 @@ const { DateTime } = require("luxon"); module.exports = function (eleventyConfig, { TIME_ZONE, defaultLanguage }) { - // {{ post.date | date("dd/MM/yyyy") }} -> 18/10/2025 - eleventyConfig.addFilter("date", function (dateObj, format = "dd/MM/yyyy") { - let dt = dateObj; - // handle string dates - if (typeof dateObj === "string") { - dt = DateTime.fromISO(dateObj, { zone: TIME_ZONE }).toJSDate(); + // {{ post.date | date("dd/MM/yyyy") }} -> 18/10/2025 + eleventyConfig.addFilter("date", function (dateObj, format = "dd/MM/yyyy") { + let dt = dateObj; + // handle string dates + if (typeof dateObj === "string") { + dt = DateTime.fromISO(dateObj, { zone: TIME_ZONE }).toJSDate(); + } + // handle DateTime objects (from addDateParsing) + if (dateObj instanceof DateTime) { + dt = dateObj.toJSDate(); + } + // check dt as valid Date object + if (!(dt instanceof Date) || isNaN(dt)) { + console.log("Invalid date input:", dateObj); + return ""; + } + // format in TIME_ZONE + const formatted = DateTime.fromJSDate(dt, { zone: TIME_ZONE }).toFormat( + format, + ); + console.log( + "Date input:", + dt, + "Formatted:", + formatted, + "Timezone:", + TIME_ZONE, + ); + return formatted; + }); + + // filters collections by current language + eleventyConfig.addFilter("i18n_filter", function (collection, limit = null) { + const lang = this.page.lang; // access page.lang from context + let filtered = collection.filter((item) => item.data.lang === lang); + if (limit !== null) { + filtered = filtered.slice(0, limit); + } + return filtered; + }); + + // takes all collections and returns only the tags not matched + // key-objects so may repurpose under different name + eleventyConfig.addFilter( + "exclude_collections", + function (collections, ...keysToExclude) { + if (!collections || typeof collections !== "object") { + console.warn( + "[exclude_collections] Invalid collections input:", + collections, + ); + return collections; + } + + const result = {}; + Object.keys(collections).forEach((key) => { + if (!keysToExclude.includes(key)) { + result[key] = collections[key]; } - // handle DateTime objects (from addDateParsing) - if (dateObj instanceof DateTime) { - dt = dateObj.toJSDate(); + }); + + if ( + process.env.LOCALE_URL_DEBUG === "1" || + process.env.LOCALE_URL_DEBUG === "true" + ) { + console.warn("[excludeCollections] Excluded keys:", keysToExclude); + console.warn( + "[excludeCollections] Resulting keys:", + Object.keys(result), + ); + } + + return result; + }, + ); + + const LOCALE_URL_DEBUG = + process.env.LOCALE_URL_DEBUG === "1" || + process.env.LOCALE_URL_DEBUG === "true"; + + // locale_url replacement that uses pre-compile filesystem + eleventyConfig.addNunjucksFilter( + "locale_url_resolve", + function (targetUrl, desiredLocale) { + const ctx = this && this.ctx ? this.ctx : {}; + const collections = ctx.collections ? ctx.collections : {}; + const all = collections.all || []; + + if (!targetUrl || typeof targetUrl !== "string") return targetUrl; + if (!targetUrl.startsWith("/")) return targetUrl; // external or relative link -> leave as is + + // determine locale to resolve to + const pageLang = + desiredLocale || + (ctx.page && ctx.page.lang) || + ctx.locale || + defaultLanguage; + + const LOCALE_URL_DEBUG = + process.env.LOCALE_URL_DEBUG === "1" || + process.env.LOCALE_URL_DEBUG === "true"; + if (LOCALE_URL_DEBUG) { + console.warn( + `[locale_url_resolve] resolving targetUrl="${targetUrl}" desiredLocale="${desiredLocale}" pageLang="${pageLang}"`, + ); + } + + // special case for homepage + if (targetUrl === "/" || targetUrl === "/index/") { + if (pageLang === defaultLanguage) { + if (LOCALE_URL_DEBUG) + console.warn( + `[locale_url_resolve] homepage, default language (${defaultLanguage}) -> "/"`, + ); + return "/"; } - // check dt as valid Date object - if (!(dt instanceof Date) || isNaN(dt)) { - console.log("Invalid date input:", dateObj); - return ""; + const homepageUrl = `/${pageLang}/`; + if (LOCALE_URL_DEBUG) + console.warn( + `[locale_url_resolve] homepage, language (${pageLang}) -> "${homepageUrl}"`, + ); + return homepageUrl; + } + + // normalize targetUrl to include trailing slash for comparison + const normUrl = targetUrl.endsWith("/") ? targetUrl : `${targetUrl}/`; + + // try to find the canonical (default language) page corresponding to targetUrl + let canonical = all.find((p) => { + return ( + (p.url === normUrl || p.url === targetUrl) && + p.data && + p.data.lang === defaultLanguage + ); + }); + + // if not found, try to find any page with that url (maybe targetUrl already localized) + if (!canonical) { + canonical = all.find((p) => p.url === normUrl || p.url === targetUrl); + } + + if (LOCALE_URL_DEBUG) { + if (canonical) { + const cs = + canonical.page && canonical.page.filePathStem + ? canonical.page.filePathStem + : "(no stem)"; + const clang = + canonical.data && canonical.data.lang + ? canonical.data.lang + : "(no lang)"; + console.warn( + `[locale_url_resolve] canonical found: url="${canonical.url}" filePathStem="${cs}" lang="${clang}"`, + ); + } else { + console.warn( + `[locale_url_resolve] canonical NOT found for targetUrl="${targetUrl}". Will fallback to prefixed URL.`, + ); } - // format in TIME_ZONE - const formatted = DateTime.fromJSDate(dt, { zone: TIME_ZONE }) - .toFormat(format); - console.log("Date input:", dt, "Formatted:", formatted, "Timezone:", TIME_ZONE); - return formatted; - }); + } - // filters collections by current language - eleventyConfig.addFilter("i18n_filter", function (collection, limit = null) { - const lang = this.page.lang; // access page.lang from context - let filtered = collection.filter(item => item.data.lang === lang); - if (limit !== null) { - filtered = filtered.slice(0, limit); - } - return filtered; - }); + // if cannot find canonical page, fall back to a prefixed URL (best effort) + if (!canonical) { + const fallback = `/${pageLang}${targetUrl}`.replace(/\/{2,}/g, "/"); + if (LOCALE_URL_DEBUG) + console.warn(`[locale_url_resolve] fallback -> "${fallback}"`); + return fallback; + } - // takes all collections and returns only the tags not matched - // key-objects so may repurpose under different name - eleventyConfig.addFilter("exclude_collections", function (collections, ...keysToExclude) { - if (!collections || typeof collections !== "object") { - console.warn("[exclude_collections] Invalid collections input:", collections); - return collections; - } + // determine canonical filePathStem (the source input path without extension) + const canonicalLang = + canonical.data && canonical.data.lang + ? canonical.data.lang + : defaultLanguage; + const canonicalStem = + canonical.page && canonical.page.filePathStem + ? canonical.page.filePathStem + : ""; - const result = {}; - Object.keys(collections).forEach(key => { - if (!keysToExclude.includes(key)) { - result[key] = collections[key]; - } - }); + // remove the canonical lang prefix from the stem to create a "key" to match across locales. + // ie "/en/about" -> "/about", "/es/about" -> "/about" + const key = canonicalStem + .replace(new RegExp(`^/${canonicalLang}`), "") + .replace(/^\/+/, ""); - if (process.env.LOCALE_URL_DEBUG === "1" || process.env.LOCALE_URL_DEBUG === "true") { - console.warn("[excludeCollections] Excluded keys:", keysToExclude); - console.warn("[excludeCollections] Resulting keys:", Object.keys(result)); - } + if (LOCALE_URL_DEBUG) { + console.warn( + `[locale_url_resolve] canonicalLang="${canonicalLang}" canonicalStem="${canonicalStem}" key="${key}"`, + ); + } - return result; - }); + // find the localized page whose filePathStem ends with that key and whose lang matches pageLang. + const localized = all.find((p) => { + const pLang = p.data && p.data.lang; + const pStem = p.page && p.page.filePathStem ? p.page.filePathStem : ""; + // be defensive: ensure pLang exists + if (!pLang) return false; + return pLang === pageLang && pStem.endsWith(key); + }); - const LOCALE_URL_DEBUG = process.env.LOCALE_URL_DEBUG === "1" || process.env.LOCALE_URL_DEBUG === "true"; - - // locale_url replacement that uses pre-compile filesystem - eleventyConfig.addNunjucksFilter("locale_url_resolve", function (targetUrl, desiredLocale) { - const ctx = (this && this.ctx) ? this.ctx : {}; - const collections = (ctx.collections) ? ctx.collections : {}; - const all = collections.all || []; - - if (!targetUrl || typeof targetUrl !== "string") return targetUrl; - if (!targetUrl.startsWith("/")) return targetUrl; // external or relative link -> leave as is - - // determine locale to resolve to - const pageLang = desiredLocale || (ctx.page && ctx.page.lang) || ctx.locale || defaultLanguage; - - const LOCALE_URL_DEBUG = process.env.LOCALE_URL_DEBUG === "1" || process.env.LOCALE_URL_DEBUG === "true"; + if (localized && localized.url) { if (LOCALE_URL_DEBUG) { - console.warn(`[locale_url_resolve] resolving targetUrl="${targetUrl}" desiredLocale="${desiredLocale}" pageLang="${pageLang}"`); + const ls = + localized.page && localized.page.filePathStem + ? localized.page.filePathStem + : "(no stem)"; + console.warn( + `[locale_url_resolve] localized found: url="${localized.url}" filePathStem="${ls}" lang="${localized.data.lang}"`, + ); } + return localized.url; + } - // special case for homepage - if (targetUrl === "/" || targetUrl === "/index/") { - if (pageLang === defaultLanguage) { - if (LOCALE_URL_DEBUG) console.warn(`[locale_url_resolve] homepage, default language (${defaultLanguage}) -> "/"`); - return "/"; - } - const homepageUrl = `/${pageLang}/`; - if (LOCALE_URL_DEBUG) console.warn(`[locale_url_resolve] homepage, language (${pageLang}) -> "${homepageUrl}"`); - return homepageUrl; - } + // fallback to prefixed URL + const fallback2 = `/${pageLang}${targetUrl}`.replace(/\/{2,}/g, "/"); + if (LOCALE_URL_DEBUG) + console.warn( + `[locale_url_resolve] localized NOT found for key="${key}" — fallback -> "${fallback2}"`, + ); + return fallback2; + }, + ); - // normalize targetUrl to include trailing slash for comparison - const normUrl = targetUrl.endsWith("/") ? targetUrl : `${targetUrl}/`; - - // try to find the canonical (default language) page corresponding to targetUrl - let canonical = all.find(p => { - return (p.url === normUrl || p.url === targetUrl) && p.data && p.data.lang === defaultLanguage; - }); - - // if not found, try to find any page with that url (maybe targetUrl already localized) - if (!canonical) { - canonical = all.find(p => (p.url === normUrl || p.url === targetUrl)); - } - - if (LOCALE_URL_DEBUG) { - if (canonical) { - const cs = (canonical.page && canonical.page.filePathStem) ? canonical.page.filePathStem : "(no stem)"; - const clang = (canonical.data && canonical.data.lang) ? canonical.data.lang : "(no lang)"; - console.warn(`[locale_url_resolve] canonical found: url="${canonical.url}" filePathStem="${cs}" lang="${clang}"`); - } else { - console.warn(`[locale_url_resolve] canonical NOT found for targetUrl="${targetUrl}". Will fallback to prefixed URL.`); - } - } - - // if cannot find canonical page, fall back to a prefixed URL (best effort) - if (!canonical) { - const fallback = `/${pageLang}${targetUrl}`.replace(/\/{2,}/g, "/"); - if (LOCALE_URL_DEBUG) console.warn(`[locale_url_resolve] fallback -> "${fallback}"`); - return fallback; - } - - // determine canonical filePathStem (the source input path without extension) - const canonicalLang = canonical.data && canonical.data.lang ? canonical.data.lang : defaultLanguage; - const canonicalStem = (canonical.page && canonical.page.filePathStem) ? canonical.page.filePathStem : ""; - - // remove the canonical lang prefix from the stem to create a "key" to match across locales. - // ie "/en/about" -> "/about", "/es/about" -> "/about" - const key = canonicalStem.replace(new RegExp(`^/${canonicalLang}`), "").replace(/^\/+/, ""); - - if (LOCALE_URL_DEBUG) { - console.warn(`[locale_url_resolve] canonicalLang="${canonicalLang}" canonicalStem="${canonicalStem}" key="${key}"`); - } - - // find the localized page whose filePathStem ends with that key and whose lang matches pageLang. - const localized = all.find(p => { - const pLang = p.data && p.data.lang; - const pStem = (p.page && p.page.filePathStem) ? p.page.filePathStem : ""; - // be defensive: ensure pLang exists - if (!pLang) return false; - return pLang === pageLang && pStem.endsWith(key); - }); - - if (localized && localized.url) { - if (LOCALE_URL_DEBUG) { - const ls = (localized.page && localized.page.filePathStem) ? localized.page.filePathStem : "(no stem)"; - console.warn(`[locale_url_resolve] localized found: url="${localized.url}" filePathStem="${ls}" lang="${localized.data.lang}"`); - } - return localized.url; - } - - // fallback to prefixed URL - const fallback2 = `/${pageLang}${targetUrl}`.replace(/\/{2,}/g, "/"); - if (LOCALE_URL_DEBUG) console.warn(`[locale_url_resolve] localized NOT found for key="${key}" — fallback -> "${fallback2}"`); - return fallback2; - }); - - // turn on disabled nunjucks filters - eleventyConfig.addFilter("keys", obj => Object.keys(obj)); - eleventyConfig.addFilter("values", obj => Object.values(obj)); + // turn on disabled nunjucks filters + eleventyConfig.addFilter("keys", (obj) => Object.keys(obj)); + eleventyConfig.addFilter("values", (obj) => Object.values(obj)); }; diff --git a/_config/plugins.js b/_config/plugins.js index 53958bc..33e2a7c 100644 --- a/_config/plugins.js +++ b/_config/plugins.js @@ -6,26 +6,26 @@ const fs = require("fs"); const path = require("path"); module.exports = function (eleventyConfig, { defaultLanguage }) { - // load translations - const translationsToml = fs.readFileSync( - path.join(__dirname, "..", "_data", "locale.toml"), - "utf-8" - ); - const translations = toml.parse(translationsToml); + // load translations + const translationsToml = fs.readFileSync( + path.join(__dirname, "..", "_data", "locale.toml"), + "utf-8", + ); + const translations = toml.parse(translationsToml); - // plugins - eleventyConfig.addPlugin(eleventySass); - eleventyConfig.addPlugin(I18nPlugin, { - defaultLanguage, - errorMode: "allow-fallback", - }); - eleventyConfig.addPlugin(i18n, { - translations, - fallbackLocales: { - "*": "en", - } - }); + // plugins + eleventyConfig.addPlugin(eleventySass); + eleventyConfig.addPlugin(I18nPlugin, { + defaultLanguage, + errorMode: "allow-fallback", + }); + eleventyConfig.addPlugin(i18n, { + translations, + fallbackLocales: { + "*": "en", + }, + }); - // data extensions - eleventyConfig.addDataExtension("toml", (contents) => toml.parse(contents)); -}; \ No newline at end of file + // data extensions + eleventyConfig.addDataExtension("toml", (contents) => toml.parse(contents)); +}; diff --git a/_config/shortcodes.js b/_config/shortcodes.js index 9b849ac..bd33235 100644 --- a/_config/shortcodes.js +++ b/_config/shortcodes.js @@ -1,30 +1,33 @@ const seperator = { - start: '', - end: '', - total: '' + start: "", + end: "", + total: "", }; module.exports = function (eleventyConfig) { - // excerpt shortcode for feed layouts - // taken from https://github.com/brob/eleventy-plugin-blog-tools - eleventyConfig.addShortcode("excerpt", function (article) { - let excerpt = article.data.excerpt ? `

${article.data.excerpt}

` : ""; - const articleContent = article.templateContent; + // excerpt shortcode for feed layouts + // taken from https://github.com/brob/eleventy-plugin-blog-tools + eleventyConfig.addShortcode("excerpt", function (article) { + let excerpt = article.data.excerpt ? `

${article.data.excerpt}

` : ""; + const articleContent = article.templateContent; - let startPosition = articleContent.toLowerCase().indexOf(seperator.start); - let endPosition = articleContent.toLowerCase().indexOf(seperator.end); - let totalPosition = articleContent.toLowerCase().indexOf(seperator.total) + let startPosition = articleContent.toLowerCase().indexOf(seperator.start); + let endPosition = articleContent.toLowerCase().indexOf(seperator.end); + let totalPosition = articleContent.toLowerCase().indexOf(seperator.total); - if (totalPosition !== -1) { - excerpt = articleContent.substring(0, totalPosition); - } else if (startPosition !== -1 && endPosition !== -1) { - excerpt = articleContent.substring(startPosition + seperator.start.length, endPosition); - } else if (!article.data.excerpt) { - let startPosition = articleContent.toLowerCase().indexOf('

'); - let endPosition = articleContent.toLowerCase().indexOf('

'); + if (totalPosition !== -1) { + excerpt = articleContent.substring(0, totalPosition); + } else if (startPosition !== -1 && endPosition !== -1) { + excerpt = articleContent.substring( + startPosition + seperator.start.length, + endPosition, + ); + } else if (!article.data.excerpt) { + let startPosition = articleContent.toLowerCase().indexOf("

"); + let endPosition = articleContent.toLowerCase().indexOf("

"); - excerpt = articleContent.substring(startPosition + 3, endPosition); - } - return excerpt - }); -}; \ No newline at end of file + excerpt = articleContent.substring(startPosition + 3, endPosition); + } + return excerpt; + }); +}; diff --git a/eleventy.config.js b/eleventy.config.js index fa04a99..269abe0 100644 --- a/eleventy.config.js +++ b/eleventy.config.js @@ -8,31 +8,34 @@ const addPlugins = require("./_config/plugins"); const addShortcodes = require("./_config/shortcodes"); module.exports = function (eleventyConfig) { - let siteData; - const siteToml = fs.readFileSync( - path.join(__dirname, "_data", "site.toml"), - "utf-8" - ); - siteData = toml.parse(siteToml); + let siteData; + const siteToml = fs.readFileSync( + path.join(__dirname, "_data", "site.toml"), + "utf-8", + ); + siteData = toml.parse(siteToml); - eleventyConfig.addGlobalData("site", siteData); + eleventyConfig.addGlobalData("site", siteData); - eleventyConfig.setLayoutsDirectory("_layouts"); + eleventyConfig.setLayoutsDirectory("_layouts"); - eleventyConfig.addPassthroughCopy("img"); - eleventyConfig.addPassthroughCopy("css/fonts"); - eleventyConfig.addPassthroughCopy("js"); - eleventyConfig.addPassthroughCopy("LICENSE.txt"); - eleventyConfig.addPassthroughCopy("robots.txt"); - eleventyConfig.addPassthroughCopy("roms"); + eleventyConfig.addPassthroughCopy("img"); + eleventyConfig.addPassthroughCopy("css/fonts"); + eleventyConfig.addPassthroughCopy("js"); + eleventyConfig.addPassthroughCopy("LICENSE.txt"); + eleventyConfig.addPassthroughCopy("robots.txt"); + eleventyConfig.addPassthroughCopy("roms"); - addDateParsing(eleventyConfig, { TIME_ZONE: siteData.timezone }); - addFilters(eleventyConfig, { TIME_ZONE: siteData.timezone, defaultLanguage: siteData.default_language }); - addPlugins(eleventyConfig, { defaultLanguage: siteData.default_language }); - addShortcodes(eleventyConfig); + addDateParsing(eleventyConfig, { TIME_ZONE: siteData.timezone }); + addFilters(eleventyConfig, { + TIME_ZONE: siteData.timezone, + defaultLanguage: siteData.default_language, + }); + addPlugins(eleventyConfig, { defaultLanguage: siteData.default_language }); + addShortcodes(eleventyConfig); - return { - markdownTemplateEngine: "njk", - htmlTemplateEngine: "njk" - } + return { + markdownTemplateEngine: "njk", + htmlTemplateEngine: "njk", + }; }; diff --git a/en/blog/blog.11tydata.js b/en/blog/blog.11tydata.js index 5529a94..e329efc 100644 --- a/en/blog/blog.11tydata.js +++ b/en/blog/blog.11tydata.js @@ -1,30 +1,32 @@ module.exports = { - eleventyComputed: { - // TODO: handle titles as slugs instead of filenames - permalink: (data) => { - // get the file path stem ie "/en/blog/2025/2025-10-18-my-post" - let stem = data.page.filePathStem; + eleventyComputed: { + // TODO: handle titles as slugs instead of filenames + permalink: (data) => { + // get the file path stem ie "/en/blog/2025/2025-10-18-my-post" + let stem = data.page.filePathStem; - // strip the leading /en/ prefix - if (stem.startsWith("/en/")) { - stem = stem.replace(/^\/en/, ""); - } + // strip the leading /en/ prefix + if (stem.startsWith("/en/")) { + stem = stem.replace(/^\/en/, ""); + } - // for blog posts under /blog/[year]/[year-month-day]-blogpost - // extract the year and the blog post slug (remove date prefix) - const blogPostMatch = stem.match(/^\/blog\/(\d{4})\/\d{4}-\d{2}-\d{2}-(.+)$/); - if (blogPostMatch) { - const [, year, slug] = blogPostMatch; - return `/blog/${year}/${slug}/index.html`; // ie /blog/2025/my-post/index.html - } + // for blog posts under /blog/[year]/[year-month-day]-blogpost + // extract the year and the blog post slug (remove date prefix) + const blogPostMatch = stem.match( + /^\/blog\/(\d{4})\/\d{4}-\d{2}-\d{2}-(.+)$/, + ); + if (blogPostMatch) { + const [, year, slug] = blogPostMatch; + return `/blog/${year}/${slug}/index.html`; // ie /blog/2025/my-post/index.html + } - // fallback for index or other pages under /blog - if (stem.endsWith("/index")) { - return `${stem}.html`; // ie /blog/index.html - } + // fallback for index or other pages under /blog + if (stem.endsWith("/index")) { + return `${stem}.html`; // ie /blog/index.html + } - // default for non-index, non-blog-post pages - return `${stem}/index.html`; - } - } + // default for non-index, non-blog-post pages + return `${stem}/index.html`; + }, + }, }; diff --git a/en/en.11tydata.js b/en/en.11tydata.js index 5c4cce0..26a0c99 100644 --- a/en/en.11tydata.js +++ b/en/en.11tydata.js @@ -1,21 +1,21 @@ module.exports = { - lang: "en", - permalink: (data) => { - // data.page.filePathStem: e.g., "/en/index", "/en/blog/index", "/en/blog/test-post" - let stem = data.page.filePathStem; + lang: "en", + permalink: (data) => { + // data.page.filePathStem: e.g., "/en/index", "/en/blog/index", "/en/blog/test-post" + let stem = data.page.filePathStem; - // strip the leading /en/ prefix - if (stem.startsWith("/en/")) { - stem = stem.replace(/^\/en/, ""); - } - - // handle index files: If ends with /index, just use stem + /index.html → e.g., /blog/index.html - // this avoids appending extra /index.html if already ending in /index - if (stem.endsWith("/index")) { - return `${stem}.html`; // /blog/index.html - } - - // for non-index files: append /index.html for pretty URLs (e.g., /blog/test-post → /blog/test-post/index.html, URL /blog/test-post/) - return `${stem}/index.html`; + // strip the leading /en/ prefix + if (stem.startsWith("/en/")) { + stem = stem.replace(/^\/en/, ""); } -}; \ No newline at end of file + + // handle index files: If ends with /index, just use stem + /index.html → e.g., /blog/index.html + // this avoids appending extra /index.html if already ending in /index + if (stem.endsWith("/index")) { + return `${stem}.html`; // /blog/index.html + } + + // for non-index files: append /index.html for pretty URLs (e.g., /blog/test-post → /blog/test-post/index.html, URL /blog/test-post/) + return `${stem}/index.html`; + }, +}; diff --git a/es/blog/blog.11tydata.js b/es/blog/blog.11tydata.js index def8c5c..1fbf457 100644 --- a/es/blog/blog.11tydata.js +++ b/es/blog/blog.11tydata.js @@ -1,34 +1,36 @@ module.exports = { - eleventyComputed: { - permalink: function (data) { - // get the file path stem - let stem = data.page.filePathStem; + eleventyComputed: { + permalink: function (data) { + // get the file path stem + let stem = data.page.filePathStem; - // extract the year from the path - const yearMatch = stem.match(/^\/es\/blog\/(\d{4})\//); - if (yearMatch) { - const year = yearMatch[1]; + // extract the year from the path + const yearMatch = stem.match(/^\/es\/blog\/(\d{4})\//); + if (yearMatch) { + const year = yearMatch[1]; - // check for slug_override first - if (data.slug_override) { - return `/es/blog/${year}/${this.slugify(data.slug_override)}/index.html`; - } - - // handle blog posts with date prefix: /es/blog/[year]/[year-month-day]-slug - const blogPostMatch = stem.match(/^\/es\/blog\/(\d{4})\/\d{4}-\d{2}-\d{2}-(.+)$/); - if (blogPostMatch) { - const [, , slug] = blogPostMatch; - return `/es/blog/${year}/${this.slugify(slug)}/index.html`; - } - } - - // handle index pages or other non-blog-post pages - if (stem.endsWith("/index")) { - return `${stem}.html`; // ie /es/blog/index.html - } - - // default for other pages under /es/blog/ - return `${stem}/index.html`; // ie /es/other-page/index.html + // check for slug_override first + if (data.slug_override) { + return `/es/blog/${year}/${this.slugify(data.slug_override)}/index.html`; } - } -}; \ No newline at end of file + + // handle blog posts with date prefix: /es/blog/[year]/[year-month-day]-slug + const blogPostMatch = stem.match( + /^\/es\/blog\/(\d{4})\/\d{4}-\d{2}-\d{2}-(.+)$/, + ); + if (blogPostMatch) { + const [, , slug] = blogPostMatch; + return `/es/blog/${year}/${this.slugify(slug)}/index.html`; + } + } + + // handle index pages or other non-blog-post pages + if (stem.endsWith("/index")) { + return `${stem}.html`; // ie /es/blog/index.html + } + + // default for other pages under /es/blog/ + return `${stem}/index.html`; // ie /es/other-page/index.html + }, + }, +}; diff --git a/es/es.11tydata.js b/es/es.11tydata.js index 6918647..20eb03b 100644 --- a/es/es.11tydata.js +++ b/es/es.11tydata.js @@ -1,19 +1,19 @@ module.exports = { - lang: 'es', - permalink: function (data) { - let stem = data.page.filePathStem; + lang: "es", + permalink: function (data) { + let stem = data.page.filePathStem; - // handle slug_override - if (data.slug_override) { - return `/${data.lang}/${this.slugify(data.slug_override)}/`; - } - - // handle index pages - if (stem.endsWith("/index")) { - return `${stem}.html`; // e.g., /es/index.html - } - - // default for other pages - return `${stem}/index.html`; // e.g., /es/about/index.html + // handle slug_override + if (data.slug_override) { + return `/${data.lang}/${this.slugify(data.slug_override)}/`; } -}; \ No newline at end of file + + // handle index pages + if (stem.endsWith("/index")) { + return `${stem}.html`; // e.g., /es/index.html + } + + // default for other pages + return `${stem}/index.html`; // e.g., /es/about/index.html + }, +}; diff --git a/js/lastfm.js b/js/lastfm.js index 28eb904..55d5a03 100644 --- a/js/lastfm.js +++ b/js/lastfm.js @@ -1,42 +1,44 @@ // this script is under the MIT license (https://max.nekoweb.org/resources/license.txt) - + const USERNAME = "kaaisudev"; // Put your LastFM username here const BASE_URL = `https://lastfm-last-played.biancarosa.com.br/${USERNAME}/latest-song`; const getTrack = async () => { - const request = await fetch(BASE_URL); - const json = await request.json(); - let status + const request = await fetch(BASE_URL); + const json = await request.json(); + let status; - let isPlaying = json.track['@attr']?.nowplaying || false; + let isPlaying = json.track["@attr"]?.nowplaying || false; - if(!isPlaying) { - // Trigger if a song isn't playing - return; - } else { - // Trigger if a song is playing - } + if (!isPlaying) { + // Trigger if a song isn't playing + return; + } else { + // Trigger if a song is playing + } - // Values: - // COVER IMAGE: json.track.image[1]['#text'] - // TITLE: json.track.name - // ARTIST: json.track.artist['#text'] + // Values: + // COVER IMAGE: json.track.image[1]['#text'] + // TITLE: json.track.name + // ARTIST: json.track.artist['#text'] - document.getElementById("listening").innerHTML = ` + document.getElementById("listening").innerHTML = `
- +

${json.track.name}

-

by ${json.track.artist['#text']}

+

by ${json.track.artist["#text"]}

- ` + `; }; getTrack(); -setInterval(() => { getTrack(); }, 10000); +setInterval(() => { + getTrack(); +}, 10000);