1
0
Fork 0
mirror of https://github.com/mat-1/matdoesdev.git synced 2025-08-02 14:46:04 +00:00

Merge branch 'main' into metasearch-post

This commit is contained in:
mat 2024-01-10 18:04:18 -06:00
commit 40f275649a
14 changed files with 593 additions and 392 deletions

Binary file not shown.

View file

@ -14,37 +14,38 @@
"postinstall": "patch-package"
},
"devDependencies": {
"@img/sharp-linux-x64": "^0.33.0",
"@img/sharp-linux-x64": "^0.33.1",
"@sveltejs/vite-plugin-svelte": "^3.0.1",
"@types/cookie": "^0.6.0",
"@types/html-minifier": "^4.0.5",
"@typescript-eslint/eslint-plugin": "^6.13.2",
"@typescript-eslint/parser": "^6.13.2",
"eslint": "^8.55.0",
"@typescript-eslint/eslint-plugin": "^6.18.1",
"@typescript-eslint/parser": "^6.18.1",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"mdsvex": "^0.11.0",
"prettier": "^3.1.0",
"prettier": "^3.1.1",
"prettier-plugin-svelte": "^3.1.2",
"sharp": "^0.33.0",
"sharp": "^0.33.1",
"svelte": "4.2.8",
"svelte-check": "^3.6.2",
"svelte-preprocess": "^5.1.1",
"svelte-preprocess": "^5.1.3",
"tslib": "^2.6.2",
"typescript": "^5.3.3"
},
"type": "module",
"dependencies": {
"@lukeed/uuid": "^2.0.1",
"@sveltejs/adapter-node": "1.3.1",
"@sveltejs/adapter-static": "^2.0.3",
"@sveltejs/kit": "1.27.7",
"@sveltejs/adapter-node": "^3.0.0",
"@sveltejs/adapter-static": "^3.0.1",
"@sveltejs/kit": "^2.3.0",
"@types/js-yaml": "^4.0.9",
"cbor-x": "^1.5.6",
"cbor-x": "^1.5.7",
"cookie": "^0.6.0",
"html-minifier": "^4.0.0",
"patch-package": "^8.0.0",
"postinstall-postinstall": "^2.1.0",
"svelte-body": "^1.4.0",
"vite": "5.0.6"
"vite": "5.0.11"
},
"engines": {
"node": ">=16"

View file

@ -19,12 +19,11 @@
<nav>
<BackAnchor href="/blog" />
</nav>
<div class="article-header">
<h1>{title}</h1>
<time>{new Date(published).toLocaleDateString()}</time>
</div>
<article>
<div class="article-header">
<h1>{title}</h1>
<time>{new Date(published).toLocaleDateString()}</time>
</div>
<slot />
</article>
</div>
@ -56,6 +55,7 @@
}
h1 {
margin-bottom: 0;
font-size: 1.5em;
}
.article-header {
margin-bottom: 1em;

View file

@ -24,7 +24,7 @@ export async function listBlogPostSlugs(): Promise<string[]> {
)
}
interface BlogPost {
export interface BlogPost {
title: string
published: string
html: string

View file

@ -20,6 +20,11 @@
})
</script>
<svelte:head>
<link rel="alternate" type="application/rss+xml" title="RSS" href="/blog.rss" />
<link rel="alternate" type="application/atom+xml" title="Atom" href="/blog.atom" />
</svelte:head>
<Head />
<div class="section-container">

View file

@ -10,7 +10,7 @@ export const load: Load = async ({ params }) => {
try {
page = await import(`../../(blog)/${slug}/index.svx`)
} catch (e) {
throw error(404, 'Not found')
error(404, 'Not found');
}
return {

View file

@ -21,7 +21,7 @@ export const GET: RequestHandler = async ({ params }) => {
if (!postSlug) throw new Error('No slug')
if (!assetName) throw new Error('No asset')
if (!(await doesAssetExist(postSlug, assetName))) throw error(404, 'Not found')
if (!(await doesAssetExist(postSlug, assetName))) error(404, 'Not found');
const file = await fs.promises.readFile(path.join(postsDir, postSlug, assetName))

View file

@ -15,7 +15,7 @@ export const GET: RequestHandler = async ({ params }) => {
const post = await getPost(slug)
if (post === null) throw error(404, 'Not found')
if (post === null) error(404, 'Not found');
return json({
title: post.title,

View file

@ -1,11 +1,16 @@
import type { RequestHandler } from '@sveltejs/kit'
import type { BlogPostPreview } from '../blog.json/+server'
import type { BlogPost } from '$lib/blog'
import { getPostsUntrimmed } from '../blog.json/preview'
export const prerender = true
export const GET: RequestHandler = async ({ fetch }) => {
const posts = (await fetch('/blog.json').then((r) => r.json())) as BlogPostPreview[]
function item(post: BlogPostPreview) {
const posts = await getPostsUntrimmed()
function item(post: BlogPost) {
const escapedPostHtml = post.html
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
return `
<entry>
<title>${post.title}</title>
@ -13,6 +18,7 @@ export const GET: RequestHandler = async ({ fetch }) => {
<id>https://matdoes.dev/${post.slug}</id>
<published>${post.published}</published>
<updated>${post.published}</updated>
<content type="xhtml">${escapedPostHtml}</content>
</entry>
`
}

View file

@ -1,80 +1,10 @@
import { getPost, listBlogPostSlugs } from '$lib/blog'
import { json, type RequestHandler } from '@sveltejs/kit'
import { getPostsUntrimmed } from './preview'
export const prerender = true
export interface BlogPostPreview {
title: string
published: string
html: string
css: string
slug: string
}
function cutOffAtLine(text: string, line: number) {
let row = 0
let column = 0
let inHtmlTag = false
for (let i = 0; i < text.length; i++) {
if (text[i] === '<') {
inHtmlTag = true
} else if (text[i] === '>') {
inHtmlTag = false
continue
}
if (text[i] === '\n') {
row++
column = 0
} else {
column++
}
if (column > 128 && !inHtmlTag) {
row++
column = 0
}
if (row >= line && !inHtmlTag) {
return text.slice(0, i) + '...'
}
}
return text
}
async function getPosts() {
const existingPosts: string[] = await listBlogPostSlugs()
const posts = (
await Promise.all(
existingPosts.map(async (slug): Promise<BlogPostPreview | null> => {
const blogPost = await getPost(slug)
// theoretically it's possible a blog post was deleted while we were reading the directory, so just ignore it if it's null
if (blogPost === null) return null
return {
title: blogPost.title,
published: blogPost.published,
// HACK: remove images, i WILL parse html with regex and you won't stop me
html: cutOffAtLine(
blogPost.html.replace(/<(img|iframe).+?\/?>|<\/?(img|iframe)>/g, ''),
6
),
css: blogPost.css,
slug: blogPost.slug,
}
})
)
)
.filter((p) => p)
.sort((a, b) => (new Date(a!.published) > new Date(b!.published) ? -1 : 1))
// typescript thinks posts is (BlogPostPreview | null)[] but it's not because of the .filter
return posts as BlogPostPreview[]
}
export const GET: RequestHandler = async () => {
const posts = await getPosts()
const posts = await getPostsUntrimmed()
return json(posts)
}

View file

@ -0,0 +1,68 @@
import { listBlogPostSlugs, type BlogPost, getPost } from '$lib/blog'
export interface BlogPostPreview {
title: string
published: string
html: string
css: string
slug: string
}
function cutOffAtLine(text: string, line: number) {
let row = 0
let column = 0
let inHtmlTag = false
for (let i = 0; i < text.length; i++) {
if (text[i] === '<') {
inHtmlTag = true
} else if (text[i] === '>') {
inHtmlTag = false
continue
}
if (text[i] === '\n') {
row++
column = 0
} else {
column++
}
if (column > 128 && !inHtmlTag) {
row++
column = 0
}
if (row >= line && !inHtmlTag) {
return text.slice(0, i) + '...'
}
}
return text
}
export async function getPostsUntrimmed(): Promise<BlogPost[]> {
const existingPosts: string[] = await listBlogPostSlugs()
const posts = (
await Promise.all(
existingPosts.map(async (slug): Promise<BlogPost | null> => {
return await getPost(slug)
})
)
)
.filter((p) => p)
.sort((a, b) => (new Date(a!.published) > new Date(b!.published) ? -1 : 1))
// typescript thinks posts is (BlogPost | null)[] but it's not because of the .filter
return posts as BlogPost[]
}
export async function getPosts() {
const posts = await getPostsUntrimmed()
return posts.map((p) => ({
title: p.title,
published: p.published,
// HACK: remove images, i WILL parse html with regex and you won't stop me
html: cutOffAtLine(p.html.replace(/<(img|iframe).+?\/?>|<\/?(img|iframe)>/g, ''), 6),
css: p.css,
slug: p.slug,
}))
}

View file

@ -1,16 +1,27 @@
import type { RequestHandler } from '@sveltejs/kit'
import type { BlogPostPreview } from '../blog.json/+server'
import { getPostsUntrimmed } from '../blog.json/preview'
import type { BlogPost } from '$lib/blog'
export const prerender = true
export const GET: RequestHandler = async ({ fetch }) => {
const posts = (await fetch('/blog.json').then((r) => r.json())) as BlogPostPreview[]
function item(post: BlogPostPreview) {
const posts = await getPostsUntrimmed()
function item(post: BlogPost) {
const escapedPostHtml = post.html
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
return `
<item>
<title>${post.title}</title>
<link>https://matdoes.dev/${post.slug}</link>
<pubDate>${post.published}</pubDate>
<description>
${escapedPostHtml}
&lt;style&gt;
${post.css}
&lt;/style&gt;
</description>
</item>
`
}

View file

@ -1,6 +1,6 @@
{
"compilerOptions": {
"moduleResolution": "node",
"moduleResolution": "bundler",
"module": "es2022",
"lib": ["es2022", "DOM", "WebWorker"],
"target": "es2020",
@ -8,7 +8,6 @@
svelte-preprocess cannot figure out whether you have a value or a type, so tell TypeScript
to enforce using \`import type\` instead of \`import\` for Types.
*/
"importsNotUsedAsValues": "error",
"isolatedModules": true,
"resolveJsonModule": true,
/**

763
yarn.lock

File diff suppressed because it is too large Load diff