update: add headings overview

This commit is contained in:
Keisuke Hirata 2024-12-18 06:02:28 +09:00
parent 7f395bcfaa
commit b529e96a6b
12 changed files with 3324 additions and 4224 deletions

View File

@ -1,6 +1,6 @@
# blog.hareworks.net
<img src="https://blog.hareworks.net/img/logo.png" width="200">
<img src="./static/img/logo.png" width="200">
## About

@ -1 +0,0 @@
Subproject commit 1b15e59b0b8a816cde268dd02a21c5dd85577980

4149
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "blog.hareworks.net",
"version": "0.0.1",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "vite dev",
@ -13,32 +13,34 @@
"format": "prettier --write ."
},
"devDependencies": {
"@playwright/test": "^1.28.1",
"@sveltejs/adapter-auto": "^3.0.0",
"@sveltejs/adapter-node": "^5.2.2",
"@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^4.0.0-next.6",
"@types/eslint": "^9.6.0",
"@types/pg": "^8.11.6",
"eslint": "^9.0.0",
"@playwright/test": "^1.49.1",
"@sveltejs/adapter-auto": "^3.3.1",
"@sveltejs/adapter-node": "^5.2.10",
"@sveltejs/kit": "^2.12.1",
"@sveltejs/vite-plugin-svelte": "^5.0.2",
"@types/eslint": "^9.6.1",
"@types/pg": "^8.11.10",
"eslint": "^9.17.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.36.0",
"globals": "^15.0.0",
"prettier": "^3.1.1",
"prettier-plugin-svelte": "^3.1.2",
"shiki": "^1.16.2",
"svelte": "^5.0.0-next.1",
"svelte-check": "^3.6.0",
"typescript": "^5.0.0",
"typescript-eslint": "^8.0.0",
"vite": "^5.0.3"
"eslint-plugin-svelte": "^2.46.1",
"globals": "^15.13.0",
"prettier": "^3.4.2",
"prettier-plugin-svelte": "^3.3.2",
"shiki": "^1.24.2",
"svelte": "^5.14.1",
"svelte-check": "4.1.1",
"typescript": "^5.7.2",
"typescript-eslint": "^8.18.1",
"vite": "^6.0.3"
},
"type": "module",
"dependencies": {
"dotenv": "^16.4.5",
"dotenv": "^16.4.7",
"mdsvex": "^0.12.3",
"pg": "^8.12.0",
"sass": "^1.77.8",
"simple-git": "^3.26.0"
"pg": "^8.13.1",
"rehype-autolink-headings": "^7.1.0",
"rehype-slug": "^6.0.0",
"sass": "^1.83.0",
"simple-git": "^3.27.0"
}
}

3127
pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
@import './ress.css';
@import '../variables.scss';
@forward './ress.css';
@forward '../variables.scss';
@font-face {
font-family: 'ZenKakuGothicNew-Regular';

View File

@ -71,6 +71,37 @@
}
}
ul,
ol {
list-style: none;
padding: 0;
margin: 0;
}
li {
position: relative;
padding-left: 1rem;
margin-bottom: 0.5rem;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
color: var(--color-concept);
}
}
ul > li {
&::before {
content: '';
}
}
ol > li {
counter-increment: item;
&::before {
content: counter(item) '.';
}
}
blockquote {
position: relative;
font-size: 1.1rem;

View File

@ -0,0 +1,67 @@
<script lang="ts">
export let html: string;
const headings: {
level: number;
id: string;
text: string;
}[] = [];
html.match(/<h(\d) id="([^"]+)">([^<]+)<\/h\d>/g)?.forEach((match) => {
console.log(match);
const [, level, id, text] = match.match(/<h(\d) id="([^"]+)">([^<]+)<\/h\d>/)!;
headings.push({ level: +level, id, text });
});
let output = '';
let lastLevel = 1;
headings.forEach(({ level, id, text }) => {
console.log(level, id, text);
if (level > lastLevel) {
output += '<ul>';
} else if (level < lastLevel) {
output += '</li></ul>'.repeat(lastLevel - level);
} else {
if (output !== '') {
}
}
output += `<li><a href="#${id}">${text}</a>`;
lastLevel = level;
});
output += '</li>'.repeat(lastLevel);
</script>
<div class="overview">
<ul>
{@html output}
</ul>
</div>
<style lang="scss">
.overview {
margin: 0;
padding: 0;
:global(ul) {
list-style-type: none;
margin-left: 0.5em;
padding-left: 0.25em;
border-left: 1px solid var(--line-primary);
}
ul {
border-left: none;
}
:global(li) {
padding: 0.5em 0.5em 0;
box-sizing: border-box;
}
:global(a) {
text-decoration: none;
color: var(--text-primary);
padding: 0.15em 0.4em;
border-radius: 0.25em;
text-wrap: nowrap;
box-sizing: border-box;
&:hover {
background-color: rgba(255, 255, 255, 0.1);
}
}
}
</style>

View File

@ -5,6 +5,7 @@
import Footer from '$lib/components/footer.svelte';
import * as publish from '$lib/publish';
import FormattedDate from '$lib/components/formatted_date.svelte';
import Overview from '$lib/components/overview.svelte';
import type { Article } from '$lib/article';
export let data: Article;
@ -32,39 +33,46 @@
</div> -->
<div class="container">
<main>
<div class="title">
<h1>{data.title}</h1>
<div class="meta">
<div class="left">
<span>
released <FormattedDate date={data.released_at} />
{#if isUpdated}<br />
updated <FormattedDate date={data.updated_at} />
{/if}
</span>
<span>
<a href="/category/{data.category}"
>{data.category[0].toUpperCase() + data.category.slice(1)}</a
>
{#each data.tags as tag}
<a href={`/search?tag=${tag}`}>{tag}</a>
{/each}
</span>
<div class="content">
<div class="title">
<h1>{data.title}</h1>
<div class="meta">
<div class="left">
<span>
released <FormattedDate date={data.released_at} />
{#if isUpdated}<br />
updated <FormattedDate date={data.updated_at} />
{/if}
</span>
<span>
<a href="/category/{data.category}"
>{data.category[0].toUpperCase() + data.category.slice(1)}</a
>
{#each data.tags as tag}
<a href={`/search?tag=${tag}`}>{tag}</a>
{/each}
</span>
</div>
<div class="right">
<img
src="https://gitea.hareworks.net/avatars/e595ec10f8052671deab92caca78220fc838f63259bcd542a0d93f53e2371d52?size=512"
alt="Author"
/>
<div>@{data.author}</div>
</div>
</div>
<div class="right">
<img
src="https://gitea.hareworks.net/avatars/e595ec10f8052671deab92caca78220fc838f63259bcd542a0d93f53e2371d52?size=512"
alt="Author"
/>
<div>@{data.author}</div>
</div>
<div class="panel">
<div class="document">
<slot />
</div>
<Footer />
</div>
</div>
<div class="panel">
<div class="document">
<slot />
<div class="card-container">
<div class="card">
<Overview html={data.content} />
</div>
<Footer />
</div>
</main>
</div>
@ -100,25 +108,43 @@
height: 100%;
object-fit: cover;
}
.card {
position: fixed;
top: 0;
right: 0;
}
main {
border: 1px solid var(--line-primary);
border-top: none;
border-bottom: none;
box-sizing: border-box;
color: white;
min-height: 100%;
display: flex;
flex-direction: row;
justify-content: center;
align-items: start;
.content {
border: 1px solid var(--line-primary);
border-top: none;
border-bottom: none;
min-height: 100%;
padding: 20px;
padding-top: 100px;
max-width: 800px;
margin: 0;
}
}
.card-container {
position: sticky;
top: 0;
overflow-y: auto;
background-color: var(--background-primary);
box-sizing: border-box;
padding: 20px;
padding-top: 100px;
max-width: 800px;
margin: 0 auto;
display: flex;
flex-direction: column;
justify-content: space-between;
.card {
width: 300px;
padding: 0.5em 0;
overflow: visible;
}
}
.title {
h1 {
font-size: 2rem;

View File

@ -2,7 +2,8 @@
import { compile, escapeSvelte } from "mdsvex";
import { createHighlighter } from "shiki";
import { kanagawa_dark as theme } from "$lib/kanagawa"
import rehypeAutolinkHeadings from "rehype-autolink-headings";
import rehypeSlug from "rehype-slug";
const highlighter = await createHighlighter({
themes: [theme],
@ -19,5 +20,6 @@ export default async function compileArticle(code: string) {
return html;
},
},
rehypePlugins: [rehypeSlug],
});
}

View File

@ -1,7 +1,7 @@
import type { Postgres } from '$lib/server/database/postgres';
import { type SimpleGit, CheckRepoActions } from 'simple-git';
import fs from 'fs';
import compile from '$lib/server/article_compiler';
import compileArticle from '$lib/server/article_compiler';
import type { TableSchema } from '$lib/server/database/table';
import server_table from '$lib/server/database/table';
import { format } from '$lib/scripts/formatted_date';
@ -33,7 +33,7 @@ const load = async (db: Postgres, git: SimpleGit) => {
console.log(`Author: ${author} <${email}>\nReleased at: ${format(released_at)}\nUpdated at: ${format(updated_at)}`);
const category = path.split('/')[3];
const compiled = await compile(fs.readFileSync(path, 'utf-8'));
const compiled = await compileArticle(fs.readFileSync(path, 'utf-8'));
const title = compiled.data.fm.title;
const tags: string[] = compiled.data.fm.tags;
const image = compiled.data.fm.image;

View File

@ -3,14 +3,9 @@ import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
/** @type {import('@sveltejs/kit').Config} */
const config = {
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
// for more information about preprocessors
preprocess: vitePreprocess(),
kit: {
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
adapter: adapter()
}
};