Broadcasting section
This commit is contained in:
37
src/lib/articleContent/articleContent.ts
Normal file
37
src/lib/articleContent/articleContent.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { error } from "@sveltejs/kit";
|
||||
import fm from "front-matter";
|
||||
import { readFile } from "fs";
|
||||
import { parseField } from "$lib/markdown/parse-markdown";
|
||||
import { promisify } from "util";
|
||||
|
||||
export interface ArticleAttributes {
|
||||
slug: string
|
||||
layout: string
|
||||
title: string
|
||||
published: boolean
|
||||
date: string
|
||||
thumbnail: string
|
||||
tags: string[]
|
||||
body: string
|
||||
}
|
||||
|
||||
export async function getArticleContent(slug: string) {
|
||||
let postSource: string
|
||||
try {
|
||||
postSource = await promisify(readFile)(`_posts/blog/${slug}.md`, 'utf-8')
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (e: any) {
|
||||
if (e.code === 'ENOENT') {
|
||||
throw error(404, 'Post not found \n' + e.toString())
|
||||
}
|
||||
throw e
|
||||
}
|
||||
|
||||
const parsedPost = fm<ArticleAttributes>(postSource)
|
||||
|
||||
const post = parseField<ArticleAttributes>('body')({
|
||||
...parsedPost.attributes,
|
||||
body: parsedPost.body,
|
||||
})
|
||||
return post
|
||||
}
|
@ -8,24 +8,13 @@ import {
|
||||
filterAndCount,
|
||||
type PaginationQuery,
|
||||
} from '$lib/pagination/pagination'
|
||||
import type { ArticleAttributes } from './articleContent'
|
||||
|
||||
export interface ArticlePreviewAttributes extends ArticleAttributes {
|
||||
preview: string
|
||||
}
|
||||
|
||||
const { NODE_ENV } = process.env
|
||||
|
||||
export interface ArticleAttributes {
|
||||
layout: string
|
||||
title: string
|
||||
published: boolean
|
||||
date: string
|
||||
thumbnail: string
|
||||
tags: string[]
|
||||
}
|
||||
|
||||
export interface ArticleContent extends ArticleAttributes {
|
||||
preview: string
|
||||
slug: string
|
||||
published: boolean
|
||||
}
|
||||
|
||||
export async function getBlogListing(paginationQuery: PaginationQuery) {
|
||||
const files = await promisify(readdir)(`_posts/blog/`, 'utf-8')
|
||||
const filteredFiles = filterDevelopmentFiles(files)
|
||||
@ -52,9 +41,8 @@ export async function getBlogListing(paginationQuery: PaginationQuery) {
|
||||
}
|
||||
})
|
||||
)
|
||||
console.log(paginationQuery);
|
||||
const filteredContents = pipe(
|
||||
sortBy<ArticleContent>(prop('date')),
|
||||
sortBy<ArticlePreviewAttributes>(prop('date')),
|
||||
(items) => reverse(items),
|
||||
filter<(typeof contents)[0]>((article) => article.published),
|
||||
filterAndCount(paginationQuery)
|
11
src/lib/markdown/parse-markdown.ts
Normal file
11
src/lib/markdown/parse-markdown.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import marked from 'marked'
|
||||
import { renderer } from './renderer-extension'
|
||||
|
||||
marked.use({ renderer })
|
||||
|
||||
export function parseField<T>(field: keyof T) {
|
||||
return (item: T): T => ({
|
||||
...item,
|
||||
[field]: marked(item[field]),
|
||||
})
|
||||
}
|
49
src/lib/markdown/renderer-extension.ts
Normal file
49
src/lib/markdown/renderer-extension.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import { generateSrcSet, getNFResize } from '$lib/large-media'
|
||||
import Prism from 'prismjs'
|
||||
import loadLanguages from 'prismjs/components/index.js'
|
||||
|
||||
loadLanguages(['bash', 'markdown', 'json', 'yaml', 'typescript'])
|
||||
|
||||
export const renderer = {
|
||||
heading(text: string, level: string) {
|
||||
const escapedText = text.toLowerCase().replace(/[^\w]+/g, '-')
|
||||
|
||||
return `
|
||||
<h${level}>
|
||||
<a name="${escapedText}" class="anchor" href="#${escapedText}">
|
||||
<span class="header-link"></span>
|
||||
</a>
|
||||
${text}
|
||||
</h${level}>
|
||||
`
|
||||
},
|
||||
image(href: string, title: string, text: string) {
|
||||
const figcaption = title ? `<figcaption>${title}</figcaption>` : ''
|
||||
const isLocal = !href.startsWith('http')
|
||||
const src = isLocal ? getNFResize(href, { height: 800, width: 800 }) : href
|
||||
const srcset = isLocal
|
||||
? `srcset="${generateSrcSet(href, { width: 800, height: 800 })}"`
|
||||
: ''
|
||||
|
||||
return `
|
||||
<figure>
|
||||
<img
|
||||
alt="${text}"
|
||||
${srcset}
|
||||
src="${src}"
|
||||
/>
|
||||
${figcaption}
|
||||
</figure>
|
||||
`
|
||||
},
|
||||
code(source: string, lang?: string) {
|
||||
// When lang is not specified it is usually an empty string which has to be handled
|
||||
const usedLang = !lang ? 'shell' : lang
|
||||
const highlightedSource = Prism.highlight(
|
||||
source,
|
||||
Prism.languages[usedLang],
|
||||
usedLang
|
||||
)
|
||||
return `<pre class='language-${usedLang}'><code class='language-${usedLang}'>${highlightedSource}</code></pre>`
|
||||
},
|
||||
}
|
21
src/lib/styles/article/article.css.ts
Normal file
21
src/lib/styles/article/article.css.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { globalStyle, style } from '@vanilla-extract/css'
|
||||
import { vars } from '$lib/styles/vars.css'
|
||||
|
||||
export const contentClass = style({})
|
||||
|
||||
globalStyle(`${contentClass} ul, ${contentClass} ol`, {
|
||||
lineHeight: vars.lineHeight['2x'],
|
||||
})
|
||||
|
||||
globalStyle(`${contentClass} li`, {
|
||||
marginBottom: vars.space['2x'],
|
||||
})
|
||||
|
||||
globalStyle(`${contentClass} img`, {
|
||||
maxHeight: vars.height.image,
|
||||
})
|
||||
|
||||
globalStyle(`${contentClass} img:only-child`, {
|
||||
display: 'block',
|
||||
margin: '0 auto',
|
||||
})
|
Reference in New Issue
Block a user