feat: initial commit
This commit is contained in:
commit
e214116e40
253 changed files with 17406 additions and 0 deletions
41
config/collections/index.js
Normal file
41
config/collections/index.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
import ics from "ics";
|
||||
|
||||
export const albumReleasesCalendar = (collection) => {
|
||||
const collectionData = collection.getAll()[0];
|
||||
const { data } = collectionData;
|
||||
const { albumReleases: { all }, globals: { url } } = data;
|
||||
|
||||
if (!all || all.length === 0) return "";
|
||||
|
||||
const events = all
|
||||
.map((album) => {
|
||||
const date = new Date(album.release_date);
|
||||
|
||||
if (isNaN(date.getTime())) return null;
|
||||
|
||||
const albumUrl = album.url?.includes("http") ? album.url : `${url}${album.url}`;
|
||||
const artistUrl = album.artist.url?.includes("http") ? album.artust.url : `${url}${album.artist.url}`;
|
||||
|
||||
return {
|
||||
start: [date.getFullYear(), date.getMonth() + 1, date.getDate()],
|
||||
startInputType: "local",
|
||||
startOutputType: "local",
|
||||
title: `Release: ${album.artist.name} - ${album.title}`,
|
||||
description: `Check out this new album release: ${albumUrl}. Read more about ${album.artist.name} at ${artistUrl}`,
|
||||
url: albumUrl,
|
||||
uid: `${album.release_timestamp}-${album.artist.name}-${album.title}`,
|
||||
};
|
||||
})
|
||||
.filter((event) => event !== null);
|
||||
|
||||
const { error, value } = ics.createEvents(events, {
|
||||
calName: "Album releases calendar • coryd.dev",
|
||||
});
|
||||
|
||||
if (error) {
|
||||
console.error("Error creating events: ", error);
|
||||
return "";
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
31
config/events/minify-js.js
Normal file
31
config/events/minify-js.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { minify } from "terser";
|
||||
|
||||
export const minifyJsComponents = async () => {
|
||||
const scriptsDir = "dist/assets/scripts";
|
||||
|
||||
const minifyJsFilesInDir = async (dir) => {
|
||||
const files = fs.readdirSync(dir);
|
||||
for (const fileName of files) {
|
||||
const filePath = path.join(dir, fileName);
|
||||
const stat = fs.statSync(filePath);
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
await minifyJsFilesInDir(filePath);
|
||||
} else if (fileName.endsWith(".js")) {
|
||||
const fileContent = fs.readFileSync(filePath, "utf8");
|
||||
const minified = await minify(fileContent);
|
||||
if (minified.error) {
|
||||
console.error(`Error minifying ${filePath}:`, minified.error);
|
||||
} else {
|
||||
fs.writeFileSync(filePath, minified.code);
|
||||
}
|
||||
} else {
|
||||
console.log(`No .js files to minify in ${filePath}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
await minifyJsFilesInDir(scriptsDir);
|
||||
};
|
21
config/filters/dates.js
Normal file
21
config/filters/dates.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
export default {
|
||||
stringToRFC822Date: (dateString) => {
|
||||
const date = new Date(dateString);
|
||||
|
||||
if (isNaN(date.getTime())) return "";
|
||||
|
||||
const options = {
|
||||
timeZone: "America/Los_Angeles",
|
||||
weekday: "short",
|
||||
day: "2-digit",
|
||||
month: "short",
|
||||
year: "numeric",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
timeZoneName: "short",
|
||||
};
|
||||
|
||||
return new Intl.DateTimeFormat("en-US", options).format(date);
|
||||
},
|
||||
};
|
28
config/filters/feeds.js
Normal file
28
config/filters/feeds.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { JSDOM } from "jsdom";
|
||||
|
||||
export default {
|
||||
convertRelativeLinks: (htmlContent, domain) => {
|
||||
if (!htmlContent || !domain) return htmlContent;
|
||||
|
||||
const dom = new JSDOM(htmlContent);
|
||||
const document = dom.window.document;
|
||||
|
||||
document.querySelectorAll("a[href]").forEach(link => {
|
||||
let href = link.getAttribute("href");
|
||||
|
||||
if (href.startsWith("#")) {
|
||||
link.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!href.startsWith("http://") && !href.startsWith("https://"))
|
||||
link.setAttribute("href", `${domain.replace(/\/$/, '')}/${href.replace(/^\/+/, '')}`);
|
||||
});
|
||||
|
||||
return document.body.innerHTML;
|
||||
},
|
||||
generatePermalink: (url, baseUrl) => {
|
||||
if (url?.includes("http") || !baseUrl) return url
|
||||
return `${baseUrl}${url}`
|
||||
}
|
||||
}
|
24
config/filters/general.js
Normal file
24
config/filters/general.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
import truncateHtml from "truncate-html";
|
||||
import { shuffleArray } from "../utilities/index.js";
|
||||
|
||||
export default {
|
||||
encodeAmp: (string) => {
|
||||
if (!string) return;
|
||||
const pattern = /&(?!(?:[a-zA-Z]+|#[0-9]+|#x[0-9a-fA-F]+);)/g;
|
||||
const replacement = "&";
|
||||
return string.replace(pattern, replacement);
|
||||
},
|
||||
replaceQuotes: (string) => string.replace(/"/g, """),
|
||||
htmlTruncate: (content, limit = 50) =>
|
||||
truncateHtml(content, limit, {
|
||||
byWords: true,
|
||||
ellipsis: "...",
|
||||
}),
|
||||
shuffleArray,
|
||||
pluralize: (count, string, trailing) => {
|
||||
const countStr = String(count).replace(/,/g, "");
|
||||
if (parseInt(countStr, 10) === 1) return string;
|
||||
return `${string}s${trailing ? `${trailing}` : ''}`;
|
||||
},
|
||||
jsonEscape: (string) => JSON.stringify(string),
|
||||
};
|
13
config/filters/index.js
Normal file
13
config/filters/index.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
import dates from "./dates.js";
|
||||
import feeds from "./feeds.js"
|
||||
import general from "./general.js";
|
||||
import media from "./media.js";
|
||||
import navigation from "./navigation.js";
|
||||
|
||||
export default {
|
||||
...dates,
|
||||
...feeds,
|
||||
...general,
|
||||
...media,
|
||||
...navigation,
|
||||
};
|
43
config/filters/media.js
Normal file
43
config/filters/media.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
export default {
|
||||
filterBooksByStatus: (books, status) =>
|
||||
books.filter((book) => book.status === status),
|
||||
findFavoriteBooks: (books) =>
|
||||
books.filter((book) => book.favorite === true),
|
||||
bookYearLinks: (years) =>
|
||||
years
|
||||
.sort((a, b) => b.value - a.value)
|
||||
.map(
|
||||
(year, index) =>
|
||||
`<a href="/books/years/${year.value}">${year.value}</a>${
|
||||
index < years.length - 1 ? " • " : ""
|
||||
}`
|
||||
)
|
||||
.join(""),
|
||||
mediaLinks: (data, type, count = 10) => {
|
||||
if (!data || !type) return "";
|
||||
|
||||
const dataSlice = data.slice(0, count);
|
||||
if (dataSlice.length === 0) return null;
|
||||
|
||||
const buildLink = (item) => {
|
||||
switch (type) {
|
||||
case "genre":
|
||||
return `<a href="${item.genre_url}">${item.genre_name}</a>`;
|
||||
case "artist":
|
||||
return `<a href="${item.url}">${item.name}</a>`;
|
||||
case "book":
|
||||
return `<a href="${item.url}">${item.title}</a>`;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
if (dataSlice.length === 1) return buildLink(dataSlice[0]);
|
||||
|
||||
const links = dataSlice.map(buildLink);
|
||||
const allButLast = links.slice(0, -1).join(", ");
|
||||
const last = links[links.length - 1];
|
||||
|
||||
return `${allButLast} and ${last}`;
|
||||
},
|
||||
};
|
5
config/filters/navigation.js
Normal file
5
config/filters/navigation.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
export default {
|
||||
isLinkActive: (category, page) =>
|
||||
page.includes(category) &&
|
||||
page.split("/").filter((a) => a !== "").length <= 1,
|
||||
};
|
33
config/plugins/css-config.js
Normal file
33
config/plugins/css-config.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import postcss from "postcss";
|
||||
import postcssImport from "postcss-import";
|
||||
import postcssImportExtGlob from "postcss-import-ext-glob";
|
||||
import autoprefixer from "autoprefixer";
|
||||
import cssnano from "cssnano";
|
||||
|
||||
export const cssConfig = (eleventyConfig) => {
|
||||
eleventyConfig.addTemplateFormats("css");
|
||||
eleventyConfig.addExtension("css", {
|
||||
outputFileExtension: "css",
|
||||
compile: async (inputContent, inputPath) => {
|
||||
const outputPath = "dist/assets/css/index.css";
|
||||
|
||||
if (inputPath.endsWith("index.css")) {
|
||||
return async () => {
|
||||
let result = await postcss([
|
||||
postcssImportExtGlob,
|
||||
postcssImport,
|
||||
autoprefixer,
|
||||
cssnano,
|
||||
]).process(inputContent, { from: inputPath });
|
||||
|
||||
await fs.mkdir(path.dirname(outputPath), { recursive: true });
|
||||
await fs.writeFile(outputPath, result.css);
|
||||
|
||||
return result.css;
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
4
config/plugins/index.js
Normal file
4
config/plugins/index.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
import { cssConfig } from "./css-config.js";
|
||||
import { markdownLib } from "./markdown.js";
|
||||
|
||||
export default { cssConfig, markdownLib };
|
25
config/plugins/markdown.js
Normal file
25
config/plugins/markdown.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
import markdownIt from "markdown-it";
|
||||
import markdownItAnchor from "markdown-it-anchor";
|
||||
import markdownItFootnote from "markdown-it-footnote";
|
||||
import markdownItLinkAttributes from "markdown-it-link-attributes";
|
||||
import markdownItPrism from "markdown-it-prism";
|
||||
|
||||
export const markdownLib = markdownIt({ html: true, linkify: true })
|
||||
.use(markdownItAnchor, {
|
||||
level: [1, 2],
|
||||
permalink: markdownItAnchor.permalink.headerLink({
|
||||
safariReaderFix: true,
|
||||
}),
|
||||
})
|
||||
.use(markdownItLinkAttributes, [
|
||||
{
|
||||
matcher(href) {
|
||||
return href.match(/^https?:\/\//);
|
||||
},
|
||||
attrs: {
|
||||
rel: "noopener",
|
||||
},
|
||||
},
|
||||
])
|
||||
.use(markdownItFootnote)
|
||||
.use(markdownItPrism);
|
10
config/utilities/index.js
Normal file
10
config/utilities/index.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
export const shuffleArray = (array) => {
|
||||
const shuffled = [...array];
|
||||
for (let i = shuffled.length - 1; i > 0; i--) {
|
||||
let j = Math.floor(Math.random() * (i + 1));
|
||||
let temp = shuffled[i];
|
||||
shuffled[i] = shuffled[j];
|
||||
shuffled[j] = temp;
|
||||
}
|
||||
return shuffled;
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue