chore: normalize formatting

This commit is contained in:
Cory Dransfeldt 2024-10-19 19:50:10 -07:00
parent 01ed2ac3b3
commit 2f6cfbe7ae
No known key found for this signature in database
61 changed files with 921 additions and 743 deletions

View file

@ -1,37 +1,45 @@
import { DateTime } from 'luxon' import { DateTime } from "luxon";
import ics from 'ics' import ics from "ics";
export const albumReleasesCalendar = (collection) => { export const albumReleasesCalendar = (collection) => {
const collectionData = collection.getAll()[0] const collectionData = collection.getAll()[0];
const { data } = collectionData const { data } = collectionData;
const { albumReleases: { all } } = data const {
if (!all || all.length === 0) return '' albumReleases: { all },
} = data;
if (!all || all.length === 0) return "";
const events = all.map(album => { const events = all
const date = DateTime.fromISO(album['release_date']) .map((album) => {
if (!date.isValid) return null const date = DateTime.fromISO(album["release_date"]);
if (!date.isValid) return null;
return { return {
start: [date.year, date.month, date.day], start: [date.year, date.month, date.day],
startInputType: 'local', startInputType: "local",
startOutputType: 'local', startOutputType: "local",
title: `Release: ${album['artist']['name']} - ${album['title']}`, title: `Release: ${album["artist"]["name"]} - ${album["title"]}`,
description: `Check out this new album release: ${album['url']}. Read more about ${album['artist']['name']} at https://coryd.dev${album['artist']['url']}`, description: `Check out this new album release: ${album["url"]}. Read more about ${album["artist"]["name"]} at https://coryd.dev${album["artist"]["url"]}`,
url: album['url'], url: album["url"],
uid: `${date.toFormat('yyyyMMdd')}-${album['artist']['name']}-${album['title']}@coryd.dev`, uid: `${date.toFormat("yyyyMMdd")}-${album["artist"]["name"]}-${
timestamp: DateTime.now().toUTC().toFormat("yyyyMMdd'T'HHmmss'Z'") album["title"]
} }@coryd.dev`,
}).filter(event => event !== null) timestamp: DateTime.now().toUTC().toFormat("yyyyMMdd'T'HHmmss'Z'"),
};
})
.filter((event) => event !== null);
const { error, value } = ics.createEvents(events, { calName: 'Album releases calendar / coryd.dev' }) const { error, value } = ics.createEvents(events, {
calName: "Album releases calendar / coryd.dev",
});
if (error) { if (error) {
console.error('Error creating events: ', error) console.error("Error creating events: ", error);
events.forEach((event, index) => { events.forEach((event, index) => {
console.error(`Event ${index}:`, event) console.error(`Event ${index}:`, event);
}) });
return '' return "";
} }
return value return value;
} };

View file

@ -1,59 +1,75 @@
import fs from 'fs' import fs from "fs";
import path from 'path' import path from "path";
import { minify } from 'terser' import { minify } from "terser";
const errorPages = ['404', '500', '1000', 'broken', 'error', 'js-challenge', 'not-allowed', 'rate-limit'] const errorPages = [
"404",
"500",
"1000",
"broken",
"error",
"js-challenge",
"not-allowed",
"rate-limit",
];
export const copyErrorPages = () => { export const copyErrorPages = () => {
errorPages.forEach((errorPage) => { errorPages.forEach((errorPage) => {
const sourcePath = path.join('_site', errorPage, 'index.html') const sourcePath = path.join("_site", errorPage, "index.html");
const destinationPath = path.join('_site', `${errorPage}.html`) const destinationPath = path.join("_site", `${errorPage}.html`);
const directoryPath = path.join('_site', errorPage) const directoryPath = path.join("_site", errorPage);
fs.copyFile(sourcePath, destinationPath, (err) => { fs.copyFile(sourcePath, destinationPath, (err) => {
if (err) { if (err) {
console.error(`Error copying ${errorPage} page:`, err) console.error(`Error copying ${errorPage} page:`, err);
return return;
} }
fs.unlink(sourcePath, (unlinkErr) => { fs.unlink(sourcePath, (unlinkErr) => {
if (unlinkErr) { if (unlinkErr) {
console.error(`Error deleting source file for ${errorPage} page:`, unlinkErr) console.error(
return `Error deleting source file for ${errorPage} page:`,
unlinkErr
);
return;
} }
fs.rmdir(directoryPath, (rmdirErr) => { fs.rmdir(directoryPath, (rmdirErr) => {
if (rmdirErr) console.error(`Error removing directory for ${errorPage} page:`, rmdirErr) if (rmdirErr)
}) console.error(
}) `Error removing directory for ${errorPage} page:`,
}) rmdirErr
}) );
} });
});
});
});
};
export const minifyJsComponents = async () => { export const minifyJsComponents = async () => {
const scriptsDir = '_site/assets/scripts' const scriptsDir = "_site/assets/scripts";
const minifyJsFilesInDir = async (dir) => { const minifyJsFilesInDir = async (dir) => {
const files = fs.readdirSync(dir) const files = fs.readdirSync(dir);
for (const fileName of files) { for (const fileName of files) {
const filePath = path.join(dir, fileName) const filePath = path.join(dir, fileName);
const stat = fs.statSync(filePath) const stat = fs.statSync(filePath);
if (stat.isDirectory()) { if (stat.isDirectory()) {
await minifyJsFilesInDir(filePath) await minifyJsFilesInDir(filePath);
} else if (fileName.endsWith('.js')) { } else if (fileName.endsWith(".js")) {
const fileContent = fs.readFileSync(filePath, 'utf8') const fileContent = fs.readFileSync(filePath, "utf8");
const minified = await minify(fileContent) const minified = await minify(fileContent);
if (minified.error) { if (minified.error) {
console.error(`Error minifying ${filePath}:`, minified.error) console.error(`Error minifying ${filePath}:`, minified.error);
} else { } else {
fs.writeFileSync(filePath, minified.code) fs.writeFileSync(filePath, minified.code);
} }
} else { } else {
console.log(`No .js files to minify in ${filePath}`) console.log(`No .js files to minify in ${filePath}`);
}
} }
} }
};
await minifyJsFilesInDir(scriptsDir) await minifyJsFilesInDir(scriptsDir);
} };

View file

@ -1,26 +1,26 @@
export default { export default {
stringToRFC822Date: (dateString) => { stringToRFC822Date: (dateString) => {
const date = new Date(dateString) const date = new Date(dateString);
if (isNaN(date)) return '' if (isNaN(date)) return "";
const options = { const options = {
weekday: 'short', weekday: "short",
day: '2-digit', day: "2-digit",
month: 'short', month: "short",
year: 'numeric', year: "numeric",
hour: '2-digit', hour: "2-digit",
minute: '2-digit', minute: "2-digit",
second: '2-digit', second: "2-digit",
timeZoneName: 'short' timeZoneName: "short",
} };
const formatter = new Intl.DateTimeFormat('en-GB', options) const formatter = new Intl.DateTimeFormat("en-GB", options);
return formatter.format(date).replace(',', '') return formatter.format(date).replace(",", "");
}, },
stringToRFC3339: (dateString) => { stringToRFC3339: (dateString) => {
const date = new Date(dateString) const date = new Date(dateString);
return isNaN(date) ? '' : date.toISOString() return isNaN(date) ? "" : date.toISOString();
} },
} };

View file

@ -1,18 +1,19 @@
import truncateHtml from 'truncate-html' import truncateHtml from "truncate-html";
import { shuffleArray } from '../utilities/index.js' import { shuffleArray } from "../utilities/index.js";
export default { export default {
encodeAmp: (string) => { encodeAmp: (string) => {
if (!string) return if (!string) return;
const pattern = /&(?!(?:[a-zA-Z]+|#[0-9]+|#x[0-9a-fA-F]+);)/g const pattern = /&(?!(?:[a-zA-Z]+|#[0-9]+|#x[0-9a-fA-F]+);)/g;
const replacement = '&' const replacement = "&";
return string.replace(pattern, replacement) return string.replace(pattern, replacement);
}, },
replaceQuotes: (string) => string.replace(/"/g, '"'), replaceQuotes: (string) => string.replace(/"/g, """),
formatNumber: (number) => number.toLocaleString('en-US'), formatNumber: (number) => number.toLocaleString("en-US"),
htmlTruncate: (content, limit = 50) => truncateHtml(content, limit, { htmlTruncate: (content, limit = 50) =>
truncateHtml(content, limit, {
byWords: true, byWords: true,
ellipsis: '...' ellipsis: "...",
}), }),
shuffleArray, shuffleArray,
} };

View file

@ -1,11 +1,11 @@
import dates from './dates.js' import dates from "./dates.js";
import general from './general.js' import general from "./general.js";
import media from './media.js' import media from "./media.js";
import navigation from './navigation.js' import navigation from "./navigation.js";
export default { export default {
...dates, ...dates,
...general, ...general,
...media, ...media,
...navigation, ...navigation,
} };

View file

@ -1,35 +1,43 @@
export default { export default {
filterBooksByStatus: (books, status) => books.filter(book => book['status'] === status), filterBooksByStatus: (books, status) =>
findFavoriteBooks: (books) => books.filter(book => book['favorite'] === true), books.filter((book) => book["status"] === status),
bookYearLinks: (years) => years findFavoriteBooks: (books) =>
.sort((a, b) => b['value'] - a['value']) books.filter((book) => book["favorite"] === true),
.map((year, index) => `<a href="/books/years/${year['value']}">${year['value']}</a>${index < years.length - 1 ? ' / ' : ''}`) bookYearLinks: (years) =>
.join(''), 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) => { mediaLinks: (data, type, count = 10) => {
if (!data || !type) return '' if (!data || !type) return "";
const dataSlice = data.slice(0, count) const dataSlice = data.slice(0, count);
if (dataSlice.length === 0) return null if (dataSlice.length === 0) return null;
const buildLink = (item) => { const buildLink = (item) => {
switch (type) { switch (type) {
case 'genre': case "genre":
return `<a href="${item['genre_url']}">${item['genre_name']}</a>` return `<a href="${item["genre_url"]}">${item["genre_name"]}</a>`;
case 'artist': case "artist":
return `<a href="${item['url']}">${item['name']}</a>` return `<a href="${item["url"]}">${item["name"]}</a>`;
case 'book': case "book":
return `<a href="${item['url']}">${item['title']}</a>` return `<a href="${item["url"]}">${item["title"]}</a>`;
default: default:
return '' return "";
}
} }
};
if (dataSlice.length === 1) return buildLink(dataSlice[0]) if (dataSlice.length === 1) return buildLink(dataSlice[0]);
const links = dataSlice.map(buildLink) const links = dataSlice.map(buildLink);
const allButLast = links.slice(0, -1).join(', ') const allButLast = links.slice(0, -1).join(", ");
const last = links[links.length - 1] const last = links[links.length - 1];
return `${allButLast} and ${last}` return `${allButLast} and ${last}`;
} },
} };

View file

@ -1,3 +1,5 @@
export default { export default {
isLinkActive: (category, page) => page.includes(category) && page.split('/').filter(a => a !== '').length <= 1 isLinkActive: (category, page) =>
} page.includes(category) &&
page.split("/").filter((a) => a !== "").length <= 1,
};

View file

@ -1,33 +1,33 @@
import fs from 'node:fs/promises' import fs from "node:fs/promises";
import path from 'node:path' import path from "node:path";
import postcss from 'postcss' import postcss from "postcss";
import postcssImport from 'postcss-import' import postcssImport from "postcss-import";
import postcssImportExtGlob from 'postcss-import-ext-glob' import postcssImportExtGlob from "postcss-import-ext-glob";
import autoprefixer from 'autoprefixer' import autoprefixer from "autoprefixer";
import cssnano from 'cssnano' import cssnano from "cssnano";
export const cssConfig = (eleventyConfig) => { export const cssConfig = (eleventyConfig) => {
eleventyConfig.addTemplateFormats('css') eleventyConfig.addTemplateFormats("css");
eleventyConfig.addExtension('css', { eleventyConfig.addExtension("css", {
outputFileExtension: 'css', outputFileExtension: "css",
compile: async (inputContent, inputPath) => { compile: async (inputContent, inputPath) => {
const outputPath = '_site/assets/css/index.css' const outputPath = "_site/assets/css/index.css";
if (inputPath.endsWith('index.css')) { if (inputPath.endsWith("index.css")) {
return async () => { return async () => {
let result = await postcss([ let result = await postcss([
postcssImportExtGlob, postcssImportExtGlob,
postcssImport, postcssImport,
autoprefixer, autoprefixer,
cssnano, cssnano,
]).process(inputContent, { from: inputPath }) ]).process(inputContent, { from: inputPath });
await fs.mkdir(path.dirname(outputPath), { recursive: true }) await fs.mkdir(path.dirname(outputPath), { recursive: true });
await fs.writeFile(outputPath, result.css) await fs.writeFile(outputPath, result.css);
return result.css return result.css;
} };
} }
}, },
}) });
} };

View file

@ -1,27 +1,28 @@
export const shuffleArray = array => { export const shuffleArray = (array) => {
const shuffled = [...array] const shuffled = [...array];
for (let i = shuffled.length - 1; i > 0; i--) { for (let i = shuffled.length - 1; i > 0; i--) {
let j = Math.floor(Math.random() * (i + 1)) let j = Math.floor(Math.random() * (i + 1));
let temp = shuffled[i] let temp = shuffled[i];
shuffled[i] = shuffled[j] shuffled[i] = shuffled[j];
shuffled[j] = temp shuffled[j] = temp;
} }
return shuffled return shuffled;
} };
export const regionNames = new Intl.DisplayNames(['en'], { type: 'region' }) export const regionNames = new Intl.DisplayNames(["en"], { type: "region" });
export const getCountryName = (countryCode) => regionNames.of(countryCode.trim()) || countryCode.trim() export const getCountryName = (countryCode) =>
regionNames.of(countryCode.trim()) || countryCode.trim();
export const parseCountryField = (countryField) => { export const parseCountryField = (countryField) => {
if (!countryField) return null if (!countryField) return null;
const delimiters = [',', '/', '&', 'and'] const delimiters = [",", "/", "&", "and"];
let countries = [countryField] let countries = [countryField];
delimiters.forEach(delimiter => { delimiters.forEach((delimiter) => {
countries = countries.flatMap(country => country.split(delimiter)) countries = countries.flatMap((country) => country.split(delimiter));
}) });
return countries.map(getCountryName).join(', ') return countries.map(getCountryName).join(", ");
} };

View file

@ -1,33 +1,36 @@
import fs from 'fs/promises' import fs from "fs/promises";
import dotenv from 'dotenv-flow' import dotenv from "dotenv-flow";
dotenv.config() dotenv.config();
const workerName = process.argv[2] const workerName = process.argv[2];
if (!workerName) { if (!workerName) {
console.error('Please specify a worker name.') console.error("Please specify a worker name.");
process.exit(1) process.exit(1);
} }
const templatePath = `workers/${workerName}/wrangler.template.toml` const templatePath = `workers/${workerName}/wrangler.template.toml`;
const outputPath = `workers/${workerName}/wrangler.toml` const outputPath = `workers/${workerName}/wrangler.toml`;
async function generateToml() { async function generateToml() {
try { try {
const template = await fs.readFile(templatePath, 'utf8') const template = await fs.readFile(templatePath, "utf8");
const output = template const output = template
.replace(/\${CF_ACCOUNT_ID}/g, process.env.CF_ACCOUNT_ID) .replace(/\${CF_ACCOUNT_ID}/g, process.env.CF_ACCOUNT_ID)
.replace(/\${CF_ZONE_ID}/g, process.env.CF_ZONE_ID) .replace(/\${CF_ZONE_ID}/g, process.env.CF_ZONE_ID)
.replace(/\${RSS_TO_MASTODON_KV_NAMESPACE_ID}/g, process.env.RSS_TO_MASTODON_KV_NAMESPACE_ID) .replace(
/\${RSS_TO_MASTODON_KV_NAMESPACE_ID}/g,
process.env.RSS_TO_MASTODON_KV_NAMESPACE_ID
);
await fs.writeFile(outputPath, output) await fs.writeFile(outputPath, output);
console.log(`Generated wrangler.toml for ${workerName}`) console.log(`Generated wrangler.toml for ${workerName}`);
} catch (error) { } catch (error) {
console.error('Error generating wrangler.toml:', error) console.error("Error generating wrangler.toml:", error);
process.exit(1) process.exit(1);
} }
} }
generateToml() generateToml();

View file

@ -1,5 +1,4 @@
html html body {
body {
color: var(--text-color); color: var(--text-color);
background: var(--background-color); background: var(--background-color);
font-family: var(--font-mono); font-family: var(--font-mono);
@ -13,8 +12,8 @@ html {
body { body {
font-size: var(--font-size-base); font-size: var(--font-size-base);
line-height: var(--line-height-base); line-height: var(--line-height-base);
letter-spacing: -.025rem; letter-spacing: -0.025rem;
word-spacing: -.05rem; word-spacing: -0.05rem;
} }
::-webkit-scrollbar { ::-webkit-scrollbar {
@ -81,7 +80,7 @@ p:not(.banner p) > svg {
:is(h1, h2, h3, h4, h5, h6):has(svg) { :is(h1, h2, h3, h4, h5, h6):has(svg) {
display: flex; display: flex;
align-items: center; align-items: center;
gap: var(--spacing-sm) gap: var(--spacing-sm);
} }
strong, strong,
@ -125,29 +124,76 @@ svg {
.search, .search,
.tattoo, .tattoo,
.tv { .tv {
&.article { --section-color: var(--article); } &.article {
&.books { --section-color: var(--books); } --section-color: var(--article);
&.brand-github { --section-color: var(--brand-github); } }
&.brand-mastodon { --section-color: var(--brand-mastodon); } &.books {
&.brand-npm { --section-color: var(--brand-npm); } --section-color: var(--books);
&.coffee { --section-color: var(--brand-buy-me-a-coffee); } }
&.collected { --section-color: var(--collected); } &.brand-github {
&.concerts { --section-color: var(--concerts); } --section-color: var(--brand-github);
&.country { --section-color: var(--country); } }
&.device-tv-old { --section-color: var(--tv); } &.brand-mastodon {
&.device-watch { --section-color: var(--now); } --section-color: var(--brand-mastodon);
&.favorite { --section-color: var(--favorite); } }
&.headphones { --section-color: var(--music); } &.brand-npm {
&.heart-handshake { --section-color: var(--webrings); } --section-color: var(--brand-npm);
&.info-circle { --section-color: var(--about); } }
&.link { --section-color: var(--link); } &.coffee {
&.mail { --section-color: var(--brand-gmail); } --section-color: var(--brand-buy-me-a-coffee);
&.mail-plus { --section-color: var(--newsletter); } }
&.movies, &.tv { --section-color: var(--tv); } &.collected {
&.music { --section-color: var(--music); } --section-color: var(--collected);
&.rss { --section-color: var(--brand-rss); } }
&.search { --section-color: var(--search); } &.concerts {
&.tattoo { --section-color: var(--tattoo); } --section-color: var(--concerts);
}
&.country {
--section-color: var(--country);
}
&.device-tv-old {
--section-color: var(--tv);
}
&.device-watch {
--section-color: var(--now);
}
&.favorite {
--section-color: var(--favorite);
}
&.headphones {
--section-color: var(--music);
}
&.heart-handshake {
--section-color: var(--webrings);
}
&.info-circle {
--section-color: var(--about);
}
&.link {
--section-color: var(--link);
}
&.mail {
--section-color: var(--brand-gmail);
}
&.mail-plus {
--section-color: var(--newsletter);
}
&.movies,
&.tv {
--section-color: var(--tv);
}
&.music {
--section-color: var(--music);
}
&.rss {
--section-color: var(--brand-rss);
}
&.search {
--section-color: var(--search);
}
&.tattoo {
--section-color: var(--tattoo);
}
color: var(--section-color); color: var(--section-color);
@ -173,14 +219,11 @@ a:active,
:is(.main-title, footer nav.sub-pages) a:focus, :is(.main-title, footer nav.sub-pages) a:focus,
:is(.main-title, footer nav.sub-pages) a:active { :is(.main-title, footer nav.sub-pages) a:active {
color: var(--accent-color-hover); color: var(--accent-color-hover);
transition: color var(--transition-duration-default) var(--transition-ease-in-out); transition: color var(--transition-duration-default)
var(--transition-ease-in-out);
} }
:is( :is(a:has(svg):hover, a:has(svg):active, a:has(svg):focus) svg {
a:has(svg):hover,
a:has(svg):active,
a:has(svg):focus
) svg {
stroke: var(--accent-color-hover); stroke: var(--accent-color-hover);
} }
@ -201,26 +244,55 @@ a:active,
} }
/* headers */ /* headers */
h1, h2, h3, h4, h5, h6 { h1,
h2,
h3,
h4,
h5,
h6 {
font-weight: var(--font-weight-bold); font-weight: var(--font-weight-bold);
line-height: var(--line-height-md); line-height: var(--line-height-md);
margin: var(--margin-vertical-base-horizontal-zero); margin: var(--margin-vertical-base-horizontal-zero);
} }
h1 { font-size: var(--font-size-2xl); } h1 {
h2 { font-size: var(--font-size-xl); } font-size: var(--font-size-2xl);
h3 { font-size: var(--font-size-lg); } }
h4 { font-size: var(--font-size-base); } h2 {
h5 { font-size: var(--font-size-md); } font-size: var(--font-size-xl);
h6 { font-size: var(--font-size-sm); } }
h3 {
font-size: var(--font-size-lg);
}
h4 {
font-size: var(--font-size-base);
}
h5 {
font-size: var(--font-size-md);
}
h6 {
font-size: var(--font-size-sm);
}
@media screen and (min-width: 768px) { @media screen and (min-width: 768px) {
h1 { font-size: var(--font-size-3xl); } h1 {
h2 { font-size: var(--font-size-2xl); } font-size: var(--font-size-3xl);
h3 { font-size: var(--font-size-xl); } }
h4 { font-size: var(--font-size-lg); } h2 {
h5 { font-size: var(--font-size-base); } font-size: var(--font-size-2xl);
h6 { font-size: var(--font-size-md); } }
h3 {
font-size: var(--font-size-xl);
}
h4 {
font-size: var(--font-size-lg);
}
h5 {
font-size: var(--font-size-base);
}
h6 {
font-size: var(--font-size-md);
}
} }
/* dividers */ /* dividers */
@ -272,7 +344,7 @@ td {
text-overflow: ellipsis; text-overflow: ellipsis;
&::after { &::after {
content: ''; content: "";
position: absolute; position: absolute;
inset-block-start: 0; inset-block-start: 0;
inset-inline-end: 0; inset-inline-end: 0;
@ -410,9 +482,9 @@ footer {
color: var(--text-color); color: var(--text-color);
} }
/* lists */ /* lists */
ul, ol { ul,
ol {
list-style-position: inside; list-style-position: inside;
margin: var(--margin-vertical-base-horizontal-zero); margin: var(--margin-vertical-base-horizontal-zero);
padding-left: var(--spacing-base); padding-left: var(--spacing-base);

View file

@ -37,12 +37,24 @@
&.old-post, &.old-post,
&.rss, &.rss,
&.warning { &.warning {
&.error { --banner-accent-color: var(--error); } &.error {
&.github { --banner-accent-color: var(--brand-github); } --banner-accent-color: var(--error);
&.npm { --banner-accent-color: var(--brand-npm); } }
&.old-post { --banner-accent-color: var(--gray-dark); } &.github {
&.rss { --banner-accent-color: var(--brand-rss); } --banner-accent-color: var(--brand-github);
&.warning { --banner-accent-color: var(--warning); } }
&.npm {
--banner-accent-color: var(--brand-npm);
}
&.old-post {
--banner-accent-color: var(--gray-dark);
}
&.rss {
--banner-accent-color: var(--brand-rss);
}
&.warning {
--banner-accent-color: var(--warning);
}
border-color: var(--banner-accent-color); border-color: var(--banner-accent-color);

View file

@ -1,5 +1,5 @@
@import url('./tab-buttons.css'); @import url("./tab-buttons.css");
@import url('./text-toggle.css'); @import url("./text-toggle.css");
button, button,
.button { .button {
@ -22,7 +22,8 @@ button,
color: var(--text-color-inverted); color: var(--text-color-inverted);
background-color: var(--accent-color); background-color: var(--accent-color);
appearance: none; appearance: none;
transition: color var(--transition-duration-default) var(--transition-ease-in-out); transition: color var(--transition-duration-default)
var(--transition-ease-in-out);
} }
&:not(.theme-toggle, .active):hover, &:not(.theme-toggle, .active):hover,

View file

@ -1,6 +1,6 @@
::placeholder { ::placeholder {
color: var(--text-color); color: var(--text-color);
opacity: .5; opacity: 0.5;
} }
input[type="text"], input[type="text"],

View file

@ -1,5 +1,6 @@
.mastodon-post-wrapper { .mastodon-post-wrapper {
& dl, dt { & dl,
dt {
display: flex; display: flex;
} }
@ -7,7 +8,7 @@
align-items: center; align-items: center;
& dd { & dd {
margin-left: var(--spacing-xs);; margin-left: var(--spacing-xs);
&:not(:last-child) { &:not(:last-child) {
margin-right: var(--spacing-lg); margin-right: var(--spacing-lg);

View file

@ -56,7 +56,7 @@
&::after { &::after {
position: absolute; position: absolute;
z-index: 1; z-index: 1;
content: ''; content: "";
top: 0; top: 0;
left: 0; left: 0;
box-shadow: var(--box-shadow-media); box-shadow: var(--box-shadow-media);
@ -64,7 +64,8 @@
height: 100%; height: 100%;
border: var(--border-default); border: var(--border-default);
border-radius: var(--border-radius-slight); border-radius: var(--border-radius-slight);
transition: border-color var(--transition-duration-default) var(--transition-ease-in-out); transition: border-color var(--transition-duration-default)
var(--transition-ease-in-out);
} }
} }

View file

@ -12,7 +12,7 @@
&::after { &::after {
position: absolute; position: absolute;
z-index: 1; z-index: 1;
content: ''; content: "";
box-shadow: var(--box-shadow-text-toggle); box-shadow: var(--box-shadow-text-toggle);
width: 100%; width: 100%;
height: 20%; height: 20%;

View file

@ -20,10 +20,14 @@ theme-toggle {
stroke: var(--accent-color-hover); stroke: var(--accent-color-hover);
} }
& > .light svg { stroke: var(--sun); } & > .light svg {
& > .dark svg { stroke: var(--moon); } stroke: var(--sun);
}
& > .dark svg {
stroke: var(--moon);
}
& > .light , & > .light,
& > .dark { & > .dark {
display: none; display: none;
} }

View file

@ -1,6 +1,6 @@
@font-face { @font-face {
font-family: MonoLisa; font-family: MonoLisa;
src: url('/assets/fonts/ml.woff2') format('woff2'); src: url("/assets/fonts/ml.woff2") format("woff2");
font-weight: 400; font-weight: 400;
font-style: normal; font-style: normal;
font-display: swap; font-display: swap;
@ -8,7 +8,7 @@
@font-face { @font-face {
font-family: MonoLisa; font-family: MonoLisa;
src: url('/assets/fonts/mlb.woff2') format('woff2'); src: url("/assets/fonts/mlb.woff2") format("woff2");
font-weight: 700; font-weight: 700;
font-style: normal; font-style: normal;
font-display: swap; font-display: swap;
@ -16,7 +16,7 @@
@font-face { @font-face {
font-family: MonoLisa; font-family: MonoLisa;
src: url('/assets/fonts/mli.woff2') format('woff2'); src: url("/assets/fonts/mli.woff2") format("woff2");
font-weight: 400; font-weight: 400;
font-style: italic; font-style: italic;
font-display: swap; font-display: swap;
@ -24,7 +24,7 @@
@font-face { @font-face {
font-family: MonoLisa; font-family: MonoLisa;
src: url('/assets/fonts/mlbi.woff2') format('woff2'); src: url("/assets/fonts/mlbi.woff2") format("woff2");
font-weight: 700; font-weight: 700;
font-style: italic; font-style: italic;
font-display: swap; font-display: swap;

View file

@ -108,11 +108,12 @@
--border-gray: 1px solid var(--gray-light); --border-gray: 1px solid var(--gray-light);
/* fonts */ /* fonts */
--font-mono: MonoLisa, Menlo, Consolas, Monaco, Liberation Mono, Lucida Console, ui-monospace, monospace; --font-mono: MonoLisa, Menlo, Consolas, Monaco, Liberation Mono,
Lucida Console, ui-monospace, monospace;
/* text */ /* text */
--font-size-xs: .7rem; --font-size-xs: 0.7rem;
--font-size-sm: .85rem; --font-size-sm: 0.85rem;
--font-size-base: 1rem; --font-size-base: 1rem;
--font-size-lg: 1.15rem; --font-size-lg: 1.15rem;
--font-size-xl: 1.3rem; --font-size-xl: 1.3rem;
@ -127,9 +128,9 @@
--line-height-base: 2; --line-height-base: 2;
/* sizing */ /* sizing */
--sizing-xs: .25rem; --sizing-xs: 0.25rem;
--sizing-sm: .5rem; --sizing-sm: 0.5rem;
--sizing-md: .75rem; --sizing-md: 0.75rem;
--sizing-lg: 1rem; --sizing-lg: 1rem;
--sizing-base: 1.5rem; --sizing-base: 1.5rem;
--sizing-xl: 1.75rem; --sizing-xl: 1.75rem;

View file

@ -1,43 +1,57 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:atom="http://www.w3.org/2005/Atom"> <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
<xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/> xmlns:atom="http://www.w3.org/2005/Atom">
<xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes" />
<xsl:template match="/"> <xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en"> <html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head> <head>
<title><xsl:value-of select="/rss/channel/title"/></title> <title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <xsl:value-of select="/rss/channel/title" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/> </title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<link rel="stylesheet" href="/assets/styles/index.css" type="text/css" /> <link rel="stylesheet" href="/assets/styles/index.css" type="text/css" />
</head> </head>
<body class="feed"> <body class="feed">
<div class="main-wrapper"> <div class="main-wrapper">
<main> <main>
<section class="main-title"> <section class="main-title">
<h1><a href="/feeds" tabindex="0"><xsl:value-of select="/rss/channel/title"/></a></h1> <h1>
<a href="/feeds" tabindex="0">
<xsl:value-of select="/rss/channel/title" />
</a>
</h1>
</section> </section>
<div class="default-wrapper"> <div class="default-wrapper">
<p><xsl:value-of select="/rss/channel/description"/></p> <p>
<p><strong class="highlight-text">Subscribe by adding the URL below to your feed reader of choice.</strong></p> <xsl:value-of select="/rss/channel/description" />
</p>
<p>
<strong class="highlight-text">Subscribe by adding the URL below to your feed reader
of choice.</strong>
</p>
<p> <p>
<pre class="small"> <pre class="small">
<code><xsl:value-of select="rss/channel/atom:link/@href"/></code> <code><xsl:value-of select="rss/channel/atom:link/@href"/></code>
</pre> </pre>
</p> </p>
<p><a href="/feeds">View more of the feeds from my site.</a></p> <p>
<a href="/feeds">View more of the feeds from my site.</a>
</p>
<hr /> <hr />
<section> <section>
<xsl:for-each select="/rss/channel/item"> <xsl:for-each select="/rss/channel/item">
<div class="item"> <div class="item">
<p class="date">Published: <xsl:value-of select="pubDate"/></p> <p class="date">Published: <xsl:value-of select="pubDate" /></p>
<h3> <h3>
<a> <a>
<xsl:attribute name="href"> <xsl:attribute name="href">
<xsl:value-of select="link"/> <xsl:value-of select="link" />
</xsl:attribute> </xsl:attribute>
<xsl:value-of select="title"/> <xsl:value-of select="title" />
</a> </a>
</h3> </h3>
<xsl:value-of select="description" disable-output-escaping="yes"/> <xsl:value-of select="description" disable-output-escaping="yes" />
<xsl:if test="enclosure"> <xsl:if test="enclosure">
<img src="{enclosure/@url}" alt="{title}" /> <img src="{enclosure/@url}" alt="{title}" />
</xsl:if> </xsl:if>
@ -48,7 +62,10 @@
</main> </main>
<footer> <footer>
<hr /> <hr />
<p>Subscribe by adding <code><xsl:value-of select="rss/channel/atom:link/@href"/></code> to your feed reader of choice.</p> <p>Subscribe by adding <code>
<xsl:value-of select="rss/channel/atom:link/@href" />
</code> to your
feed reader of choice.</p>
</footer> </footer>
</div> </div>
</body> </body>

View file

@ -1,40 +1,40 @@
@layer reset, defaults, base, page, components, plugins; @layer reset, defaults, base, page, components, plugins;
/* style resets */ /* style resets */
@import url('./reset.css') layer(reset); @import url("./reset.css") layer(reset);
/* core defaults */ /* core defaults */
@import url('./defaults/fonts.css') layer(defaults); @import url("./defaults/fonts.css") layer(defaults);
@import url('./defaults/vars.css') layer(defaults); @import url("./defaults/vars.css") layer(defaults);
/* base styles */ /* base styles */
@import url('./base/index.css') layer(base); @import url("./base/index.css") layer(base);
/* plugins */ /* plugins */
@import url('./plugins/prism.css') layer(plugins); @import url("./plugins/prism.css") layer(plugins);
/* page styles */ /* page styles */
@import url('./pages/about.css') layer(page); @import url("./pages/about.css") layer(page);
@import url('./pages/books.css') layer(page); @import url("./pages/books.css") layer(page);
@import url('./pages/blogroll.css') layer(page); @import url("./pages/blogroll.css") layer(page);
@import url('./pages/contact.css') layer(page); @import url("./pages/contact.css") layer(page);
@import url('./pages/feeds.css') layer(page); @import url("./pages/feeds.css") layer(page);
@import url('./pages/links.css') layer(page); @import url("./pages/links.css") layer(page);
@import url('./pages/music.css') layer(page); @import url("./pages/music.css") layer(page);
@import url('./pages/articles.css') layer(page); @import url("./pages/articles.css") layer(page);
@import url('./pages/watching.css') layer(page); @import url("./pages/watching.css") layer(page);
@import url('./pages/webrings.css') layer(page); @import url("./pages/webrings.css") layer(page);
/* component styles */ /* component styles */
@import url('./components/badge-grid.css') layer(components); @import url("./components/badge-grid.css") layer(components);
@import url('./components/banners.css') layer(components); @import url("./components/banners.css") layer(components);
@import url('./components/buttons.css') layer(components); @import url("./components/buttons.css") layer(components);
@import url('./components/forms.css') layer(components); @import url("./components/forms.css") layer(components);
@import url('./components/mastodon-post.css') layer(components); @import url("./components/mastodon-post.css") layer(components);
@import url('./components/media-grid.css') layer(components); @import url("./components/media-grid.css") layer(components);
@import url('./components/menu.css') layer(components); @import url("./components/menu.css") layer(components);
@import url('./components/modal.css') layer(components); @import url("./components/modal.css") layer(components);
@import url('./components/music-chart.css') layer(components); @import url("./components/music-chart.css") layer(components);
@import url('./components/paginator.css') layer(components); @import url("./components/paginator.css") layer(components);
@import url('./components/progress-bar.css') layer(components); @import url("./components/progress-bar.css") layer(components);
@import url('./components/theme-toggle.css') layer(components); @import url("./components/theme-toggle.css") layer(components);

View file

@ -27,7 +27,8 @@
max-width: calc(var(--sizing-3xl) * 4); max-width: calc(var(--sizing-3xl) * 4);
height: auto; height: auto;
aspect-ratio: var(--aspect-ratio-vertical); aspect-ratio: var(--aspect-ratio-vertical);
transition: border-color var(--transition-duration-default) var(--transition-ease-in-out); transition: border-color var(--transition-duration-default)
var(--transition-ease-in-out);
} }
& a:focus img, & a:focus img,

View file

@ -45,7 +45,7 @@ a:active > .watching.hero::after {
&::after { &::after {
position: absolute; position: absolute;
z-index: 1; z-index: 1;
content: ''; content: "";
top: 0; top: 0;
left: 0; left: 0;
box-shadow: var(--box-shadow-media); box-shadow: var(--box-shadow-media);
@ -53,7 +53,8 @@ a:active > .watching.hero::after {
height: 100%; height: 100%;
border: var(--border-default); border: var(--border-default);
border-radius: var(--border-radius-slight); border-radius: var(--border-radius-slight);
transition: border-color var(--transition-duration-default) var(--transition-ease-in-out); transition: border-color var(--transition-duration-default)
var(--transition-ease-in-out);
} }
} }

View file

@ -1,4 +1,6 @@
*, *::before, *::after { *,
*::before,
*::after {
box-sizing: border-box; box-sizing: border-box;
margin: 0; margin: 0;
} }
@ -9,10 +11,19 @@ body {
-webkit-text-size-adjust: none; -webkit-text-size-adjust: none;
} }
input, button, textarea, select { input,
button,
textarea,
select {
font: inherit; font: inherit;
} }
p, h1, h2, h3, h4, h5, h6 { p,
h1,
h2,
h3,
h4,
h5,
h6 {
overflow-wrap: break-word; overflow-wrap: break-word;
} }

View file

@ -1,20 +1,20 @@
import { createClient } from '@supabase/supabase-js' import { createClient } from "@supabase/supabase-js";
const SUPABASE_URL = process.env.SUPABASE_URL const SUPABASE_URL = process.env.SUPABASE_URL;
const SUPABASE_KEY = process.env.SUPABASE_KEY const SUPABASE_KEY = process.env.SUPABASE_KEY;
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY) const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
export default async function fetchActivity() { export default async function fetchActivity() {
const { data, error } = await supabase const { data, error } = await supabase
.from('optimized_all_activity') .from("optimized_all_activity")
.select('feed') .select("feed");
if (error) { if (error) {
console.error('Error fetching activity data:', error) console.error("Error fetching activity data:", error);
return [] return [];
} }
const [{ feed } = {}] = data const [{ feed } = {}] = data;
return feed?.filter(item => item['feed'] !== null) || [] return feed?.filter((item) => item["feed"] !== null) || [];
} }

View file

@ -1,43 +1,47 @@
import { createClient } from '@supabase/supabase-js' import { createClient } from "@supabase/supabase-js";
import { DateTime } from 'luxon' import { DateTime } from "luxon";
const SUPABASE_URL = process.env.SUPABASE_URL const SUPABASE_URL = process.env.SUPABASE_URL;
const SUPABASE_KEY = process.env.SUPABASE_KEY const SUPABASE_KEY = process.env.SUPABASE_KEY;
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY) const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
const fetchAlbumReleases = async () => { const fetchAlbumReleases = async () => {
const today = DateTime.utc().startOf('day').toSeconds() const today = DateTime.utc().startOf("day").toSeconds();
const { data, error } = await supabase const { data, error } = await supabase
.from('optimized_album_releases') .from("optimized_album_releases")
.select('*') .select("*");
if (error) { if (error) {
console.error('Error fetching data:', error) console.error("Error fetching data:", error);
return [] return [];
} }
const all = data.map(album => { const all = data
const releaseDate = DateTime.fromSeconds(album['release_timestamp']).toUTC().startOf('day') .map((album) => {
const releaseDate = DateTime.fromSeconds(album["release_timestamp"])
.toUTC()
.startOf("day");
return { return {
...album, ...album,
description: album['artist']['description'], description: album["artist"]["description"],
date: releaseDate.toLocaleString(DateTime.DATE_FULL), date: releaseDate.toLocaleString(DateTime.DATE_FULL),
timestamp: releaseDate.toSeconds() timestamp: releaseDate.toSeconds(),
} };
}).sort((a, b) => a['timestamp'] - b['timestamp']) })
.sort((a, b) => a["timestamp"] - b["timestamp"]);
const upcoming = all.filter(album => album['release_timestamp'] > today) const upcoming = all.filter((album) => album["release_timestamp"] > today);
return { all, upcoming } return { all, upcoming };
} };
export default async function () { export default async function () {
try { try {
return await fetchAlbumReleases() return await fetchAlbumReleases();
} catch (error) { } catch (error) {
console.error('Error fetching and processing album releases:', error) console.error("Error fetching and processing album releases:", error);
return [] return [];
} }
} }

View file

@ -1,47 +1,47 @@
import { createClient } from '@supabase/supabase-js' import { createClient } from "@supabase/supabase-js";
import { parseCountryField } from '../../config/utilities/index.js' import { parseCountryField } from "../../config/utilities/index.js";
const SUPABASE_URL = process.env.SUPABASE_URL const SUPABASE_URL = process.env.SUPABASE_URL;
const SUPABASE_KEY = process.env.SUPABASE_KEY const SUPABASE_KEY = process.env.SUPABASE_KEY;
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY) const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
const PAGE_SIZE = 1000 const PAGE_SIZE = 1000;
const fetchAllArtists = async () => { const fetchAllArtists = async () => {
let artists = [] let artists = [];
let rangeStart = 0 let rangeStart = 0;
while (true) { while (true) {
const { data, error } = await supabase const { data, error } = await supabase
.from('optimized_artists') .from("optimized_artists")
.select('*') .select("*")
.range(rangeStart, rangeStart + PAGE_SIZE - 1) .range(rangeStart, rangeStart + PAGE_SIZE - 1);
if (error) { if (error) {
console.error('Error fetching artists:', error) console.error("Error fetching artists:", error);
break break;
} }
artists = artists.concat(data) artists = artists.concat(data);
if (data.length < PAGE_SIZE) break if (data.length < PAGE_SIZE) break;
rangeStart += PAGE_SIZE rangeStart += PAGE_SIZE;
} }
return artists return artists;
} };
const processArtists = (artists) => { const processArtists = (artists) => {
return artists.map(artist => ({ return artists.map((artist) => ({
...artist, ...artist,
country: parseCountryField(artist['country']), country: parseCountryField(artist["country"]),
})) }));
} };
export default async function () { export default async function () {
try { try {
const artists = await fetchAllArtists() const artists = await fetchAllArtists();
return processArtists(artists) return processArtists(artists);
} catch (error) { } catch (error) {
console.error('Error fetching and processing artists data:', error) console.error("Error fetching and processing artists data:", error);
return [] return [];
} }
} }

View file

@ -1,29 +1,31 @@
import { createClient } from '@supabase/supabase-js' import { createClient } from "@supabase/supabase-js";
const SUPABASE_URL = process.env.SUPABASE_URL const SUPABASE_URL = process.env.SUPABASE_URL;
const SUPABASE_KEY = process.env.SUPABASE_KEY const SUPABASE_KEY = process.env.SUPABASE_KEY;
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY) const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
const fetchBlogroll = async () => { const fetchBlogroll = async () => {
const { data, error } = await supabase const { data, error } = await supabase
.from('authors') .from("authors")
.select('*') .select("*")
.eq('blogroll', true) .eq("blogroll", true)
.order('name', { ascending: true }) .order("name", { ascending: true });
if (error) { if (error) {
console.error('Error fetching authors for the blogroll:', error) console.error("Error fetching authors for the blogroll:", error);
return [] return [];
} }
return data.sort((a, b) => a['name'].toLowerCase().localeCompare(b['name'].toLowerCase())) return data.sort((a, b) =>
} a["name"].toLowerCase().localeCompare(b["name"].toLowerCase())
);
};
export default async function () { export default async function () {
try { try {
return await fetchBlogroll() return await fetchBlogroll();
} catch (error) { } catch (error) {
console.error('Error fetching and processing the blogroll:', error) console.error("Error fetching and processing the blogroll:", error);
return [] return [];
} }
} }

View file

@ -1,60 +1,60 @@
import { createClient } from '@supabase/supabase-js' import { createClient } from "@supabase/supabase-js";
const SUPABASE_URL = process.env.SUPABASE_URL const SUPABASE_URL = process.env.SUPABASE_URL;
const SUPABASE_KEY = process.env.SUPABASE_KEY const SUPABASE_KEY = process.env.SUPABASE_KEY;
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY) const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
const PAGE_SIZE = 1000 const PAGE_SIZE = 1000;
const fetchAllBooks = async () => { const fetchAllBooks = async () => {
let books = [] let books = [];
let rangeStart = 0 let rangeStart = 0;
while (true) { while (true) {
const { data, error } = await supabase const { data, error } = await supabase
.from('optimized_books') .from("optimized_books")
.select('*') .select("*")
.order('date_finished', { ascending: false }) .order("date_finished", { ascending: false })
.range(rangeStart, rangeStart + PAGE_SIZE - 1) .range(rangeStart, rangeStart + PAGE_SIZE - 1);
if (error) { if (error) {
console.error('Error fetching books:', error) console.error("Error fetching books:", error);
break break;
} }
books = books.concat(data) books = books.concat(data);
if (data.length < PAGE_SIZE) break if (data.length < PAGE_SIZE) break;
rangeStart += PAGE_SIZE rangeStart += PAGE_SIZE;
} }
return books return books;
} };
const sortBooksByYear = (books) => { const sortBooksByYear = (books) => {
const years = {} const years = {};
books.forEach(book => { books.forEach((book) => {
const year = book['year'] const year = book["year"];
if (!years[year]) { if (!years[year]) {
years[year] = { value: year, data: [book] } years[year] = { value: year, data: [book] };
} else { } else {
years[year]['data'].push(book) years[year]["data"].push(book);
} }
}) });
return Object.values(years).filter(year => year['value'] > 2017) return Object.values(years).filter((year) => year["value"] > 2017);
} };
const currentYear = new Date().getFullYear() const currentYear = new Date().getFullYear();
export default async function () { export default async function () {
const books = await fetchAllBooks() const books = await fetchAllBooks();
const sortedByYear = sortBooksByYear(books) const sortedByYear = sortBooksByYear(books);
const booksForCurrentYear = sortedByYear.find( const booksForCurrentYear =
yearGroup => yearGroup.value === currentYear sortedByYear.find((yearGroup) => yearGroup.value === currentYear)?.data ||
)?.data || [] [];
return { return {
all: books, all: books,
years: sortedByYear, years: sortedByYear,
currentYear: booksForCurrentYear, currentYear: booksForCurrentYear,
feed: books.filter(book => book['feed']) feed: books.filter((book) => book["feed"]),
} };
} }

View file

@ -1,46 +1,46 @@
import { createClient } from '@supabase/supabase-js' import { createClient } from "@supabase/supabase-js";
const SUPABASE_URL = process.env.SUPABASE_URL const SUPABASE_URL = process.env.SUPABASE_URL;
const SUPABASE_KEY = process.env.SUPABASE_KEY const SUPABASE_KEY = process.env.SUPABASE_KEY;
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY) const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
const PAGE_SIZE = 1000 const PAGE_SIZE = 1000;
const fetchAllConcerts = async () => { const fetchAllConcerts = async () => {
let concerts = [] let concerts = [];
let rangeStart = 0 let rangeStart = 0;
while (true) { while (true) {
const { data, error } = await supabase const { data, error } = await supabase
.from('optimized_concerts') .from("optimized_concerts")
.select('*') .select("*")
.range(rangeStart, rangeStart + PAGE_SIZE - 1) .range(rangeStart, rangeStart + PAGE_SIZE - 1);
if (error) { if (error) {
console.error('Error fetching concerts:', error) console.error("Error fetching concerts:", error);
break break;
} }
concerts = concerts.concat(data) concerts = concerts.concat(data);
if (data.length < PAGE_SIZE) break if (data.length < PAGE_SIZE) break;
rangeStart += PAGE_SIZE rangeStart += PAGE_SIZE;
} }
return concerts return concerts;
} };
const processConcerts = (concerts) => { const processConcerts = (concerts) => {
return concerts.map(concert => ({ return concerts.map((concert) => ({
...concert, ...concert,
artist: concert.artist || { name: concert.artist_name_string, url: null }, artist: concert.artist || { name: concert.artist_name_string, url: null },
})) }));
} };
export default async function () { export default async function () {
try { try {
const concerts = await fetchAllConcerts() const concerts = await fetchAllConcerts();
return processConcerts(concerts) return processConcerts(concerts);
} catch (error) { } catch (error) {
console.error('Error fetching and processing concerts data:', error) console.error("Error fetching and processing concerts data:", error);
return [] return [];
} }
} }

View file

@ -1,27 +1,25 @@
import { createClient } from '@supabase/supabase-js' import { createClient } from "@supabase/supabase-js";
const SUPABASE_URL = process.env.SUPABASE_URL const SUPABASE_URL = process.env.SUPABASE_URL;
const SUPABASE_KEY = process.env.SUPABASE_KEY const SUPABASE_KEY = process.env.SUPABASE_KEY;
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY) const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
const fetchGenres = async () => { const fetchGenres = async () => {
const { data, error } = await supabase const { data, error } = await supabase.from("optimized_genres").select("*");
.from('optimized_genres')
.select('*')
if (error) { if (error) {
console.error('Error fetching genres with artists:', error) console.error("Error fetching genres with artists:", error);
return [] return [];
} }
return data return data;
} };
export default async function () { export default async function () {
try { try {
return await fetchGenres() return await fetchGenres();
} catch (error) { } catch (error) {
console.error('Error fetching and processing genres:', error) console.error("Error fetching and processing genres:", error);
return [] return [];
} }
} }

View file

@ -1,28 +1,28 @@
import { createClient } from '@supabase/supabase-js' import { createClient } from "@supabase/supabase-js";
const SUPABASE_URL = process.env.SUPABASE_URL const SUPABASE_URL = process.env.SUPABASE_URL;
const SUPABASE_KEY = process.env.SUPABASE_KEY const SUPABASE_KEY = process.env.SUPABASE_KEY;
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY) const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
const fetchGlobals = async () => { const fetchGlobals = async () => {
const { data, error } = await supabase const { data, error } = await supabase
.from('optimized_globals') .from("optimized_globals")
.select('*') .select("*")
.single() .single();
if (error) { if (error) {
console.error('Error fetching globals:', error) console.error("Error fetching globals:", error);
return {} return {};
} }
return data return data;
} };
export default async function () { export default async function () {
try { try {
return await fetchGlobals() return await fetchGlobals();
} catch (error) { } catch (error) {
console.error('Error fetching and processing globals:', error) console.error("Error fetching and processing globals:", error);
return {} return {};
} }
} }

View file

@ -1,40 +1,40 @@
import { createClient } from '@supabase/supabase-js' import { createClient } from "@supabase/supabase-js";
const SUPABASE_URL = process.env.SUPABASE_URL const SUPABASE_URL = process.env.SUPABASE_URL;
const SUPABASE_KEY = process.env.SUPABASE_KEY const SUPABASE_KEY = process.env.SUPABASE_KEY;
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY) const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
const PAGE_SIZE = 1000 const PAGE_SIZE = 1000;
const fetchAllLinks = async () => { const fetchAllLinks = async () => {
let links = [] let links = [];
let page = 0 let page = 0;
let fetchMore = true let fetchMore = true;
while (fetchMore) { while (fetchMore) {
const { data, error } = await supabase const { data, error } = await supabase
.from('optimized_links') .from("optimized_links")
.select('*') .select("*")
.range(page * PAGE_SIZE, (page + 1) * PAGE_SIZE - 1) .range(page * PAGE_SIZE, (page + 1) * PAGE_SIZE - 1);
if (error) { if (error) {
console.error('Error fetching links:', error) console.error("Error fetching links:", error);
return links return links;
} }
if (data.length < PAGE_SIZE) fetchMore = false if (data.length < PAGE_SIZE) fetchMore = false;
links = links.concat(data) links = links.concat(data);
page++ page++;
} }
return links return links;
} };
export default async function () { export default async function () {
try { try {
return await fetchAllLinks() return await fetchAllLinks();
} catch (error) { } catch (error) {
console.error('Error fetching and processing links:', error) console.error("Error fetching and processing links:", error);
return [] return [];
} }
} }

View file

@ -1,62 +1,67 @@
import { createClient } from '@supabase/supabase-js' import { createClient } from "@supabase/supabase-js";
import { DateTime } from 'luxon' import { DateTime } from "luxon";
const SUPABASE_URL = process.env.SUPABASE_URL const SUPABASE_URL = process.env.SUPABASE_URL;
const SUPABASE_KEY = process.env.SUPABASE_KEY const SUPABASE_KEY = process.env.SUPABASE_KEY;
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY) const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
const PAGE_SIZE = 1000 const PAGE_SIZE = 1000;
const fetchAllMovies = async () => { const fetchAllMovies = async () => {
let movies = [] let movies = [];
let rangeStart = 0 let rangeStart = 0;
while (true) { while (true) {
const { data, error } = await supabase const { data, error } = await supabase
.from('optimized_movies') .from("optimized_movies")
.select('*') .select("*")
.range(rangeStart, rangeStart + PAGE_SIZE - 1) .range(rangeStart, rangeStart + PAGE_SIZE - 1);
if (error) { if (error) {
console.error('Error fetching movies:', error) console.error("Error fetching movies:", error);
break break;
} }
movies = movies.concat(data) movies = movies.concat(data);
if (data.length < PAGE_SIZE) break if (data.length < PAGE_SIZE) break;
rangeStart += PAGE_SIZE rangeStart += PAGE_SIZE;
} }
return movies return movies;
} };
export default async function () { export default async function () {
const year = DateTime.now().year const year = DateTime.now().year;
try { try {
const movies = await fetchAllMovies() const movies = await fetchAllMovies();
const favoriteMovies = movies.filter(movie => movie['favorite']) const favoriteMovies = movies.filter((movie) => movie["favorite"]);
const now = DateTime.now(); const now = DateTime.now();
const recentlyWatchedMovies = movies.filter(movie => { const recentlyWatchedMovies = movies.filter((movie) => {
const lastWatched = movie['last_watched'] const lastWatched = movie["last_watched"];
return (lastWatched && now.diff(DateTime.fromISO(lastWatched), 'months').months <= 6) return (
}) lastWatched &&
now.diff(DateTime.fromISO(lastWatched), "months").months <= 6
);
});
return { return {
movies, movies,
watchHistory: movies.filter(movie => movie['last_watched']), watchHistory: movies.filter((movie) => movie["last_watched"]),
recentlyWatched: recentlyWatchedMovies, recentlyWatched: recentlyWatchedMovies,
favorites: favoriteMovies.sort((a, b) => a['title'].localeCompare(b['title'])), favorites: favoriteMovies.sort((a, b) =>
feed: movies.filter(movie => movie['feed']), a["title"].localeCompare(b["title"])
} ),
feed: movies.filter((movie) => movie["feed"]),
};
} catch (error) { } catch (error) {
console.error('Error fetching and processing movies data:', error) console.error("Error fetching and processing movies data:", error);
return { return {
movies: [], movies: [],
watchHistory: [], watchHistory: [],
recentlyWatched: [], recentlyWatched: [],
favorites: [], favorites: [],
feed: [] feed: [],
} };
} }
} }

View file

@ -1,35 +1,35 @@
import { createClient } from '@supabase/supabase-js' import { createClient } from "@supabase/supabase-js";
const SUPABASE_URL = process.env.SUPABASE_URL const SUPABASE_URL = process.env.SUPABASE_URL;
const SUPABASE_KEY = process.env.SUPABASE_KEY const SUPABASE_KEY = process.env.SUPABASE_KEY;
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY) const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
const PAGE_SIZE = 1000 const PAGE_SIZE = 1000;
const fetchDataFromView = async (viewName) => { const fetchDataFromView = async (viewName) => {
let rows = [] let rows = [];
let rangeStart = 0 let rangeStart = 0;
while (true) { while (true) {
const { data, error } = await supabase const { data, error } = await supabase
.from(viewName) .from(viewName)
.select('*') .select("*")
.range(rangeStart, rangeStart + PAGE_SIZE - 1) .range(rangeStart, rangeStart + PAGE_SIZE - 1);
if (error) { if (error) {
console.error(`Error fetching data from view ${viewName}:`, error) console.error(`Error fetching data from view ${viewName}:`, error);
break break;
} }
if (data.length === 0) break if (data.length === 0) break;
rows = [...rows, ...data] rows = [...rows, ...data];
if (data.length < PAGE_SIZE) break if (data.length < PAGE_SIZE) break;
rangeStart += PAGE_SIZE rangeStart += PAGE_SIZE;
} }
return rows return rows;
} };
export default async function fetchMusicData() { export default async function fetchMusicData() {
try { try {
@ -44,16 +44,16 @@ export default async function fetchMusicData() {
monthAlbums, monthAlbums,
monthGenres, monthGenres,
] = await Promise.all([ ] = await Promise.all([
fetchDataFromView('recent_tracks'), fetchDataFromView("recent_tracks"),
fetchDataFromView('week_tracks'), fetchDataFromView("week_tracks"),
fetchDataFromView('week_artists'), fetchDataFromView("week_artists"),
fetchDataFromView('week_albums'), fetchDataFromView("week_albums"),
fetchDataFromView('week_genres'), fetchDataFromView("week_genres"),
fetchDataFromView('month_tracks'), fetchDataFromView("month_tracks"),
fetchDataFromView('month_artists'), fetchDataFromView("month_artists"),
fetchDataFromView('month_albums'), fetchDataFromView("month_albums"),
fetchDataFromView('month_genres'), fetchDataFromView("month_genres"),
]) ]);
return { return {
recent: recentTracks, recent: recentTracks,
@ -64,7 +64,7 @@ export default async function fetchMusicData() {
genres: weekGenres, genres: weekGenres,
totalTracks: weekTracks totalTracks: weekTracks
.reduce((acc, track) => acc + track.plays, 0) .reduce((acc, track) => acc + track.plays, 0)
.toLocaleString('en-US'), .toLocaleString("en-US"),
}, },
month: { month: {
tracks: monthTracks, tracks: monthTracks,
@ -73,11 +73,11 @@ export default async function fetchMusicData() {
genres: monthGenres, genres: monthGenres,
totalTracks: monthTracks totalTracks: monthTracks
.reduce((acc, track) => acc + track.plays, 0) .reduce((acc, track) => acc + track.plays, 0)
.toLocaleString('en-US'), .toLocaleString("en-US"),
}, },
} };
} catch (error) { } catch (error) {
console.error('Error fetching and processing music data:', error) console.error("Error fetching and processing music data:", error);
return {} return {};
} }
} }

View file

@ -1,48 +1,48 @@
import { createClient } from '@supabase/supabase-js' import { createClient } from "@supabase/supabase-js";
const SUPABASE_URL = process.env.SUPABASE_URL const SUPABASE_URL = process.env.SUPABASE_URL;
const SUPABASE_KEY = process.env.SUPABASE_KEY const SUPABASE_KEY = process.env.SUPABASE_KEY;
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY) const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
const fetchAllNavigation = async () => { const fetchAllNavigation = async () => {
const { data, error } = await supabase const { data, error } = await supabase
.from('optimized_navigation') .from("optimized_navigation")
.select('*') .select("*");
if (error) { if (error) {
console.error('Error fetching navigation data:', error) console.error("Error fetching navigation data:", error);
return {} return {};
} }
const menu = data.reduce((acc, item) => { const menu = data.reduce((acc, item) => {
const menuItem = { const menuItem = {
title: item['title'] || item['page_title'], title: item["title"] || item["page_title"],
permalink: item['permalink'] || item ['page_permalink'], permalink: item["permalink"] || item["page_permalink"],
icon: item['icon'], icon: item["icon"],
sort: item['sort'] sort: item["sort"],
} };
if (!acc[item['menu_location']]) { if (!acc[item["menu_location"]]) {
acc[item['menu_location']] = [menuItem] acc[item["menu_location"]] = [menuItem];
} else { } else {
acc[item['menu_location']].push(menuItem) acc[item["menu_location"]].push(menuItem);
} }
return acc return acc;
}, {}) }, {});
Object.keys(menu).forEach(location => { Object.keys(menu).forEach((location) => {
menu[location].sort((a, b) => a['sort'] - b['sort']) menu[location].sort((a, b) => a["sort"] - b["sort"]);
}) });
return menu return menu;
} };
export default async function () { export default async function () {
try { try {
return await fetchAllNavigation() return await fetchAllNavigation();
} catch (error) { } catch (error) {
console.error('Error fetching and processing navigation data:', error) console.error("Error fetching and processing navigation data:", error);
return {} return {};
} }
} }

View file

@ -1,33 +1,35 @@
import { createClient } from '@supabase/supabase-js' import { createClient } from "@supabase/supabase-js";
const SUPABASE_URL = process.env.SUPABASE_URL const SUPABASE_URL = process.env.SUPABASE_URL;
const SUPABASE_KEY = process.env.SUPABASE_KEY const SUPABASE_KEY = process.env.SUPABASE_KEY;
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY) const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
const fetchNowPlaying = async () => { const fetchNowPlaying = async () => {
const { data, error } = await supabase const { data, error } = await supabase
.from('optimized_latest_listen') .from("optimized_latest_listen")
.select('*') .select("*")
.single() .single();
if (error) { if (error) {
console.error('Error fetching the latest track:', error) console.error("Error fetching the latest track:", error);
return {} return {};
} }
const genreEmoji = data.genre_emoji const genreEmoji = data.genre_emoji;
const emoji = data.artist_emoji || genreEmoji const emoji = data.artist_emoji || genreEmoji;
return { return {
content: `${emoji || '🎧'} ${data.track_name} by <a href="https://coryd.dev${data.url}">${data.artist_name}</a>`, content: `${emoji || "🎧"} ${
} data.track_name
} } by <a href="https://coryd.dev${data.url}">${data.artist_name}</a>`,
};
};
export default async function () { export default async function () {
try { try {
return await fetchNowPlaying() return await fetchNowPlaying();
} catch (error) { } catch (error) {
console.error('Error fetching and processing now-playing data:', error) console.error("Error fetching and processing now-playing data:", error);
return {} return {};
} }
} }

View file

@ -1,40 +1,40 @@
import { createClient } from '@supabase/supabase-js' import { createClient } from "@supabase/supabase-js";
const SUPABASE_URL = process.env['SUPABASE_URL'] const SUPABASE_URL = process.env["SUPABASE_URL"];
const SUPABASE_KEY = process.env['SUPABASE_KEY'] const SUPABASE_KEY = process.env["SUPABASE_KEY"];
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY) const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
const PAGE_SIZE = 250 const PAGE_SIZE = 250;
const fetchAllPages = async () => { const fetchAllPages = async () => {
let pages = [] let pages = [];
let page = 0 let page = 0;
let fetchMore = true let fetchMore = true;
while (fetchMore) { while (fetchMore) {
const { data, error } = await supabase const { data, error } = await supabase
.from('optimized_pages') .from("optimized_pages")
.select('*') .select("*")
.range(page * PAGE_SIZE, (page + 1) * PAGE_SIZE - 1) .range(page * PAGE_SIZE, (page + 1) * PAGE_SIZE - 1);
if (error) { if (error) {
console.error('Error fetching pages:', error) console.error("Error fetching pages:", error);
return pages return pages;
} }
if (data.length < PAGE_SIZE) fetchMore = false if (data.length < PAGE_SIZE) fetchMore = false;
pages = pages.concat(data) pages = pages.concat(data);
page++ page++;
} }
return pages return pages;
} };
export default async function () { export default async function () {
try { try {
return await fetchAllPages() return await fetchAllPages();
} catch (error) { } catch (error) {
console.error('Error fetching and processing pages:', error) console.error("Error fetching and processing pages:", error);
return [] return [];
} }
} }

View file

@ -1,41 +1,41 @@
import { createClient } from '@supabase/supabase-js' import { createClient } from "@supabase/supabase-js";
const SUPABASE_URL = process.env['SUPABASE_URL'] const SUPABASE_URL = process.env["SUPABASE_URL"];
const SUPABASE_KEY = process.env['SUPABASE_KEY'] const SUPABASE_KEY = process.env["SUPABASE_KEY"];
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY) const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
const PAGE_SIZE = 1000 const PAGE_SIZE = 1000;
const fetchAllPosts = async () => { const fetchAllPosts = async () => {
let posts = [] let posts = [];
let page = 0 let page = 0;
let fetchMore = true let fetchMore = true;
while (fetchMore) { while (fetchMore) {
const { data, error } = await supabase const { data, error } = await supabase
.from('optimized_posts') .from("optimized_posts")
.select('*') .select("*")
.order('date', { ascending: false }) .order("date", { ascending: false })
.range(page * PAGE_SIZE, (page + 1) * PAGE_SIZE - 1) .range(page * PAGE_SIZE, (page + 1) * PAGE_SIZE - 1);
if (error) { if (error) {
console.error('Error fetching posts:', error) console.error("Error fetching posts:", error);
return posts return posts;
} }
if (data.length < PAGE_SIZE) fetchMore = false if (data.length < PAGE_SIZE) fetchMore = false;
posts = posts.concat(data) posts = posts.concat(data);
page++ page++;
} }
return posts return posts;
} };
export default async function () { export default async function () {
try { try {
return await fetchAllPosts() return await fetchAllPosts();
} catch (error) { } catch (error) {
console.error('Error fetching and processing posts:', error) console.error("Error fetching and processing posts:", error);
return [] return [];
} }
} }

View file

@ -1,38 +1,40 @@
import { createClient } from '@supabase/supabase-js' import { createClient } from "@supabase/supabase-js";
const SUPABASE_URL = process.env.SUPABASE_URL const SUPABASE_URL = process.env.SUPABASE_URL;
const SUPABASE_KEY = process.env.SUPABASE_KEY const SUPABASE_KEY = process.env.SUPABASE_KEY;
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY) const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
const PAGE_SIZE = 500 const PAGE_SIZE = 500;
const fetchAllRobots = async () => { const fetchAllRobots = async () => {
let robots = [] let robots = [];
let from = 0 let from = 0;
while (true) { while (true) {
const { data, error } = await supabase const { data, error } = await supabase
.from('robots') .from("robots")
.select('user_agent') .select("user_agent")
.range(from, from + PAGE_SIZE - 1) .range(from, from + PAGE_SIZE - 1);
if (error) { if (error) {
console.error('Error fetching robot data:', error) console.error("Error fetching robot data:", error);
return [] return [];
} }
robots = robots.concat(data) robots = robots.concat(data);
if (data.length < PAGE_SIZE) break if (data.length < PAGE_SIZE) break;
from += PAGE_SIZE from += PAGE_SIZE;
} }
return robots.map(robot => robot['user_agent']).sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase())) return robots
} .map((robot) => robot["user_agent"])
.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
};
export default async function () { export default async function () {
try { try {
return await fetchAllRobots() return await fetchAllRobots();
} catch (error) { } catch (error) {
console.error('Error fetching and processing robot data:', error) console.error("Error fetching and processing robot data:", error);
return [] return [];
} }
} }

View file

@ -1,20 +1,20 @@
import { createClient } from '@supabase/supabase-js' import { createClient } from "@supabase/supabase-js";
const SUPABASE_URL = process.env.SUPABASE_URL const SUPABASE_URL = process.env.SUPABASE_URL;
const SUPABASE_KEY = process.env.SUPABASE_KEY const SUPABASE_KEY = process.env.SUPABASE_KEY;
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY) const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
export default async function fetchSyndication() { export default async function fetchSyndication() {
const { data, error } = await supabase const { data, error } = await supabase
.from('optimized_syndication') .from("optimized_syndication")
.select('syndication') .select("syndication");
if (error) { if (error) {
console.error('Error fetching search index data:', error) console.error("Error fetching search index data:", error);
return [] return [];
} }
const [{ syndication } = {}] = data const [{ syndication } = {}] = data;
return syndication?.filter(item => item['syndication'] !== null) || [] return syndication?.filter((item) => item["syndication"] !== null) || [];
} }

View file

@ -1,61 +1,65 @@
import { createClient } from '@supabase/supabase-js' import { createClient } from "@supabase/supabase-js";
const SUPABASE_URL = process.env.SUPABASE_URL const SUPABASE_URL = process.env.SUPABASE_URL;
const SUPABASE_KEY = process.env.SUPABASE_KEY const SUPABASE_KEY = process.env.SUPABASE_KEY;
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY) const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
const PAGE_SIZE = 1000 const PAGE_SIZE = 1000;
const fetchAllShows = async () => { const fetchAllShows = async () => {
let shows = [] let shows = [];
let rangeStart = 0 let rangeStart = 0;
while (true) { while (true) {
const { data, error } = await supabase const { data, error } = await supabase
.from('optimized_shows') .from("optimized_shows")
.select('*') .select("*")
.range(rangeStart, rangeStart + PAGE_SIZE - 1) .range(rangeStart, rangeStart + PAGE_SIZE - 1);
if (error) { if (error) {
console.error('Error fetching shows:', error) console.error("Error fetching shows:", error);
break break;
} }
shows = shows.concat(data) shows = shows.concat(data);
if (data.length < PAGE_SIZE) break if (data.length < PAGE_SIZE) break;
rangeStart += PAGE_SIZE rangeStart += PAGE_SIZE;
} }
return shows return shows;
} };
export default async function () { export default async function () {
try { try {
const shows = await fetchAllShows() const shows = await fetchAllShows();
const watchedShows = shows.filter(show => show['last_watched_at'] !== null) const watchedShows = shows.filter(
const episodes = watchedShows.map(show => ({ (show) => show["last_watched_at"] !== null
title: show['episode']['title'], );
year: show['year'], const episodes = watchedShows.map((show) => ({
formatted_episode: show['episode']['formatted_episode'], title: show["episode"]["title"],
url: show['episode']['url'], year: show["year"],
image: show['episode']['image'], formatted_episode: show["episode"]["formatted_episode"],
backdrop: show['episode']['backdrop'], url: show["episode"]["url"],
last_watched_at: show['episode']['last_watched_at'], image: show["episode"]["image"],
grid: show['grid'], backdrop: show["episode"]["backdrop"],
type: 'tv' last_watched_at: show["episode"]["last_watched_at"],
})) grid: show["grid"],
type: "tv",
}));
return { return {
shows, shows,
recentlyWatched: episodes.slice(0, 125), recentlyWatched: episodes.slice(0, 125),
favorites: shows.filter(show => show.favorite).sort((a, b) => a.title.localeCompare(b.title)), favorites: shows
} .filter((show) => show.favorite)
.sort((a, b) => a.title.localeCompare(b.title)),
};
} catch (error) { } catch (error) {
console.error('Error fetching and processing shows data:', error) console.error("Error fetching and processing shows data:", error);
return { return {
shows: [], shows: [],
recentlyWatched: [], recentlyWatched: [],
favorites: [], favorites: [],
} };
} }
} }