Skip to content

Commit

Permalink
feat(site-2): Make blog logic consistent with other content (#8447)
Browse files Browse the repository at this point in the history
  • Loading branch information
PuruVJ authored Apr 3, 2023
1 parent b569018 commit 050c103
Show file tree
Hide file tree
Showing 14 changed files with 1,265 additions and 543 deletions.
1,310 changes: 1,088 additions & 222 deletions sites/svelte.dev/package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion sites/svelte.dev/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"@resvg/resvg-js": "^2.4.1",
"@sveltejs/adapter-vercel": "^2.4.1",
"@sveltejs/kit": "^1.15.0",
"@sveltejs/site-kit": "^3.3.6",
"@sveltejs/site-kit": "^3.3.7",
"@sveltejs/vite-plugin-svelte": "^2.0.4",
"@types/marked": "^4.0.8",
"@types/prismjs": "^1.26.0",
Expand Down
60 changes: 60 additions & 0 deletions sites/svelte.dev/src/lib/server/blog/get-blog-data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// @ts-check
import fs from 'fs';
import { extract_frontmatter } from '../markdown';

const BLOG_NAME_REGEX = /^(\d{4}-\d{2}-\d{2})-(.+)\.md$/;
const BASE = '../../site/content/blog';

/** @returns {import('./types').BlogData} */
export function get_blog_data(base = BASE) {
/** @type {import('./types').BlogData} */
const blog_posts = [];

for (const file of fs.readdirSync(base).reverse()) {
if (!BLOG_NAME_REGEX.test(file)) continue;

const { date, date_formatted, slug } = get_date_and_slug(file);
const { metadata, body } = extract_frontmatter(fs.readFileSync(`${base}/${file}`, 'utf-8'));

blog_posts.push({
date,
date_formatted,
content: body,
description: metadata.description,
draft: metadata.draft === 'true',
slug,
title: metadata.title,
author: {
name: metadata.author,
url: metadata.authorURL
}
});
}

return blog_posts;
}

/** @param {import('./types').BlogData} blog_data */
export function get_blog_list(blog_data) {
return blog_data.map(({ slug, date, title, description, draft }) => ({
slug,
date,
title,
description,
draft
}));
}

/** @param {string} filename */
function get_date_and_slug(filename) {
const match = BLOG_NAME_REGEX.exec(filename);
if (!match) throw new Error(`Invalid filename for blog: '${filename}'`);

const [, date, slug] = match;
const [y, m, d] = date.split('-');
const date_formatted = `${months[+m - 1]} ${+d} ${y}`;

return { date, date_formatted, slug };
}

const months = 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'.split(' ');
141 changes: 81 additions & 60 deletions sites/svelte.dev/src/lib/server/blog/index.js
Original file line number Diff line number Diff line change
@@ -1,75 +1,96 @@
import fs from 'fs';
import { extract_frontmatter } from '../markdown';
import { transform } from './marked';

const base = '../../site/content/blog';
// @ts-check
import { createShikiHighlighter } from 'shiki-twoslash';
import { SHIKI_LANGUAGE_MAP, escape, transform } from '../markdown';

/**
* @returns {import('./types').BlogPostSummary[]}
* @param {import('./types').BlogData} blog_data
* @param {string} slug
*/
export function get_index() {
return fs
.readdirSync(base)
.reverse()
.map((file) => {
if (!file.endsWith('.md')) return;
export async function get_processed_blog_post(blog_data, slug) {
const post = blog_data.find((post) => post.slug === slug);

const { date, slug } = get_date_and_slug(file);
if (!post) return null;

const content = fs.readFileSync(`${base}/${file}`, 'utf-8');
const { metadata } = extract_frontmatter(content);
const highlighter = await createShikiHighlighter({ theme: 'css-variables' });

return {
slug,
date,
title: metadata.title,
description: metadata.description,
draft: !!metadata.draft
};
});
}
return {
...post,
content: transform(post.content, {
/**
* @param {string} html
*/
heading(html) {
const title = html
.replace(/<\/?code>/g, '')
.replace(/&quot;/g, '"')
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>');

/**
* @param {string} slug
* @returns {import('./types').BlogPost}
*/
export function get_post(slug) {
for (const file of fs.readdirSync(`${base}`)) {
if (!file.endsWith('.md')) continue;
if (file.slice(11, -3) !== slug) continue;
return title;
},
code: (source, language) => {
let html = '';

const { date, date_formatted } = get_date_and_slug(file);
source = source
.replace(/^([\-\+])?((?: )+)/gm, (match, prefix = '', spaces) => {
if (prefix && language !== 'diff') return match;

const content = fs.readFileSync(`${base}/${file}`, 'utf-8');
const { metadata, body } = extract_frontmatter(content);
// for no good reason at all, marked replaces tabs with spaces
let tabs = '';
for (let i = 0; i < spaces.length; i += 4) {
tabs += ' ';
}
return prefix + tabs;
})
.replace(/\*\\\//g, '*/');

return {
date,
date_formatted,
title: metadata.title,
description: metadata.description,
author: {
name: metadata.author,
url: metadata.authorURL
},
draft: !!metadata.draft,
content: transform(body)
};
}
}
if (language === 'diff') {
const lines = source.split('\n').map((content) => {
let type = null;
if (/^[\+\-]/.test(content)) {
type = content[0] === '+' ? 'inserted' : 'deleted';
content = content.slice(1);
}

/** @param {string} filename */
function get_date_and_slug(filename) {
const match = /^(\d{4}-\d{2}-\d{2})-(.+)\.md$/.exec(filename);
if (!match) throw new Error(`Invalid filename for blog: '${filename}'`);
return {
type,
content: escape(content)
};
});

const [, date, slug] = match;
const [y, m, d] = date.split('-');
const date_formatted = `${months[+m - 1]} ${+d} ${y}`;
html = `<pre class="language-diff"><code>${lines
.map((line) => {
if (line.type) return `<span class="${line.type}">${line.content}\n</span>`;
return line.content + '\n';
})
.join('')}</code></pre>`;
} else {
html = highlighter.codeToHtml(source, { lang: SHIKI_LANGUAGE_MAP[language] });

return { date, date_formatted, slug };
}
html = html
.replace(
/^(\s+)<span class="token comment">([\s\S]+?)<\/span>\n/gm,
(match, intro_whitespace, content) => {
// we use some CSS trickery to make comments break onto multiple lines while preserving indentation
const lines = (intro_whitespace + content).split('\n');
return lines
.map((line) => {
const match = /^(\s*)(.*)/.exec(line);
const indent = (match[1] ?? '').replace(/\t/g, ' ').length;

const months = 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'.split(' ');
return `<span class="token comment wrapped" style="--indent: ${indent}ch">${
line ?? ''
}</span>`;
})
.join('');
}
)
.replace(/\/\*\*\//g, '…');
}

function format_date(date) {}
return html;
},
codespan: (text) => '<code>' + text + '</code>'
})
};
}
Loading

1 comment on commit 050c103

@vercel
Copy link

@vercel vercel bot commented on 050c103 Apr 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

svelte-dev-2 – ./

svelte-dev-2-git-sites-svelte.vercel.app
svelte-dev-2.vercel.app
svelte-dev-2-svelte.vercel.app

Please sign in to comment.