vowel 0.1.13 → 0.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -122
- package/package.json +1 -1
- package/server.js +0 -8
- package/src/app.html +20 -0
- package/src/lib/components/DefaultStyles.svelte +3 -21
- package/src/lib/components/Markdown/index.svelte +0 -5
- package/src/lib/components/index.js +1 -1
- package/src/lib/utilities/createPageClass.js +3 -2
- package/src/routes/[...path]/+layout.server.js +5 -1
- package/src/routes/[...path]/+page.svelte +570 -10
- package/vite.config.js +6 -0
package/README.md
CHANGED
|
@@ -1,136 +1,31 @@
|
|
|
1
|
-
|
|
1
|
+
# Vowel
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
- [x] Add RSS
|
|
6
|
-
- [x] Add robots.txt
|
|
7
|
-
- [x] AI
|
|
8
|
-
- [x] Search
|
|
9
|
-
- [x] Image
|
|
10
|
-
- [x] Typing
|
|
11
|
-
- [x] Add sitemap
|
|
12
|
-
- [x] Make taxonomies linkable in frontmatter (if a corresponding folder exists)
|
|
13
|
-
- [x] Add header metadata (meta tags)
|
|
14
|
-
- [x] CSS handling
|
|
15
|
-
- [x] Favicon handling
|
|
16
|
-
- [x] Docs
|
|
17
|
-
- [x] Build action
|
|
3
|
+
[![npm version][npm-version-src]][npm-version-href]
|
|
4
|
+
[![npm downloads][npm-downloads-src]][npm-downloads-href]
|
|
18
5
|
|
|
19
|
-
|
|
6
|
+
The easiest way to code your own website.
|
|
20
7
|
|
|
21
|
-
|
|
22
|
-
- [ ] Create post list element (`#tags/blue`, `@tags/blue`, `~tags/blue`)
|
|
23
|
-
- [x] Better favicon and styles handling
|
|
24
|
-
- [ ] Ignore README files
|
|
25
|
-
- [ ] Add more header metadata
|
|
26
|
-
- [ ] Define folder settings
|
|
27
|
-
- [ ] Title
|
|
28
|
-
- [ ] Breadrumb
|
|
29
|
-
- [x] Define special page properties
|
|
30
|
-
- [x] Title
|
|
31
|
-
- [x] Description
|
|
32
|
-
- [x] Meta image
|
|
33
|
-
- [x] Date
|
|
34
|
-
- [ ] Modified date
|
|
35
|
-
- [ ] Tags
|
|
36
|
-
- [ ] Author/Authors
|
|
37
|
-
- [ ] Make file names kebab-cased for URLs and links
|
|
38
|
-
- [ ] Add hidden routes (`$`)
|
|
39
|
-
- [ ] Image alt text
|
|
40
|
-
- [ ] Code highlighter
|
|
41
|
-
- [x] Deploy action (Vercel)
|
|
42
|
-
- [ ] Add anchor links for headings
|
|
43
|
-
- [ ] Post TOC
|
|
44
|
-
- [ ] GitHub-style notes
|
|
45
|
-
- [ ] Add in-browser search
|
|
46
|
-
- [x] Figure out how to stop components from remounting on every change
|
|
47
|
-
- [ ] Make RSS optional
|
|
48
|
-
- [ ] Pagination
|
|
49
|
-
- [ ] Demote headings global option
|
|
8
|
+
[Try it on StackBlitz](https://stackblitz.com/~/github.com/samlfair/vowel-site?file=home.md).
|
|
50
9
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
- [ ] Automatic file creation
|
|
54
|
-
- [ ] Image serving and optimization
|
|
55
|
-
- [ ] GUI
|
|
56
|
-
- [ ] More deploy actions
|
|
57
|
-
- [ ] Optional JSON interactivity (ratings, comments, SubPubHub)
|
|
58
|
-
- [ ] Redirects
|
|
59
|
-
- [ ] Advanced markdown
|
|
60
|
-
- [ ] Highlight
|
|
61
|
-
- [ ] Sanitize
|
|
62
|
-
- [ ] Tables
|
|
63
|
-
- [ ] Strike
|
|
64
|
-
- [ ] Task lists
|
|
65
|
-
- [ ] Footnotes
|
|
66
|
-
- [ ] Mermaid
|
|
67
|
-
- [ ] Math
|
|
68
|
-
- [ ] Wikilinks
|
|
69
|
-
|
|
70
|
-
## Ideas
|
|
71
|
-
|
|
72
|
-
https://github.com/arobase-che/remark-attr
|
|
73
|
-
https://github.com/wataru-chocola/remark-definition-list
|
|
74
|
-
https://github.com/FinnRG/remark-mentions
|
|
75
|
-
https://github.com/remarkjs/remark-toc
|
|
76
|
-
|
|
77
|
-
- Docusaurus
|
|
78
|
-
- MkDocs
|
|
79
|
-
- Coolify
|
|
80
|
-
- NodeGui
|
|
81
|
-
|
|
82
|
-
https://www.nngroup.com/articles/breadcrumb-navigation-useful/
|
|
83
|
-
https://www.nngroup.com/articles/url-as-ui/
|
|
84
|
-
|
|
85
|
-
CSS Frameworks:
|
|
86
|
-
|
|
87
|
-
- Open Props
|
|
88
|
-
- Pico
|
|
89
|
-
- Milligram
|
|
90
|
-
- Spectre
|
|
91
|
-
|
|
92
|
-
## Docs
|
|
93
|
-
|
|
94
|
-
Welcome to Vowel! This project is under development.
|
|
95
|
-
|
|
96
|
-
Vowel is a Really Simple Static Site Generator. Write Markdown files, and Vowel will generate a website for you. Eventually, you will also be able to write a `style.css` file to style your website. When complete, Vowel will generate:
|
|
97
|
-
|
|
98
|
-
- An RSS feed
|
|
99
|
-
- A sitemap
|
|
100
|
-
- Rich link previews (internal and external)
|
|
101
|
-
- Post lists
|
|
102
|
-
- Navigation
|
|
103
|
-
- Optimized images
|
|
104
|
-
- Metadata
|
|
105
|
-
- And more
|
|
106
|
-
|
|
107
|
-
Each file in Vowel is a page. Index pages are called `home.md`.
|
|
10
|
+
Turn a folder of Markdown files into a website by running one command:
|
|
108
11
|
|
|
109
12
|
```
|
|
110
|
-
|
|
111
|
-
├── home.md
|
|
112
|
-
├── settings.md
|
|
113
|
-
├── about.md
|
|
114
|
-
└── posts/
|
|
115
|
-
├── home.md
|
|
116
|
-
├── red-car.md
|
|
117
|
-
├── blue-true.md
|
|
118
|
-
└── green-van.md
|
|
13
|
+
npx -y -p svelte@next -p vowel@latest npx vowel
|
|
119
14
|
```
|
|
120
15
|
|
|
121
|
-
|
|
16
|
+
No installs. No config.
|
|
122
17
|
|
|
123
|
-
|
|
18
|
+
Create a blog, a documentation site, a landing page, a wiki (whatever you want), using just Markdown and CSS.
|
|
124
19
|
|
|
125
|
-
|
|
126
|
-
- `/example-page/home.md`
|
|
127
|
-
Both of the above will generate the `/example-page` URL. You cannot have both files.
|
|
20
|
+
No HTML.
|
|
128
21
|
|
|
129
|
-
|
|
22
|
+
No JavaScript.
|
|
130
23
|
|
|
131
|
-
|
|
132
|
-
- `breadcrumb`: The root breadcrumb
|
|
24
|
+
[Read the docs](https://vowel.cc/docs).
|
|
133
25
|
|
|
134
|
-
|
|
26
|
+
For comments, questions, bugs, and contributions, please reach out to me on Twitter: [@samlfair](https://twitter.com/samlfair).
|
|
135
27
|
|
|
136
|
-
-
|
|
28
|
+
[npm-version-src]: https://img.shields.io/npm/v/vowel/latest.svg
|
|
29
|
+
[npm-version-href]: https://npmjs.com/package/vowel
|
|
30
|
+
[npm-downloads-src]: https://img.shields.io/npm/dm/vowel.svg
|
|
31
|
+
[npm-downloads-href]: https://npmjs.com/package/vowel
|
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -46,21 +46,13 @@ async function buildProject() {
|
|
|
46
46
|
let projectData = null;
|
|
47
47
|
|
|
48
48
|
try {
|
|
49
|
-
console.log({ config });
|
|
50
49
|
if (existsSync(projectJsonPath)) {
|
|
51
|
-
console.log('inside');
|
|
52
50
|
const data = await readFile(projectJsonPath, 'utf-8');
|
|
53
|
-
console.log({ data });
|
|
54
51
|
projectData = JSON.parse(data);
|
|
55
52
|
}
|
|
56
53
|
|
|
57
|
-
console.log({ projectData });
|
|
58
|
-
console.log('Building...');
|
|
59
|
-
|
|
60
54
|
await build(config);
|
|
61
55
|
|
|
62
|
-
console.log('Build completed.');
|
|
63
|
-
|
|
64
56
|
if (projectData !== null) {
|
|
65
57
|
await mkdir(vercelDirPath, { recursive: true });
|
|
66
58
|
await writeFile(projectJsonPath, JSON.stringify(projectData, null, 2), 'utf-8');
|
package/src/app.html
CHANGED
|
@@ -3,6 +3,26 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<style>
|
|
7
|
+
html {
|
|
8
|
+
-webkit-text-size-adjust: 100%;
|
|
9
|
+
margin: 0;
|
|
10
|
+
font-size: 62.5%;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
body {
|
|
14
|
+
font-size: 1.6rem;
|
|
15
|
+
line-height: 1.5;
|
|
16
|
+
-webkit-font-smoothing: antialiased;
|
|
17
|
+
font-weight: 400;
|
|
18
|
+
margin: 0;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.container {
|
|
22
|
+
height: 100vh;
|
|
23
|
+
overflow-y: scroll;
|
|
24
|
+
}
|
|
25
|
+
</style>
|
|
6
26
|
%sveltekit.head%
|
|
7
27
|
</head>
|
|
8
28
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
Barebones, Basic.css, Pico, Typeplate, Simple.css, and more
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
.theme-default {
|
|
8
8
|
/* Variables */
|
|
9
9
|
|
|
10
10
|
:root {
|
|
@@ -48,19 +48,6 @@
|
|
|
48
48
|
margin: 0;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
html {
|
|
52
|
-
line-height: 1.15;
|
|
53
|
-
-webkit-text-size-adjust: 100%;
|
|
54
|
-
font-size: 62.5%;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
body {
|
|
58
|
-
font-size: 1.6rem;
|
|
59
|
-
line-height: 1.5;
|
|
60
|
-
-webkit-font-smoothing: antialiased;
|
|
61
|
-
font-weight: 400;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
51
|
main,
|
|
65
52
|
img,
|
|
66
53
|
details,
|
|
@@ -138,13 +125,8 @@
|
|
|
138
125
|
|
|
139
126
|
/* Layout */
|
|
140
127
|
|
|
141
|
-
.container {
|
|
142
|
-
height: 100vh;
|
|
143
|
-
overflow-y: scroll;
|
|
144
|
-
font-family: var(--font-sans);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
128
|
.page {
|
|
129
|
+
font-family: var(--font-sans);
|
|
148
130
|
max-width: 60ch;
|
|
149
131
|
margin: auto;
|
|
150
132
|
min-height: 100vh;
|
|
@@ -452,7 +434,7 @@
|
|
|
452
434
|
/* Sidebar */
|
|
453
435
|
|
|
454
436
|
.sidebar {
|
|
455
|
-
margin: auto;
|
|
437
|
+
margin-inline: auto;
|
|
456
438
|
}
|
|
457
439
|
|
|
458
440
|
/* Footer */
|
|
@@ -13,10 +13,6 @@
|
|
|
13
13
|
|
|
14
14
|
let { ast, level, website, format, identifier } = $derived(props);
|
|
15
15
|
|
|
16
|
-
if (identifier) {
|
|
17
|
-
console.log(identifier);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
16
|
function getElement(node) {
|
|
21
17
|
if (node.type === 'heading') {
|
|
22
18
|
return ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div', 'div'][node.depth - 1];
|
|
@@ -44,7 +40,6 @@
|
|
|
44
40
|
// Handle `footnoteDefinition` and `footnoteReference`
|
|
45
41
|
|
|
46
42
|
if (elements[node.type]) return elements[node.type];
|
|
47
|
-
console.log(node);
|
|
48
43
|
}
|
|
49
44
|
|
|
50
45
|
const noteTypes = {
|
|
@@ -6,4 +6,4 @@ export { default as Page } from './Page.svelte';
|
|
|
6
6
|
export { default as Sitemap } from './Sitemap.svelte';
|
|
7
7
|
export { default as FrontmatterProperty } from './FrontmatterProperty.svelte';
|
|
8
8
|
export { default as FrontmatterTaxonomy } from './FrontMatterTaxonomy.svelte';
|
|
9
|
-
export { default as DefaultStyles } from './DefaultStyles.svelte';
|
|
9
|
+
// export { default as DefaultStyles } from './DefaultStyles.svelte';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export default function createPageClass(url, type = 'page') {
|
|
1
|
+
export default function createPageClass(url, type = 'page', theme) {
|
|
2
2
|
if (!url) return 'item';
|
|
3
|
-
if (url === '/') return
|
|
3
|
+
if (url === '/') return `page home${theme ? ` theme-${theme}` : ''}`;
|
|
4
|
+
if (type === 'page') return `page ${url.split('/').join(' ')}${theme ? ` theme-${theme}` : ''}`;
|
|
4
5
|
return type + url.split('/').join(' ');
|
|
5
6
|
}
|
|
@@ -3,6 +3,10 @@ import { access } from 'fs/promises';
|
|
|
3
3
|
import { constants } from 'fs';
|
|
4
4
|
import { normalize, join, basename } from 'path';
|
|
5
5
|
import { dev } from '$app/environment';
|
|
6
|
+
import mri from 'mri';
|
|
7
|
+
|
|
8
|
+
const args = mri(process.argv);
|
|
9
|
+
const isBuild = args._.includes('build');
|
|
6
10
|
|
|
7
11
|
export const prerender = true;
|
|
8
12
|
export const csr = dev;
|
|
@@ -24,7 +28,7 @@ async function checkFileExists(filePath, homeDir) {
|
|
|
24
28
|
export async function load() {
|
|
25
29
|
// const startLoad = performance.now();
|
|
26
30
|
const now = Date.now();
|
|
27
|
-
const contentCacheDuration = 60000; // Cache for 1
|
|
31
|
+
const contentCacheDuration = isBuild ? 60000 : 0; // Cache for 1 second
|
|
28
32
|
const initialURLCache = await loadCache($home[0]);
|
|
29
33
|
|
|
30
34
|
const cssExists = await checkFileExists(normalize('/assets/styles.css'), $home[0]);
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
import { Nav, Page, Breadcrumbs, Sitemap
|
|
2
|
+
import { Nav, Page, Breadcrumbs, Sitemap } from '$lib/components/index.js';
|
|
3
3
|
import { getPage, createPageClass } from '$lib/utilities/index.js';
|
|
4
4
|
import LinkPreview from '$lib/components/Markdown/LinkPreview.svelte';
|
|
5
5
|
import getFileLabel from '../../lib/utilities/getFileLabel';
|
|
6
6
|
import { error } from '@sveltejs/kit';
|
|
7
7
|
import { getFolder, getFolderLabel } from '../../lib/utilities';
|
|
8
8
|
import { page as pageStore } from '$app/stores';
|
|
9
|
-
import
|
|
9
|
+
import { goto, invalidate, invalidateAll } from '$app/navigation';
|
|
10
10
|
|
|
11
11
|
let { data } = $props();
|
|
12
12
|
|
|
@@ -56,23 +56,34 @@
|
|
|
56
56
|
|
|
57
57
|
const favicon = getFavicon();
|
|
58
58
|
|
|
59
|
+
let key = $state(Date.now());
|
|
60
|
+
|
|
59
61
|
$effect(() => {
|
|
60
62
|
// Update website on file change
|
|
61
63
|
if (import.meta.hot) {
|
|
62
64
|
import.meta.hot.on('vowel:update', ({ path, file }) => {
|
|
63
65
|
let updatedPage = getPage(website, path);
|
|
66
|
+
if (!updatedPage) {
|
|
67
|
+
invalidateAll().then(() => {
|
|
68
|
+
window.location.reload();
|
|
69
|
+
});
|
|
70
|
+
}
|
|
64
71
|
|
|
65
72
|
for (const key in file) {
|
|
73
|
+
if (!updatedPage[key]) updatedPage[key] = {};
|
|
66
74
|
updatedPage[key] = file[key];
|
|
67
75
|
}
|
|
68
76
|
});
|
|
77
|
+
import.meta.hot.on('vowel:refresh', () => {
|
|
78
|
+
console.log('Refresh');
|
|
79
|
+
invalidateAll().then(() => {
|
|
80
|
+
window.location.reload();
|
|
81
|
+
});
|
|
82
|
+
});
|
|
69
83
|
}
|
|
70
84
|
});
|
|
71
85
|
</script>
|
|
72
86
|
|
|
73
|
-
<!-- svelte-ignore state_referenced_locally -->
|
|
74
|
-
<!-- svelte-ignore state_referenced_locally -->
|
|
75
|
-
|
|
76
87
|
<svelte:head>
|
|
77
88
|
<title>{makePageMetaTitle()}</title>
|
|
78
89
|
<meta property="”og:url”" content={page.url} />
|
|
@@ -91,9 +102,10 @@
|
|
|
91
102
|
{/if}
|
|
92
103
|
</svelte:head>
|
|
93
104
|
|
|
94
|
-
<
|
|
95
|
-
|
|
96
|
-
|
|
105
|
+
<div
|
|
106
|
+
data-sveltekit-preload-data="hover"
|
|
107
|
+
class={createPageClass(page.url, null, website._.theme === 'default' ? 'default' : false)}
|
|
108
|
+
>
|
|
97
109
|
<header>
|
|
98
110
|
{#if website._.logo}
|
|
99
111
|
<a href="/" class="site-logo">
|
|
@@ -106,7 +118,7 @@
|
|
|
106
118
|
{#if website._.slogan}
|
|
107
119
|
<p class="slogan">{website._.slogan}</p>
|
|
108
120
|
{/if}
|
|
109
|
-
<Nav folder={
|
|
121
|
+
<Nav folder={website} segments={data.path.split('/')} />
|
|
110
122
|
<nav class="breadcrumbs" aria-label="Breadcrumb">
|
|
111
123
|
<Breadcrumbs level={0} />
|
|
112
124
|
</nav>
|
|
@@ -115,10 +127,558 @@
|
|
|
115
127
|
<Page level={0} {page} {website} path={data.path} />
|
|
116
128
|
</main>
|
|
117
129
|
<nav class="sidebar">
|
|
118
|
-
<Sitemap section={
|
|
130
|
+
<Sitemap section={website} segments={data.path.split('/')} root />
|
|
119
131
|
</nav>
|
|
120
132
|
<footer>
|
|
121
133
|
© {website._.author ? website._.author + ' ' : ''}
|
|
122
134
|
{new Date().getFullYear()}
|
|
123
135
|
</footer>
|
|
124
136
|
</div>
|
|
137
|
+
|
|
138
|
+
<style>
|
|
139
|
+
/*
|
|
140
|
+
Inspiration for this stylesheet comes from Normalize.css, Josh Comeau,
|
|
141
|
+
Barebones, Basic.css, Pico, Typeplate, Simple.css, and more
|
|
142
|
+
*/
|
|
143
|
+
|
|
144
|
+
:global {
|
|
145
|
+
body:has(> div > .theme-default) {
|
|
146
|
+
--font-sans: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue,
|
|
147
|
+
helvetica, Cantarell, Ubuntu, roboto, noto, arial, sans-serif;
|
|
148
|
+
--font-serif: Iowan Old Style, Apple Garamond, Baskerville, Times New Roman, Droid Serif,
|
|
149
|
+
Times, Source Serif Pro, serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
|
|
150
|
+
--font-mono: Menlo, Consolas, Monaco, Liberation Mono, Lucida Console, monospace;
|
|
151
|
+
--text-color: hsl(0, 0%, 13%);
|
|
152
|
+
--accent-color: hsl(215, 100%, 35%);
|
|
153
|
+
--accent-color-hover: hsl(215, 76%, 49%);
|
|
154
|
+
--border-color: hsl(0, 0%, 73%);
|
|
155
|
+
--main-background: hsl(0, 0%, 100%);
|
|
156
|
+
--code-background: hsl(0, 0%, 95%);
|
|
157
|
+
--soft-background: hsl(0, 0%, 95%);
|
|
158
|
+
|
|
159
|
+
@media (prefers-color-scheme: dark) {
|
|
160
|
+
--text-color: hsl(0, 0%, 80%);
|
|
161
|
+
--accent-color: hsl(194, 76%, 49%);
|
|
162
|
+
--accent-color-hover: hsl(194, 86%, 57%);
|
|
163
|
+
--border-color: hsl(0, 0%, 27%);
|
|
164
|
+
--main-background: hsl(0, 0%, 12%);
|
|
165
|
+
--code-background: hsl(0, 0%, 5%);
|
|
166
|
+
--soft-background: hsl(0, 0%, 14%);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
color: var(--text-color);
|
|
170
|
+
background: var(--main-background);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.theme-default {
|
|
174
|
+
&.page {
|
|
175
|
+
font-family: var(--font-sans);
|
|
176
|
+
max-width: 60ch;
|
|
177
|
+
margin: auto;
|
|
178
|
+
min-height: 100vh;
|
|
179
|
+
display: flex;
|
|
180
|
+
flex-direction: column;
|
|
181
|
+
padding: 1rem;
|
|
182
|
+
overflow-x: hidden;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/*
|
|
186
|
+
Reset
|
|
187
|
+
*/
|
|
188
|
+
|
|
189
|
+
*,
|
|
190
|
+
*::before,
|
|
191
|
+
*::after {
|
|
192
|
+
box-sizing: border-box;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
* {
|
|
196
|
+
margin: 0;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
main,
|
|
200
|
+
img,
|
|
201
|
+
details,
|
|
202
|
+
picture,
|
|
203
|
+
video,
|
|
204
|
+
canvas,
|
|
205
|
+
svg {
|
|
206
|
+
display: block;
|
|
207
|
+
max-width: 100%;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
summary {
|
|
211
|
+
display: list-item;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
hr {
|
|
215
|
+
box-sizing: content-box;
|
|
216
|
+
height: 0;
|
|
217
|
+
overflow: visible;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
pre {
|
|
221
|
+
font-family: monospace, monospace;
|
|
222
|
+
font-size: 1em;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
a {
|
|
226
|
+
background-color: transparent;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
abbr[title] {
|
|
230
|
+
border-bottom: none;
|
|
231
|
+
text-decoration: underline;
|
|
232
|
+
text-decoration: underline dotted;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
b,
|
|
236
|
+
strong {
|
|
237
|
+
font-weight: bolder;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
code,
|
|
241
|
+
kbd,
|
|
242
|
+
samp {
|
|
243
|
+
font-family: monospace, monospace;
|
|
244
|
+
font-size: 1em;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
small {
|
|
248
|
+
font-size: 80%;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
sub,
|
|
252
|
+
sup {
|
|
253
|
+
font-size: 75%;
|
|
254
|
+
line-height: 0;
|
|
255
|
+
position: relative;
|
|
256
|
+
vertical-align: baseline;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
sub {
|
|
260
|
+
bottom: -0.25em;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
sup {
|
|
264
|
+
top: -0.5em;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
img {
|
|
268
|
+
border-style: none;
|
|
269
|
+
height: auto;
|
|
270
|
+
border-radius: 5px;
|
|
271
|
+
overflow: hidden;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/* Layout */
|
|
275
|
+
|
|
276
|
+
main {
|
|
277
|
+
margin-bottom: auto;
|
|
278
|
+
padding-bottom: 4rem;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/* Colors */
|
|
282
|
+
|
|
283
|
+
a {
|
|
284
|
+
color: var(--accent-color);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
a:hover {
|
|
288
|
+
color: var(--accent-color-hover);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/* Typography */
|
|
292
|
+
|
|
293
|
+
p,
|
|
294
|
+
h1,
|
|
295
|
+
h2,
|
|
296
|
+
h3,
|
|
297
|
+
h4,
|
|
298
|
+
h5,
|
|
299
|
+
h6 {
|
|
300
|
+
overflow-wrap: break-word;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
h1,
|
|
304
|
+
h2,
|
|
305
|
+
h3,
|
|
306
|
+
h4,
|
|
307
|
+
h5,
|
|
308
|
+
h6 {
|
|
309
|
+
margin-top: 0.5rem;
|
|
310
|
+
margin-bottom: 1rem;
|
|
311
|
+
text-rendering: optimizeLegibility;
|
|
312
|
+
font-weight: 600;
|
|
313
|
+
line-height: 1.1;
|
|
314
|
+
}
|
|
315
|
+
h1 {
|
|
316
|
+
font-size: 3rem;
|
|
317
|
+
line-height: 1.2;
|
|
318
|
+
font-weight: 800;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
h2 {
|
|
322
|
+
font-size: 2.6rem;
|
|
323
|
+
margin-top: 3rem;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
h3 {
|
|
327
|
+
font-size: 2rem;
|
|
328
|
+
margin-top: 3rem;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
h4 {
|
|
332
|
+
font-size: 1.44rem;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
h5 {
|
|
336
|
+
font-size: 1.15rem;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
h6 {
|
|
340
|
+
font-size: 0.96rem;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
article h1 {
|
|
344
|
+
font-weight: 600;
|
|
345
|
+
font-size: 2rem;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
@media only screen and (max-width: 720px) {
|
|
349
|
+
h1 {
|
|
350
|
+
font-size: 2.5rem;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
h2 {
|
|
354
|
+
font-size: 2.1rem;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
h3 {
|
|
358
|
+
font-size: 1.75rem;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
h4 {
|
|
362
|
+
font-size: 1.25rem;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
p {
|
|
367
|
+
margin-top: 0;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
ol,
|
|
371
|
+
ul {
|
|
372
|
+
/* padding-left: 0; */
|
|
373
|
+
margin-top: 0;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
ul ul,
|
|
377
|
+
ul ol,
|
|
378
|
+
ol ol,
|
|
379
|
+
ol ul {
|
|
380
|
+
font-size: 100%;
|
|
381
|
+
/* margin: 1rem 0 1rem 3rem; */
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
li {
|
|
385
|
+
margin-bottom: 0.5rem;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/* Extra selector for specificity, see below */
|
|
389
|
+
li > p:not(:last-child) {
|
|
390
|
+
margin: 0;
|
|
391
|
+
padding: 0;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
code {
|
|
395
|
+
background: var(--code-background);
|
|
396
|
+
font-size: 0.9em;
|
|
397
|
+
white-space: nowrap;
|
|
398
|
+
margin-inline: 0px;
|
|
399
|
+
padding: 3px 4px;
|
|
400
|
+
border-radius: 5px;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
code,
|
|
404
|
+
mark {
|
|
405
|
+
-webkit-box-decoration-break: clone;
|
|
406
|
+
box-decoration-break: clone;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
pre {
|
|
410
|
+
background: var(--code-background);
|
|
411
|
+
padding: 1rem 1.5rem;
|
|
412
|
+
border-radius: 5px;
|
|
413
|
+
overflow-x: auto;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
dt {
|
|
417
|
+
float: left;
|
|
418
|
+
margin: 0 20px 0 0;
|
|
419
|
+
width: 120px;
|
|
420
|
+
color: #daf2fd;
|
|
421
|
+
font-weight: 500;
|
|
422
|
+
text-align: right;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
dd {
|
|
426
|
+
margin: 0 0 5px 0;
|
|
427
|
+
text-align: left;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
blockquote {
|
|
431
|
+
margin: 1.5em 0;
|
|
432
|
+
padding: 0 1.6em 0 1.6em;
|
|
433
|
+
border-left: 5px solid var(--border-color);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
a {
|
|
437
|
+
text-decoration: none;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
figcaption {
|
|
441
|
+
margin-top: 0.5rem;
|
|
442
|
+
font-style: italic;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
article {
|
|
446
|
+
border: 1px solid var(--border-color);
|
|
447
|
+
background: var(--soft-background);
|
|
448
|
+
padding: 1rem 2rem 1.5rem;
|
|
449
|
+
border-radius: 0.5rem;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
article + article {
|
|
453
|
+
margin-top: 1rem;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
th,
|
|
457
|
+
td {
|
|
458
|
+
padding: 12px 15px;
|
|
459
|
+
text-align: left;
|
|
460
|
+
border-bottom: 1px solid var(--border-color-softer);
|
|
461
|
+
}
|
|
462
|
+
th:first-child,
|
|
463
|
+
td:first-child {
|
|
464
|
+
padding-left: 0;
|
|
465
|
+
}
|
|
466
|
+
th:last-child,
|
|
467
|
+
td:last-child {
|
|
468
|
+
padding-right: 0;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
:where(pre, blockquote, dl, figure, table, p, ul, ol, form, article, section, aside):not(
|
|
472
|
+
:last-child
|
|
473
|
+
) {
|
|
474
|
+
margin-bottom: 2.5rem;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
hr {
|
|
478
|
+
margin-top: 3rem;
|
|
479
|
+
margin-bottom: 3.5rem;
|
|
480
|
+
border-width: 0px;
|
|
481
|
+
border-top: 1px solid var(--text-color);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/* Header */
|
|
485
|
+
|
|
486
|
+
header {
|
|
487
|
+
margin-top: 4rem;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
nav.top-bar {
|
|
491
|
+
border: 1px solid var(--border-color);
|
|
492
|
+
padding: 6px 10px;
|
|
493
|
+
margin-inline: -3px;
|
|
494
|
+
border-radius: 5px;
|
|
495
|
+
display: flex;
|
|
496
|
+
column-gap: 2rem;
|
|
497
|
+
row-gap: 0.5rem;
|
|
498
|
+
flex-wrap: wrap;
|
|
499
|
+
justify-content: flex-start;
|
|
500
|
+
background: var(--soft-background);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
nav.top-bar:has(+ nav.top-bar) {
|
|
504
|
+
border-bottom: none;
|
|
505
|
+
border-bottom-left-radius: 0;
|
|
506
|
+
border-bottom-right-radius: 0;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
nav.top-bar:has(+ nav.top-bar):after {
|
|
510
|
+
display: block;
|
|
511
|
+
content: '';
|
|
512
|
+
border-bottom: 1px solid var(--border-color);
|
|
513
|
+
flex-basis: 100%;
|
|
514
|
+
margin-top: 0.7rem;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
nav.top-bar + nav.top-bar {
|
|
518
|
+
border-top-left-radius: 0;
|
|
519
|
+
border-top-right-radius: 0;
|
|
520
|
+
border-top: none;
|
|
521
|
+
margin-top: 0;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
nav > a {
|
|
525
|
+
text-wrap: nowrap;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
header a.site-title {
|
|
529
|
+
color: unset;
|
|
530
|
+
text-decoration: none;
|
|
531
|
+
font-weight: 900;
|
|
532
|
+
font-size: 2.8em;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
header .slogan {
|
|
536
|
+
/* font-family: var(--font-serif); */
|
|
537
|
+
font-weight: 500;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
nav :where([aria-current='page'], [aria-current='true']),
|
|
541
|
+
nav :where([aria-current='page'], [aria-current='true']):hover {
|
|
542
|
+
text-decoration: none;
|
|
543
|
+
color: unset;
|
|
544
|
+
cursor: default;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
header .breadcrumbs > a:only-child {
|
|
548
|
+
display: none;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
header .breadcrumbs {
|
|
552
|
+
margin-block: 4rem 1rem;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
header .breadcrumbs a {
|
|
556
|
+
font-size: 0.9em;
|
|
557
|
+
text-decoration: none;
|
|
558
|
+
color: unset;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
header .breadcrumbs .separator:after {
|
|
562
|
+
margin-inline: 0.5rem;
|
|
563
|
+
content: '|';
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/* Sidebar */
|
|
567
|
+
|
|
568
|
+
.sidebar {
|
|
569
|
+
margin-inline: auto;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/* Footer */
|
|
573
|
+
|
|
574
|
+
footer {
|
|
575
|
+
text-align: center;
|
|
576
|
+
margin-block: 6rem 8rem;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/* Pages */
|
|
580
|
+
|
|
581
|
+
.page.home > main > h1 {
|
|
582
|
+
display: none;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
.page.home .content p:first-child {
|
|
586
|
+
font-size: 1.2em;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
section[class*='$'] {
|
|
590
|
+
display: grid;
|
|
591
|
+
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
|
|
592
|
+
grid-auto-rows: auto;
|
|
593
|
+
grid-gap: 2rem;
|
|
594
|
+
|
|
595
|
+
& article {
|
|
596
|
+
margin: 0;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
article.item {
|
|
601
|
+
display: grid;
|
|
602
|
+
flex-direction: column;
|
|
603
|
+
grid-template-areas:
|
|
604
|
+
'title icon'
|
|
605
|
+
'description description';
|
|
606
|
+
align-content: start;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
article.item h1 {
|
|
610
|
+
grid-area: title;
|
|
611
|
+
font-size: 1.6rem;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
article.item dl.icon {
|
|
615
|
+
grid-area: icon;
|
|
616
|
+
font-size: 1.5em;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
article.item dl.icon dd {
|
|
620
|
+
text-align: right;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
article.item .description {
|
|
624
|
+
grid-area: description;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
article.item dt {
|
|
628
|
+
display: none;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
article.item dl.icon {
|
|
632
|
+
order: -1;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
aside.note {
|
|
636
|
+
&.note {
|
|
637
|
+
--icon: 'ℹ️';
|
|
638
|
+
--rgb: 71, 139, 230;
|
|
639
|
+
}
|
|
640
|
+
&.tip {
|
|
641
|
+
--icon: '💡';
|
|
642
|
+
--rgb: 87, 171, 90;
|
|
643
|
+
}
|
|
644
|
+
&.important {
|
|
645
|
+
--icon: '💬';
|
|
646
|
+
--rgb: 152, 110, 226;
|
|
647
|
+
}
|
|
648
|
+
&.warning {
|
|
649
|
+
--icon: '⚠️';
|
|
650
|
+
--rgb: 198, 144, 38;
|
|
651
|
+
}
|
|
652
|
+
&.caution {
|
|
653
|
+
--icon: '⛔️';
|
|
654
|
+
--rgb: 229, 83, 75;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
border-left: 3px solid rgb(var(--rgb));
|
|
658
|
+
padding: 1.5rem 2rem;
|
|
659
|
+
background: rgba(var(--rgb), 0.04);
|
|
660
|
+
|
|
661
|
+
h2 {
|
|
662
|
+
margin: 0 0 0.5em 0;
|
|
663
|
+
font-size: 1.1em;
|
|
664
|
+
color: rgb(var(--rgb));
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
h2:before {
|
|
668
|
+
font-size: 0.8em;
|
|
669
|
+
margin-right: 0.7rem;
|
|
670
|
+
opacity: 0.9;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
h2:before {
|
|
674
|
+
content: var(--icon);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
li.checked,
|
|
679
|
+
li.unchecked {
|
|
680
|
+
padding-left: 0.8rem;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
</style>
|
package/vite.config.js
CHANGED
|
@@ -23,6 +23,12 @@ export default defineConfig({
|
|
|
23
23
|
name: 'markdown:watch',
|
|
24
24
|
configureServer(server) {
|
|
25
25
|
server.watcher.add(homeDir);
|
|
26
|
+
server.watcher.on('add', () => {
|
|
27
|
+
server.ws.send('vowel:refresh');
|
|
28
|
+
});
|
|
29
|
+
server.watcher.on('unlink', () => {
|
|
30
|
+
server.ws.send('vowel:refresh');
|
|
31
|
+
});
|
|
26
32
|
server.watcher.on('change', async (homePath, stats) => {
|
|
27
33
|
if (homePath.endsWith('.md')) {
|
|
28
34
|
// Remove `.md`
|