Compare commits

..

No commits in common. "bd1855a65eb8473a99d89459a0c7e443fea29fa5" and "6c659fe1d0ea18a050a6733138d963275c5eddf4" have entirely different histories.

73 changed files with 795 additions and 1391 deletions

View file

@ -1 +0,0 @@
npx lint-staged

View file

@ -4,4 +4,4 @@
"MD033": false, "MD033": false,
"MD041": false, "MD041": false,
"MD047": false "MD047": false
} }

View file

@ -1,15 +0,0 @@
# output
dist/
# deps
node_modules/
vendor/
# minified assets
*.min.js
*.min.css
*.bundle.js
*.bundle.css
# env
.env

View file

@ -1,14 +0,0 @@
{
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"quoteProps": "as-needed",
"trailingComma": "none",
"bracketSpacing": true,
"arrowParens": "always",
"endOfLine": "lf",
"proseWrap": "preserve",
"embeddedLanguageFormatting": "auto"
}

View file

@ -12,27 +12,18 @@ import { runTasksMenu } from '../lib/tasks/index.js';
process.on('unhandledRejection', (err) => handleExitError(err, 'Unhandled rejection')); process.on('unhandledRejection', (err) => handleExitError(err, 'Unhandled rejection'));
process.on('uncaughtException', (err) => handleExitError(err, 'Uncaught exception')); process.on('uncaughtException', (err) => handleExitError(err, 'Uncaught exception'));
program program.name('coryd').description('🪄 Handle tasks, run commands or jobs, download things and have fun.').version('3.2.5');
.name('coryd') program.command('init').description('Initialize CLI and populate required config.').action(async () => {
.description('🪄 Handle tasks, run commands or jobs, download things and have fun.') const { initConfig } = await import('../lib/config.js');
.version('3.2.5'); await initConfig();
program });
.command('init')
.description('Initialize CLI and populate required config.')
.action(async () => {
const { initConfig } = await import('../lib/config.js');
await initConfig();
});
program.command('run [script]').description('Run site scripts and commands.').action(runRootScript); program.command('run [script]').description('Run site scripts and commands.').action(runRootScript);
program.command('tasks').description('Handle repeated tasks.').action(runTasksMenu); program.command('tasks').description('Handle repeated tasks.').action(runTasksMenu);
program.command('jobs').description('Trigger jobs and scripts.').action(runJobsMenu); program.command('jobs').description('Trigger jobs and scripts.').action(runJobsMenu);
program program.command('download').description('Download, name and store image assets.').action(async () => {
.command('download') const { downloadAsset } = await import('../lib/download.js');
.description('Download, name and store image assets.') await downloadAsset();
.action(async () => { });
const { downloadAsset } = await import('../lib/download.js');
await downloadAsset();
});
if (process.argv.length <= 2) { if (process.argv.length <= 2) {
const ascii = figlet.textSync('coryd.dev', { horizontalLayout: 'default' }); const ascii = figlet.textSync('coryd.dev', { horizontalLayout: 'default' });

View file

@ -14,50 +14,42 @@ const ASSET_TYPES = ['poster', 'backdrop'];
dotenv.config({ path: path.resolve(__dirname, '..', '..', '.env') }); dotenv.config({ path: path.resolve(__dirname, '..', '..', '.env') });
export const initConfig = async () => { export const initConfig = async () => {
const existingConfig = (await fs.pathExists(CONFIG_PATH)) ? await fs.readJson(CONFIG_PATH) : {}; const existingConfig = await fs.pathExists(CONFIG_PATH) ? await fs.readJson(CONFIG_PATH) : {};
const config = { ...existingConfig }; const config = { ...existingConfig };
if (config.storageDir) { if (config.storageDir) {
const { updateStorage } = await inquirer.prompt([ const { updateStorage } = await inquirer.prompt([{
{ type: 'confirm',
type: 'confirm', name: 'updateStorage',
name: 'updateStorage', message: `Storage directory is already set to "${config.storageDir}". Do you want to update it?`,
message: `Storage directory is already set to "${config.storageDir}". Do you want to update it?`, default: false
default: false }]);
}
]);
if (updateStorage) { if (updateStorage) {
const { storageDir } = await inquirer.prompt([ const { storageDir } = await inquirer.prompt([{
{ name: 'storageDir',
name: 'storageDir', message: 'Where is your storage root directory?',
message: 'Where is your storage root directory?', validate: fs.pathExists
validate: fs.pathExists }]);
}
]);
config.storageDir = storageDir; config.storageDir = storageDir;
} }
} else { } else {
const { storageDir } = await inquirer.prompt([ const { storageDir } = await inquirer.prompt([{
{ name: 'storageDir',
name: 'storageDir', message: 'Where is your storage root directory?',
message: 'Where is your storage root directory?', validate: fs.pathExists
validate: fs.pathExists }]);
}
]);
config.storageDir = storageDir; config.storageDir = storageDir;
} }
const { customize } = await inquirer.prompt([ const { customize } = await inquirer.prompt([{
{ type: 'confirm',
type: 'confirm', name: 'customize',
name: 'customize', message: 'Do you want to customize default media paths?',
message: 'Do you want to customize default media paths?', default: false
default: false }]);
}
]);
config.mediaPaths = {}; config.mediaPaths = {};
@ -71,13 +63,11 @@ export const initConfig = async () => {
let subpath = defaultPath; let subpath = defaultPath;
if (customize) { if (customize) {
const response = await inquirer.prompt([ const response = await inquirer.prompt([{
{ name: 'subpath',
name: 'subpath', message: `Subpath for ${mediaType}/${assetType} (relative to storage root):`,
message: `Subpath for ${mediaType}/${assetType} (relative to storage root):`, default: defaultPath
default: defaultPath }]);
}
]);
subpath = response.subpath; subpath = response.subpath;
} }
@ -123,34 +113,28 @@ export const initConfig = async () => {
: 'Media assets/books'; : 'Media assets/books';
if (config.directus?.apiUrl) { if (config.directus?.apiUrl) {
const { updateApiUrl } = await inquirer.prompt([ const { updateApiUrl } = await inquirer.prompt([{
{ type: 'confirm',
type: 'confirm', name: 'updateApiUrl',
name: 'updateApiUrl', message: `Directus API URL is already set to "${config.directus.apiUrl}". Do you want to update it?`,
message: `Directus API URL is already set to "${config.directus.apiUrl}". Do you want to update it?`, default: false
default: false }]);
}
]);
if (updateApiUrl) { if (updateApiUrl) {
const { apiUrl } = await inquirer.prompt([ const { apiUrl } = await inquirer.prompt([{
{ name: 'apiUrl',
name: 'apiUrl', message: 'Enter your Directus instance URL:',
message: 'Enter your Directus instance URL:', validate: input => input.startsWith('http') || 'Must be a valid URL'
validate: (input) => input.startsWith('http') || 'Must be a valid URL' }]);
}
]);
config.directus.apiUrl = apiUrl; config.directus.apiUrl = apiUrl;
} }
} else { } else {
const { apiUrl } = await inquirer.prompt([ const { apiUrl } = await inquirer.prompt([{
{ name: 'apiUrl',
name: 'apiUrl', message: 'Enter your Directus URL:',
message: 'Enter your Directus URL:', validate: input => input.startsWith('http') || 'Must be a valid URL'
validate: (input) => input.startsWith('http') || 'Must be a valid URL' }]);
}
]);
config.directus = { ...(config.directus || {}), apiUrl }; config.directus = { ...(config.directus || {}), apiUrl };
} }
@ -166,7 +150,7 @@ export const initConfig = async () => {
}; };
export const loadConfig = async () => { export const loadConfig = async () => {
if (!(await fs.pathExists(CONFIG_PATH))) { if (!await fs.pathExists(CONFIG_PATH)) {
console.error('❌ Config not found. Run `coryd init` first.'); console.error('❌ Config not found. Run `coryd init` first.');
process.exit(1); process.exit(1);
} }

View file

@ -32,9 +32,9 @@ const request = async (method, endpoint, body = null) => {
method, method,
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
Authorization: `Bearer ${API_TOKEN}` Authorization: `Bearer ${API_TOKEN}`,
}, },
body: body ? JSON.stringify(body) : null body: body ? JSON.stringify(body) : null,
}); });
if (!res.ok) { if (!res.ok) {
@ -63,8 +63,8 @@ export const searchItems = async (collection, query = '', filters = {}) => {
method: 'GET', method: 'GET',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
Authorization: `Bearer ${API_TOKEN}` Authorization: `Bearer ${API_TOKEN}`,
} },
}); });
const data = await res.json(); const data = await res.json();
@ -76,7 +76,6 @@ export const searchItems = async (collection, query = '', filters = {}) => {
} }
}; };
export const updateItem = async (collection, id, values) => export const updateItem = async (collection, id, values) => await request('PATCH', `${collection}/${id}`, values);
await request('PATCH', `${collection}/${id}`, values);
export const createItem = async (collection, values) => await request('POST', collection, values); export const createItem = async (collection, values) => await request('POST', collection, values);

View file

@ -25,13 +25,13 @@ export const promptForMultipleRelations = async (collection, label = collection)
type: 'checkbox', type: 'checkbox',
name: 'selected', name: 'selected',
message: `✔ Select ${label} to add:`, message: `✔ Select ${label} to add:`,
choices: results.map((item) => ({ choices: results.map(item => ({
name: item.name || item.title || item.id, name: item.name || item.title || item.id,
value: item.id value: item.id
})) }))
}); });
selected.forEach((id) => selectedIds.add(id)); selected.forEach(id => selectedIds.add(id));
const { again } = await inquirer.prompt({ const { again } = await inquirer.prompt({
type: 'confirm', type: 'confirm',

View file

@ -7,22 +7,17 @@ import { loadConfig } from './config.js';
import { sanitizeMediaString } from './sanitize.js'; import { sanitizeMediaString } from './sanitize.js';
const __dirname = path.dirname(fileURLToPath(import.meta.url)); const __dirname = path.dirname(fileURLToPath(import.meta.url));
const downloadImage = (url, dest) => const downloadImage = (url, dest) => new Promise((resolve, reject) => {
new Promise((resolve, reject) => { const file = fs.createWriteStream(dest);
const file = fs.createWriteStream(dest);
https https.get(url, response => {
.get(url, (response) => { if (response.statusCode !== 200) return reject(new Error(`Failed to download. Status: ${response.statusCode}`));
if (response.statusCode !== 200)
return reject(new Error(`Failed to download. Status: ${response.statusCode}`));
response.pipe(file); response.pipe(file);
file.on('finish', () => file.close(resolve)); file.on('finish', () => file.close(resolve));
}) }).on('error', reject);
.on('error', reject); });
}); const isValidTMDBUrl = (val) => /^https:\/\/image\.tmdb\.org\/t\/p\//.test(val) || '❌ Must be a valid TMDB image url';
const isValidTMDBUrl = (val) =>
/^https:\/\/image\.tmdb\.org\/t\/p\//.test(val) || '❌ Must be a valid TMDB image url';
const overwriteImageDownloadPrompt = async (url, finalPath, fileName) => { const overwriteImageDownloadPrompt = async (url, finalPath, fileName) => {
await fs.ensureDir(path.dirname(finalPath)); await fs.ensureDir(path.dirname(finalPath));
@ -65,30 +60,25 @@ export const downloadWatchingImages = async () => {
return; return;
} }
const { posterUrl, backdropUrl } = await inquirer.prompt([ const { posterUrl, backdropUrl } = await inquirer.prompt([{
{ name: 'posterUrl',
name: 'posterUrl', message: 'Enter the poster url:',
message: 'Enter the poster url:', validate: (val) => {
validate: (val) => { if (!val) return true;
if (!val) return true;
return isValidTMDBUrl(val); return isValidTMDBUrl(val);
}
},
{
name: 'backdropUrl',
message: 'Enter the backdrop url:',
validate: (val) => {
if (!val) return true;
return isValidTMDBUrl(val);
}
} }
]); },
const types = [ {
{ type: 'poster', url: posterUrl }, name: 'backdropUrl',
{ type: 'backdrop', url: backdropUrl } message: 'Enter the backdrop url:',
]; validate: (val) => {
if (!val) return true;
return isValidTMDBUrl(val);
}
}]);
const types = [{ type: 'poster', url: posterUrl }, { type: 'backdrop', url: backdropUrl }];
for (const { type, url } of types) { for (const { type, url } of types) {
if (!url) continue; if (!url) continue;
@ -108,7 +98,7 @@ export const downloadWatchingImages = async () => {
await overwriteImageDownloadPrompt(url, finalPath, fileName); await overwriteImageDownloadPrompt(url, finalPath, fileName);
} }
}; }
export const downloadArtistImage = async () => { export const downloadArtistImage = async () => {
const config = await loadConfig(); const config = await loadConfig();
@ -144,7 +134,7 @@ export const downloadArtistImage = async () => {
const finalPath = path.join(targetDir, fileName); const finalPath = path.join(targetDir, fileName);
await overwriteImageDownloadPrompt(imageUrl, finalPath, fileName); await overwriteImageDownloadPrompt(imageUrl, finalPath, fileName);
}; }
export const downloadAlbumImage = async () => { export const downloadAlbumImage = async () => {
const config = await loadConfig(); const config = await loadConfig();
@ -200,8 +190,7 @@ export const downloadBookImage = async () => {
const { isbn } = await inquirer.prompt({ const { isbn } = await inquirer.prompt({
name: 'isbn', name: 'isbn',
message: 'Enter the ISBN (no spaces):', message: 'Enter the ISBN (no spaces):',
validate: (val) => validate: (val) => /^[a-zA-Z0-9-]+$/.test(val) || 'ISBN must contain only letters, numbers, or hyphens'
/^[a-zA-Z0-9-]+$/.test(val) || 'ISBN must contain only letters, numbers, or hyphens'
}); });
const { bookTitle } = await inquirer.prompt({ const { bookTitle } = await inquirer.prompt({
name: 'bookTitle', name: 'bookTitle',
@ -234,7 +223,8 @@ export const downloadBookImage = async () => {
const finalPath = path.join(targetDir, fileName); const finalPath = path.join(targetDir, fileName);
await overwriteImageDownloadPrompt(imageUrl, finalPath, fileName); await overwriteImageDownloadPrompt(imageUrl, finalPath, fileName);
}; }
export const downloadAsset = async () => { export const downloadAsset = async () => {
const { type } = await inquirer.prompt({ const { type } = await inquirer.prompt({
@ -253,4 +243,4 @@ export const downloadAsset = async () => {
} else { } else {
await downloadWatchingImages(); await downloadWatchingImages();
} }
}; }

View file

@ -1,8 +1,5 @@
export const handleExitError = (err, type = 'Unhandled error') => { export const handleExitError = (err, type = 'Unhandled error') => {
const isExit = const isExit = err?.name === 'ExitPromptError' || err?.code === 'ERR_CANCELED' || err?.message?.includes('SIGINT');
err?.name === 'ExitPromptError' ||
err?.code === 'ERR_CANCELED' ||
err?.message?.includes('SIGINT');
if (isExit) { if (isExit) {
console.log('\n👋 Exiting. Cya!\n'); console.log('\n👋 Exiting. Cya!\n');
@ -11,4 +8,4 @@ export const handleExitError = (err, type = 'Unhandled error') => {
console.error(`${type}:`, err); console.error(`${type}:`, err);
process.exit(1); process.exit(1);
}; }

View file

@ -45,14 +45,12 @@ export const runJobsMenu = async () => {
apiUrl: `${config.url}/api/artist-import.php`, apiUrl: `${config.url}/api/artist-import.php`,
tokenEnvVar: 'ARTIST_IMPORT_TOKEN', tokenEnvVar: 'ARTIST_IMPORT_TOKEN',
method: 'POST', method: 'POST',
paramsPrompt: [ paramsPrompt: [{
{ type: 'input',
type: 'input', name: 'artistId',
name: 'artistId', message: 'Enter the Navidrome artist ID:',
message: 'Enter the Navidrome artist ID:', validate: input => input ? true : 'Artist ID is required'
validate: (input) => (input ? true : 'Artist ID is required') }]
}
]
}, },
{ {
name: '📖 Import book', name: '📖 Import book',
@ -60,14 +58,12 @@ export const runJobsMenu = async () => {
apiUrl: `${config.url}/api/book-import.php`, apiUrl: `${config.url}/api/book-import.php`,
tokenEnvVar: 'BOOK_IMPORT_TOKEN', tokenEnvVar: 'BOOK_IMPORT_TOKEN',
method: 'POST', method: 'POST',
paramsPrompt: [ paramsPrompt: [{
{ type: 'input',
type: 'input', name: 'isbn',
name: 'isbn', message: 'Enter the book\'s ISBN:',
message: "Enter the book's ISBN:", validate: input => input ? true : 'ISBN is required'
validate: (input) => (input ? true : 'ISBN is required') }]
}
]
}, },
{ {
name: '📽 Import movie or show', name: '📽 Import movie or show',
@ -76,20 +72,19 @@ export const runJobsMenu = async () => {
tokenEnvVar: 'WATCHING_IMPORT_TOKEN', tokenEnvVar: 'WATCHING_IMPORT_TOKEN',
method: 'POST', method: 'POST',
tokenIncludeInParams: true, tokenIncludeInParams: true,
paramsPrompt: [ paramsPrompt: [{
{ type: 'input',
type: 'input', name: 'tmdb_id',
name: 'tmdb_id', message: 'Enter the TMDB ID:',
message: 'Enter the TMDB ID:', validate: (input) =>
validate: (input) => (/^\d+$/.test(input) ? true : 'Please enter a valid TMDB ID') /^\d+$/.test(input) ? true : 'Please enter a valid TMDB ID'
}, },
{ {
type: 'list', type: 'list',
name: 'media_type', name: 'media_type',
message: 'Is this a movie or a show?', message: 'Is this a movie or a show?',
choices: ['movie', 'show'] choices: ['movie', 'show']
} }]
]
}, },
{ {
name: '📺 Import upcoming TV seasons', name: '📺 Import upcoming TV seasons',
@ -97,20 +92,17 @@ export const runJobsMenu = async () => {
apiUrl: `${config.url}/api/seasons-import.php`, apiUrl: `${config.url}/api/seasons-import.php`,
tokenEnvVar: 'SEASONS_IMPORT_TOKEN', tokenEnvVar: 'SEASONS_IMPORT_TOKEN',
method: 'POST' method: 'POST'
} }];
];
const { selectedJob } = await inquirer.prompt([ const { selectedJob } = await inquirer.prompt([{
{ type: 'list',
type: 'list', name: 'selectedJob',
name: 'selectedJob', message: 'Select a job to run:',
message: 'Select a job to run:', choices: JOBS.map((job, index) => ({
choices: JOBS.map((job, index) => ({ name: job.name,
name: job.name, value: index
value: index }))
})) }]);
}
]);
const job = JOBS[selectedJob]; const job = JOBS[selectedJob];
@ -132,7 +124,7 @@ export const runJobsMenu = async () => {
const runCurl = async ({ const runCurl = async ({
urlEnvVar, urlEnvVar,
apiUrl = '', apiUrl = "",
tokenEnvVar, tokenEnvVar,
method = 'POST', method = 'POST',
name, name,

View file

@ -15,14 +15,12 @@ export const runRootScript = async (scriptArg) => {
let script = scriptArg; let script = scriptArg;
if (!script) { if (!script) {
const { selected } = await inquirer.prompt([ const { selected } = await inquirer.prompt([{
{ type: 'list',
type: 'list', name: 'selected',
name: 'selected', message: 'Select a script to run:',
message: 'Select a script to run:', choices: Object.keys(scripts)
choices: Object.keys(scripts) }]);
}
]);
script = selected; script = selected;
} }
@ -41,4 +39,4 @@ export const runRootScript = async (scriptArg) => {
console.error(`❌ Failed to run script "${script}"`); console.error(`❌ Failed to run script "${script}"`);
process.exit(1); process.exit(1);
} }
}; }

View file

@ -6,6 +6,6 @@ export const sanitizeMediaString = (input) => {
const slugified = cleaned.replace(/[\s-]+/g, '-').toLowerCase(); const slugified = cleaned.replace(/[\s-]+/g, '-').toLowerCase();
return slugified.replace(/^-+|-+$/g, ''); return slugified.replace(/^-+|-+$/g, '');
}; }
export const removeUrlProtocol = (url) => (url ? url.replace(/^https?:\/\//, '') : ''); export const removeUrlProtocol = (url) => url ? url.replace(/^https?:\/\//, '') : '';

View file

@ -8,7 +8,7 @@ export const addBlockedRobot = async () => {
initDirectusClient(config); initDirectusClient(config);
const robots = await searchItems('robots', '/'); const robots = await searchItems('robots', '/');
let rootRobot = robots.find((r) => r.path === '/'); let rootRobot = robots.find(r => r.path === '/');
if (!rootRobot) { if (!rootRobot) {
console.log(' No robots entry for `/` found. Creating one...'); console.log(' No robots entry for `/` found. Creating one...');
@ -23,7 +23,7 @@ export const addBlockedRobot = async () => {
const { userAgent } = await inquirer.prompt({ const { userAgent } = await inquirer.prompt({
name: 'userAgent', name: 'userAgent',
message: '🤖 Enter the user-agent string to block:', message: '🤖 Enter the user-agent string to block:',
validate: (input) => !!input || 'User-agent cannot be empty' validate: input => !!input || 'User-agent cannot be empty'
}); });
const createdAgent = await createItem('user_agents', { const createdAgent = await createItem('user_agents', {

View file

@ -1,12 +1,6 @@
import inquirer from 'inquirer'; import inquirer from 'inquirer';
import { loadConfig } from '../config.js'; import { loadConfig } from '../config.js';
import { import { initDirectusClient, getDirectusClient, searchItems, createItem, updateItem } from '../directus/client.js';
initDirectusClient,
getDirectusClient,
searchItems,
createItem,
updateItem
} from '../directus/client.js';
export const addEpisodeToShow = async () => { export const addEpisodeToShow = async () => {
const config = await loadConfig(); const config = await loadConfig();
@ -16,7 +10,7 @@ export const addEpisodeToShow = async () => {
const directus = getDirectusClient(); const directus = getDirectusClient();
const showResults = await inquirer.prompt({ const showResults = await inquirer.prompt({
name: 'query', name: 'query',
message: 'Search for a show:' message: 'Search for a show:',
}); });
const matches = await searchItems('shows', showResults.query); const matches = await searchItems('shows', showResults.query);
@ -30,35 +24,34 @@ export const addEpisodeToShow = async () => {
type: 'list', type: 'list',
name: 'showId', name: 'showId',
message: 'Select a show:', message: 'Select a show:',
choices: matches.map((s) => ({ choices: matches.map(s => ({
name: s.title || s.name || s.id, name: s.title || s.name || s.id,
value: s.id value: s.id,
})) })),
}); });
const { season_number, episode_number, plays } = await inquirer.prompt([ const { season_number, episode_number, plays } = await inquirer.prompt([
{ {
name: 'season_number', name: 'season_number',
message: 'Season number:', message: 'Season number:',
validate: (val) => !isNaN(val) validate: val => !isNaN(val),
}, },
{ {
name: 'episode_number', name: 'episode_number',
message: 'Episode number:', message: 'Episode number:',
validate: (val) => !isNaN(val) validate: val => !isNaN(val),
}, },
{ {
name: 'plays', name: 'plays',
message: 'Play count:', message: 'Play count:',
default: 0, default: 0,
validate: (val) => !isNaN(val) validate: val => !isNaN(val),
} },
]); ]);
const existing = await searchItems('episodes', `${season_number} ${episode_number}`); const existing = await searchItems('episodes', `${season_number} ${episode_number}`);
const match = existing.find( const match = existing.find(e =>
(e) => Number(e.season_number) === Number(season_number) &&
Number(e.season_number) === Number(season_number) && Number(e.episode_number) === Number(episode_number) &&
Number(e.episode_number) === Number(episode_number) && e.show === showId
e.show === showId
); );
if (match) { if (match) {
@ -66,7 +59,7 @@ export const addEpisodeToShow = async () => {
type: 'confirm', type: 'confirm',
name: 'update', name: 'update',
message: `Episode exists. Update play count from ${match.plays ?? 0} to ${plays}?`, message: `Episode exists. Update play count from ${match.plays ?? 0} to ${plays}?`,
default: true default: true,
}); });
if (update) { if (update) {
@ -81,7 +74,7 @@ export const addEpisodeToShow = async () => {
season_number: Number(season_number), season_number: Number(season_number),
episode_number: Number(episode_number), episode_number: Number(episode_number),
plays: Number(plays), plays: Number(plays),
show: showId show: showId,
}); });
console.log(`📺 Created episode S${season_number}E${episode_number}`); console.log(`📺 Created episode S${season_number}E${episode_number}`);

View file

@ -12,12 +12,12 @@ export const addLinkToShare = async () => {
{ {
name: 'title', name: 'title',
message: '📝 Title for the link:', message: '📝 Title for the link:',
validate: (input) => !!input || 'Title is required' validate: input => !!input || 'Title is required'
}, },
{ {
name: 'link', name: 'link',
message: '🔗 URL to share:', message: '🔗 URL to share:',
validate: (input) => input.startsWith('http') || 'Must be a valid URL' validate: input => input.startsWith('http') || 'Must be a valid URL'
}, },
{ {
name: 'description', name: 'description',
@ -26,7 +26,7 @@ export const addLinkToShare = async () => {
}, },
{ {
name: 'authorQuery', name: 'authorQuery',
message: '👤 Search for an author:' message: '👤 Search for an author:',
} }
]); ]);
@ -38,17 +38,13 @@ export const addLinkToShare = async () => {
type: 'confirm', type: 'confirm',
name: 'shouldCreate', name: 'shouldCreate',
message: '❌ No authors found. Do you want to create a new one?', message: '❌ No authors found. Do you want to create a new one?',
default: true default: true,
}); });
if (!shouldCreate) return; if (!shouldCreate) return;
const { name, url, mastodon, rss, json, newsletter, blogroll } = await inquirer.prompt([ const { name, url, mastodon, rss, json, newsletter, blogroll } = await inquirer.prompt([
{ { name: 'name', message: '👤 Author name:', validate: input => !!input || 'Name is required' },
name: 'name',
message: '👤 Author name:',
validate: (input) => !!input || 'Name is required'
},
{ name: 'url', message: '🔗 URL (optional):', default: '' }, { name: 'url', message: '🔗 URL (optional):', default: '' },
{ name: 'mastodon', message: '🐘 Mastodon handle (optional):', default: '' }, { name: 'mastodon', message: '🐘 Mastodon handle (optional):', default: '' },
{ name: 'rss', message: '📡 RSS feed (optional):', default: '' }, { name: 'rss', message: '📡 RSS feed (optional):', default: '' },
@ -73,13 +69,13 @@ export const addLinkToShare = async () => {
type: 'list', type: 'list',
name: 'author', name: 'author',
message: 'Select an author:', message: 'Select an author:',
choices: authorMatches.map((a) => { choices: authorMatches.map(a => {
const cleanUrl = removeUrlProtocol(a.url); const cleanUrl = removeUrlProtocol(a.url);
const display = cleanUrl ? `${a.name} (${cleanUrl})` : a.name; const display = cleanUrl ? `${a.name} (${cleanUrl})` : a.name;
return { return {
name: display, name: display,
value: a.id value: a.id,
}; };
}) })
}); });
@ -92,7 +88,7 @@ export const addLinkToShare = async () => {
while (true) { while (true) {
const { query } = await inquirer.prompt({ const { query } = await inquirer.prompt({
name: 'query', name: 'query',
message: '🏷 Search for tags (or leave blank to finish):' message: '🏷 Search for tags (or leave blank to finish):',
}); });
const trimmedQuery = query.trim(); const trimmedQuery = query.trim();
@ -110,7 +106,7 @@ export const addLinkToShare = async () => {
type: 'checkbox', type: 'checkbox',
name: 'selected', name: 'selected',
message: '✔ Select tags to add:', message: '✔ Select tags to add:',
choices: tags.map((tag) => ({ name: tag.name, value: tag.id })) choices: tags.map(tag => ({ name: tag.name, value: tag.id }))
}); });
tagIds.push(...selected); tagIds.push(...selected);
@ -119,7 +115,7 @@ export const addLinkToShare = async () => {
type: 'confirm', type: 'confirm',
name: 'again', name: 'again',
message: 'Search and select more tags?', message: 'Search and select more tags?',
default: false default: false,
}); });
if (!again) break; if (!again) break;
@ -130,7 +126,7 @@ export const addLinkToShare = async () => {
link, link,
description, description,
author, author,
link_tags: tagIds.map((tagId) => ({ tags_id: tagId })), link_tags: tagIds.map(tagId => ({ tags_id: tagId })),
date: new Date().toISOString() date: new Date().toISOString()
}); });

View file

@ -18,36 +18,34 @@ export const addPost = async () => {
initDirectusClient(config); initDirectusClient(config);
const { title, description, content, featured } = await inquirer.prompt([ const { title, description, content, featured } = await inquirer.prompt([{
{ name: 'title',
name: 'title', message: '📝 Title:',
message: '📝 Title:', validate: input => !!input || 'Title is required'
validate: (input) => !!input || 'Title is required' },
}, {
{ name: 'description',
name: 'description', message: '🗒 Description:',
message: '🗒 Description:', default: ''
default: '' },
}, {
{ name: 'content',
name: 'content', message: '📄 Content:',
message: '📄 Content:', default: ''
default: '' },
}, {
{ type: 'confirm',
type: 'confirm', name: 'featured',
name: 'featured', message: '⭐ Featured?',
message: '⭐ Featured?', default: false
default: false }]);
}
]);
let tagIds = []; let tagIds = [];
while (true) { while (true) {
const { query } = await inquirer.prompt({ const { query } = await inquirer.prompt({
name: 'query', name: 'query',
message: '🏷 Search for tags (or leave blank to finish):' message: '🏷 Search for tags (or leave blank to finish):',
}); });
const trimmedQuery = query.trim(); const trimmedQuery = query.trim();
@ -65,7 +63,7 @@ export const addPost = async () => {
type: 'checkbox', type: 'checkbox',
name: 'selected', name: 'selected',
message: '✔ Select tags to add:', message: '✔ Select tags to add:',
choices: tags.map((tag) => ({ name: tag.name, value: tag.id })) choices: tags.map(tag => ({ name: tag.name, value: tag.id }))
}); });
tagIds.push(...selected); tagIds.push(...selected);
@ -74,7 +72,7 @@ export const addPost = async () => {
type: 'confirm', type: 'confirm',
name: 'again', name: 'again',
message: 'Search and select more tags?', message: 'Search and select more tags?',
default: false default: false,
}); });
if (!again) break; if (!again) break;
@ -115,7 +113,7 @@ export const addPost = async () => {
type: 'list', type: 'list',
name: 'itemId', name: 'itemId',
message: `Select an item from ${collection}:`, message: `Select an item from ${collection}:`,
choices: results.map((item) => ({ choices: results.map(item => ({
name: item.title || item.name || item.id, name: item.title || item.name || item.id,
value: item.id value: item.id
})) }))
@ -163,16 +161,13 @@ export const addPost = async () => {
type: 'checkbox', type: 'checkbox',
name: 'selected', name: 'selected',
message: `✔ Select ${mediaType} to associate:`, message: `✔ Select ${mediaType} to associate:`,
choices: matches.map((m) => ({ choices: matches.map(m => ({
name: m.name_string || m.title || m.name || m.label || m.id, name: m.name_string || m.title || m.name || m.label || m.id,
value: m.id value: m.id
})) }))
}); });
if (selected.length) if (selected.length) associatedMediaPayload[`${mediaType}`] = selected.map(id => ({ [`${mediaType}_id`]: id }));
associatedMediaPayload[`${mediaType}`] = selected.map((id) => ({
[`${mediaType}_id`]: id
}));
} }
} }
@ -183,7 +178,7 @@ export const addPost = async () => {
content, content,
featured, featured,
date: new Date().toISOString(), date: new Date().toISOString(),
post_tags: tagIds.map((tagId) => ({ tags_id: tagId })), post_tags: tagIds.map(tagId => ({ tags_id: tagId })),
blocks: selectedBlocks, blocks: selectedBlocks,
...associatedMediaPayload ...associatedMediaPayload
}; };

View file

@ -10,7 +10,7 @@ const TASKS = [
{ name: '🔗 Add link to share', handler: addLinkToShare }, { name: '🔗 Add link to share', handler: addLinkToShare },
{ name: ' Add episode to show', handler: addEpisodeToShow }, { name: ' Add episode to show', handler: addEpisodeToShow },
{ name: '📚 Update reading progress', handler: updateReadingProgress }, { name: '📚 Update reading progress', handler: updateReadingProgress },
{ name: '🤖 Block robot', handler: addBlockedRobot } { name: '🤖 Block robot', handler: addBlockedRobot },
]; ];
export const runTasksMenu = async () => { export const runTasksMenu = async () => {
@ -19,7 +19,7 @@ export const runTasksMenu = async () => {
type: 'list', type: 'list',
name: 'task', name: 'task',
message: 'Select a task to perform:', message: 'Select a task to perform:',
choices: TASKS.map((t) => ({ name: t.name, value: t.handler })) choices: TASKS.map(t => ({ name: t.name, value: t.handler }))
} }
]); ]);

View file

@ -19,7 +19,7 @@ export const updateReadingProgress = async () => {
type: 'list', type: 'list',
name: 'bookId', name: 'bookId',
message: '📚 Select a book to update progress:', message: '📚 Select a book to update progress:',
choices: readingBooks.map((book) => { choices: readingBooks.map(book => {
const title = book.title || book.name || `Book #${book.id}`; const title = book.title || book.name || `Book #${book.id}`;
const progress = book.progress ?? 0; const progress = book.progress ?? 0;
@ -32,10 +32,10 @@ export const updateReadingProgress = async () => {
const { progress } = await inquirer.prompt({ const { progress } = await inquirer.prompt({
name: 'progress', name: 'progress',
message: '📕 New progress percentage (0100):', message: '📕 New progress percentage (0100):',
validate: (input) => { validate: input => {
const num = Number(input); const num = Number(input);
return (!isNaN(num) && num >= 0 && num <= 100) || 'Enter a number from 0 to 100'; return !isNaN(num) && num >= 0 && num <= 100 || 'Enter a number from 0 to 100';
} }
}); });

View file

@ -1,14 +1,11 @@
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 { const { albumReleases: { all }, globals: { url } } = data;
albumReleases: { all },
globals: { url }
} = data;
if (!all || all.length === 0) return ''; if (!all || all.length === 0) return "";
const events = all const events = all
.map((album) => { .map((album) => {
@ -16,30 +13,27 @@ export const albumReleasesCalendar = (collection) => {
if (isNaN(date.getTime())) return null; if (isNaN(date.getTime())) return null;
const albumUrl = album.url?.includes('http') ? album.url : `${url}${album.url}`; const albumUrl = album.url?.includes("http") ? album.url : `${url}${album.url}`;
const artistUrl = album.artist.url?.includes('http') const artistUrl = album.artist.url?.includes("http") ? album.artust.url : `${url}${album.artist.url}`;
? album.artust.url
: `${url}${album.artist.url}`;
return { return {
start: [date.getFullYear(), date.getMonth() + 1, date.getDate()], start: [date.getFullYear(), date.getMonth() + 1, date.getDate()],
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: ${albumUrl}. Read more about ${album.artist.name} at ${artistUrl}`, description: `Check out this new album release: ${albumUrl}. Read more about ${album.artist.name} at ${artistUrl}`,
url: albumUrl, url: albumUrl,
uid: `${album.release_timestamp}-${album.artist.name}-${album.title}` uid: `${album.release_timestamp}-${album.artist.name}-${album.title}`,
}; };
}) }).filter((event) => event !== null);
.filter((event) => event !== null);
const { error, value } = ics.createEvents(events, { const { error, value } = ics.createEvents(events, {
calName: 'Album releases calendar • coryd.dev' calName: "Album releases calendar • coryd.dev",
}); });
if (error) { if (error) {
console.error('Error creating events: ', error); console.error("Error creating events: ", error);
return ''; return "";
} }
return value; return value;

View file

@ -1,9 +1,9 @@
import fs from 'fs'; import fs from "fs";
import path from 'path'; import path from "path";
import { minify } from 'terser'; import { minify } from "terser";
export const minifyJsComponents = async () => { export const minifyJsComponents = async () => {
const scriptsDir = 'dist/assets/scripts'; const scriptsDir = "dist/assets/scripts";
const minifyJsFilesInDir = async (dir) => { const minifyJsFilesInDir = async (dir) => {
const files = fs.readdirSync(dir); const files = fs.readdirSync(dir);
@ -13,8 +13,8 @@ export const minifyJsComponents = async () => {
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) {

View file

@ -6,32 +6,32 @@ export default {
const $ = cheerio.load(htmlContent); const $ = cheerio.load(htmlContent);
$('a[href]').each((_, link) => { $("a[href]").each((_, link) => {
const $link = $(link); const $link = $(link);
let href = $link.attr('href'); let href = $link.attr("href");
if (href.startsWith('#')) { if (href.startsWith("#")) {
$link.replaceWith($('<span>').text($link.text())); $link.replaceWith($("<span>").text($link.text()));
} else if (!href.startsWith('http://') && !href.startsWith('https://')) { } else if (!href.startsWith("http://") && !href.startsWith("https://")) {
const normalizedDomain = domain.replace(/\/$/, ''); const normalizedDomain = domain.replace(/\/$/, '');
const normalizedHref = href.replace(/^\/+/, ''); const normalizedHref = href.replace(/^\/+/, '');
$link.attr('href', `${normalizedDomain}/${normalizedHref}`); $link.attr("href", `${normalizedDomain}/${normalizedHref}`);
} }
}); });
return $.html(); return $.html();
}, },
generatePermalink: (url, baseUrl) => { generatePermalink: (url, baseUrl) => {
if (url?.includes('http') || !baseUrl) return url; if (url?.includes("http") || !baseUrl) return url
return `${baseUrl}${url}`; return `${baseUrl}${url}`
}, },
getRemoteFileSize: async (url) => { getRemoteFileSize: async (url) => {
try { try {
const response = await fetch(url, { method: 'HEAD' }); const response = await fetch(url, { method: "HEAD" });
if (!response.ok) return 0; if (!response.ok) return 0;
const contentLength = response.headers.get('content-length'); const contentLength = response.headers.get("content-length");
if (!contentLength) return 0; if (!contentLength) return 0;
@ -40,4 +40,4 @@ export default {
return 0; return 0;
} }
} }
}; }

View file

@ -1,22 +1,21 @@
import truncateHtml from 'truncate-html'; import truncateHtml from "truncate-html";
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 = '&amp;'; const replacement = "&amp;";
return string.replace(pattern, replacement); return string.replace(pattern, replacement);
}, },
replaceQuotes: (string) => { replaceQuotes: (string) => {
if (!string) return ''; if (!string) return '';
return string.replace(/"/g, '&quot;'); return string.replace(/"/g, "&quot;");
}, },
htmlTruncate: (content, limit = 50) => htmlTruncate: (content, limit = 50) => truncateHtml(content, limit, {
truncateHtml(content, limit, {
byWords: true, byWords: true,
ellipsis: '...' ellipsis: "...",
}), }),
shuffleArray: (array) => { shuffleArray: (array) => {
const shuffled = [...array]; const shuffled = [...array];
@ -30,9 +29,9 @@ export default {
return shuffled; return shuffled;
}, },
mergeArray: (a, b) => (Array.isArray(a) && Array.isArray(b) ? [...new Set([...a, ...b])] : []), mergeArray: (a, b) => Array.isArray(a) && Array.isArray(b) ? [...new Set([...a, ...b])] : [],
pluralize: (count, string, trailing) => { pluralize: (count, string, trailing) => {
const countStr = String(count).replace(/,/g, ''); const countStr = String(count).replace(/,/g, "");
if (parseInt(countStr, 10) === 1) return string; if (parseInt(countStr, 10) === 1) return string;

View file

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

View file

@ -1,18 +1,12 @@
export default { export default {
filterBooksByStatus: (books, status) => books.filter((book) => book.status === status), filterBooksByStatus: (books, status) => books.filter((book) => book.status === status),
findFavoriteBooks: (books) => books.filter((book) => book.favorite === true), findFavoriteBooks: (books) => books.filter((book) => book.favorite === true),
bookYearLinks: (years) => bookYearLinks: (years) => years.sort((a, b) => b.value - a.value).map((year, index) =>
years `<a href="/reading/years/${year.value}">${year.value}</a>${
.sort((a, b) => b.value - a.value) index < years.length - 1 ? " • " : ""
.map( }`).join(""),
(year, index) =>
`<a href="/reading/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);
@ -20,23 +14,23 @@ export default {
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,16 +1,13 @@
export default { export default {
getMetadata: (data = {}, globals = {}, page = {}, title = '', description = '', schema = '') => { getMetadata: (data = {}, globals = {}, page = {}, title = "", description = "", schema = "") => {
const metadata = data?.metadata; const metadata = data?.metadata;
const baseUrl = globals.url || ''; const baseUrl = globals.url || "";
const ogPath = '/og/w800'; const ogPath = "/og/w800";
const image = const image = metadata?.open_graph_image || globals.metadata?.open_graph_image || globals.avatar;
metadata?.open_graph_image || globals.metadata?.open_graph_image || globals.avatar;
const rawTitle = title || page.title || metadata?.title || globals.site_name; const rawTitle = title || page.title || metadata?.title || globals.site_name;
const resolvedTitle = const resolvedTitle = rawTitle === globals.site_name ? globals.site_name : `${rawTitle}${globals.site_name}`;
rawTitle === globals.site_name ? globals.site_name : `${rawTitle}${globals.site_name}`; const resolvedDescription = description || metadata?.description || page.description || globals.site_description;
const resolvedDescription = const url = metadata?.url || (page.url ? `${baseUrl}${page.url}` : "#");
description || metadata?.description || page.description || globals.site_description;
const url = metadata?.url || (page.url ? `${baseUrl}${page.url}` : '#');
return { return {
title: resolvedTitle, title: resolvedTitle,

View file

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

View file

@ -1,23 +1,24 @@
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 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 = 'dist/assets/css/index.css'; const outputPath = "dist/assets/css/index.css";
if (inputPath.endsWith('index.css')) { if (inputPath.endsWith("index.css")) {
return async () => { return async () => {
let result = await postcss([postcssImportExtGlob, postcssImport, cssnano]).process( let result = await postcss([
inputContent, postcssImportExtGlob,
{ from: inputPath } postcssImport,
); cssnano,
]).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);
@ -25,6 +26,6 @@ export const cssConfig = (eleventyConfig) => {
return result.css; return result.css;
}; };
} }
} },
}); });
}; };

View file

@ -1,5 +1,5 @@
import { cssConfig } from './css-config.js'; import { cssConfig } from "./css-config.js";
import { htmlConfig } from './html-config.js'; import { htmlConfig } from "./html-config.js";
import { markdownLib } from './markdown.js'; import { markdownLib } from "./markdown.js";
export default { cssConfig, htmlConfig, markdownLib }; export default { cssConfig, htmlConfig, markdownLib };

View file

@ -1,15 +1,15 @@
import markdownIt from 'markdown-it'; import markdownIt from "markdown-it";
import markdownItAnchor from 'markdown-it-anchor'; import markdownItAnchor from "markdown-it-anchor";
import markdownItFootnote from 'markdown-it-footnote'; import markdownItFootnote from "markdown-it-footnote";
import markdownItLinkAttributes from 'markdown-it-link-attributes'; import markdownItLinkAttributes from "markdown-it-link-attributes";
import markdownItPrism from 'markdown-it-prism'; import markdownItPrism from "markdown-it-prism";
export const markdownLib = markdownIt({ html: true, linkify: true }) export const markdownLib = markdownIt({ html: true, linkify: true })
.use(markdownItAnchor, { .use(markdownItAnchor, {
level: [1, 2], level: [1, 2],
permalink: markdownItAnchor.permalink.headerLink({ permalink: markdownItAnchor.permalink.headerLink({
safariReaderFix: true safariReaderFix: true,
}) }),
}) })
.use(markdownItLinkAttributes, [ .use(markdownItLinkAttributes, [
{ {
@ -17,9 +17,9 @@ export const markdownLib = markdownIt({ html: true, linkify: true })
return href.match(/^https?:\/\//); return href.match(/^https?:\/\//);
}, },
attrs: { attrs: {
rel: 'noopener' rel: "noopener",
} },
} },
]) ])
.use(markdownItFootnote) .use(markdownItFootnote)
.use(markdownItPrism); .use(markdownItPrism);

View file

@ -1,13 +1,13 @@
import { createRequire } from 'module'; import { createRequire } from "module";
import 'dotenv/config'; import "dotenv/config";
import filters from './config/filters/index.js'; import filters from "./config/filters/index.js";
import tablerIcons from '@cdransf/eleventy-plugin-tabler-icons'; import tablerIcons from "@cdransf/eleventy-plugin-tabler-icons";
import { minifyJsComponents } from './config/events/minify-js.js'; import { minifyJsComponents } from "./config/events/minify-js.js";
import { albumReleasesCalendar } from './config/collections/index.js'; import { albumReleasesCalendar } from "./config/collections/index.js";
import plugins from './config/plugins/index.js'; import plugins from "./config/plugins/index.js";
const require = createRequire(import.meta.url); const require = createRequire(import.meta.url);
const appVersion = require('./package.json').version; const appVersion = require("./package.json").version;
export default async function (eleventyConfig) { export default async function (eleventyConfig) {
eleventyConfig.addPlugin(tablerIcons); eleventyConfig.addPlugin(tablerIcons);
@ -18,22 +18,23 @@ export default async function (eleventyConfig) {
eleventyConfig.configureErrorReporting({ allowMissingExtensions: true }); eleventyConfig.configureErrorReporting({ allowMissingExtensions: true });
eleventyConfig.setLiquidOptions({ jsTruthy: true }); eleventyConfig.setLiquidOptions({ jsTruthy: true });
eleventyConfig.watchIgnores.add('queries/**'); eleventyConfig.watchIgnores.add("queries/**");
eleventyConfig.addPassthroughCopy('src/assets'); eleventyConfig.addPassthroughCopy("src/assets");
eleventyConfig.addPassthroughCopy('api'); eleventyConfig.addPassthroughCopy("api");
eleventyConfig.addPassthroughCopy('bootstrap.php'); eleventyConfig.addPassthroughCopy("bootstrap.php");
eleventyConfig.addPassthroughCopy({ eleventyConfig.addPassthroughCopy({
'node_modules/minisearch/dist/umd/index.js': 'assets/scripts/components/minisearch.js', "node_modules/minisearch/dist/umd/index.js":
'node_modules/youtube-video-element/dist/youtube-video-element.js': "assets/scripts/components/minisearch.js",
'assets/scripts/components/youtube-video-element.js' "node_modules/youtube-video-element/dist/youtube-video-element.js":
"assets/scripts/components/youtube-video-element.js",
}); });
eleventyConfig.addCollection('albumReleasesCalendar', albumReleasesCalendar); eleventyConfig.addCollection("albumReleasesCalendar", albumReleasesCalendar);
eleventyConfig.setLibrary('md', plugins.markdownLib); eleventyConfig.setLibrary("md", plugins.markdownLib);
eleventyConfig.addLiquidFilter('markdown', (content) => { eleventyConfig.addLiquidFilter("markdown", (content) => {
if (!content) return; if (!content) return;
return plugins.markdownLib.render(content); return plugins.markdownLib.render(content);
}); });
@ -42,17 +43,17 @@ export default async function (eleventyConfig) {
eleventyConfig.addLiquidFilter(filterName, filters[filterName]); eleventyConfig.addLiquidFilter(filterName, filters[filterName]);
}); });
eleventyConfig.addShortcode('appVersion', () => appVersion); eleventyConfig.addShortcode("appVersion", () => appVersion);
eleventyConfig.on('afterBuild', minifyJsComponents); eleventyConfig.on("afterBuild", minifyJsComponents);
return { return {
dir: { dir: {
input: 'src', input: "src",
includes: 'includes', includes: "includes",
layouts: 'layouts', layouts: "layouts",
data: 'data', data: "data",
output: 'dist' output: "dist",
} }
}; };
} }

542
package-lock.json generated
View file

@ -1,12 +1,12 @@
{ {
"name": "coryd.dev", "name": "coryd.dev",
"version": "10.1.4", "version": "10.0.4",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "coryd.dev", "name": "coryd.dev",
"version": "10.1.4", "version": "10.0.4",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"minisearch": "^7.1.2", "minisearch": "^7.1.2",
@ -21,9 +21,7 @@
"cssnano": "^7.0.7", "cssnano": "^7.0.7",
"dotenv": "16.5.0", "dotenv": "16.5.0",
"html-minifier-terser": "7.2.0", "html-minifier-terser": "7.2.0",
"husky": "9.1.7",
"ics": "^3.8.1", "ics": "^3.8.1",
"lint-staged": "16.1.1",
"markdown-it": "^14.1.0", "markdown-it": "^14.1.0",
"markdown-it-anchor": "^9.2.0", "markdown-it-anchor": "^9.2.0",
"markdown-it-footnote": "^4.0.0", "markdown-it-footnote": "^4.0.0",
@ -32,7 +30,6 @@
"postcss": "^8.5.5", "postcss": "^8.5.5",
"postcss-import": "^16.1.0", "postcss-import": "^16.1.0",
"postcss-import-ext-glob": "^2.1.1", "postcss-import-ext-glob": "^2.1.1",
"prettier": "3.5.3",
"rimraf": "^6.0.1", "rimraf": "^6.0.1",
"terser": "^5.42.0", "terser": "^5.42.0",
"truncate-html": "^1.2.2" "truncate-html": "^1.2.2"
@ -295,62 +292,6 @@
"node": ">=12" "node": ">=12"
} }
}, },
"node_modules/@isaacs/cliui/node_modules/ansi-styles": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/@isaacs/cliui/node_modules/emoji-regex": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
"dev": true,
"license": "MIT"
},
"node_modules/@isaacs/cliui/node_modules/string-width": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
"dev": true,
"license": "MIT",
"dependencies": {
"eastasianwidth": "^0.2.0",
"emoji-regex": "^9.2.2",
"strip-ansi": "^7.0.1"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@isaacs/cliui/node_modules/wrap-ansi": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-styles": "^6.1.0",
"string-width": "^5.0.1",
"strip-ansi": "^7.0.1"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/@jridgewell/gen-mapping": { "node_modules/@jridgewell/gen-mapping": {
"version": "0.3.8", "version": "0.3.8",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
@ -567,22 +508,6 @@
"node": ">=0.4.0" "node": ">=0.4.0"
} }
}, },
"node_modules/ansi-escapes": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz",
"integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"environment": "^1.0.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/ansi-regex": { "node_modules/ansi-regex": {
"version": "6.1.0", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
@ -986,39 +911,6 @@
"node": ">= 10.0" "node": ">= 10.0"
} }
}, },
"node_modules/cli-cursor": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz",
"integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==",
"dev": true,
"license": "MIT",
"dependencies": {
"restore-cursor": "^5.0.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/cli-truncate": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz",
"integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==",
"dev": true,
"license": "MIT",
"dependencies": {
"slice-ansi": "^5.0.0",
"string-width": "^7.0.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/cliui": { "node_modules/cliui": {
"version": "8.0.1", "version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
@ -1051,16 +943,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/cliui/node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/cliui/node_modules/string-width": { "node_modules/cliui/node_modules/string-width": {
"version": "4.2.3", "version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@ -1134,13 +1016,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/colorette": {
"version": "2.0.20",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
"integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
"dev": true,
"license": "MIT"
},
"node_modules/commander": { "node_modules/commander": {
"version": "10.0.1", "version": "10.0.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
@ -1540,9 +1415,9 @@
"license": "ISC" "license": "ISC"
}, },
"node_modules/emoji-regex": { "node_modules/emoji-regex": {
"version": "10.4.0", "version": "9.2.2",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
"integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
@ -1583,19 +1458,6 @@
"url": "https://github.com/fb55/entities?sponsor=1" "url": "https://github.com/fb55/entities?sponsor=1"
} }
}, },
"node_modules/environment": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz",
"integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/errno": { "node_modules/errno": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/errno/-/errno-1.0.0.tgz", "resolved": "https://registry.npmjs.org/errno/-/errno-1.0.0.tgz",
@ -1684,9 +1546,9 @@
} }
}, },
"node_modules/eventemitter3": { "node_modules/eventemitter3": {
"version": "5.0.1", "version": "4.0.7",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
"integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
@ -1880,19 +1742,6 @@
"node": "6.* || 8.* || >= 10.*" "node": "6.* || 8.* || >= 10.*"
} }
}, },
"node_modules/get-east-asian-width": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz",
"integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/glob": { "node_modules/glob": {
"version": "11.0.3", "version": "11.0.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-11.0.3.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.3.tgz",
@ -2091,22 +1940,6 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/husky": {
"version": "9.1.7",
"resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz",
"integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==",
"dev": true,
"license": "MIT",
"bin": {
"husky": "bin.js"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/typicode"
}
},
"node_modules/iconv-lite": { "node_modules/iconv-lite": {
"version": "0.6.3", "version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
@ -2226,16 +2059,13 @@
} }
}, },
"node_modules/is-fullwidth-code-point": { "node_modules/is-fullwidth-code-point": {
"version": "4.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=12" "node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/is-glob": { "node_modules/is-glob": {
@ -2367,57 +2197,6 @@
"uc.micro": "^2.0.0" "uc.micro": "^2.0.0"
} }
}, },
"node_modules/lint-staged": {
"version": "16.1.1",
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.1.1.tgz",
"integrity": "sha512-kVZvRAHw9WuufENnwuZLiB1X/8B8YpGszzjMET0bP+uJSjjB7KXeaX2ckYRtQyHfeQdCWMc6tRK34t4geHL9sg==",
"dev": true,
"license": "MIT",
"dependencies": {
"chalk": "^5.4.1",
"commander": "^14.0.0",
"debug": "^4.4.1",
"lilconfig": "^3.1.3",
"listr2": "^8.3.3",
"micromatch": "^4.0.8",
"nano-spawn": "^1.0.2",
"pidtree": "^0.6.0",
"string-argv": "^0.3.2",
"yaml": "^2.8.0"
},
"bin": {
"lint-staged": "bin/lint-staged.js"
},
"engines": {
"node": ">=20.17"
},
"funding": {
"url": "https://opencollective.com/lint-staged"
}
},
"node_modules/lint-staged/node_modules/chalk": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz",
"integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^12.17.0 || ^14.13 || >=16.0.0"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/lint-staged/node_modules/commander": {
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-14.0.0.tgz",
"integrity": "sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=20"
}
},
"node_modules/liquidjs": { "node_modules/liquidjs": {
"version": "10.21.1", "version": "10.21.1",
"resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-10.21.1.tgz", "resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-10.21.1.tgz",
@ -2446,24 +2225,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/listr2": {
"version": "8.3.3",
"resolved": "https://registry.npmjs.org/listr2/-/listr2-8.3.3.tgz",
"integrity": "sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"cli-truncate": "^4.0.0",
"colorette": "^2.0.20",
"eventemitter3": "^5.0.1",
"log-update": "^6.1.0",
"rfdc": "^1.4.1",
"wrap-ansi": "^9.0.0"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/lodash": { "node_modules/lodash": {
"version": "4.17.21", "version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
@ -2485,72 +2246,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/log-update": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz",
"integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-escapes": "^7.0.0",
"cli-cursor": "^5.0.0",
"slice-ansi": "^7.1.0",
"strip-ansi": "^7.1.0",
"wrap-ansi": "^9.0.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/log-update/node_modules/ansi-styles": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/log-update/node_modules/is-fullwidth-code-point": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz",
"integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==",
"dev": true,
"license": "MIT",
"dependencies": {
"get-east-asian-width": "^1.0.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/log-update/node_modules/slice-ansi": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz",
"integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-styles": "^6.2.1",
"is-fullwidth-code-point": "^5.0.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/chalk/slice-ansi?sponsor=1"
}
},
"node_modules/lower-case": { "node_modules/lower-case": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
@ -2753,19 +2448,6 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/mimic-function": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz",
"integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/minimatch": { "node_modules/minimatch": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@ -2826,19 +2508,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/nano-spawn": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-1.0.2.tgz",
"integrity": "sha512-21t+ozMQDAL/UGgQVBbZ/xXvNO10++ZPuTmKRO8k9V3AClVRht49ahtDjfY8l1q6nSHOrE5ASfthzH3ol6R/hg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=20.17"
},
"funding": {
"url": "https://github.com/sindresorhus/nano-spawn?sponsor=1"
}
},
"node_modules/nanoid": { "node_modules/nanoid": {
"version": "3.3.11", "version": "3.3.11",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
@ -2960,22 +2629,6 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/onetime": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz",
"integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"mimic-function": "^5.0.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/p-finally": { "node_modules/p-finally": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
@ -3003,13 +2656,6 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/p-queue/node_modules/eventemitter3": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
"dev": true,
"license": "MIT"
},
"node_modules/p-timeout": { "node_modules/p-timeout": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz",
@ -3163,19 +2809,6 @@
"url": "https://github.com/sponsors/jonschlinkert" "url": "https://github.com/sponsors/jonschlinkert"
} }
}, },
"node_modules/pidtree": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz",
"integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==",
"dev": true,
"license": "MIT",
"bin": {
"pidtree": "bin/pidtree.js"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/pify": { "node_modules/pify": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
@ -3859,22 +3492,6 @@
"node": ">=12" "node": ">=12"
} }
}, },
"node_modules/prettier": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
"dev": true,
"license": "MIT",
"bin": {
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/prismjs": { "node_modules/prismjs": {
"version": "1.30.0", "version": "1.30.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz",
@ -4017,23 +3634,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/restore-cursor": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz",
"integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==",
"dev": true,
"license": "MIT",
"dependencies": {
"onetime": "^7.0.0",
"signal-exit": "^4.1.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/reusify": { "node_modules/reusify": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
@ -4045,13 +3645,6 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/rfdc": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
"dev": true,
"license": "MIT"
},
"node_modules/rimraf": { "node_modules/rimraf": {
"version": "6.0.1", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz",
@ -4243,36 +3836,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/slice-ansi": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz",
"integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-styles": "^6.0.0",
"is-fullwidth-code-point": "^4.0.0"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/slice-ansi?sponsor=1"
}
},
"node_modules/slice-ansi/node_modules/ansi-styles": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/slugify": { "node_modules/slugify": {
"version": "1.6.6", "version": "1.6.6",
"resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz", "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz",
@ -4344,29 +3907,19 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/string-argv": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz",
"integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.6.19"
}
},
"node_modules/string-width": { "node_modules/string-width": {
"version": "7.2.0", "version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
"integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"emoji-regex": "^10.3.0", "eastasianwidth": "^0.2.0",
"get-east-asian-width": "^1.0.0", "emoji-regex": "^9.2.2",
"strip-ansi": "^7.1.0" "strip-ansi": "^7.0.1"
}, },
"engines": { "engines": {
"node": ">=18" "node": ">=12"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
@ -4405,16 +3958,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/string-width-cjs/node_modules/strip-ansi": { "node_modules/string-width-cjs/node_modules/strip-ansi": {
"version": "6.0.1", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
@ -4847,18 +4390,18 @@
} }
}, },
"node_modules/wrap-ansi": { "node_modules/wrap-ansi": {
"version": "9.0.0", "version": "8.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
"integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"ansi-styles": "^6.2.1", "ansi-styles": "^6.1.0",
"string-width": "^7.0.0", "string-width": "^5.0.1",
"strip-ansi": "^7.1.0" "strip-ansi": "^7.0.1"
}, },
"engines": { "engines": {
"node": ">=18" "node": ">=12"
}, },
"funding": { "funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1" "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
@ -4900,16 +4443,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/wrap-ansi-cjs/node_modules/string-width": { "node_modules/wrap-ansi-cjs/node_modules/string-width": {
"version": "4.2.3", "version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@ -4983,19 +4516,6 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/yaml": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz",
"integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==",
"dev": true,
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
},
"engines": {
"node": ">= 14.6"
}
},
"node_modules/yargs": { "node_modules/yargs": {
"version": "17.7.2", "version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
@ -5042,16 +4562,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/yargs/node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/yargs/node_modules/string-width": { "node_modules/yargs/node_modules/string-width": {
"version": "4.2.3", "version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",

View file

@ -1,6 +1,6 @@
{ {
"name": "coryd.dev", "name": "coryd.dev",
"version": "10.1.4", "version": "10.0.4",
"description": "The source for my personal site. Built using 11ty (and other tools).", "description": "The source for my personal site. Built using 11ty (and other tools).",
"type": "module", "type": "module",
"engines": { "engines": {
@ -13,14 +13,9 @@
"php": "export $(grep -v '^#' .env | xargs) && php -d error_reporting=E_ALL^E_DEPRECATED -S localhost:8080 -t dist", "php": "export $(grep -v '^#' .env | xargs) && php -d error_reporting=E_ALL^E_DEPRECATED -S localhost:8080 -t dist",
"build": "eleventy", "build": "eleventy",
"clean": "rimraf dist .cache", "clean": "rimraf dist .cache",
"format": "npx prettier --write '**/*.{js,ts,json,css,md}'",
"update": "composer update && npm upgrade && npm --prefix cli upgrade && ncu && ncu --cwd cli", "update": "composer update && npm upgrade && npm --prefix cli upgrade && ncu && ncu --cwd cli",
"setup": "sh ./scripts/setup.sh", "setup": "sh ./scripts/setup.sh",
"setup:deploy": "sh ./scripts/setup.sh --deploy", "setup:deploy": "sh ./scripts/setup.sh --deploy"
"prepare": "husky"
},
"lint-staged": {
"*.{js,json,css,md}": "prettier --write"
}, },
"keywords": [ "keywords": [
"11ty", "11ty",
@ -46,9 +41,7 @@
"cssnano": "^7.0.7", "cssnano": "^7.0.7",
"dotenv": "16.5.0", "dotenv": "16.5.0",
"html-minifier-terser": "7.2.0", "html-minifier-terser": "7.2.0",
"husky": "9.1.7",
"ics": "^3.8.1", "ics": "^3.8.1",
"lint-staged": "16.1.1",
"markdown-it": "^14.1.0", "markdown-it": "^14.1.0",
"markdown-it-anchor": "^9.2.0", "markdown-it-anchor": "^9.2.0",
"markdown-it-footnote": "^4.0.0", "markdown-it-footnote": "^4.0.0",
@ -57,7 +50,6 @@
"postcss": "^8.5.5", "postcss": "^8.5.5",
"postcss-import": "^16.1.0", "postcss-import": "^16.1.0",
"postcss-import-ext-glob": "^2.1.1", "postcss-import-ext-glob": "^2.1.1",
"prettier": "3.5.3",
"rimraf": "^6.0.1", "rimraf": "^6.0.1",
"terser": "^5.42.0", "terser": "^5.42.0",
"truncate-html": "^1.2.2" "truncate-html": "^1.2.2"

View file

@ -69,9 +69,6 @@ export $(grep -v '^#' .env | xargs)
echo "${COLOR_BLUE}📦 Installing root project dependencies...${COLOR_RESET}" echo "${COLOR_BLUE}📦 Installing root project dependencies...${COLOR_RESET}"
npm install npm install
echo "${COLOR_BLUE}🐺 Initializing Husky Git hooks...${COLOR_RESET}"
npm run prepare
echo "${COLOR_BLUE}📦 Installing PHP dependencies (composer)...${COLOR_RESET}" echo "${COLOR_BLUE}📦 Installing PHP dependencies (composer)...${COLOR_RESET}"
composer install composer install

View file

@ -1,52 +1,52 @@
class SelectPagination extends HTMLElement { class SelectPagination extends HTMLElement {
static register(tagName = 'select-pagination') { static register(tagName = 'select-pagination') {
if ('customElements' in window) customElements.define(tagName, this); if ("customElements" in window) customElements.define(tagName, this)
} }
static get observedAttributes() { static get observedAttributes() {
return ['data-base-index']; return ['data-base-index']
} }
get baseIndex() { get baseIndex() {
return parseInt(this.getAttribute('data-base-index') || '0', 10); return parseInt(this.getAttribute('data-base-index') || '0', 10)
} }
connectedCallback() { connectedCallback() {
if (this.shadowRoot) return; if (this.shadowRoot) return
this.attachShadow({ mode: 'open' }).appendChild(document.createElement('slot')); this.attachShadow({ mode: 'open' }).appendChild(document.createElement('slot'))
const uriSegments = window.location.pathname.split('/').filter(Boolean); const uriSegments = window.location.pathname.split('/').filter(Boolean)
let pageNumber = this.extractPageNumber(uriSegments); let pageNumber = this.extractPageNumber(uriSegments)
if (pageNumber === null) pageNumber = this.baseIndex; if (pageNumber === null) pageNumber = this.baseIndex
this.control = this.querySelector('select'); this.control = this.querySelector('select')
this.control.value = pageNumber.toString(); this.control.value = pageNumber.toString()
this.control.addEventListener('change', (event) => { this.control.addEventListener('change', (event) => {
pageNumber = parseInt(event.target.value); pageNumber = parseInt(event.target.value)
const updatedUrlSegments = this.updateUrlSegments(uriSegments, pageNumber); const updatedUrlSegments = this.updateUrlSegments(uriSegments, pageNumber)
window.location.href = `${window.location.origin}/${updatedUrlSegments.join('/')}`; window.location.href = `${window.location.origin}/${updatedUrlSegments.join('/')}`
}); })
} }
extractPageNumber(segments) { extractPageNumber(segments) {
const lastSegment = segments[segments.length - 1]; const lastSegment = segments[segments.length - 1]
return !isNaN(lastSegment) ? parseInt(lastSegment) : null; return !isNaN(lastSegment) ? parseInt(lastSegment) : null
} }
updateUrlSegments(segments, pageNumber) { updateUrlSegments(segments, pageNumber) {
const lastIsPage = !isNaN(segments[segments.length - 1]); const lastIsPage = !isNaN(segments[segments.length - 1])
if (lastIsPage) { if (lastIsPage) {
segments[segments.length - 1] = pageNumber.toString(); segments[segments.length - 1] = pageNumber.toString()
} else { } else {
segments.push(pageNumber.toString()); segments.push(pageNumber.toString())
} }
if (pageNumber === this.baseIndex) segments.pop(); if (pageNumber === this.baseIndex) segments.pop()
return segments; return segments
} }
} }
SelectPagination.register(); SelectPagination.register()

View file

@ -21,9 +21,7 @@ window.addEventListener('load', () => {
if (isDynamic && !isLoaded) { if (isDynamic && !isLoaded) {
const markdownFields = dialog.dataset.markdown || ''; const markdownFields = dialog.dataset.markdown || '';
try { try {
const res = await fetch( const res = await fetch(`/api/query.php?data=${isDynamic}&id=${dialogId}&markdown=${encodeURIComponent(markdownFields)}`);
`/api/query.php?data=${isDynamic}&id=${dialogId}&markdown=${encodeURIComponent(markdownFields)}`
);
const [data] = await res.json(); const [data] = await res.json();
const firstField = markdownFields.split(',')[0]?.trim(); const firstField = markdownFields.split(',')[0]?.trim();
const html = data?.[`${firstField}_html`] || '<p>No notes available.</p>'; const html = data?.[`${firstField}_html`] || '<p>No notes available.</p>';

View file

@ -7,23 +7,22 @@ const staticAssets = [
'/assets/fonts/dmi.woff2', '/assets/fonts/dmi.woff2',
'/assets/fonts/ml.woff2', '/assets/fonts/ml.woff2',
'/assets/scripts/index.js', '/assets/scripts/index.js',
'/assets/scripts/components/select-pagination.js' '/assets/scripts/components/select-pagination.js',
]; ];
self.addEventListener('install', (event) => { self.addEventListener('install', event => {
event.waitUntil( event.waitUntil(
caches caches.open(cacheName)
.open(cacheName) .then(cache => cache.addAll(staticAssets))
.then((cache) => cache.addAll(staticAssets))
.then(() => self.skipWaiting()) .then(() => self.skipWaiting())
); );
}); });
self.addEventListener('activate', (event) => { self.addEventListener('activate', event => {
event.waitUntil( event.waitUntil(
(async () => { (async () => {
const keys = await caches.keys(); const keys = await caches.keys();
await Promise.all(keys.filter((key) => key !== cacheName).map((key) => caches.delete(key))); await Promise.all(keys.filter(key => key !== cacheName).map(key => caches.delete(key)));
if (self.registration.navigationPreload) await self.registration.navigationPreload.enable(); if (self.registration.navigationPreload) await self.registration.navigationPreload.enable();
@ -32,7 +31,7 @@ self.addEventListener('activate', (event) => {
); );
}); });
self.addEventListener('fetch', (event) => { self.addEventListener('fetch', event => {
const request = event.request; const request = event.request;
if (request.method !== 'GET') return; if (request.method !== 'GET') return;
@ -52,5 +51,6 @@ self.addEventListener('fetch', (event) => {
return; return;
} }
event.respondWith(caches.match(request).then((response) => response || fetch(request))); event.respondWith(caches.match(request).then(response => response || fetch(request))
);
}); });

View file

@ -1,46 +1,46 @@
@font-face { @font-face {
font-family: 'Space Grotesk'; font-family: "Space Grotesk";
src: url('/assets/fonts/sg.woff2') format('woff2'); src: url("/assets/fonts/sg.woff2") format("woff2");
font-weight: 700; font-weight: 700;
font-style: normal; font-style: normal;
font-display: swap; font-display: swap;
} }
@font-face { @font-face {
font-family: 'DM Sans'; font-family: "DM Sans";
src: url('/assets/fonts/dm-regular.woff2') format('woff2'); src: url("/assets/fonts/dm-regular.woff2") format("woff2");
font-weight: 400; font-weight: 400;
font-style: normal; font-style: normal;
font-display: swap; font-display: swap;
} }
@font-face { @font-face {
font-family: 'DM Sans'; font-family: "DM Sans";
src: url('/assets/fonts/dm-bold.woff2') format('woff2'); src: url("/assets/fonts/dm-bold.woff2") format("woff2");
font-weight: 700; font-weight: 700;
font-style: normal; font-style: normal;
font-display: swap; font-display: swap;
} }
@font-face { @font-face {
font-family: 'DM Sans'; font-family: "DM Sans";
src: url('/assets/fonts/dm-regular-italic.woff2') format('woff2'); src: url("/assets/fonts/dm-regular-italic.woff2") format("woff2");
font-weight: 400; font-weight: 400;
font-style: italic; font-style: italic;
font-display: optional; font-display: optional;
} }
@font-face { @font-face {
font-family: 'DM Sans'; font-family: "DM Sans";
src: url('/assets/fonts/dm-bold-italic.woff2') format('woff2'); src: url("/assets/fonts/dm-bold-italic.woff2") format("woff2");
font-weight: 700; font-weight: 700;
font-style: italic; font-style: italic;
font-display: optional; font-display: optional;
} }
@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;

View file

@ -82,7 +82,7 @@ img {
border-radius: var(--border-radius-slight); border-radius: var(--border-radius-slight);
&.image-banner { &.image-banner {
border: var(--border-gray); border: var(--border-gray);
height: auto; height: auto;
width: var(--sizing-full); width: var(--sizing-full);
margin: var(--margin-vertical-base-horizontal-zero); margin: var(--margin-vertical-base-horizontal-zero);
@ -302,9 +302,7 @@ a {
} }
/* headers */ /* headers */
h1, h1, h2, h3 {
h2,
h3 {
font-family: var(--font-heading); font-family: var(--font-heading);
font-weight: var(--font-weight-bold); font-weight: var(--font-weight-bold);
line-height: var(--line-height-md); line-height: var(--line-height-md);
@ -442,7 +440,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;
@ -494,7 +492,7 @@ main {
main, main,
footer { footer {
width: calc(var(--sizing-full) * 0.8); width: calc(var(--sizing-full) * .8);
@media screen and (min-width: 768px) { @media screen and (min-width: 768px) {
max-width: 768px; max-width: 768px;

View file

@ -71,10 +71,9 @@
--border-gray: 1px solid var(--gray-light); --border-gray: 1px solid var(--gray-light);
/* fonts */ /* fonts */
--font-body: 'DM Sans', Helvetica Neue, Helvetica, Arial, system-ui, sans-serif; --font-body: "DM Sans", Helvetica Neue, Helvetica, Arial, system-ui, sans-serif;
--font-heading: 'Space Grotesk', 'Arial Black', 'Arial Bold', Gadget, sans-serif; --font-heading: "Space Grotesk", "Arial Black", "Arial Bold", Gadget, sans-serif;
--font-code: --font-code: "MonoLisa", SFMono-Regular, Menlo, Consolas, Monaco, Liberation Mono, Lucida Console, monospace;
'MonoLisa', SFMono-Regular, Menlo, Consolas, Monaco, Liberation Mono, Lucida Console, monospace;
/* text */ /* text */
--font-size-xs: 0.7rem; --font-size-xs: 0.7rem;
@ -153,7 +152,7 @@
} }
/* transitions */ /* transitions */
--transition-ease-in-out: cubic-bezier(0.4, 0, 0.2, 1); --transition-ease-in-out: cubic-bezier(.4, 0, .2, 1);
--transition-duration-default: 300ms; --transition-duration-default: 300ms;
/* transforms */ /* transforms */
@ -166,10 +165,10 @@
--button-offset-hover: 0; --button-offset-hover: 0;
} }
/* filters */ /* filters */
--filter-image-default: contrast(1) saturate(1) brightness(1); --filter-image-default: contrast(1) saturate(1) brightness(1);
--filter-image-light: contrast(1.2) saturate(1.2) brightness(0.9); --filter-image-light: contrast(1.2) saturate(1.2) brightness(0.9);
--filter-image-dark: contrast(1.1) saturate(1.1) brightness(1.1); --filter-image-dark: contrast(1.1) saturate(1.1) brightness(1.1);
/* svgs */ /* svgs */
--stroke-width-default: 1.3; --stroke-width-default: 1.3;

View file

@ -1,4 +1,4 @@
@import url('./text-toggle.css'); @import url("./text-toggle.css");
button:not([data-dialog-button]), button:not([data-dialog-button]),
.button { .button {

View file

@ -1,23 +1,11 @@
@keyframes fadeIn { @keyframes fadeIn {
from { from { opacity: 0; transform: scale(0.95); }
opacity: 0; to { opacity: 1; transform: scale(1); }
transform: scale(0.95);
}
to {
opacity: 1;
transform: scale(1);
}
} }
@keyframes fadeOut { @keyframes fadeOut {
from { from { opacity: 1; transform: scale(1); }
opacity: 1; to { opacity: 0; transform: scale(0.95); }
transform: scale(1);
}
to {
opacity: 0;
transform: scale(0.95);
}
} }
.dialog-open, .dialog-open,
@ -26,8 +14,7 @@
vertical-align: middle; vertical-align: middle;
color: var(--section-color, var(--accent-color)); color: var(--section-color, var(--accent-color));
transform: var(--transform-icon-default); transform: var(--transform-icon-default);
transition: transition: color var(--transition-duration-default) var(--transition-ease-in-out),
color var(--transition-duration-default) var(--transition-ease-in-out),
transform var(--transition-duration-default) var(--transition-ease-in-out); transform var(--transition-duration-default) var(--transition-ease-in-out);
&:is(:hover, :focus, :active) { &:is(:hover, :focus, :active) {
@ -74,9 +61,9 @@ dialog {
} }
@media (min-width: 768px) { @media (min-width: 768px) {
max-width: calc(var(--sizing-full) * 0.6); max-width: calc(var(--sizing-full) * .6);
max-height: calc(var(--sizing-full) * 0.75); max-height: calc(var(--sizing-full) * .75);
inset: calc(var(--sizing-full) * 0.125) calc(var(--sizing-full) * 0.2); inset: calc(var(--sizing-full) * .125) calc(var(--sizing-full) * .2);
border: var(--border-gray); border: var(--border-gray);
} }

View file

@ -1,18 +1,18 @@
::placeholder { ::placeholder {
color: var(--text-color); color: var(--text-color);
opacity: 0.5; opacity: .5;
} }
input { input {
accent-color: var(--section-color, var(--accent-color)); accent-color: var(--section-color, var(--accent-color));
} }
input:not([type='button']):not([type='submit']):not([type='reset']):not([type='checkbox']), input:not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="checkbox"]),
textarea { textarea {
width: var(--sizing-full); width: var(--sizing-full);
} }
input:not([type='button']):not([type='submit']):not([type='reset']):not([type='checkbox']), input:not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="checkbox"]),
textarea, textarea,
select { select {
color: var(--text-color); color: var(--text-color);
@ -23,7 +23,7 @@ select {
} }
form, form,
input:not([type='button']):not([type='submit']):not([type='reset']):not([type='checkbox']), input:not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="checkbox"]),
textarea { textarea {
margin-bottom: var(--spacing-base); margin-bottom: var(--spacing-base);
} }
@ -50,7 +50,7 @@ label svg {
cursor: pointer; cursor: pointer;
} }
detail label:has(input[type='checkbox']) { detail label:has(input[type="checkbox"]) {
display: inline-flex; display: inline-flex;
gap: var(--spacing-xs); gap: var(--spacing-xs);
} }

View file

@ -50,7 +50,7 @@
progress { progress {
@media screen and (min-width: 768px) { @media screen and (min-width: 768px) {
max-width: calc(var(--sizing-full) * 0.8); max-width: calc(var(--sizing-full) * .8);
} }
} }
} }

View file

@ -11,10 +11,10 @@
&::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: var(--sizing-full); width: var(--sizing-full);
height: calc(var(--sizing-full) * 0.2); height: calc(var(--sizing-full) * .2);
bottom: 0; bottom: 0;
left: 0; left: 0;
} }

View file

@ -1,36 +1,36 @@
@layer reset, defaults, base, page, components, plugins; @layer reset, defaults, base, page, components, plugins;
/* style resets */ /* style resets */
@import url('./base/reset.css') layer(reset); @import url("./base/reset.css") layer(reset);
/* core defaults */ /* core defaults */
@import url('./base/fonts.css') layer(defaults); @import url("./base/fonts.css") layer(defaults);
@import url('./base/vars.css') layer(defaults); @import url("./base/vars.css") layer(defaults);
/* base styles */ /* base styles */
@import url('./base/index.css') layer(base); @import url("./base/index.css") layer(base);
/* page styles */ /* page styles */
@import url('./pages/contact.css') layer(page); @import url("./pages/contact.css") layer(page);
@import url('./pages/links.css') layer(page); @import url("./pages/links.css") layer(page);
@import url('./pages/media.css') layer(page); @import url("./pages/media.css") layer(page);
@import url('./pages/music.css') layer(page); @import url("./pages/music.css") layer(page);
@import url('./pages/reading.css') layer(page); @import url("./pages/reading.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);
/* plugins */ /* plugins */
@import url('./plugins/prism.css') layer(plugins); @import url("./plugins/prism.css") layer(plugins);
/* component styles */ /* component styles */
@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/header.css') layer(components); @import url("./components/header.css") layer(components);
@import url('./components/media-grid.css') layer(components); @import url("./components/media-grid.css") layer(components);
@import url('./components/nav.css') layer(components); @import url("./components/nav.css") layer(components);
@import url('./components/dialog.css') layer(components); @import url("./components/dialog.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/youtube-player.css') layer(components); @import url("./components/youtube-player.css") layer(components);

View file

@ -1,6 +1,6 @@
/* generic helper to hide client side content */ /* generic helper to hide client side content */
.client-side { .client-side {
display: none; display:none
} }
/* unset text toggle implementation on artist + genre pages */ /* unset text toggle implementation on artist + genre pages */

View file

@ -1,23 +1,26 @@
import EleventyFetch from '@11ty/eleventy-fetch'; import EleventyFetch from "@11ty/eleventy-fetch";
const { POSTGREST_URL, POSTGREST_API_KEY } = process.env; const { POSTGREST_URL, POSTGREST_API_KEY } = process.env;
const fetchAlbumReleases = async () => { const fetchAlbumReleases = async () => {
try { try {
const data = await EleventyFetch(`${POSTGREST_URL}/optimized_album_releases`, { const data = await EleventyFetch(
duration: '1d', `${POSTGREST_URL}/optimized_album_releases`,
type: 'json', {
fetchOptions: { duration: "1d",
method: 'GET', type: "json",
headers: { fetchOptions: {
'Content-Type': 'application/json', method: "GET",
Authorization: `Bearer ${POSTGREST_API_KEY}` headers: {
} "Content-Type": "application/json",
} Authorization: `Bearer ${POSTGREST_API_KEY}`,
}); },
},
},
);
const pacificNow = new Date().toLocaleString('en-US', { const pacificNow = new Date().toLocaleString("en-US", {
timeZone: 'America/Los_Angeles' timeZone: "America/Los_Angeles",
}); });
const pacificDate = new Date(pacificNow); const pacificDate = new Date(pacificNow);
pacificDate.setHours(0, 0, 0, 0); pacificDate.setHours(0, 0, 0, 0);
@ -29,23 +32,25 @@ const fetchAlbumReleases = async () => {
return { return {
...album, ...album,
description: album.artist?.description || 'No description', description: album.artist?.description || "No description",
date: releaseDate.toLocaleDateString('en-US', { date: releaseDate.toLocaleDateString("en-US", {
year: 'numeric', year: "numeric",
month: 'long', month: "long",
day: 'numeric' day: "numeric",
}) }),
}; };
}) })
.sort((a, b) => a.release_timestamp - b.release_timestamp); .sort((a, b) => a.release_timestamp - b.release_timestamp);
const upcoming = all.filter( const upcoming = all.filter(
(album) => album.release_timestamp > todayTimestamp && album.total_plays === 0 (album) =>
album.release_timestamp > todayTimestamp &&
album.total_plays === 0,
); );
return { all, upcoming }; return { all, upcoming };
} catch (error) { } catch (error) {
console.error('Error fetching and processing album releases:', error); console.error("Error fetching and processing album releases:", error);
return { all: [], upcoming: [] }; return { all: [], upcoming: [] };
} }
}; };

View file

@ -1,24 +1,27 @@
import EleventyFetch from '@11ty/eleventy-fetch'; import EleventyFetch from "@11ty/eleventy-fetch";
const { POSTGREST_URL, POSTGREST_API_KEY } = process.env; const { POSTGREST_URL, POSTGREST_API_KEY } = process.env;
export default async function fetchAllActivity() { export default async function fetchAllActivity() {
try { try {
const data = await EleventyFetch(`${POSTGREST_URL}/optimized_all_activity`, { const data = await EleventyFetch(
duration: '1h', `${POSTGREST_URL}/optimized_all_activity`,
type: 'json', {
fetchOptions: { duration: "1h",
method: 'GET', type: "json",
headers: { fetchOptions: {
'Content-Type': 'application/json', method: "GET",
Authorization: `Bearer ${POSTGREST_API_KEY}` headers: {
} "Content-Type": "application/json",
Authorization: `Bearer ${POSTGREST_API_KEY}`,
},
},
} }
}); );
return data?.[0] || []; return data?.[0] || [];
} catch (error) { } catch (error) {
console.error('Error fetching activity:', error); console.error("Error fetching activity:", error);
return []; return [];
} }
} }

View file

@ -1,22 +1,22 @@
import EleventyFetch from '@11ty/eleventy-fetch'; import EleventyFetch from "@11ty/eleventy-fetch";
const { POSTGREST_URL, POSTGREST_API_KEY } = process.env; const { POSTGREST_URL, POSTGREST_API_KEY } = process.env;
const fetchBlogroll = async () => { const fetchBlogroll = async () => {
try { try {
return await EleventyFetch(`${POSTGREST_URL}/optimized_blogroll`, { return await EleventyFetch(`${POSTGREST_URL}/optimized_blogroll`, {
duration: '1d', duration: "1d",
type: 'json', type: "json",
fetchOptions: { fetchOptions: {
method: 'GET', method: "GET",
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
Authorization: `Bearer ${POSTGREST_API_KEY}` Authorization: `Bearer ${POSTGREST_API_KEY}`,
} },
} },
}); });
} 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,22 +1,25 @@
import EleventyFetch from '@11ty/eleventy-fetch'; import EleventyFetch from "@11ty/eleventy-fetch";
const { POSTGREST_URL, POSTGREST_API_KEY } = process.env; const { POSTGREST_URL, POSTGREST_API_KEY } = process.env;
const fetchAllBooks = async () => { const fetchAllBooks = async () => {
try { try {
return await EleventyFetch(`${POSTGREST_URL}/optimized_books?order=date_finished.desc`, { return await EleventyFetch(
duration: '1h', `${POSTGREST_URL}/optimized_books?order=date_finished.desc`,
type: 'json', {
fetchOptions: { duration: "1h",
method: 'GET', type: "json",
headers: { fetchOptions: {
'Content-Type': 'application/json', method: "GET",
Authorization: `Bearer ${POSTGREST_API_KEY}` headers: {
} "Content-Type": "application/json",
} Authorization: `Bearer ${POSTGREST_API_KEY}`,
}); },
},
},
);
} catch (error) { } catch (error) {
console.error('Error fetching books:', error); console.error("Error fetching books:", error);
return []; return [];
} }
}; };
@ -42,7 +45,7 @@ export default async function () {
const booksForCurrentYear = const booksForCurrentYear =
sortedByYear sortedByYear
.find((yearGroup) => yearGroup.value === currentYear) .find((yearGroup) => yearGroup.value === currentYear)
?.data.filter((book) => book.status === 'finished') || []; ?.data.filter((book) => book.status === "finished") || [];
return { return {
all: books, all: books,

View file

@ -1,22 +1,22 @@
import EleventyFetch from '@11ty/eleventy-fetch'; import EleventyFetch from "@11ty/eleventy-fetch";
const { POSTGREST_URL, POSTGREST_API_KEY } = process.env; const { POSTGREST_URL, POSTGREST_API_KEY } = process.env;
const fetchAllConcerts = async () => { const fetchAllConcerts = async () => {
try { try {
return await EleventyFetch(`${POSTGREST_URL}/optimized_concerts`, { return await EleventyFetch(`${POSTGREST_URL}/optimized_concerts`, {
duration: '1h', duration: "1h",
type: 'json', type: "json",
fetchOptions: { fetchOptions: {
method: 'GET', method: "GET",
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
Authorization: `Bearer ${POSTGREST_API_KEY}` Authorization: `Bearer ${POSTGREST_API_KEY}`,
} },
} },
}); });
} catch (error) { } catch (error) {
console.error('Error fetching concerts:', error); console.error("Error fetching concerts:", error);
return []; return [];
} }
}; };
@ -24,7 +24,7 @@ const fetchAllConcerts = async () => {
const processConcerts = (concerts) => const processConcerts = (concerts) =>
concerts.map((concert) => ({ 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 () {
@ -32,7 +32,7 @@ export default async function () {
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,22 +1,22 @@
import EleventyFetch from '@11ty/eleventy-fetch'; import EleventyFetch from "@11ty/eleventy-fetch";
const { POSTGREST_URL, POSTGREST_API_KEY } = process.env; const { POSTGREST_URL, POSTGREST_API_KEY } = process.env;
const fetchFeeds = async () => { const fetchFeeds = async () => {
try { try {
return await EleventyFetch(`${POSTGREST_URL}/optimized_feeds?select=*`, { return await EleventyFetch(`${POSTGREST_URL}/optimized_feeds?select=*`, {
duration: '1h', duration: "1h",
type: 'json', type: "json",
fetchOptions: { fetchOptions: {
method: 'GET', method: "GET",
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
Authorization: `Bearer ${POSTGREST_API_KEY}` Authorization: `Bearer ${POSTGREST_API_KEY}`,
} },
} },
}); });
} catch (error) { } catch (error) {
console.error('Error fetching feed metadata:', error); console.error("Error fetching feed metadata:", error);
return []; return [];
} }
}; };
@ -24,16 +24,16 @@ const fetchFeeds = async () => {
const fetchFeedData = async (feedKey) => { const fetchFeedData = async (feedKey) => {
try { try {
return await EleventyFetch(`${POSTGREST_URL}/rpc/get_feed_data`, { return await EleventyFetch(`${POSTGREST_URL}/rpc/get_feed_data`, {
duration: '1h', duration: "1h",
type: 'json', type: "json",
fetchOptions: { fetchOptions: {
method: 'POST', method: "POST",
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
Authorization: `Bearer ${POSTGREST_API_KEY}` Authorization: `Bearer ${POSTGREST_API_KEY}`,
}, },
body: JSON.stringify({ feed_key: feedKey }) body: JSON.stringify({ feed_key: feedKey }),
} },
}); });
} catch (error) { } catch (error) {
console.error(`Error fetching feed data for ${feedKey}:`, error); console.error(`Error fetching feed data for ${feedKey}:`, error);
@ -48,9 +48,9 @@ export default async function () {
for (const feed of feeds) { for (const feed of feeds) {
feedsWithData.push({ feedsWithData.push({
...feed, ...feed,
entries: await fetchFeedData(feed.data) entries: await fetchFeedData(feed.data),
}); });
} }
return feedsWithData; return feedsWithData;
} };

View file

@ -1,24 +1,27 @@
import EleventyFetch from '@11ty/eleventy-fetch'; import EleventyFetch from "@11ty/eleventy-fetch";
const { POSTGREST_URL, POSTGREST_API_KEY } = process.env; const { POSTGREST_URL, POSTGREST_API_KEY } = process.env;
const fetchGlobals = async () => { const fetchGlobals = async () => {
try { try {
const data = await EleventyFetch(`${POSTGREST_URL}/optimized_globals?select=*`, { const data = await EleventyFetch(
duration: '1d', `${POSTGREST_URL}/optimized_globals?select=*`,
type: 'json', {
fetchOptions: { duration: "1d",
method: 'GET', type: "json",
headers: { fetchOptions: {
'Content-Type': 'application/json', method: "GET",
Authorization: `Bearer ${POSTGREST_API_KEY}` headers: {
} "Content-Type": "application/json",
} Authorization: `Bearer ${POSTGREST_API_KEY}`,
}); },
},
},
);
return data[0]; return data[0];
} catch (error) { } catch (error) {
console.error('Error fetching globals:', error); console.error("Error fetching globals:", error);
return {}; return {};
} }
}; };

View file

@ -1,31 +1,29 @@
import EleventyFetch from '@11ty/eleventy-fetch'; import EleventyFetch from "@11ty/eleventy-fetch";
const { POSTGREST_URL, POSTGREST_API_KEY } = process.env; const { POSTGREST_URL, POSTGREST_API_KEY } = process.env;
export default async function () { export default async function () {
const res = await EleventyFetch(`${POSTGREST_URL}/optimized_all_tags?order=tag.asc`, { const res = await EleventyFetch(`${POSTGREST_URL}/optimized_all_tags?order=tag.asc`, {
duration: '1h', duration: "1h",
type: 'json', type: "json",
fetchOptions: { fetchOptions: {
method: 'GET', method: "GET",
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
Authorization: `Bearer ${POSTGREST_API_KEY}` Authorization: `Bearer ${POSTGREST_API_KEY}`,
} },
} },
}); });
const tags = await res; const tags = await res;
const groupedMap = new Map(); const groupedMap = new Map();
for (const tag of tags) { for (const tag of tags) {
const letter = /^[a-zA-Z]/.test(tag.tag) ? tag.tag[0].toUpperCase() : '#'; const letter = /^[a-zA-Z]/.test(tag.tag) ? tag.tag[0].toUpperCase() : "#";
if (!groupedMap.has(letter)) groupedMap.set(letter, []); if (!groupedMap.has(letter)) groupedMap.set(letter, []);
groupedMap.get(letter).push(tag); groupedMap.get(letter).push(tag);
} }
return [...groupedMap.entries()] return [...groupedMap.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([letter, tags]) => ({ letter, tags: tags.sort((a, b) => a.tag.localeCompare(b.tag)) }));
.sort(([a], [b]) => a.localeCompare(b))
.map(([letter, tags]) => ({ letter, tags: tags.sort((a, b) => a.tag.localeCompare(b.tag)) }));
} }

View file

@ -1,22 +1,22 @@
import EleventyFetch from '@11ty/eleventy-fetch'; import EleventyFetch from "@11ty/eleventy-fetch";
const { POSTGREST_URL, POSTGREST_API_KEY } = process.env; const { POSTGREST_URL, POSTGREST_API_KEY } = process.env;
const fetchHeaders = async () => { const fetchHeaders = async () => {
try { try {
return await EleventyFetch(`${POSTGREST_URL}/optimized_headers?select=*`, { return await EleventyFetch(`${POSTGREST_URL}/optimized_headers?select=*`, {
duration: '1h', duration: "1h",
type: 'json', type: "json",
fetchOptions: { fetchOptions: {
method: 'GET', method: "GET",
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
Authorization: `Bearer ${POSTGREST_API_KEY}` Authorization: `Bearer ${POSTGREST_API_KEY}`,
} },
} },
}); });
} catch (error) { } catch (error) {
console.error('Error fetching header data:', error); console.error("Error fetching header data:", error);
return []; return [];
} }
}; };

View file

@ -1,22 +1,22 @@
import EleventyFetch from '@11ty/eleventy-fetch'; import EleventyFetch from "@11ty/eleventy-fetch";
const { POSTGREST_URL, POSTGREST_API_KEY } = process.env; const { POSTGREST_URL, POSTGREST_API_KEY } = process.env;
const fetchAllLinks = async () => { const fetchAllLinks = async () => {
try { try {
return await EleventyFetch(`${POSTGREST_URL}/optimized_links?select=*`, { return await EleventyFetch(`${POSTGREST_URL}/optimized_links?select=*`, {
duration: '1h', duration: "1h",
type: 'json', type: "json",
fetchOptions: { fetchOptions: {
method: 'GET', method: "GET",
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
Authorization: `Bearer ${POSTGREST_API_KEY}` Authorization: `Bearer ${POSTGREST_API_KEY}`,
} },
} },
}); });
} catch (error) { } catch (error) {
console.error('Error fetching links:', error); console.error("Error fetching links:", error);
return []; return [];
} }
}; };
@ -26,6 +26,6 @@ export default async function () {
return { return {
all: links, all: links,
feed: links.filter((links) => links.feed) feed: links.filter((links) => links.feed),
}; }
} }

View file

@ -1,22 +1,22 @@
import EleventyFetch from '@11ty/eleventy-fetch'; import EleventyFetch from "@11ty/eleventy-fetch";
const { POSTGREST_URL, POSTGREST_API_KEY } = process.env; const { POSTGREST_URL, POSTGREST_API_KEY } = process.env;
const fetchAllMovies = async () => { const fetchAllMovies = async () => {
try { try {
return await EleventyFetch(`${POSTGREST_URL}/optimized_movies?select=*`, { return await EleventyFetch(`${POSTGREST_URL}/optimized_movies?select=*`, {
duration: '1h', duration: "1h",
type: 'json', type: "json",
fetchOptions: { fetchOptions: {
method: 'GET', method: "GET",
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
Authorization: `Bearer ${POSTGREST_API_KEY}` Authorization: `Bearer ${POSTGREST_API_KEY}`,
} },
} },
}); });
} catch (error) { } catch (error) {
console.error('Error fetching movies:', error); console.error("Error fetching movies:", error);
return []; return [];
} }
}; };
@ -44,17 +44,19 @@ export default async function () {
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,19 +1,19 @@
import EleventyFetch from '@11ty/eleventy-fetch'; import EleventyFetch from "@11ty/eleventy-fetch";
const { POSTGREST_URL, POSTGREST_API_KEY } = process.env; const { POSTGREST_URL, POSTGREST_API_KEY } = process.env;
const fetchDataFromView = async (viewName) => { const fetchDataFromView = async (viewName) => {
try { try {
return await EleventyFetch(`${POSTGREST_URL}/${viewName}?select=*`, { return await EleventyFetch(`${POSTGREST_URL}/${viewName}?select=*`, {
duration: '1h', duration: "1h",
type: 'json', type: "json",
fetchOptions: { fetchOptions: {
method: 'GET', method: "GET",
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
Authorization: `Bearer ${POSTGREST_API_KEY}` Authorization: `Bearer ${POSTGREST_API_KEY}`,
} },
} },
}); });
} catch (error) { } catch (error) {
console.error(`Error fetching data from view ${viewName}:`, error); console.error(`Error fetching data from view ${viewName}:`, error);
@ -32,17 +32,17 @@ export default async function fetchMusicData() {
monthTracks, monthTracks,
monthArtists, monthArtists,
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 {
@ -52,7 +52,9 @@ export default async function fetchMusicData() {
artists: weekArtists, artists: weekArtists,
albums: weekAlbums, albums: weekAlbums,
genres: weekGenres, genres: weekGenres,
totalTracks: weekTracks.reduce((acc, track) => acc + track.plays, 0).toLocaleString('en-US') totalTracks: weekTracks
.reduce((acc, track) => acc + track.plays, 0)
.toLocaleString("en-US"),
}, },
month: { month: {
tracks: monthTracks, tracks: monthTracks,
@ -61,11 +63,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 {
recent: [], recent: [],
week: { week: {
@ -73,15 +75,15 @@ export default async function fetchMusicData() {
artists: [], artists: [],
albums: [], albums: [],
genres: [], genres: [],
totalTracks: '0' totalTracks: "0",
}, },
month: { month: {
tracks: [], tracks: [],
artists: [], artists: [],
albums: [], albums: [],
genres: [], genres: [],
totalTracks: '0' totalTracks: "0",
} },
}; };
} }
} }

View file

@ -1,20 +1,23 @@
import EleventyFetch from '@11ty/eleventy-fetch'; import EleventyFetch from "@11ty/eleventy-fetch";
const { POSTGREST_URL, POSTGREST_API_KEY } = process.env; const { POSTGREST_URL, POSTGREST_API_KEY } = process.env;
const fetchAllNavigation = async () => { const fetchAllNavigation = async () => {
try { try {
const data = await EleventyFetch(`${POSTGREST_URL}/optimized_navigation?select=*`, { const data = await EleventyFetch(
duration: '1d', `${POSTGREST_URL}/optimized_navigation?select=*`,
type: 'json', {
fetchOptions: { duration: "1d",
method: 'GET', type: "json",
headers: { fetchOptions: {
'Content-Type': 'application/json', method: "GET",
Authorization: `Bearer ${POSTGREST_API_KEY}` headers: {
} "Content-Type": "application/json",
} Authorization: `Bearer ${POSTGREST_API_KEY}`,
}); },
},
},
);
const nav = data.reduce((acc, item) => { const nav = data.reduce((acc, item) => {
const navItem = { const navItem = {
@ -22,7 +25,7 @@ const fetchAllNavigation = async () => {
permalink: item.permalink || item.page_permalink, permalink: item.permalink || item.page_permalink,
icon: item.icon, icon: item.icon,
section: item.section, section: item.section,
sort: item.sort sort: item.sort,
}; };
if (!acc[item.menu_location]) { if (!acc[item.menu_location]) {
@ -40,7 +43,7 @@ const fetchAllNavigation = async () => {
return nav; return nav;
} catch (error) { } catch (error) {
console.error('Error fetching navigation data:', error); console.error("Error fetching navigation data:", error);
return {}; return {};
} }
}; };

View file

@ -1,22 +1,22 @@
import EleventyFetch from '@11ty/eleventy-fetch'; import EleventyFetch from "@11ty/eleventy-fetch";
const { POSTGREST_URL, POSTGREST_API_KEY } = process.env; const { POSTGREST_URL, POSTGREST_API_KEY } = process.env;
const fetchAllPages = async () => { const fetchAllPages = async () => {
try { try {
return await EleventyFetch(`${POSTGREST_URL}/optimized_pages?select=*`, { return await EleventyFetch(`${POSTGREST_URL}/optimized_pages?select=*`, {
duration: '1d', duration: "1d",
type: 'json', type: "json",
fetchOptions: { fetchOptions: {
method: 'GET', method: "GET",
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
Authorization: `Bearer ${POSTGREST_API_KEY}` Authorization: `Bearer ${POSTGREST_API_KEY}`,
} },
} },
}); });
} catch (error) { } catch (error) {
console.error('Error fetching pages:', error); console.error("Error fetching pages:", error);
return []; return [];
} }
}; };

View file

@ -1,22 +1,25 @@
import EleventyFetch from '@11ty/eleventy-fetch'; import EleventyFetch from "@11ty/eleventy-fetch";
const { POSTGREST_URL, POSTGREST_API_KEY } = process.env; const { POSTGREST_URL, POSTGREST_API_KEY } = process.env;
const fetchAllPosts = async () => { const fetchAllPosts = async () => {
try { try {
return await EleventyFetch(`${POSTGREST_URL}/optimized_posts?select=*&order=date.desc`, { return await EleventyFetch(
duration: '1d', `${POSTGREST_URL}/optimized_posts?select=*&order=date.desc`,
type: 'json', {
fetchOptions: { duration: "1d",
method: 'GET', type: "json",
headers: { fetchOptions: {
'Content-Type': 'application/json', method: "GET",
Authorization: `Bearer ${POSTGREST_API_KEY}` headers: {
} "Content-Type": "application/json",
} Authorization: `Bearer ${POSTGREST_API_KEY}`,
}); },
},
},
);
} catch (error) { } catch (error) {
console.error('Error fetching posts:', error); console.error("Error fetching posts:", error);
return []; return [];
} }
}; };
@ -26,6 +29,6 @@ export default async function () {
return { return {
all: posts, all: posts,
feed: posts.filter((posts) => posts.feed) feed: posts.filter((posts) => posts.feed),
}; };
} }

View file

@ -1,26 +1,29 @@
import EleventyFetch from '@11ty/eleventy-fetch'; import EleventyFetch from "@11ty/eleventy-fetch";
const { POSTGREST_URL, POSTGREST_API_KEY } = process.env; const { POSTGREST_URL, POSTGREST_API_KEY } = process.env;
export default async function () { export default async function () {
try { try {
const data = await EleventyFetch(`${POSTGREST_URL}/optimized_recent_activity`, { const data = await EleventyFetch(
duration: '1h', `${POSTGREST_URL}/optimized_recent_activity`,
type: 'json', {
fetchOptions: { duration: "1h",
method: 'GET', type: "json",
headers: { fetchOptions: {
'Content-Type': 'application/json', method: "GET",
Authorization: `Bearer ${POSTGREST_API_KEY}` headers: {
} "Content-Type": "application/json",
Authorization: `Bearer ${POSTGREST_API_KEY}`,
},
},
} }
}); );
const feeds = data?.[0]?.feed || []; const feeds = data?.[0]?.feed || [];
return feeds.filter((item) => item !== null); return feeds.filter((item) => item !== null);
} catch (error) { } catch (error) {
console.error('Error fetching recent activity:', error); console.error("Error fetching recent activity:", error);
return []; return [];
} }
} }

View file

@ -1,22 +1,25 @@
import EleventyFetch from '@11ty/eleventy-fetch'; import EleventyFetch from "@11ty/eleventy-fetch";
const { POSTGREST_URL, POSTGREST_API_KEY } = process.env; const { POSTGREST_URL, POSTGREST_API_KEY } = process.env;
const fetchRedirects = async () => { const fetchRedirects = async () => {
try { try {
return await EleventyFetch(`${POSTGREST_URL}/optimized_redirects?select=*`, { return await EleventyFetch(
duration: '1h', `${POSTGREST_URL}/optimized_redirects?select=*`,
type: 'json', {
fetchOptions: { duration: "1h",
method: 'GET', type: "json",
headers: { fetchOptions: {
'Content-Type': 'application/json', method: "GET",
Authorization: `Bearer ${POSTGREST_API_KEY}` headers: {
} "Content-Type": "application/json",
} Authorization: `Bearer ${POSTGREST_API_KEY}`,
}); },
},
},
);
} catch (error) { } catch (error) {
console.error('Error fetching redirect data:', error); console.error("Error fetching redirect data:", error);
return []; return [];
} }
}; };

View file

@ -1,30 +1,33 @@
import EleventyFetch from '@11ty/eleventy-fetch'; import EleventyFetch from "@11ty/eleventy-fetch";
const { POSTGREST_URL, POSTGREST_API_KEY } = process.env; const { POSTGREST_URL, POSTGREST_API_KEY } = process.env;
const fetchAllRobots = async () => { const fetchAllRobots = async () => {
try { try {
const data = await EleventyFetch(`${POSTGREST_URL}/optimized_robots?select=path,user_agents`, { const data = await EleventyFetch(
duration: '1h', `${POSTGREST_URL}/optimized_robots?select=path,user_agents`,
type: 'json', {
fetchOptions: { duration: "1h",
method: 'GET', type: "json",
headers: { fetchOptions: {
'Content-Type': 'application/json', method: "GET",
Authorization: `Bearer ${POSTGREST_API_KEY}` headers: {
} "Content-Type": "application/json",
} Authorization: `Bearer ${POSTGREST_API_KEY}`,
}); },
},
},
);
const sortedData = data.sort((a, b) => { const sortedData = data.sort((a, b) => {
const aHasWildcard = a.user_agents.includes('*') ? 0 : 1; const aHasWildcard = a.user_agents.includes("*") ? 0 : 1;
const bHasWildcard = b.user_agents.includes('*') ? 0 : 1; const bHasWildcard = b.user_agents.includes("*") ? 0 : 1;
return aHasWildcard - bHasWildcard || a.path.localeCompare(b.path); return aHasWildcard - bHasWildcard || a.path.localeCompare(b.path);
}); });
return sortedData; return sortedData;
} catch (error) { } catch (error) {
console.error('Error fetching robot data:', error); console.error("Error fetching robot data:", error);
return []; return [];
} }
}; };

View file

@ -1,22 +1,22 @@
import EleventyFetch from '@11ty/eleventy-fetch'; import EleventyFetch from "@11ty/eleventy-fetch";
const { POSTGREST_URL, POSTGREST_API_KEY } = process.env; const { POSTGREST_URL, POSTGREST_API_KEY } = process.env;
const fetchSitemap = async () => { const fetchSitemap = async () => {
try { try {
return await EleventyFetch(`${POSTGREST_URL}/optimized_sitemap?select=*`, { return await EleventyFetch(`${POSTGREST_URL}/optimized_sitemap?select=*`, {
duration: '1h', duration: "1h",
type: 'json', type: "json",
fetchOptions: { fetchOptions: {
method: 'GET', method: "GET",
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
Authorization: `Bearer ${POSTGREST_API_KEY}` Authorization: `Bearer ${POSTGREST_API_KEY}`,
} },
} },
}); });
} catch (error) { } catch (error) {
console.error('Error fetching sitemap entries:', error); console.error("Error fetching sitemap entries:", error);
return []; return [];
} }
}; };

View file

@ -1,22 +1,22 @@
import EleventyFetch from '@11ty/eleventy-fetch'; import EleventyFetch from "@11ty/eleventy-fetch";
const { POSTGREST_URL, POSTGREST_API_KEY } = process.env; const { POSTGREST_URL, POSTGREST_API_KEY } = process.env;
const fetchStats = async () => { const fetchStats = async () => {
try { try {
return await EleventyFetch(`${POSTGREST_URL}/optimized_stats?select=*`, { return await EleventyFetch(`${POSTGREST_URL}/optimized_stats?select=*`, {
duration: '1h', duration: "1h",
type: 'json', type: "json",
fetchOptions: { fetchOptions: {
method: 'GET', method: "GET",
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
Authorization: `Bearer ${POSTGREST_API_KEY}` Authorization: `Bearer ${POSTGREST_API_KEY}`,
} },
} },
}); });
} catch (error) { } catch (error) {
console.error('Error fetching stats data:', error); console.error("Error fetching stats data:", error);
return []; return [];
} }
}; };

View file

@ -1,4 +1,4 @@
import EleventyFetch from '@11ty/eleventy-fetch'; import EleventyFetch from "@11ty/eleventy-fetch";
const { POSTGREST_URL, POSTGREST_API_KEY } = process.env; const { POSTGREST_URL, POSTGREST_API_KEY } = process.env;
@ -7,21 +7,21 @@ const fetchTopAlbums = async () => {
const data = await EleventyFetch( const data = await EleventyFetch(
`${POSTGREST_URL}/optimized_albums?select=table&order=total_plays_raw.desc&limit=8`, `${POSTGREST_URL}/optimized_albums?select=table&order=total_plays_raw.desc&limit=8`,
{ {
duration: '1d', duration: "1d",
type: 'json', type: "json",
fetchOptions: { fetchOptions: {
method: 'GET', method: "GET",
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
Authorization: `Bearer ${POSTGREST_API_KEY}` Authorization: `Bearer ${POSTGREST_API_KEY}`,
} },
} },
} },
); );
return data; return data;
} catch (error) { } catch (error) {
console.error('Error fetching top albums:', error); console.error("Error fetching top albums:", error);
return {}; return {};
} }
}; };

View file

@ -1,4 +1,4 @@
import EleventyFetch from '@11ty/eleventy-fetch'; import EleventyFetch from "@11ty/eleventy-fetch";
const { POSTGREST_URL, POSTGREST_API_KEY } = process.env; const { POSTGREST_URL, POSTGREST_API_KEY } = process.env;
@ -7,21 +7,21 @@ const fetchTopArtists = async () => {
const data = await EleventyFetch( const data = await EleventyFetch(
`${POSTGREST_URL}/optimized_artists?select=table&order=total_plays_raw.desc&limit=8`, `${POSTGREST_URL}/optimized_artists?select=table&order=total_plays_raw.desc&limit=8`,
{ {
duration: '1d', duration: "1d",
type: 'json', type: "json",
fetchOptions: { fetchOptions: {
method: 'GET', method: "GET",
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
Authorization: `Bearer ${POSTGREST_API_KEY}` Authorization: `Bearer ${POSTGREST_API_KEY}`,
} },
} },
} },
); );
return data; return data;
} catch (error) { } catch (error) {
console.error('Error fetching top artists:', error); console.error("Error fetching top artists:", error);
return {}; return {};
} }
}; };

View file

@ -1,22 +1,22 @@
import EleventyFetch from '@11ty/eleventy-fetch'; import EleventyFetch from "@11ty/eleventy-fetch";
const { POSTGREST_URL, POSTGREST_API_KEY } = process.env; const { POSTGREST_URL, POSTGREST_API_KEY } = process.env;
const fetchTopTags = async () => { const fetchTopTags = async () => {
try { try {
return await EleventyFetch(`${POSTGREST_URL}/rpc/get_top_tag_groups`, { return await EleventyFetch(`${POSTGREST_URL}/rpc/get_top_tag_groups`, {
duration: '1h', duration: "1h",
type: 'json', type: "json",
fetchOptions: { fetchOptions: {
method: 'POST', method: "POST",
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
Authorization: `Bearer ${POSTGREST_API_KEY}` Authorization: `Bearer ${POSTGREST_API_KEY}`,
} },
} },
}); });
} catch (error) { } catch (error) {
console.error('Error fetching top tag entries:', error); console.error("Error fetching top tag entries:", error);
return []; return [];
} }
}; };

View file

@ -1,22 +1,22 @@
import EleventyFetch from '@11ty/eleventy-fetch'; import EleventyFetch from "@11ty/eleventy-fetch";
const { POSTGREST_URL, POSTGREST_API_KEY } = process.env; const { POSTGREST_URL, POSTGREST_API_KEY } = process.env;
const fetchAllShows = async () => { const fetchAllShows = async () => {
try { try {
return await EleventyFetch(`${POSTGREST_URL}/optimized_shows?select=*`, { return await EleventyFetch(`${POSTGREST_URL}/optimized_shows?select=*`, {
duration: '1h', duration: "1h",
type: 'json', type: "json",
fetchOptions: { fetchOptions: {
method: 'GET', method: "GET",
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
Authorization: `Bearer ${POSTGREST_API_KEY}` Authorization: `Bearer ${POSTGREST_API_KEY}`,
} },
} },
}); });
} catch (error) { } catch (error) {
console.error('Error fetching shows:', error); console.error("Error fetching shows:", error);
return []; return [];
} }
}; };
@ -25,7 +25,9 @@ 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(
(show) => show.last_watched_at !== null,
);
const episodes = watchedShows.map((show) => ({ const episodes = watchedShows.map((show) => ({
title: show.episode.title, title: show.episode.title,
@ -35,7 +37,7 @@ export default async function () {
image: show.episode.image, image: show.episode.image,
backdrop: show.episode.backdrop, backdrop: show.episode.backdrop,
last_watched_at: show.episode.last_watched_at, last_watched_at: show.episode.last_watched_at,
grid: show.grid grid: show.grid,
})); }));
return { return {
@ -43,15 +45,15 @@ export default async function () {
recentlyWatched: episodes.slice(0, 125), recentlyWatched: episodes.slice(0, 125),
favorites: shows favorites: shows
.filter((show) => show.favorite) .filter((show) => show.favorite)
.sort((a, b) => a.title.localeCompare(b.title)) .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: [],
}; };
} }
} }

View file

@ -1,22 +1,22 @@
import EleventyFetch from '@11ty/eleventy-fetch'; import EleventyFetch from "@11ty/eleventy-fetch";
const { POSTGREST_URL, POSTGREST_API_KEY } = process.env; const { POSTGREST_URL, POSTGREST_API_KEY } = process.env;
const fetchUpcomingShows = async () => { const fetchUpcomingShows = async () => {
try { try {
return await EleventyFetch(`${POSTGREST_URL}/optimized_scheduled_shows?select=*`, { return await EleventyFetch(`${POSTGREST_URL}/optimized_scheduled_shows?select=*`, {
duration: '1h', duration: "1h",
type: 'json', type: "json",
fetchOptions: { fetchOptions: {
method: 'GET', method: "GET",
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
Authorization: `Bearer ${POSTGREST_API_KEY}` Authorization: `Bearer ${POSTGREST_API_KEY}`,
} },
} },
}); });
} catch (error) { } catch (error) {
console.error('Error fetching upcoming shows:', error); console.error("Error fetching upcoming shows:", error);
return []; return [];
} }
}; };
@ -25,5 +25,5 @@ export default async function () {
const data = await fetchUpcomingShows(); const data = await fetchUpcomingShows();
const upcomingShows = data?.[0]?.scheduled_shows; const upcomingShows = data?.[0]?.scheduled_shows;
return upcomingShows; return upcomingShows
} }

View file

@ -1,3 +1,3 @@
{ {
"layout": "base.liquid" "layout": "base.liquid"
} }