Fix some alignment issues, add reading time estimates
This commit is contained in:
parent
5e8eb94d6b
commit
25f07fd9bb
24
package-lock.json
generated
24
package-lock.json
generated
|
@ -8,11 +8,13 @@
|
||||||
"name": "bgenc.net-new",
|
"name": "bgenc.net-new",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sveltejs/adapter-static": "^2.0.3"
|
"@sveltejs/adapter-static": "^2.0.3",
|
||||||
|
"reading-time-estimator": "^1.11.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sveltejs/kit": "^1.27.6",
|
"@sveltejs/kit": "^1.27.6",
|
||||||
"@types/lodash": "^4.14.201",
|
"@types/lodash": "^4.14.201",
|
||||||
|
"@types/node": "^20.12.8",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.11.0",
|
"@typescript-eslint/eslint-plugin": "^6.11.0",
|
||||||
"@typescript-eslint/parser": "^6.11.0",
|
"@typescript-eslint/parser": "^6.11.0",
|
||||||
"date-fns": "^2.30.0",
|
"date-fns": "^2.30.0",
|
||||||
|
@ -360,6 +362,15 @@
|
||||||
"integrity": "sha512-y9euML0cim1JrykNxADLfaG0FgD1g/yTHwUs/Jg9ZIU7WKj2/4IW9Lbb1WZbvck78W/lfGXFfe+u2EGfIJXdLQ==",
|
"integrity": "sha512-y9euML0cim1JrykNxADLfaG0FgD1g/yTHwUs/Jg9ZIU7WKj2/4IW9Lbb1WZbvck78W/lfGXFfe+u2EGfIJXdLQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/node": {
|
||||||
|
"version": "20.12.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.8.tgz",
|
||||||
|
"integrity": "sha512-NU0rJLJnshZWdE/097cdCBbyW1h4hEg0xpovcoAQYHl8dnEyp/NAOiE45pvc+Bd1Dt+2r94v2eGFpQJ4R7g+2w==",
|
||||||
|
"devOptional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": "~5.26.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/pug": {
|
"node_modules/@types/pug": {
|
||||||
"version": "2.0.9",
|
"version": "2.0.9",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
@ -2356,6 +2367,11 @@
|
||||||
"node": ">=8.10.0"
|
"node": ">=8.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/reading-time-estimator": {
|
||||||
|
"version": "1.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/reading-time-estimator/-/reading-time-estimator-1.11.0.tgz",
|
||||||
|
"integrity": "sha512-2813WXSxCPsDvgrYq+cPBI4gGqgmtKlo62rpI0mwnhrMfZJIqbDfOeidr9Y36OruDesQGmYA9DkVRmvsBbv2DA=="
|
||||||
|
},
|
||||||
"node_modules/regenerator-runtime": {
|
"node_modules/regenerator-runtime": {
|
||||||
"version": "0.14.0",
|
"version": "0.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz",
|
||||||
|
@ -2966,6 +2982,12 @@
|
||||||
"node": ">=14.0"
|
"node": ">=14.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/undici-types": {
|
||||||
|
"version": "5.26.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||||
|
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||||
|
"devOptional": true
|
||||||
|
},
|
||||||
"node_modules/unist-util-stringify-position": {
|
"node_modules/unist-util-stringify-position": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sveltejs/kit": "^1.27.6",
|
"@sveltejs/kit": "^1.27.6",
|
||||||
"@types/lodash": "^4.14.201",
|
"@types/lodash": "^4.14.201",
|
||||||
|
"@types/node": "^20.12.8",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.11.0",
|
"@typescript-eslint/eslint-plugin": "^6.11.0",
|
||||||
"@typescript-eslint/parser": "^6.11.0",
|
"@typescript-eslint/parser": "^6.11.0",
|
||||||
"date-fns": "^2.30.0",
|
"date-fns": "^2.30.0",
|
||||||
|
@ -34,6 +35,7 @@
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sveltejs/adapter-static": "^2.0.3"
|
"@sveltejs/adapter-static": "^2.0.3",
|
||||||
|
"reading-time-estimator": "^1.11.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,9 @@
|
||||||
<style>
|
<style>
|
||||||
a,
|
a,
|
||||||
button {
|
button {
|
||||||
display: inline-block;
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
color: hsl(var(--color-text-h), var(--color-text-s), calc(100% - var(--color-text-l)));
|
color: hsl(var(--color-text-h), var(--color-text-s), calc(100% - var(--color-text-l)));
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<header>
|
<header>
|
||||||
<a href="/">
|
<a class="logo" href="/">
|
||||||
<picture class="logo">
|
<picture>
|
||||||
<source srcset={Avif} type="image/avif" />
|
<source srcset={Avif} type="image/avif" />
|
||||||
<source srcset={WebP} type="image/webp" />
|
<source srcset={WebP} type="image/webp" />
|
||||||
<img
|
<img
|
||||||
|
@ -31,9 +31,11 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-right: 4rem;
|
margin-right: 4rem;
|
||||||
gap: 2rem;
|
gap: 2rem;
|
||||||
|
margin-bottom: -3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
width: 12rem;
|
width: 12rem;
|
||||||
|
align-self: flex-start;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,4 +1,10 @@
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
import { readingTime } from 'reading-time-estimator';
|
||||||
|
import path from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
import { readFile } from 'fs/promises';
|
||||||
|
|
||||||
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
const PAGE_SIZE = 10;
|
const PAGE_SIZE = 10;
|
||||||
|
|
||||||
|
@ -7,15 +13,18 @@ export async function load({ params }) {
|
||||||
const iterablePostFiles = Object.entries(allPostFiles);
|
const iterablePostFiles = Object.entries(allPostFiles);
|
||||||
|
|
||||||
const posts = await Promise.all(
|
const posts = await Promise.all(
|
||||||
iterablePostFiles.map(async ([path, resolver]) => {
|
iterablePostFiles.map(async ([filePath, resolver]) => {
|
||||||
const { metadata } = await resolver();
|
const { metadata } = await resolver();
|
||||||
|
|
||||||
const slug = /[/]([^/]*)[.]md$/.exec(path)?.[1];
|
const slug = /[/]([^/]*)[.]md$/.exec(filePath)?.[1];
|
||||||
if (!slug) throw new Error(`Could not parse slug from path: ${path}`);
|
if (!slug) throw new Error(`Could not parse slug from path: ${filePath}`);
|
||||||
|
|
||||||
|
const contents = await readFile(path.join(__dirname, '..', `${slug}.md`), 'utf8');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
meta: metadata,
|
meta: metadata,
|
||||||
path: slug,
|
path: slug,
|
||||||
|
readingTime: readingTime(contents),
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
@ -33,3 +42,4 @@ export async function load({ params }) {
|
||||||
pageCount: Math.ceil(posts.length / PAGE_SIZE),
|
pageCount: Math.ceil(posts.length / PAGE_SIZE),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
export type Post = Awaited<ReturnType<typeof load>>['posts'][number];
|
|
@ -1,11 +1,13 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Button from '$lib/Button.svelte';
|
import Button from '$lib/Button.svelte';
|
||||||
|
import { ArrowLeft, ArrowLineLeft, ArrowLineRight, ArrowRight } from 'phosphor-svelte';
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
|
import type { Post } from './+page.server';
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
|
|
||||||
function groupPosts(posts: any[]) {
|
function groupPosts(posts: Post[]) {
|
||||||
const postsByYear = new Map<string, any[]>();
|
const postsByYear = new Map<string, Post[]>();
|
||||||
posts.forEach((post) => {
|
posts.forEach((post) => {
|
||||||
const year = format(new Date(post.meta.date), 'yyyy');
|
const year = format(new Date(post.meta.date), 'yyyy');
|
||||||
if (!postsByYear.has(year)) {
|
if (!postsByYear.has(year)) {
|
||||||
|
@ -31,6 +33,7 @@
|
||||||
<time datetime={post.meta.date}>
|
<time datetime={post.meta.date}>
|
||||||
{format(new Date(post.meta.date), 'MMMM d')}
|
{format(new Date(post.meta.date), 'MMMM d')}
|
||||||
</time>
|
</time>
|
||||||
|
<span>about {post.readingTime.text}</span>
|
||||||
</li>
|
</li>
|
||||||
</a>
|
</a>
|
||||||
{/each}
|
{/each}
|
||||||
|
@ -40,16 +43,14 @@
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="pagination-controls">
|
<div class="pagination-controls">
|
||||||
<Button disabled={data.page < 3} href={'/posts/'}>{data.page < 3 ? '_' : data.page - 1}</Button>
|
<Button disabled={data.page < 3} href={'/posts/'}><ArrowLineLeft /></Button>
|
||||||
<Button disabled={data.page === 1} href={data.page === 2 ? '/posts/' : `/posts/${data.page - 1}`}
|
<Button disabled={data.page === 1} href={data.page === 2 ? '/posts/' : `/posts/${data.page - 1}`}
|
||||||
>{data.page === 1 ? '_' : data.page - 1}</Button
|
><ArrowLeft /></Button
|
||||||
>
|
>
|
||||||
<span class="current-page">{data.page}</span>
|
<span class="current-page">{data.page}</span>
|
||||||
<Button disabled={!data.hasMore} href="/posts/{data.page + 1}"
|
<Button disabled={!data.hasMore} href="/posts/{data.page + 1}"><ArrowRight /></Button>
|
||||||
>{data.hasMore ? data.page + 1 : '_'}</Button
|
|
||||||
>
|
|
||||||
<Button disabled={data.page > data.pageCount - 2} href="/posts/{data.pageCount}"
|
<Button disabled={data.page > data.pageCount - 2} href="/posts/{data.pageCount}"
|
||||||
>{data.page > data.pageCount - 2 ? '_' : data.pageCount}</Button
|
><ArrowLineRight /></Button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -65,25 +66,14 @@
|
||||||
gap: 0.2rem;
|
gap: 0.2rem;
|
||||||
margin-top: 2rem;
|
margin-top: 2rem;
|
||||||
}
|
}
|
||||||
:global(.pagination-controls > :first-child) {
|
|
||||||
margin-right: 1rem;
|
|
||||||
}
|
|
||||||
:global(.pagination-controls > :last-child) {
|
|
||||||
margin-left: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.current-page {
|
.current-page {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
color: hsl(var(--color-text-h), var(--color-text-s), calc(100% - var(--color-text-l)));
|
font-weight: bolder;
|
||||||
font-weight: 600;
|
color: var(--color-primary);
|
||||||
text-decoration: none;
|
|
||||||
opacity: 0.6;
|
|
||||||
cursor: unset;
|
cursor: unset;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
background-color: var(--color-primary);
|
|
||||||
padding: 0.5rem 1rem;
|
padding: 0.5rem 1rem;
|
||||||
clip-path: var(--clip-path-button);
|
|
||||||
transition: all var(--animation-speed) var(--animation-type);
|
|
||||||
}
|
}
|
||||||
.post-title {
|
.post-title {
|
||||||
margin-bottom: 0.3rem;
|
margin-bottom: 0.3rem;
|
||||||
|
|
Loading…
Reference in a new issue