diff options
| author | Fuwn <[email protected]> | 2024-05-24 07:31:37 -0700 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2024-05-24 07:31:37 -0700 |
| commit | 017364a6ac6146fe7213b6654532de7607597d43 (patch) | |
| tree | 8c11ec591e5153b58a67bebfb18f2ed922e682ae | |
| parent | fix(badges): shadow hide refresh (diff) | |
| download | due.moe-017364a6ac6146fe7213b6654532de7607597d43.tar.xz due.moe-017364a6ac6146fe7213b6654532de7607597d43.zip | |
fix(match): delayed and subtitled time compatibility
| -rw-r--r-- | package.json | 106 | ||||
| -rw-r--r-- | src/lib/Database/userBadges.ts | 136 | ||||
| -rw-r--r-- | src/lib/List/Anime/CleanAnimeList.svelte | 6 | ||||
| -rw-r--r-- | src/lib/Media/Anime/Airing/Subtitled/match.ts | 18 | ||||
| -rw-r--r-- | src/routes/api/badges/+server.ts | 243 | ||||
| -rw-r--r-- | src/routes/user/[user]/badges/+page.svelte | 8 | ||||
| -rw-r--r-- | static/styles/LaTeX.css | 647 |
7 files changed, 583 insertions, 581 deletions
diff --git a/package.json b/package.json index da8e9ced..39c17c61 100644 --- a/package.json +++ b/package.json @@ -1,55 +1,55 @@ { - "name": "due.moe", - "version": "0.0.0", - "private": true, - "scripts": { - "dev": "vite dev", - "build": "vite build", - "preview": "vite preview", - "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", - "lint": "prettier --plugin-search-dir . --check . && eslint .", - "format": "prettier --plugin-search-dir . --write ." - }, - "devDependencies": { - "@iconify/svelte": "^3.1.6", - "@sveltejs/adapter-vercel": "next", - "@sveltejs/kit": "^1.20.4", - "@types/fast-levenshtein": "^0.0.4", - "@types/jsdom": "^21.1.6", - "@types/string-similarity": "^4.0.2", - "@typescript-eslint/eslint-plugin": "^5.45.0", - "@typescript-eslint/parser": "^5.45.0", - "autoprefixer": "^10.4.16", - "eslint": "^8.28.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-svelte": "^2.30.0", - "prettier": "^2.8.0", - "prettier-plugin-svelte": "^2.10.1", - "sass": "^1.69.7", - "svelte": "^4.0.5", - "svelte-check": "^3.4.3", - "svelte-preprocess": "^5.1.3", - "sveltekit-rate-limiter": "^0.4.2", - "tslib": "^2.4.1", - "typescript": "^5.0.0", - "vite": "^4.4.2" - }, - "type": "module", - "dependencies": { - "@supabase/supabase-js": "^2.39.3", - "@vercel/speed-insights": "^1.0.9", - "dexie": "^4.0.1-alpha.25", - "jsdom": "^23.0.1", - "jszip": "^3.10.1", - "lz-string": "^1.5.0", - "modern-screenshot": "^4.4.33", - "rss-parser": "^3.13.0", - "sortablejs": "^1.15.2", - "string-similarity": "^4.0.4", - "svelte-i18n": "^4.0.0", - "svelte-markdown": "^0.4.1", - "svelte-notifications": "^0.9.98", - "wanakana": "^5.3.1" - } + "name": "due.moe", + "version": "0.0.0", + "private": true, + "scripts": { + "dev": "vite dev", + "build": "vite build", + "preview": "vite preview", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "lint": "prettier --plugin-search-dir . --check . && eslint .", + "format": "prettier --plugin-search-dir . --write ." + }, + "devDependencies": { + "@iconify/svelte": "^3.1.6", + "@sveltejs/adapter-vercel": "next", + "@sveltejs/kit": "^1.20.4", + "@types/fast-levenshtein": "^0.0.4", + "@types/jsdom": "^21.1.6", + "@types/string-similarity": "^4.0.2", + "@typescript-eslint/eslint-plugin": "^5.45.0", + "@typescript-eslint/parser": "^5.45.0", + "autoprefixer": "^10.4.16", + "eslint": "^8.28.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-svelte": "^2.30.0", + "prettier": "^2.8.0", + "prettier-plugin-svelte": "^2.10.1", + "sass": "^1.69.7", + "svelte": "^4.0.5", + "svelte-check": "^3.4.3", + "svelte-preprocess": "^5.1.3", + "sveltekit-rate-limiter": "^0.4.2", + "tslib": "^2.4.1", + "typescript": "^5.0.0", + "vite": "^4.4.2" + }, + "type": "module", + "dependencies": { + "@supabase/supabase-js": "^2.39.3", + "@vercel/speed-insights": "^1.0.9", + "dexie": "^4.0.1-alpha.25", + "jsdom": "^23.0.1", + "jszip": "^3.10.1", + "lz-string": "^1.5.0", + "modern-screenshot": "^4.4.33", + "rss-parser": "^3.13.0", + "sortablejs": "^1.15.2", + "string-similarity": "^4.0.4", + "svelte-i18n": "^4.0.0", + "svelte-markdown": "^0.4.1", + "svelte-notifications": "^0.9.98", + "wanakana": "^5.3.1" + } } diff --git a/src/lib/Database/userBadges.ts b/src/lib/Database/userBadges.ts index c29f06d5..3ce88d29 100644 --- a/src/lib/Database/userBadges.ts +++ b/src/lib/Database/userBadges.ts @@ -2,97 +2,101 @@ import { databaseTimeToDate } from '$lib/Utility/time'; import supabase from './supabase'; export interface Badge { - post?: string; - image?: string; - description?: string | null; - id?: number; - time?: string; - category?: string | null; - hidden?: boolean; - source?: string | null; - designer?: string | null; - shadow_hidden?: boolean; + post?: string; + image?: string; + description?: string | null; + id?: number; + time?: string; + category?: string | null; + hidden?: boolean; + source?: string | null; + designer?: string | null; + shadow_hidden?: boolean; } export const getUserBadges = async (userId: number): Promise<Badge[]> => { - const { data, error } = await supabase.from('user_badges').select('*').eq('user_id', userId); + const { data, error } = await supabase.from('user_badges').select('*').eq('user_id', userId); - if (error) return []; + if (error) return []; - return data.sort((a, b) => - databaseTimeToDate((a as Badge).time ?? '').getTime() > - databaseTimeToDate((b as Badge).time ?? '').getTime() - ? -1 - : 1 - ) as Badge[]; + return data.sort((a, b) => + databaseTimeToDate((a as Badge).time ?? '').getTime() > + databaseTimeToDate((b as Badge).time ?? '').getTime() + ? -1 + : 1 + ) as Badge[]; }; export const addUserBadge = async (userId: number, badge: Badge) => { - const { post, image, description, time, category, hidden, source, designer } = badge; + const { post, image, description, time, category, hidden, source, designer } = badge; - if (post === undefined || image === undefined) return; + if (post === undefined || image === undefined) return; - if (time) { - await supabase.from('user_badges').insert({ - user_id: userId, - post, - image, - description, - time, - category, - hidden, - source, - designer - }); - } else { - await supabase - .from('user_badges') - .insert({ user_id: userId, post, image, description, category, hidden, source, designer }); - } + if (time) { + await supabase.from('user_badges').insert({ + user_id: userId, + post, + image, + description, + time, + category, + hidden, + source, + designer + }); + } else { + await supabase + .from('user_badges') + .insert({ user_id: userId, post, image, description, category, hidden, source, designer }); + } }; export const removeUserBadge = async (userId: number, id: number) => { - if (!isNaN(id)) await supabase.from('user_badges').delete().eq('id', id).eq('user_id', userId); + if (!isNaN(id)) await supabase.from('user_badges').delete().eq('id', id).eq('user_id', userId); }; export const updateUserBadge = async (userId: number, id: number, badge: Badge) => { - if (badge.post === undefined || badge.image === undefined) return; + if (badge.post === undefined || badge.image === undefined) return; - await supabase - .from('user_badges') - .update({ - post: badge.post, - image: badge.image, - description: badge.description, - category: badge.category, - time: badge.time, - hidden: badge.hidden, - source: badge.source, - designer: badge.designer - }) - .eq('id', id) - .eq('user_id', userId); + await supabase + .from('user_badges') + .update({ + post: badge.post, + image: badge.image, + description: badge.description, + category: badge.category, + time: badge.time, + hidden: badge.hidden, + source: badge.source, + designer: badge.designer + }) + .eq('id', id) + .eq('user_id', userId); }; export const renameCategory = async (userId: number, oldName: string, newName: string) => - await supabase - .from('user_badges') - .update({ category: newName }) - .eq('category', oldName) - .eq('user_id', userId); + await supabase + .from('user_badges') + .update({ category: newName }) + .eq('category', oldName) + .eq('user_id', userId); export const removeAllUserBadges = async (userId: number) => - await supabase.from('user_badges').delete().eq('user_id', userId); + await supabase.from('user_badges').delete().eq('user_id', userId); export const migrateCategory = async (userId: number, oldName: string, newName: string) => - await supabase - .from('user_badges') - .update({ category: newName }) - .eq('category', oldName) - .eq('user_id', userId); + await supabase + .from('user_badges') + .update({ category: newName }) + .eq('category', oldName) + .eq('user_id', userId); export const setShadowHidden = async (userId: number, shadowHide: boolean) => - await supabase.from('user_badges').update({ shadow_hidden: shadowHide }).eq('user_id', userId); + await supabase.from('user_badges').update({ shadow_hidden: shadowHide }).eq('user_id', userId); export const setShadowHiddenBadge = async (userId: number, id: number, shadowHide: boolean) => - await supabase.from('user_badges').update({ shadow_hidden: shadowHide }).eq('id', id).eq('user_id', userId); + await supabase + .from('user_badges') + .update({ shadow_hidden: shadowHide }) + .eq('id', id) + .eq('user_id', userId); diff --git a/src/lib/List/Anime/CleanAnimeList.svelte b/src/lib/List/Anime/CleanAnimeList.svelte index 60d46a07..c55de6d7 100644 --- a/src/lib/List/Anime/CleanAnimeList.svelte +++ b/src/lib/List/Anime/CleanAnimeList.svelte @@ -140,11 +140,7 @@ {#if !completed} [{anime.nextAiringEpisode?.episode === -1 ? '?' - : (anime.nextAiringEpisode?.episode || 1) - - ((anime.nextAiringEpisode?.airingAt || 999) < - (anime.nextAiringEpisode?.nativeAiringAt || 0) - ? 2 - : 1)}] + : (anime.nextAiringEpisode?.episode || 1) - 1}] <span class:countdown={$settings.displayCountdownRightAligned}> <AiringTime originalAnime={anime} {subsPlease} /> </span> diff --git a/src/lib/Media/Anime/Airing/Subtitled/match.ts b/src/lib/Media/Anime/Airing/Subtitled/match.ts index d8534090..b5cdc7d7 100644 --- a/src/lib/Media/Anime/Airing/Subtitled/match.ts +++ b/src/lib/Media/Anime/Airing/Subtitled/match.ts @@ -142,6 +142,7 @@ export const injectAiringTime = (anime: Media, subsPlease: SubsPlease | null) => if (season() !== anime.season) return anime; const airingAt = anime.nextAiringEpisode?.airingAt; + const now = new Date(); // const nativeUntilAiring = airingAt // ? Math.round((airingAt - Date.now() / 1000) * 100) / 100 // : undefined; @@ -180,13 +181,18 @@ export const injectAiringTime = (anime: Media, subsPlease: SubsPlease | null) => } } - if ( - airingAt && - nativeTime.getTime() !== time.getTime() && - nativeTime.getTime() - time.getTime() > 24 * 60 * 60 * 1000 && - nativeTime.getTime() - Date.now() < 7 * 24 * 60 * 60 * 1000 - ) + if (now >= nativeTime && now < time) { nextEpisode -= 1; + } + + if (nativeTime.getTime() - now.getTime() > 7 * 24 * 60 * 60 * 1000) { + const beforeTime = time; + + time = nativeTime; + + time.setHours(beforeTime.getHours()); + time.setMinutes(beforeTime.getMinutes()); + } return { ...anime, diff --git a/src/routes/api/badges/+server.ts b/src/routes/api/badges/+server.ts index 0b72e348..21561cbb 100644 --- a/src/routes/api/badges/+server.ts +++ b/src/routes/api/badges/+server.ts @@ -1,142 +1,143 @@ import { userIdentity } from '$lib/Data/AniList/identity'; import { - removeAllUserBadges, - removeUserBadge, - updateUserBadge, - getUserBadges, - addUserBadge, - type Badge, - migrateCategory, - setShadowHidden, - setShadowHiddenBadge + removeAllUserBadges, + removeUserBadge, + updateUserBadge, + getUserBadges, + addUserBadge, + type Badge, + migrateCategory, + setShadowHidden, + setShadowHiddenBadge } from '$lib/Database/userBadges'; import authorisedJson from '$lib/Data/Static/authorised.json'; const unauthorised = new Response('Unauthorised', { status: 401 }); const badges = async (id: number) => - Response.json(await getUserBadges(id), { - headers: { - 'Access-Control-Allow-Origin': 'https://due.moe' - } - }); + Response.json(await getUserBadges(id), { + headers: { + 'Access-Control-Allow-Origin': 'https://due.moe' + } + }); export const GET = async ({ url }) => { - return await badges(Number(url.searchParams.get('id') || 0)); + return await badges(Number(url.searchParams.get('id') || 0)); }; export const DELETE = async ({ url, cookies }) => { - const userCookie = cookies.get('user'); + const userCookie = cookies.get('user'); - if (!userCookie) return unauthorised; + if (!userCookie) return unauthorised; - const user = JSON.parse(userCookie); - const identity = await userIdentity({ - tokenType: user['token_type'], - expiresIn: user['expires_in'], - accessToken: user['access_token'], - refreshToken: user['refresh_token'] - }); + const user = JSON.parse(userCookie); + const identity = await userIdentity({ + tokenType: user['token_type'], + expiresIn: user['expires_in'], + accessToken: user['access_token'], + refreshToken: user['refresh_token'] + }); - if ((url.searchParams.get('prune') || 0) === 'true') { - await removeAllUserBadges(identity.id); - } else { - await removeUserBadge(identity.id, Number(url.searchParams.get('id'))); - } + if ((url.searchParams.get('prune') || 0) === 'true') { + await removeAllUserBadges(identity.id); + } else { + await removeUserBadge(identity.id, Number(url.searchParams.get('id'))); + } - return await badges(identity.id); + return await badges(identity.id); }; export const PUT = async ({ cookies, url, request }) => { - const userCookie = cookies.get('user'); - - if (!userCookie) return unauthorised; - - const user = JSON.parse(userCookie); - const identity = await userIdentity({ - tokenType: user['token_type'], - expiresIn: user['expires_in'], - accessToken: user['access_token'], - refreshToken: user['refresh_token'] - }); - const authorised = authorisedJson.includes(identity.id); - - if (url.searchParams.get('shadowHide')) - setShadowHidden( - Number(url.searchParams.get('shadowHide')), - authorised - ); - - if (url.searchParams.get('import') || undefined) { - await Promise.all( - (await request.json()).map(async (badge: Badge) => await addUserBadge(identity.id, badge)) - ); - - return await badges(identity.id); - } else if (url.searchParams.get('migrate') || undefined) { - await migrateCategory( - identity.id, - url.searchParams.get('original') || '', - url.searchParams.get('new') || '' - ); - - return await badges(identity.id); - } - - if (url.searchParams.get('hide') || undefined) { - const allBadges = await getUserBadges(identity.id); - - await Promise.all( - allBadges - .filter((badge) => badge.category === (url.searchParams.get('category') || '')) - .map(async (badge) => { - await updateUserBadge(identity.id, badge.id as number, { - ...badge, - hidden: - allBadges - .filter((badge) => badge.category === (url.searchParams.get('category') || '')) - .filter((badge) => badge.hidden).length > - allBadges.filter( - (badge) => badge.category === (url.searchParams.get('category') || '') - ).length / - 2 - ? false - : true - }); - }) - ); - - return await badges(identity.id); - } - - if (url.searchParams.get("shadowHideBadge") || undefined) { - if (!authorised) return unauthorised; - - await setShadowHiddenBadge(Number(url.searchParams.get("id")), Number(url.searchParams.get("shadowHideBadge")), url.searchParams.get("status") == "true" ? false : true); - - return await badges(Number(url.searchParams.get("id"))); - } - - const badge = { - post: url.searchParams.get('post') || undefined, - image: url.searchParams.get('image') || undefined, - description: url.searchParams.get('description') || null, - time: url.searchParams.get('time') || undefined, - category: url.searchParams.get('category') || null, - hidden: url.searchParams.get('hidden') || false, - source: url.searchParams.get('source') || null, - designer: url.searchParams.get('designer') || null - }; - - if ( - (await getUserBadges(identity.id)).find( - (badge) => Number(badge.id) === Number(url.searchParams.get('update')) - ) - ) { - await updateUserBadge(identity.id, Number(url.searchParams.get('update')), badge as Badge); - } else { - await addUserBadge(identity.id, badge as Badge); - } - - return await badges(identity.id); + const userCookie = cookies.get('user'); + + if (!userCookie) return unauthorised; + + const user = JSON.parse(userCookie); + const identity = await userIdentity({ + tokenType: user['token_type'], + expiresIn: user['expires_in'], + accessToken: user['access_token'], + refreshToken: user['refresh_token'] + }); + const authorised = authorisedJson.includes(identity.id); + + if (url.searchParams.get('shadowHide')) + setShadowHidden(Number(url.searchParams.get('shadowHide')), authorised); + + if (url.searchParams.get('import') || undefined) { + await Promise.all( + (await request.json()).map(async (badge: Badge) => await addUserBadge(identity.id, badge)) + ); + + return await badges(identity.id); + } else if (url.searchParams.get('migrate') || undefined) { + await migrateCategory( + identity.id, + url.searchParams.get('original') || '', + url.searchParams.get('new') || '' + ); + + return await badges(identity.id); + } + + if (url.searchParams.get('hide') || undefined) { + const allBadges = await getUserBadges(identity.id); + + await Promise.all( + allBadges + .filter((badge) => badge.category === (url.searchParams.get('category') || '')) + .map(async (badge) => { + await updateUserBadge(identity.id, badge.id as number, { + ...badge, + hidden: + allBadges + .filter((badge) => badge.category === (url.searchParams.get('category') || '')) + .filter((badge) => badge.hidden).length > + allBadges.filter( + (badge) => badge.category === (url.searchParams.get('category') || '') + ).length / + 2 + ? false + : true + }); + }) + ); + + return await badges(identity.id); + } + + if (url.searchParams.get('shadowHideBadge') || undefined) { + if (!authorised) return unauthorised; + + await setShadowHiddenBadge( + Number(url.searchParams.get('id')), + Number(url.searchParams.get('shadowHideBadge')), + url.searchParams.get('status') == 'true' ? false : true + ); + + return await badges(Number(url.searchParams.get('id'))); + } + + const badge = { + post: url.searchParams.get('post') || undefined, + image: url.searchParams.get('image') || undefined, + description: url.searchParams.get('description') || null, + time: url.searchParams.get('time') || undefined, + category: url.searchParams.get('category') || null, + hidden: url.searchParams.get('hidden') || false, + source: url.searchParams.get('source') || null, + designer: url.searchParams.get('designer') || null + }; + + if ( + (await getUserBadges(identity.id)).find( + (badge) => Number(badge.id) === Number(url.searchParams.get('update')) + ) + ) { + await updateUserBadge(identity.id, Number(url.searchParams.get('update')), badge as Badge); + } else { + await addUserBadge(identity.id, badge as Badge); + } + + return await badges(identity.id); }; diff --git a/src/routes/user/[user]/badges/+page.svelte b/src/routes/user/[user]/badges/+page.svelte index 97e4999c..c1a3ae51 100644 --- a/src/routes/user/[user]/badges/+page.svelte +++ b/src/routes/user/[user]/badges/+page.svelte @@ -512,10 +512,10 @@ )} {#if isOwner || authorised} - {@const shadowHiddenCount = - ungroupedBadges.filter((badge) => badge.shadow_hidden).length} - {@const shadowHidden = - shadowHiddenCount > 0} + {@const shadowHiddenCount = ungroupedBadges.filter( + (badge) => badge.shadow_hidden + ).length} + {@const shadowHidden = shadowHiddenCount > 0} {#if shadowHidden} <div class="card"> diff --git a/static/styles/LaTeX.css b/static/styles/LaTeX.css index 39b159e0..b58df428 100644 --- a/static/styles/LaTeX.css +++ b/static/styles/LaTeX.css @@ -6,114 +6,111 @@ */ @font-face { - font-family: 'Latin Modern'; - font-style: normal; - font-weight: normal; - font-display: swap; - src: url('./fonts/LM-regular.woff2') format('woff2'), - url('./fonts/LM-regular.woff') format('woff'), - url('./fonts/LM-regular.ttf') format('truetype'); + font-family: 'Latin Modern'; + font-style: normal; + font-weight: normal; + font-display: swap; + src: url('./fonts/LM-regular.woff2') format('woff2'), + url('./fonts/LM-regular.woff') format('woff'), url('./fonts/LM-regular.ttf') format('truetype'); } @font-face { - font-family: 'Latin Modern'; - font-style: italic; - font-weight: normal; - font-display: swap; - src: url('./fonts/LM-italic.woff2') format('woff2'), - url('./fonts/LM-italic.woff') format('woff'), - url('./fonts/LM-italic.ttf') format('truetype'); + font-family: 'Latin Modern'; + font-style: italic; + font-weight: normal; + font-display: swap; + src: url('./fonts/LM-italic.woff2') format('woff2'), url('./fonts/LM-italic.woff') format('woff'), + url('./fonts/LM-italic.ttf') format('truetype'); } @font-face { - font-family: 'Latin Modern'; - font-style: normal; - font-weight: bold; - font-display: swap; - src: url('./fonts/LM-bold.woff2') format('woff2'), - url('./fonts/LM-bold.woff') format('woff'), - url('./fonts/LM-bold.ttf') format('truetype'); + font-family: 'Latin Modern'; + font-style: normal; + font-weight: bold; + font-display: swap; + src: url('./fonts/LM-bold.woff2') format('woff2'), url('./fonts/LM-bold.woff') format('woff'), + url('./fonts/LM-bold.ttf') format('truetype'); } @font-face { - font-family: 'Latin Modern'; - font-style: italic; - font-weight: bold; - font-display: swap; - src: url('./fonts/LM-bold-italic.woff2') format('woff2'), - url('./fonts/LM-bold-italic.woff') format('woff'), - url('./fonts/LM-bold-italic.ttf') format('truetype'); + font-family: 'Latin Modern'; + font-style: italic; + font-weight: bold; + font-display: swap; + src: url('./fonts/LM-bold-italic.woff2') format('woff2'), + url('./fonts/LM-bold-italic.woff') format('woff'), + url('./fonts/LM-bold-italic.ttf') format('truetype'); } @font-face { - font-family: 'Libertinus'; - font-style: normal; - font-weight: normal; - font-display: swap; - src: url('./fonts/Libertinus-regular.woff2') format('woff2'); + font-family: 'Libertinus'; + font-style: normal; + font-weight: normal; + font-display: swap; + src: url('./fonts/Libertinus-regular.woff2') format('woff2'); } @font-face { - font-family: 'Libertinus'; - font-style: italic; - font-weight: normal; - font-display: swap; - src: url('./fonts/Libertinus-italic.woff2') format('woff2'); + font-family: 'Libertinus'; + font-style: italic; + font-weight: normal; + font-display: swap; + src: url('./fonts/Libertinus-italic.woff2') format('woff2'); } @font-face { - font-family: 'Libertinus'; - font-style: normal; - font-weight: bold; - font-display: swap; - src: url('./fonts/Libertinus-bold.woff2') format('woff2'); + font-family: 'Libertinus'; + font-style: normal; + font-weight: bold; + font-display: swap; + src: url('./fonts/Libertinus-bold.woff2') format('woff2'); } @font-face { - font-family: 'Libertinus'; - font-style: italic; - font-weight: bold; - font-display: swap; - src: url('./fonts/Libertinus-bold-italic.woff2') format('woff2'); + font-family: 'Libertinus'; + font-style: italic; + font-weight: bold; + font-display: swap; + src: url('./fonts/Libertinus-bold-italic.woff2') format('woff2'); } @font-face { - font-family: 'Libertinus'; - font-style: normal; - font-weight: 600; - font-display: swap; - src: url('./fonts/Libertinus-semibold.woff2') format('woff2'); + font-family: 'Libertinus'; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url('./fonts/Libertinus-semibold.woff2') format('woff2'); } @font-face { - font-family: 'Libertinus'; - font-style: italic; - font-weight: 600; - font-display: swap; - src: url('./fonts/Libertinus-semibold-italic.woff2') format('woff2'); + font-family: 'Libertinus'; + font-style: italic; + font-weight: 600; + font-display: swap; + src: url('./fonts/Libertinus-semibold-italic.woff2') format('woff2'); } /* Box sizing rules */ *, *::before, *::after { - box-sizing: border-box; + box-sizing: border-box; } :root { - --body-color: hsl(0, 5%, 10%); - --body-bg-color: hsl(210, 20%, 98%); - --link-visited: hsl(0, 100%, 33%); - --link-focus-outline: hsl(220, 90%, 52%); - --pre-bg-color: hsl(210, 28%, 93%); - --kbd-bg-color: hsl(210, 5%, 100%); - --kbd-border-color: hsl(210, 5%, 70%); - --table-border-color: black; - --border-width-thin: 1.36px; - --border-width-thick: 2.27px; - --sidenote-target-border-color: hsl(55, 55%, 70%); - --footnotes-border-color: hsl(0, 0%, 39%); - --text-indent-size: 1.463rem; /* In 12pt [Latin Modern font] LaTeX article + --body-color: hsl(0, 5%, 10%); + --body-bg-color: hsl(210, 20%, 98%); + --link-visited: hsl(0, 100%, 33%); + --link-focus-outline: hsl(220, 90%, 52%); + --pre-bg-color: hsl(210, 28%, 93%); + --kbd-bg-color: hsl(210, 5%, 100%); + --kbd-border-color: hsl(210, 5%, 70%); + --table-border-color: black; + --border-width-thin: 1.36px; + --border-width-thick: 2.27px; + --sidenote-target-border-color: hsl(55, 55%, 70%); + --footnotes-border-color: hsl(0, 0%, 39%); + --text-indent-size: 1.463rem; /* In 12pt [Latin Modern font] LaTeX article \parindent =~ 17.625pt; taking also into account the ratio 1pt[LaTeX] = (72 / 72.27) * 1pt[HTML], with default 12pt/1rem LaTeX.css font size, the identation value in rem CSS units is: @@ -121,33 +118,33 @@ } .latex-dark { - --body-color: hsl(0, 0%, 86%); - --body-bg-color: hsl(0, 0%, 16%); - --link-visited: hsl(196 80% 77%); - --link-focus-outline: hsl(215, 63%, 73%); - --pre-bg-color: hsl(0, 1%, 25%); - --kbd-bg-color: hsl(0, 0%, 16%); - --kbd-border-color: hsl(210, 5%, 70%); - --table-border-color: white; - --sidenote-target-border-color: hsl(0, 0%, 59%); - --footnotes-border-color: hsl(0, 0%, 59%); - --proof-symbol-filter: invert(80%); + --body-color: hsl(0, 0%, 86%); + --body-bg-color: hsl(0, 0%, 16%); + --link-visited: hsl(196 80% 77%); + --link-focus-outline: hsl(215, 63%, 73%); + --pre-bg-color: hsl(0, 1%, 25%); + --kbd-bg-color: hsl(0, 0%, 16%); + --kbd-border-color: hsl(210, 5%, 70%); + --table-border-color: white; + --sidenote-target-border-color: hsl(0, 0%, 59%); + --footnotes-border-color: hsl(0, 0%, 59%); + --proof-symbol-filter: invert(80%); } @media (prefers-color-scheme: dark) { - .latex-dark-auto { - --body-color: hsl(0, 0%, 86%); - --body-bg-color: hsl(0, 0%, 16%); - --link-visited: hsl(196 80% 77%); - --link-focus-outline: hsl(215, 63%, 73%); - --pre-bg-color: hsl(0, 1%, 25%); - --kbd-bg-color: hsl(0, 0%, 16%); - --kbd-border-color: hsl(210, 5%, 70%); - --table-border-color: white; - --sidenote-target-border-color: hsl(0, 0%, 59%); - --footnotes-border-color: hsl(0, 0%, 59%); - --proof-symbol-filter: invert(80%); - } + .latex-dark-auto { + --body-color: hsl(0, 0%, 86%); + --body-bg-color: hsl(0, 0%, 16%); + --link-visited: hsl(196 80% 77%); + --link-focus-outline: hsl(215, 63%, 73%); + --pre-bg-color: hsl(0, 1%, 25%); + --kbd-bg-color: hsl(0, 0%, 16%); + --kbd-border-color: hsl(210, 5%, 70%); + --table-border-color: white; + --sidenote-target-border-color: hsl(0, 0%, 59%); + --footnotes-border-color: hsl(0, 0%, 59%); + --proof-symbol-filter: invert(80%); + } } /* Remove default margin */ @@ -164,92 +161,92 @@ figure, figcaption, dl, dd { - margin: 0; + margin: 0; } /* Make default font-size 1rem and add smooth scrolling to anchors */ html { - font-size: 1rem; + font-size: 1rem; } @media (prefers-reduced-motion: no-preference) { - html { - scroll-behavior: smooth; - } + html { + scroll-behavior: smooth; + } } body.libertinus { - font-family: 'Libertinus', Georgia, Cambria, 'Times New Roman', Times, serif; + font-family: 'Libertinus', Georgia, Cambria, 'Times New Roman', Times, serif; } body { - font-family: 'Latin Modern', Georgia, Cambria, 'Times New Roman', Times, serif; - line-height: 1.8; + font-family: 'Latin Modern', Georgia, Cambria, 'Times New Roman', Times, serif; + line-height: 1.8; - max-width: 80ch; - min-height: 100vh; - overflow-x: hidden; - margin: 0 auto; - padding: 2rem 1.25rem; + max-width: 80ch; + min-height: 100vh; + overflow-x: hidden; + margin: 0 auto; + padding: 2rem 1.25rem; - counter-reset: theorem definition sidenote-counter; + counter-reset: theorem definition sidenote-counter; - color: var(--body-color); - background-color: var(--body-bg-color); + color: var(--body-color); + background-color: var(--body-bg-color); - text-rendering: optimizeLegibility; + text-rendering: optimizeLegibility; } /* Justify and hyphenate all paragraphs */ p { - text-align: justify; - hyphens: auto; - -webkit-hyphens: auto; - -moz-hyphens: auto; - margin-top: 1rem; + text-align: justify; + hyphens: auto; + -webkit-hyphens: auto; + -moz-hyphens: auto; + margin-top: 1rem; } /* Indents paragraphs like in LaTeX documents*/ .indent-pars p { - text-indent: var(--text-indent-size); + text-indent: var(--text-indent-size); } .indent-pars p.no-indent, p.no-indent { - text-indent: 0; + text-indent: 0; } .indent-pars ol p, .indent-pars ul p { - text-indent: 0; + text-indent: 0; } .indent-pars h2 + p, .indent-pars h3 + p, .indent-pars h4 + p { - text-indent: 0; + text-indent: 0; } /* A elements that don't have a class get default styles */ a:not([class]) { - text-decoration-skip-ink: auto; + text-decoration-skip-ink: auto; } /* Make links red */ a, a:visited { - color: var(--link-visited); + color: var(--link-visited); } a:focus { - outline-offset: 2px; - outline: 2px solid var(--link-focus-outline); + outline-offset: 2px; + outline: 2px solid var(--link-focus-outline); } /* Make images easier to work with */ img { - max-width: 100%; - height: auto; - display: block; + max-width: 100%; + height: auto; + display: block; } /* Inherit fonts for inputs and buttons */ @@ -257,142 +254,141 @@ input, button, textarea, select { - font: inherit; + font: inherit; } /* Prevent textarea from overflowing */ textarea { - width: 100%; + width: 100%; } /* Natural flow and rhythm in articles by default */ article > * + * { - margin-top: 1em; + margin-top: 1em; } /* Styles for inline code or code snippets */ code, pre, kbd { - font-family: Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', - monospace; - font-size: 85%; + font-family: Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; + font-size: 85%; } pre { - padding: 1rem 1.4rem; - max-width: 100%; - overflow: auto; - border-radius: 4px; - background: var(--pre-bg-color); + padding: 1rem 1.4rem; + max-width: 100%; + overflow: auto; + border-radius: 4px; + background: var(--pre-bg-color); } pre code { - font-size: 95%; - position: relative; + font-size: 95%; + position: relative; } kbd { - background: var(--kbd-bg-color); - border: 1px solid var(--kbd-border-color); - border-radius: 2px; - padding: 2px 4px; - font-size: 75%; + background: var(--kbd-bg-color); + border: 1px solid var(--kbd-border-color); + border-radius: 2px; + padding: 2px 4px; + font-size: 75%; } /* Better tables */ table:not(.borders-custom) { - border-collapse: collapse; - border-spacing: 0; - width: auto; - max-width: 100%; - border-top: var(--border-width-thick) solid var(--table-border-color); - border-bottom: var(--border-width-thick) solid var(--table-border-color); - /* display: block; */ - overflow-x: auto; /* does not work because element is not block */ - /* white-space: nowrap; */ - counter-increment: caption; + border-collapse: collapse; + border-spacing: 0; + width: auto; + max-width: 100%; + border-top: var(--border-width-thick) solid var(--table-border-color); + border-bottom: var(--border-width-thick) solid var(--table-border-color); + /* display: block; */ + overflow-x: auto; /* does not work because element is not block */ + /* white-space: nowrap; */ + counter-increment: caption; } /* add bottom border on column table headings */ table:not(.borders-custom) tr > th[scope='col'] { - border-bottom: var(--border-width-thin) solid var(--table-border-color); + border-bottom: var(--border-width-thin) solid var(--table-border-color); } /* add right border on row table headings */ table:not(.borders-custom) tr > th[scope='row'] { - border-right: var(--border-width-thin) solid var(--table-border-color); + border-right: var(--border-width-thin) solid var(--table-border-color); } table:not(.borders-custom) > tbody > tr:first-child > td, table:not(.borders-custom) > tbody > tr:first-child > th { - border-top: var(--border-width-thin) solid var(--table-border-color); + border-top: var(--border-width-thin) solid var(--table-border-color); } table:not(.borders-custom) > tbody > tr:last-child > td, table:not(.borders-custom) > tbody > tr:last-child > th { - border-bottom: var(--border-width-thin) solid var(--table-border-color); + border-bottom: var(--border-width-thin) solid var(--table-border-color); } th, td { - text-align: left; - padding: 0.5rem; - line-height: 1.1; + text-align: left; + padding: 0.5rem; + line-height: 1.1; } /* Table caption */ caption { - text-align: left; - font-size: 0.923em; - /* border-bottom: 2pt solid #000; */ - padding: 0 0.25em 0.25em; - width: 100%; - margin-left: 0; + text-align: left; + font-size: 0.923em; + /* border-bottom: 2pt solid #000; */ + padding: 0 0.25em 0.25em; + width: 100%; + margin-left: 0; } caption::before { - content: 'Table ' counter(caption) '. '; - font-weight: bold; + content: 'Table ' counter(caption) '. '; + font-weight: bold; } /* allow scroll on the x-axis */ .scroll-wrapper { - overflow-x: auto; + overflow-x: auto; } /* if a table is wrapped in a scroll wrapper, the table cells shouldn't wrap */ .scroll-wrapper > table td { - white-space: nowrap; + white-space: nowrap; } /* Table custom borders */ table.borders-custom { - border-collapse: collapse; - border-spacing: 0; - width: auto; - max-width: 100%; - overflow-x: auto; - counter-increment: caption; + border-collapse: collapse; + border-spacing: 0; + width: auto; + max-width: 100%; + overflow-x: auto; + counter-increment: caption; } .border-top-thick { - border-top: var(--border-width-thick) solid var(--table-border-color); + border-top: var(--border-width-thick) solid var(--table-border-color); } .border-right-thick { - border-right: var(--border-width-thick) solid var(--table-border-color); + border-right: var(--border-width-thick) solid var(--table-border-color); } .border-bottom-thick { - border-bottom: var(--border-width-thick) solid var(--table-border-color); + border-bottom: var(--border-width-thick) solid var(--table-border-color); } .border-left-thick { - border-left: var(--border-width-thick) solid var(--table-border-color); + border-left: var(--border-width-thick) solid var(--table-border-color); } .border-top-thin { - border-top: var(--border-width-thin) solid var(--table-border-color); + border-top: var(--border-width-thin) solid var(--table-border-color); } .border-right-thin { - border-right: var(--border-width-thin) solid var(--table-border-color); + border-right: var(--border-width-thin) solid var(--table-border-color); } .border-bottom-thin { - border-bottom: var(--border-width-thin) solid var(--table-border-color); + border-bottom: var(--border-width-thin) solid var(--table-border-color); } .border-left-thin { - border-left: var(--border-width-thin) solid var(--table-border-color); + border-left: var(--border-width-thin) solid var(--table-border-color); } /* Table column alignment */ @@ -408,7 +404,7 @@ table.borders-custom { .col-10-l tr > :nth-child(10), .col-11-l tr > :nth-child(11), .col-12-l tr > :nth-child(12) { - text-align: left; + text-align: left; } .col-1-c tr > :nth-child(1), .col-2-c tr > :nth-child(2), @@ -422,7 +418,7 @@ table.borders-custom { .col-10-c tr > :nth-child(10), .col-11-c tr > :nth-child(11), .col-12-c tr > :nth-child(12) { - text-align: center; + text-align: center; } .col-1-r tr > :nth-child(1), .col-2-r tr > :nth-child(2), @@ -436,289 +432,288 @@ table.borders-custom { .col-10-r tr > :nth-child(10), .col-11-r tr > :nth-child(11), .col-12-r tr > :nth-child(12) { - text-align: right; + text-align: right; } /* Center align the title */ h1:first-child { - text-align: center; + text-align: center; } /* Nested ordered list for ToC */ nav ol { - counter-reset: item; - padding-left: 2rem; + counter-reset: item; + padding-left: 2rem; } nav li { - display: block; + display: block; } nav li:before { - content: counters(item, '.') ' '; - counter-increment: item; - padding-right: 0.85rem; + content: counters(item, '.') ' '; + counter-increment: item; + padding-right: 0.85rem; } /* Center definitions (most useful for display equations) */ dl dd { - text-align: center; + text-align: center; } /* Theorem */ .theorem { - counter-increment: theorem; - display: block; - margin: 12px 0; - font-style: italic; + counter-increment: theorem; + display: block; + margin: 12px 0; + font-style: italic; } .theorem::before { - content: 'Theorem ' counter(theorem) '. '; - font-weight: bold; - font-style: normal; + content: 'Theorem ' counter(theorem) '. '; + font-weight: bold; + font-style: normal; } /* Lemma */ .lemma { - counter-increment: theorem; - display: block; - margin: 12px 0; - font-style: italic; + counter-increment: theorem; + display: block; + margin: 12px 0; + font-style: italic; } .lemma::before { - content: 'Lemma ' counter(theorem) '. '; - font-weight: bold; - font-style: normal; + content: 'Lemma ' counter(theorem) '. '; + font-weight: bold; + font-style: normal; } /* Proof */ .proof { - display: block; - margin: 12px 0; - font-style: normal; - position: relative; + display: block; + margin: 12px 0; + font-style: normal; + position: relative; } .proof::before { - content: 'Proof. ' attr(title); - font-style: italic; + content: 'Proof. ' attr(title); + font-style: italic; } .proof:after { - content: '◾️'; - filter: var(--proof-symbol-filter); - position: absolute; - right: -12px; - bottom: -2px; + content: '◾️'; + filter: var(--proof-symbol-filter); + position: absolute; + right: -12px; + bottom: -2px; } /* Definition */ .definition { - counter-increment: definition; - display: block; - margin: 12px 0; - font-style: normal; + counter-increment: definition; + display: block; + margin: 12px 0; + font-style: normal; } .definition::before { - content: 'Definition ' counter(definition) '. '; - font-weight: bold; - font-style: normal; + content: 'Definition ' counter(definition) '. '; + font-weight: bold; + font-style: normal; } /* Center align author name, use small caps and add vertical spacing */ .author { - margin: 0.85rem 0; - font-variant-caps: small-caps; - text-align: center; + margin: 0.85rem 0; + font-variant-caps: small-caps; + text-align: center; } /* Sidenotes */ .sidenote { - font-size: 0.8rem; - float: right; - clear: right; - width: 18vw; - margin-right: -20vw; - margin-bottom: 1em; - text-indent: 0; + font-size: 0.8rem; + float: right; + clear: right; + width: 18vw; + margin-right: -20vw; + margin-bottom: 1em; + text-indent: 0; } .sidenote.left { - float: left; - margin-left: -20vw; - margin-bottom: 1em; - text-indent: 0; + float: left; + margin-left: -20vw; + margin-bottom: 1em; + text-indent: 0; } /* (WIP) add border when a sidenote is clicked on */ .sidenote:target { - border: var(--sidenote-target-border-color) 1.5px solid; - padding: 0 .5rem; - scroll-margin-block-start: 10rem; + border: var(--sidenote-target-border-color) 1.5px solid; + padding: 0 0.5rem; + scroll-margin-block-start: 10rem; } /* sidenote counter */ .sidenote-number { - counter-increment: sidenote-counter; + counter-increment: sidenote-counter; } .sidenote-number::after, .sidenote::before { - position: relative; - vertical-align: baseline; + position: relative; + vertical-align: baseline; } /* add number in main content */ .sidenote-number::after { - content: counter(sidenote-counter); - font-size: 0.7rem; - top: -0.5rem; - left: 0.1rem; + content: counter(sidenote-counter); + font-size: 0.7rem; + top: -0.5rem; + left: 0.1rem; } /* add number in front of the sidenote */ .sidenote-number ~ .sidenote::before { - content: counter(sidenote-counter) ' '; - font-size: 0.7rem; - top: -0.5rem; + content: counter(sidenote-counter) ' '; + font-size: 0.7rem; + top: -0.5rem; } label.sidenote-toggle:not(.sidenote-number) { - display: none; + display: none; } /* sidenotes inside blockquotes are indented more */ blockquote .sidenote { - margin-right: -24vw; - width: 18vw; + margin-right: -24vw; + width: 18vw; } - label.sidenote-toggle { - display: inline; - cursor: pointer; + display: inline; + cursor: pointer; } input.sidenote-toggle { - display: none; + display: none; } @media (max-width: 1050px) { - label.sidenote-toggle:not(.sidenote-number) { - display: inline; - } - .sidenote { - display: none; - } - .sidenote-toggle:checked + .sidenote { - display: block; - margin: 0.5rem 1.25rem 1rem 0.5rem; - float: left; - left: 1rem; - clear: both; - width: 95%; - } - /* tweak indentation of sidenote inside a blockquote */ - blockquote .sidenote { - margin-right: -25vw; - width: 16vw; - } + label.sidenote-toggle:not(.sidenote-number) { + display: inline; + } + .sidenote { + display: none; + } + .sidenote-toggle:checked + .sidenote { + display: block; + margin: 0.5rem 1.25rem 1rem 0.5rem; + float: left; + left: 1rem; + clear: both; + width: 95%; + } + /* tweak indentation of sidenote inside a blockquote */ + blockquote .sidenote { + margin-right: -25vw; + width: 16vw; + } } /* Make footnote text smaller and left align it (looks bad with long URLs) */ .footnotes p { - text-align: left; - line-height: 1.5; - font-size: 85%; - margin-bottom: 0.4rem; + text-align: left; + line-height: 1.5; + font-size: 85%; + margin-bottom: 0.4rem; } .footnotes { - border-top: 1px solid var(--footnotes-border-color); + border-top: 1px solid var(--footnotes-border-color); } /* Center title and paragraph */ .abstract, .abstract p { - text-align: center; - margin-top: 0; + text-align: center; + margin-top: 0; } .abstract { - margin: 2.25rem 0; + margin: 2.25rem 0; } .abstract > h2 { - font-size: 1rem; - margin-bottom: -0.2rem; + font-size: 1rem; + margin-bottom: -0.2rem; } /* Format the LaTeX symbol correctly (a higher up, e lower) */ .latex span:nth-child(1) { - text-transform: uppercase; - font-size: 0.75em; - vertical-align: 0.28em; - margin-left: -0.48em; - margin-right: -0.15em; - line-height: 1ex; + text-transform: uppercase; + font-size: 0.75em; + vertical-align: 0.28em; + margin-left: -0.48em; + margin-right: -0.15em; + line-height: 1ex; } .latex span:nth-child(2) { - text-transform: uppercase; - vertical-align: -0.5ex; - margin-left: -0.1667em; - margin-right: -0.125em; - line-height: 1ex; + text-transform: uppercase; + vertical-align: -0.5ex; + margin-left: -0.1667em; + margin-right: -0.125em; + line-height: 1ex; } /* Heading typography */ h1 { - font-size: 2.5rem; - line-height: 3.25rem; - margin-bottom: 1.625rem; + font-size: 2.5rem; + line-height: 3.25rem; + margin-bottom: 1.625rem; } h2 { - font-size: 1.7rem; - line-height: 2rem; - margin-top: 3rem; + font-size: 1.7rem; + line-height: 2rem; + margin-top: 3rem; } h3 { - font-size: 1.4rem; - margin-top: 2.5rem; + font-size: 1.4rem; + margin-top: 2.5rem; } h4 { - font-size: 1.2rem; - margin-top: 2rem; + font-size: 1.2rem; + margin-top: 2rem; } h5 { - font-size: 1rem; - margin-top: 1.8rem; + font-size: 1rem; + margin-top: 1.8rem; } h6 { - font-size: 1rem; - font-style: italic; - font-weight: normal; - margin-top: 2.5rem; + font-size: 1rem; + font-style: italic; + font-weight: normal; + margin-top: 2.5rem; } h3, h4, h5, h6 { - line-height: 1.625rem; + line-height: 1.625rem; } h1 + h2 { - margin-top: 1.625rem; + margin-top: 1.625rem; } h2 + h3, h3 + h4, h4 + h5 { - margin-top: 0.8rem; + margin-top: 0.8rem; } h5 + h6 { - margin-top: -0.8rem; + margin-top: -0.8rem; } h2, @@ -726,5 +721,5 @@ h3, h4, h5, h6 { - margin-bottom: 0.8rem; + margin-bottom: 0.8rem; } |