update formatting of all js files
This commit is contained in:
parent
81412117d8
commit
96630677ca
10 changed files with 435 additions and 342 deletions
|
|
@ -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();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
};
|
||||
// data extensions
|
||||
eleventyConfig.addDataExtension("toml", (contents) => toml.parse(contents));
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,30 +1,33 @@
|
|||
const seperator = {
|
||||
start: '<!-- excerpt start -->',
|
||||
end: '<!-- excerpt end -->',
|
||||
total: '<!-- excerpt -->'
|
||||
start: "<!-- excerpt start -->",
|
||||
end: "<!-- excerpt end -->",
|
||||
total: "<!-- excerpt -->",
|
||||
};
|
||||
|
||||
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 ? `<p>${article.data.excerpt}</p>` : "";
|
||||
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 ? `<p>${article.data.excerpt}</p>` : "";
|
||||
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('<p>');
|
||||
let endPosition = articleContent.toLowerCase().indexOf('</p>');
|
||||
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("<p>");
|
||||
let endPosition = articleContent.toLowerCase().indexOf("</p>");
|
||||
|
||||
excerpt = articleContent.substring(startPosition + 3, endPosition);
|
||||
}
|
||||
return excerpt
|
||||
});
|
||||
};
|
||||
excerpt = articleContent.substring(startPosition + 3, endPosition);
|
||||
}
|
||||
return excerpt;
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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`;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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/, "");
|
||||
}
|
||||
};
|
||||
|
||||
// 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`;
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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`;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 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
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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)}/`;
|
||||
}
|
||||
};
|
||||
|
||||
// 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
|
||||
},
|
||||
};
|
||||
|
|
|
|||
42
js/lastfm.js
42
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 = `
|
||||
<div class="now-playing-wrapper box">
|
||||
<!--<h2>listening to:</h2>-->
|
||||
<a href="https://fm.yuki.k4w411.net/" target="_blank">
|
||||
<div id="trackInfo">
|
||||
<img src="${json.track.image[1]['#text']}">
|
||||
<img src="${json.track.image[1]["#text"]}">
|
||||
<div id="trackInfoText">
|
||||
<h3 id="trackName">${json.track.name}</h3>
|
||||
<p id="artistName">by ${json.track.artist['#text']}</p>
|
||||
<p id="artistName">by ${json.track.artist["#text"]}</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
`
|
||||
`;
|
||||
};
|
||||
|
||||
getTrack();
|
||||
setInterval(() => { getTrack(); }, 10000);
|
||||
setInterval(() => {
|
||||
getTrack();
|
||||
}, 10000);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue