vowel 0.0.2 → 0.1.0
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/.prettierrc +8 -0
- package/.vscode/settings.json +3 -0
- package/README.md +123 -27
- package/bin.js +30 -0
- package/content/.cache.json +627 -0
- package/content/.obsidian/app.json +3 -0
- package/content/.obsidian/appearance.json +3 -0
- package/content/.obsidian/core-plugins-migration.json +30 -0
- package/content/.obsidian/core-plugins.json +20 -0
- package/content/.obsidian/workspace.json +168 -0
- package/content/about.md +3 -0
- package/content/assets/open-props.css +1630 -0
- package/content/assets/styles-2.css +128 -0
- package/content/assets/styles-3.css +275 -0
- package/content/docs/file-structure.md +31 -0
- package/content/docs/folder-settings.md +22 -0
- package/content/docs/home.md +8 -0
- package/content/docs/images.md +10 -0
- package/content/docs/pages.md +64 -0
- package/content/docs/quickstart.md +52 -0
- package/content/docs/run-build-deploy.md +20 -0
- package/content/docs/settings.md +4 -0
- package/content/docs/styling.md +10 -0
- package/content/docs/taxonomies.md +37 -0
- package/content/home.md +73 -0
- package/content/roadmap.md +81 -0
- package/content/settings.md +12 -0
- package/content/vercel.json +5 -0
- package/jsconfig.json +18 -0
- package/package.json +37 -19
- package/server.js +80 -0
- package/src/app.d.ts +12 -0
- package/src/app.html +12 -0
- package/src/lib/components/Breadcrumbs.svelte +19 -0
- package/src/lib/components/DefaultStyles.svelte +126 -0
- package/src/lib/components/FrontMatterTaxonomy.svelte +48 -0
- package/src/lib/components/Frontmatter.svelte +54 -0
- package/src/lib/components/FrontmatterProperty.svelte +72 -0
- package/src/lib/components/Markdown/Image.svelte +48 -0
- package/src/lib/components/Markdown/Link.svelte +10 -0
- package/src/lib/components/Markdown/LinkPreview.svelte +39 -0
- package/src/lib/components/Markdown/Text.svelte +6 -0
- package/src/lib/components/Markdown/index.svelte +84 -0
- package/src/lib/components/Markdown/validators.js +29 -0
- package/src/lib/components/Nav.svelte +39 -0
- package/src/lib/components/Page.svelte +59 -0
- package/src/lib/components/Sitemap.svelte +38 -0
- package/src/lib/components/index.js +9 -0
- package/src/lib/index.js +1 -0
- package/src/lib/utilities/buildURL.js +18 -0
- package/src/lib/utilities/checkFileExists.js +16 -0
- package/src/lib/utilities/createFolderClass.js +4 -0
- package/src/lib/utilities/createPageClass.js +4 -0
- package/src/lib/utilities/getFileLabel.js +18 -0
- package/src/lib/utilities/getFolder.js +16 -0
- package/src/lib/utilities/getFolderLabel.js +8 -0
- package/src/lib/utilities/getPage.js +24 -0
- package/src/lib/utilities/getPagesByFolder.js +93 -0
- package/src/lib/utilities/index.js +20 -0
- package/src/lib/utilities/isActiveLink.js +12 -0
- package/src/lib/utilities/isObject.js +8 -0
- package/src/lib/utilities/loadCache.js +28 -0
- package/src/lib/utilities/mutateMarkdownAST.js +59 -0
- package/src/lib/utilities/mutateMarkdownFrontmatter.js +115 -0
- package/src/lib/utilities/parseDate.js +43 -0
- package/src/lib/utilities/processMarkdownFiles.js +212 -0
- package/src/lib/utilities/readMarkdownFile.js +134 -0
- package/src/lib/utilities/regexPatterns.js +12 -0
- package/src/lib/utilities/resolveHomeDirPath.js +5 -0
- package/src/lib/utilities/writeCache.js +14 -0
- package/src/routes/[...path]/+layout.server.js +71 -0
- package/src/routes/[...path]/+page.server.js +22 -0
- package/src/routes/[...path]/+page.svelte +125 -0
- package/src/routes/feed.xml/+server.js +120 -0
- package/src/routes/robots.txt/+server.js +54 -0
- package/src/routes/sitemap.xml/+server.js +68 -0
- package/static/favicon.png +0 -0
- package/static/styles.css +0 -0
- package/svelte.config.js +32 -0
- package/vercel.json +5 -0
- package/vite.config.js +72 -0
- package/index.js +0 -28
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { Nav, Page, Breadcrumbs, Sitemap, DefaultStyles } from '$lib/components/index.js';
|
|
3
|
+
import { getPage, createPageClass } from '$lib/utilities/index.js';
|
|
4
|
+
import LinkPreview from '$lib/components/Markdown/LinkPreview.svelte';
|
|
5
|
+
import getFileLabel from '../../lib/utilities/getFileLabel';
|
|
6
|
+
import { error } from '@sveltejs/kit';
|
|
7
|
+
import { getFolder, getFolderLabel } from '../../lib/utilities';
|
|
8
|
+
import { page as pageStore } from '$app/stores';
|
|
9
|
+
import { dev, building } from '$app/environment';
|
|
10
|
+
|
|
11
|
+
let { data } = $props();
|
|
12
|
+
|
|
13
|
+
const { website, folderName } = $derived(data);
|
|
14
|
+
const { slogan } = website;
|
|
15
|
+
|
|
16
|
+
if (data.files.css.exists && dev) {
|
|
17
|
+
// Import styles in dev mode
|
|
18
|
+
import(/* @vite-ignore */ data.files.css.path);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const page = $derived(getPage(website, data.path));
|
|
22
|
+
|
|
23
|
+
if (!page) {
|
|
24
|
+
error(404, 'Page not found');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const websiteTitle = data.website._.title || data.folderName;
|
|
28
|
+
const pageMetaTitle = $derived(getFileLabel(page));
|
|
29
|
+
const siteTitle = website._.title || folderName;
|
|
30
|
+
|
|
31
|
+
function getBreadcrumbs(level = 0) {
|
|
32
|
+
const path = $pageStore.data.segments.slice(0, level).join('/');
|
|
33
|
+
const crumbyPage = getFolder($pageStore.data.website, path);
|
|
34
|
+
const folderLabel = getFolderLabel(crumbyPage);
|
|
35
|
+
const active = level > $pageStore.data.segments.length;
|
|
36
|
+
if (!active) return [folderLabel, ...getBreadcrumbs(level + 1)];
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function makePageMetaTitle() {
|
|
41
|
+
if (page.url === '/') {
|
|
42
|
+
if (slogan) return `${siteTitle || pageMetaTitle} - ${slogan}`;
|
|
43
|
+
return siteTitle || pageMetaTitle;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const breadcrumbs = getBreadcrumbs().slice(1, -1).reverse();
|
|
47
|
+
const breadcrumbSegment = breadcrumbs.length ? `${breadcrumbs.join(' - ')}` : '';
|
|
48
|
+
return `${pageMetaTitle} - ${breadcrumbSegment} - ${siteTitle}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function getFavicon() {
|
|
52
|
+
if (website._?.icon)
|
|
53
|
+
return `data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 20 90 60%22><text y=%22.9em%22 font-size=%2290%22>${website._.icon}</text></svg>`;
|
|
54
|
+
if (data.files.favicon.exists) return '/favicon.png';
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const favicon = getFavicon();
|
|
59
|
+
|
|
60
|
+
$effect(() => {
|
|
61
|
+
// Update website on file change
|
|
62
|
+
if (import.meta.hot) {
|
|
63
|
+
import.meta.hot.on('vowel:update', ({ path, file }) => {
|
|
64
|
+
let page = getPage(website, path);
|
|
65
|
+
|
|
66
|
+
for (const key in file) {
|
|
67
|
+
page[key] = file[key];
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
</script>
|
|
73
|
+
|
|
74
|
+
<!-- svelte-ignore state_referenced_locally -->
|
|
75
|
+
<!-- svelte-ignore state_referenced_locally -->
|
|
76
|
+
<svelte:head>
|
|
77
|
+
<title>{makePageMetaTitle()}</title>
|
|
78
|
+
<meta property="”og:url”" content={page.url} />
|
|
79
|
+
<meta property="og:site_name" content={website._.title || folderName} />
|
|
80
|
+
{#if page.hasOwnProperty('description') || page.imputedProperties?.hasOwnProperty('description')}
|
|
81
|
+
<meta
|
|
82
|
+
property="og:description"
|
|
83
|
+
content={page.description || page.imputedProperties.description}
|
|
84
|
+
/>
|
|
85
|
+
{/if}
|
|
86
|
+
{#if favicon}
|
|
87
|
+
<link rel="icon" href={favicon} />
|
|
88
|
+
{/if}
|
|
89
|
+
{#if data.files.css.exists && !dev}
|
|
90
|
+
<!-- Import styles in build mode -->
|
|
91
|
+
<link rel="stylesheet" href="styles.css" />
|
|
92
|
+
{/if}
|
|
93
|
+
</svelte:head>
|
|
94
|
+
|
|
95
|
+
<DefaultStyles />
|
|
96
|
+
|
|
97
|
+
<div data-sveltekit-preload-data="hover" class={createPageClass(page.url)}>
|
|
98
|
+
<header>
|
|
99
|
+
{#if website._.logo}
|
|
100
|
+
<a href="/" class="site-logo">
|
|
101
|
+
<img alt="website logo" src={website._.logo} />
|
|
102
|
+
</a>
|
|
103
|
+
{/if}
|
|
104
|
+
{#if siteTitle}
|
|
105
|
+
<a href="/" class="site-title">{siteTitle}</a>
|
|
106
|
+
{/if}
|
|
107
|
+
{#if website._.slogan}
|
|
108
|
+
<p class="slogan">{website._.slogan}</p>
|
|
109
|
+
{/if}
|
|
110
|
+
<Nav folder={data.website} segments={data.path.split('/')} />
|
|
111
|
+
<nav class="breadcrumbs" aria-label="Breadcrumb">
|
|
112
|
+
<Breadcrumbs level={0} />
|
|
113
|
+
</nav>
|
|
114
|
+
</header>
|
|
115
|
+
<main>
|
|
116
|
+
<Page level={0} {page} {website} path={data.path} />
|
|
117
|
+
</main>
|
|
118
|
+
<aside class="sitemap">
|
|
119
|
+
<Sitemap section={data.website} segments={data.path.split('/')} root />
|
|
120
|
+
</aside>
|
|
121
|
+
<footer>
|
|
122
|
+
© {website._.author ? website._.author + ' ' : ''}
|
|
123
|
+
{new Date().getFullYear()}
|
|
124
|
+
</footer>
|
|
125
|
+
</div>
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import xml from 'xml';
|
|
2
|
+
import { render } from 'svelte/server';
|
|
3
|
+
import Page from './../../lib/components/Page.svelte';
|
|
4
|
+
import {
|
|
5
|
+
getPagesByFolder,
|
|
6
|
+
getFileLabel,
|
|
7
|
+
processMarkdownFiles,
|
|
8
|
+
loadCache
|
|
9
|
+
} from '../../lib/utilities';
|
|
10
|
+
|
|
11
|
+
export const prerender = true;
|
|
12
|
+
|
|
13
|
+
export async function GET({}) {
|
|
14
|
+
/*
|
|
15
|
+
It's wasteful to load everything here, but it should only run
|
|
16
|
+
once at buildtime, so it's not a significant issue.
|
|
17
|
+
*/
|
|
18
|
+
const initialCache = await loadCache($home[0]);
|
|
19
|
+
|
|
20
|
+
const { folder: website } = await processMarkdownFiles(initialCache);
|
|
21
|
+
|
|
22
|
+
const allPages = getPagesByFolder(website, '/');
|
|
23
|
+
|
|
24
|
+
const sortedPages = allPages.filter((page) => page.hasOwnProperty('date'));
|
|
25
|
+
|
|
26
|
+
const site_title = {
|
|
27
|
+
title: website._.title || 'Untitled'
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const feed = [];
|
|
31
|
+
|
|
32
|
+
feed.push({
|
|
33
|
+
_attr: {
|
|
34
|
+
xmlns: 'http://www.w3.org/2005/Atom'
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
feed.push(site_title);
|
|
39
|
+
|
|
40
|
+
if (website._.domain)
|
|
41
|
+
feed.push(
|
|
42
|
+
{
|
|
43
|
+
link: {
|
|
44
|
+
_attr: {
|
|
45
|
+
rel: 'self',
|
|
46
|
+
href: `${website._.domain}/feed`
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: 'https://littlefair.ca/feed'
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
if (website._.author)
|
|
56
|
+
feed.push(
|
|
57
|
+
{
|
|
58
|
+
author: {
|
|
59
|
+
name: 'Sam Littlefair'
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
{ rights: `Copyright (c) ${new Date().getFullYear()} Sam Littlefair` }
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
feed.push(
|
|
66
|
+
...sortedPages.map((page) => {
|
|
67
|
+
const url = website._.domain ? website._.domain + page.url : 'undefined';
|
|
68
|
+
const entry = [
|
|
69
|
+
{
|
|
70
|
+
title: getFileLabel(page)
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
link: {
|
|
74
|
+
_attr: {
|
|
75
|
+
rel: 'alternate',
|
|
76
|
+
href: url
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
{ id: url },
|
|
81
|
+
{ updated: page.date }
|
|
82
|
+
];
|
|
83
|
+
|
|
84
|
+
if (page.description) {
|
|
85
|
+
entry.push({
|
|
86
|
+
summary: page.description
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (page.author) {
|
|
91
|
+
entry.push({
|
|
92
|
+
author: {
|
|
93
|
+
name: page.author
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
entry.push({
|
|
99
|
+
content: [
|
|
100
|
+
{ _attr: { type: 'html' } },
|
|
101
|
+
render(Page, { props: { page, level: 0, format: 'xml' } }).html
|
|
102
|
+
]
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
entry
|
|
107
|
+
};
|
|
108
|
+
})
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
const headers = {
|
|
112
|
+
'Cache-Control': 'max-age=0, s-maxage=3600',
|
|
113
|
+
'Content-Type': 'text/xml'
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const response = new Response(`<?xml version="1.0" encoding="utf-8"?>` + xml({ feed }, true), {
|
|
117
|
+
headers
|
|
118
|
+
});
|
|
119
|
+
return response;
|
|
120
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { processMarkdownFiles, loadCache } from '../../lib/utilities';
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
TODO: Will this work at this location? Otherwise, figure out how to move it.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const allow = `Allow: /`;
|
|
8
|
+
const disallow = `Disallow: /`;
|
|
9
|
+
|
|
10
|
+
const google_images = `User-agent: Googlebot-Image`;
|
|
11
|
+
|
|
12
|
+
const google_general = `User-agent: Google-Extended`;
|
|
13
|
+
|
|
14
|
+
const gpt_bot = `User-agent: GPTBot`;
|
|
15
|
+
|
|
16
|
+
const gpt_user = `User-agent: ChatGPT-User`;
|
|
17
|
+
|
|
18
|
+
const common_crawl = `User-agent: CCBot`;
|
|
19
|
+
|
|
20
|
+
export const prerender = true;
|
|
21
|
+
|
|
22
|
+
export async function GET({}) {
|
|
23
|
+
/*
|
|
24
|
+
It's wasteful to load everything here, but it should only run
|
|
25
|
+
once at buildtime, so it's not a significant issue.
|
|
26
|
+
*/
|
|
27
|
+
const initialCache = await loadCache($home[0]);
|
|
28
|
+
|
|
29
|
+
const { folder: website } = await processMarkdownFiles(initialCache);
|
|
30
|
+
|
|
31
|
+
const declarations = [];
|
|
32
|
+
|
|
33
|
+
declarations.push(
|
|
34
|
+
google_general + '\n' + (website._.robots?.google === false ? disallow : allow)
|
|
35
|
+
);
|
|
36
|
+
declarations.push(
|
|
37
|
+
google_images + '\n' + (website._.robots?.google_images === false ? disallow : allow)
|
|
38
|
+
);
|
|
39
|
+
declarations.push(gpt_bot + '\n' + (website._.robots?.ai === false ? disallow : allow));
|
|
40
|
+
declarations.push(gpt_user + '\n' + (website._.robots?.ai === false ? disallow : allow));
|
|
41
|
+
declarations.push(common_crawl + '\n' + (website._.robots?.ai === false ? disallow : allow));
|
|
42
|
+
|
|
43
|
+
const text = declarations.join('\n\n') || '';
|
|
44
|
+
|
|
45
|
+
const headers = {
|
|
46
|
+
'Cache-Control': 'max-age=0, s-maxage=3600',
|
|
47
|
+
'Content-Type': 'text/plain'
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const response = new Response(text, {
|
|
51
|
+
headers
|
|
52
|
+
});
|
|
53
|
+
return response;
|
|
54
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { getPagesByFolder, processMarkdownFiles, loadCache } from '../../lib/utilities';
|
|
2
|
+
|
|
3
|
+
export const prerender = true;
|
|
4
|
+
|
|
5
|
+
export async function GET({}) {
|
|
6
|
+
const fallback = {
|
|
7
|
+
folder: {}
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const initialCache = await loadCache($home[0]);
|
|
11
|
+
|
|
12
|
+
const { folder: website } = await processMarkdownFiles(initialCache);
|
|
13
|
+
|
|
14
|
+
const pages = getPagesByFolder(website, '/');
|
|
15
|
+
|
|
16
|
+
const site_title = {
|
|
17
|
+
title: website._.title || 'Untitled'
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const domain = website._.domain || false;
|
|
21
|
+
|
|
22
|
+
function createEntry(page) {
|
|
23
|
+
return `
|
|
24
|
+
<url>
|
|
25
|
+
<loc>${new URL(page.url || '/', domain)}</loc>
|
|
26
|
+
<changefreq>daily</changefreq>
|
|
27
|
+
<priority>0.7</priority>
|
|
28
|
+
</url>
|
|
29
|
+
`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function createSitemap(pages, domain) {
|
|
33
|
+
return `<?xml version="1.0" encoding="UTF-8" ?>
|
|
34
|
+
<urlset
|
|
35
|
+
xmlns="https://www.sitemaps.org/schemas/sitemap/0.9"
|
|
36
|
+
xmlns:news="https://www.google.com/schemas/sitemap-news/0.9"
|
|
37
|
+
xmlns:xhtml="https://www.w3.org/1999/xhtml"
|
|
38
|
+
xmlns:mobile="https://www.google.com/schemas/sitemap-mobile/1.0"
|
|
39
|
+
xmlns:image="https://www.google.com/schemas/sitemap-image/1.1"
|
|
40
|
+
xmlns:video="https://www.google.com/schemas/sitemap-video/1.1"
|
|
41
|
+
>
|
|
42
|
+
<url>
|
|
43
|
+
<loc>${domain}</loc>
|
|
44
|
+
<changefreq>daily</changefreq>
|
|
45
|
+
<priority>0.7</priority>
|
|
46
|
+
</url>
|
|
47
|
+
${pages.map(createEntry).join('')}
|
|
48
|
+
</urlset>
|
|
49
|
+
`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function createFallBackSitemap() {
|
|
53
|
+
return `<?xml version="1.0" encoding="UTF-8" ?><message>Specify a 'domain' in /settings.md</message>`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const sitemap = domain ? createSitemap(pages, domain) : createFallBackSitemap();
|
|
57
|
+
|
|
58
|
+
const headers = {
|
|
59
|
+
'Cache-Control': 'max-age=0, s-maxage=3600',
|
|
60
|
+
'Content-Type': 'text/xml'
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const response = new Response(sitemap, {
|
|
64
|
+
headers
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return response;
|
|
68
|
+
}
|
|
Binary file
|
|
File without changes
|
package/svelte.config.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import adapter from '@sveltejs/adapter-static';
|
|
2
|
+
import path, { join } from 'path';
|
|
3
|
+
|
|
4
|
+
const demoDir = process.cwd() + '/content';
|
|
5
|
+
const NPMRunDev = process.argv[2] === 'dev';
|
|
6
|
+
const isBuild = process.argv[2] === 'build';
|
|
7
|
+
const receivedHomePath = NPMRunDev || isBuild ? false : process.argv[2];
|
|
8
|
+
const homeDir = receivedHomePath || demoDir;
|
|
9
|
+
const relativePathToHome = path.relative(process.cwd(), homeDir);
|
|
10
|
+
|
|
11
|
+
/** @type {import('@sveltejs/kit').Config} */
|
|
12
|
+
const config = {
|
|
13
|
+
kit: {
|
|
14
|
+
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
|
|
15
|
+
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
|
|
16
|
+
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
|
|
17
|
+
adapter: adapter({
|
|
18
|
+
pages: join(relativePathToHome, '.output'),
|
|
19
|
+
assets: join(relativePathToHome, '.output'),
|
|
20
|
+
strict: false
|
|
21
|
+
}),
|
|
22
|
+
files: {
|
|
23
|
+
assets: join(relativePathToHome, 'assets')
|
|
24
|
+
},
|
|
25
|
+
prerender: {
|
|
26
|
+
handleHttpError: 'warn',
|
|
27
|
+
entries: ['*', '/', '/robots.txt', '/sitemap.xml', '/feed.xml']
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export default config;
|
package/vercel.json
ADDED
package/vite.config.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { sveltekit } from '@sveltejs/kit/vite';
|
|
2
|
+
import { defineConfig } from 'vite';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { readMarkdownFile, loadCache } from './src/lib/utilities/index';
|
|
5
|
+
|
|
6
|
+
const demoDir = process.cwd() + '/content';
|
|
7
|
+
const NPMRunDev = process.argv[2] === 'dev';
|
|
8
|
+
const isBuild = process.argv[2] === 'build';
|
|
9
|
+
const receivedHomePath = NPMRunDev || isBuild ? false : process.argv[2];
|
|
10
|
+
|
|
11
|
+
const homeDir = receivedHomePath || demoDir;
|
|
12
|
+
|
|
13
|
+
const $home = [homeDir];
|
|
14
|
+
|
|
15
|
+
export default defineConfig({
|
|
16
|
+
plugins: [
|
|
17
|
+
sveltekit(),
|
|
18
|
+
{
|
|
19
|
+
// Hot reload markdown
|
|
20
|
+
name: 'markdown:watch',
|
|
21
|
+
configureServer(server) {
|
|
22
|
+
console.log(`Root directory: ${homeDir}`);
|
|
23
|
+
server.watcher.add(homeDir);
|
|
24
|
+
server.watcher.on('change', async (homePath, stats) => {
|
|
25
|
+
if (homePath.endsWith('.md')) {
|
|
26
|
+
// Remove `.md`
|
|
27
|
+
const cache = await loadCache(homeDir);
|
|
28
|
+
const file = await readMarkdownFile(homePath, cache);
|
|
29
|
+
Object.assign(file, file.frontmatter);
|
|
30
|
+
const relativePath = path
|
|
31
|
+
.relative(homeDir, homePath)
|
|
32
|
+
.slice(0, -3)
|
|
33
|
+
.replace(/\/?(home|settings)$/, '');
|
|
34
|
+
server.ws.send('vowel:update', {
|
|
35
|
+
path: relativePath,
|
|
36
|
+
stats,
|
|
37
|
+
file
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
],
|
|
44
|
+
define: { $home },
|
|
45
|
+
optimizeDeps: {
|
|
46
|
+
exclude: ['svelte', 'remark', 'remark-frontmatter', 'remark-html'],
|
|
47
|
+
include: [
|
|
48
|
+
'micromark',
|
|
49
|
+
'unified',
|
|
50
|
+
'fault',
|
|
51
|
+
'url-metadata',
|
|
52
|
+
'any-date-parser',
|
|
53
|
+
'any-date-parser/src/formats/ago/ago.js',
|
|
54
|
+
'any-date-parser/src/formats/ago/ago.js',
|
|
55
|
+
'any-date-parser/src/formats/chinese/chinese.js',
|
|
56
|
+
'any-date-parser/src/formats/dayMonth/dayMonth.js',
|
|
57
|
+
'any-date-parser/src/formats/dayMonthname/dayMonthname.js',
|
|
58
|
+
'any-date-parser/src/formats/monthDay/monthDay.js',
|
|
59
|
+
'any-date-parser/src/formats/monthnameDay/monthnameDay.js',
|
|
60
|
+
'any-date-parser/src/formats/today/today.js'
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
server: {
|
|
64
|
+
fs: {
|
|
65
|
+
strict: false,
|
|
66
|
+
allow: homeDir
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
resolve: {
|
|
70
|
+
// extensions: ['.css']
|
|
71
|
+
}
|
|
72
|
+
});
|
package/index.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
const vowels = ['a', 'e', 'i', 'o', 'u'];
|
|
2
|
-
|
|
3
|
-
function isVowel(c) {
|
|
4
|
-
return vowels.indexOf(c.toLowerCase()) !== -1;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
function includesVowel(s) {
|
|
8
|
-
for (let i = 0; i < s.length; i += 1) {
|
|
9
|
-
if (isVowel(s.charAt(i))) return true;
|
|
10
|
-
}
|
|
11
|
-
return false;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function startsWithVowel(s) {
|
|
15
|
-
return vowels.some(v => s.toLowerCase().startsWith(v));
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function endsWithVowel(s) {
|
|
19
|
-
return vowels.some(v => s.toLowerCase().endsWith(v));
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
module.exports = {
|
|
23
|
-
vowels,
|
|
24
|
-
isVowel,
|
|
25
|
-
includesVowel,
|
|
26
|
-
startsWithVowel,
|
|
27
|
-
endsWithVowel,
|
|
28
|
-
};
|