Mdsvex Posts, posts Api. config
This commit is contained in:
parent
4fa47b2ac3
commit
e4dc0e56cc
|
@ -57,4 +57,7 @@ public/api/vendor
|
||||||
/test-results/
|
/test-results/
|
||||||
/playwright-report/
|
/playwright-report/
|
||||||
/playwright/.cache/
|
/playwright/.cache/
|
||||||
|
/test-results/
|
||||||
|
/playwright-report/
|
||||||
|
/blob-report/
|
||||||
|
/playwright/.cache/
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
import { defineMDSveXConfig as defineConfig } from 'mdsvex';
|
||||||
|
import headings from 'remark-autolink-headings';
|
||||||
|
import remarkExternalLinks from 'remark-external-links';
|
||||||
|
import slug from 'remark-slug';
|
||||||
|
import remarkSetImagePath from './src/lib/utils/remark-set-image-path.js';
|
||||||
|
import remarkLinkWithImageAsOnlyChild from './src/lib/utils/remark-link-with-image-as-only-child.js';
|
||||||
|
import remarkHeadingsPermaLinks from './src/lib/utils/remark-headings-permalinks.js';
|
||||||
|
import { toString } from 'mdast-util-to-string';
|
||||||
|
import rehypeWrap from 'rehype-wrap-all';
|
||||||
|
import rehypeImgSize from 'rehype-img-size';
|
||||||
|
import { h } from 'hastscript';
|
||||||
|
import { visit } from 'unist-util-visit';
|
||||||
|
import remarkToc from 'remark-toc';
|
||||||
|
import getHeadings from './src/lib/utils/get-headings.js';
|
||||||
|
// import { highlightCode } from './src/lib/utils/highlighter.js';
|
||||||
|
|
||||||
|
/** @type {import('mdsvex').MdsvexOptions} */
|
||||||
|
const config = defineConfig({
|
||||||
|
extensions: ['.svelte.md', '.md', '.svx'],
|
||||||
|
smartypants: {
|
||||||
|
dashes: 'oldschool'
|
||||||
|
},
|
||||||
|
// Wait for skeleton to implement Prismjs, for now use <CodeBlock /> in .md files
|
||||||
|
// highlight: {},
|
||||||
|
// layout: {
|
||||||
|
// blog: './src/lib/components/blog/_blog-layout.svelte',
|
||||||
|
// project: './src/lib/components/projects/_project-layout.svelte',
|
||||||
|
// _: './src/lib/components/fallback/_layout.svelte'
|
||||||
|
// },
|
||||||
|
rehypePlugins: [
|
||||||
|
[rehypeWrap, { selector: 'table', wrapper: 'div.overflow-auto' }],
|
||||||
|
[rehypeImgSize, { dir: './static' }],
|
||||||
|
[
|
||||||
|
/** Custom rehype plugin to add loading="lazy" to all images */
|
||||||
|
() => {
|
||||||
|
return (tree) => {
|
||||||
|
visit(tree, 'element', (node) => {
|
||||||
|
if (node.tagName === 'img') {
|
||||||
|
node.properties.loading = 'lazy';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
remarkPlugins: [
|
||||||
|
[remarkToc, { maxDepth: 3, tight: true }][
|
||||||
|
(remarkExternalLinks,
|
||||||
|
{
|
||||||
|
target: '_blank'
|
||||||
|
})
|
||||||
|
],
|
||||||
|
slug,
|
||||||
|
[
|
||||||
|
headings,
|
||||||
|
{
|
||||||
|
behavior: 'append',
|
||||||
|
linkProperties: {},
|
||||||
|
content: function (node) {
|
||||||
|
return [
|
||||||
|
h('span.icon.icon-link header-anchor', {
|
||||||
|
ariaLabel: toString(node) + ' permalink'
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
remarkSetImagePath,
|
||||||
|
remarkLinkWithImageAsOnlyChild,
|
||||||
|
remarkHeadingsPermaLinks,
|
||||||
|
getHeadings
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
export default config;
|
66
package.json
66
package.json
|
@ -20,57 +20,61 @@
|
||||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||||
"test": "vitest",
|
"test": "vitest",
|
||||||
"lint": "prettier --plugin-search-dir . --check . && eslint .",
|
"lint": "prettier --plugin-search-dir . --check . && eslint .",
|
||||||
"format": "prettier --plugin-search-dir . --write ."
|
"format": "prettier --plugin-search-dir . --write .",
|
||||||
|
"test-ct": "playwright test -c playwright-ct.config.ts"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@playwright/experimental-ct-svelte": "^1.39.0",
|
||||||
"@skeletonlabs/skeleton": "2.0.0",
|
"@skeletonlabs/skeleton": "2.0.0",
|
||||||
"@skeletonlabs/tw-plugin": "0.1.0",
|
"@skeletonlabs/tw-plugin": "0.1.0",
|
||||||
"@sveltejs/adapter-cloudflare": "^2.3.3",
|
"@sveltejs/adapter-cloudflare": "^2.3.3",
|
||||||
"@sveltejs/kit": "^1.20.4",
|
"@sveltejs/kit": "^1.27.3",
|
||||||
"@tailwindcss/forms": "0.5.6",
|
"@tailwindcss/forms": "0.5.6",
|
||||||
"@tailwindcss/typography": "0.5.9",
|
"@tailwindcss/typography": "0.5.9",
|
||||||
"@types/js-cookie": "^3.0.5",
|
"@types/js-cookie": "^3.0.5",
|
||||||
"@types/node": "20.5.7",
|
"@types/node": "20.5.7",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
"@types/prismjs": "^1.26.2",
|
||||||
"@typescript-eslint/parser": "^5.45.0",
|
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
||||||
|
"@typescript-eslint/parser": "^5.62.0",
|
||||||
"autoprefixer": "10.4.15",
|
"autoprefixer": "10.4.15",
|
||||||
"emoji-regex": "^10.3.0",
|
"emoji-regex": "^10.3.0",
|
||||||
"eslint": "^8.28.0",
|
"eslint": "^8.53.0",
|
||||||
"eslint-config-prettier": "^8.5.0",
|
"eslint-config-prettier": "^8.10.0",
|
||||||
"eslint-plugin-svelte": "^2.30.0",
|
"eslint-plugin-svelte": "^2.34.1",
|
||||||
"js-cookie": "^3.0.5",
|
|
||||||
"postcss": "8.4.29",
|
|
||||||
"prettier": "^2.8.0",
|
|
||||||
"prettier-plugin-svelte": "^2.10.1",
|
|
||||||
"sass": "^1.66.1",
|
|
||||||
"svelte": "^4.0.5",
|
|
||||||
"svelte-check": "^3.4.3",
|
|
||||||
"tailwindcss": "3.3.3",
|
|
||||||
"tslib": "^2.4.1",
|
|
||||||
"typescript": "^5.2.2",
|
|
||||||
"vite": "^4.4.2",
|
|
||||||
"vite-plugin-tailwind-purgecss": "0.1.3",
|
|
||||||
"vitest": "^0.34.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@floating-ui/dom": "1.5.1",
|
|
||||||
"@threlte/core": "^6.0.10",
|
|
||||||
"@threlte/extras": "^7.0.0",
|
|
||||||
"@yushijinhun/three-minifier-rollup": "^0.4.0",
|
|
||||||
"hastscript": "^8.0.0",
|
"hastscript": "^8.0.0",
|
||||||
"highlight.js": "11.8.0",
|
"js-cookie": "^3.0.5",
|
||||||
"linkedom": "^0.15.3",
|
|
||||||
"mdast-util-to-string": "^4.0.0",
|
"mdast-util-to-string": "^4.0.0",
|
||||||
"mdsvex": "^0.11.0",
|
"mdsvex": "^0.11.0",
|
||||||
"prismjs": "^1.29.0",
|
"postcss": "8.4.29",
|
||||||
|
"prettier": "^2.8.8",
|
||||||
|
"prettier-plugin-svelte": "^2.10.1",
|
||||||
"rehype-img-size": "^1.0.1",
|
"rehype-img-size": "^1.0.1",
|
||||||
"rehype-wrap-all": "^1.1.0",
|
"rehype-wrap-all": "^1.1.0",
|
||||||
"remark-autolink-headings": "^7.0.1",
|
"remark-autolink-headings": "^7.0.1",
|
||||||
"remark-external-links": "^9.0.1",
|
"remark-external-links": "^9.0.1",
|
||||||
"remark-slug": "^7.0.1",
|
"remark-slug": "^7.0.1",
|
||||||
|
"sass": "^1.69.5",
|
||||||
|
"svelte": "^4.2.2",
|
||||||
|
"svelte-check": "^3.5.2",
|
||||||
|
"tailwindcss": "3.3.3",
|
||||||
|
"tslib": "^2.6.2",
|
||||||
|
"typescript": "^5.2.2",
|
||||||
|
"unist-util-visit": "^5.0.0",
|
||||||
|
"vite": "^4.5.0",
|
||||||
|
"vite-plugin-tailwind-purgecss": "0.1.3",
|
||||||
|
"vitest": "^0.34.6"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@floating-ui/dom": "1.5.1",
|
||||||
|
"@threlte/core": "^6.1.0",
|
||||||
|
"@threlte/extras": "^7.5.0",
|
||||||
|
"@yushijinhun/three-minifier-rollup": "^0.4.0",
|
||||||
|
"highlight.js": "11.8.0",
|
||||||
|
"linkedom": "^0.15.6",
|
||||||
|
"prismjs": "^1.29.0",
|
||||||
|
"remark-toc": "^9.0.0",
|
||||||
"rss": "^1.2.2",
|
"rss": "^1.2.2",
|
||||||
"svelte-preprocess": "^5.0.4",
|
"svelte-preprocess": "^5.0.4"
|
||||||
"unist-util-visit": "^5.0.0"
|
|
||||||
},
|
},
|
||||||
"type": "module"
|
"type": "module"
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { defineConfig, devices } from '@playwright/experimental-ct-svelte';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See https://playwright.dev/docs/test-configuration.
|
||||||
|
*/
|
||||||
|
export default defineConfig({
|
||||||
|
testDir: './',
|
||||||
|
/* The base directory, relative to the config file, for snapshot files created with toMatchSnapshot and toHaveScreenshot. */
|
||||||
|
snapshotDir: './__snapshots__',
|
||||||
|
/* Maximum time one test can run for. */
|
||||||
|
timeout: 10 * 1000,
|
||||||
|
/* Run tests in files in parallel */
|
||||||
|
fullyParallel: true,
|
||||||
|
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||||
|
forbidOnly: !!process.env.CI,
|
||||||
|
/* Retry on CI only */
|
||||||
|
retries: process.env.CI ? 2 : 0,
|
||||||
|
/* Opt out of parallel tests on CI. */
|
||||||
|
workers: process.env.CI ? 1 : undefined,
|
||||||
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||||
|
reporter: 'html',
|
||||||
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||||
|
use: {
|
||||||
|
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||||
|
trace: 'on-first-retry',
|
||||||
|
|
||||||
|
/* Port to use for Playwright component endpoint. */
|
||||||
|
ctPort: 3100,
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Configure projects for major browsers */
|
||||||
|
projects: [
|
||||||
|
{
|
||||||
|
name: 'chromium',
|
||||||
|
use: { ...devices['Desktop Chrome'] },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'firefox',
|
||||||
|
use: { ...devices['Desktop Firefox'] },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'webkit',
|
||||||
|
use: { ...devices['Desktop Safari'] },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
1067
pnpm-lock.yaml
1067
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,52 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { formatDate } from '$src/content/utils';
|
||||||
|
import '$lib/assets/prism-nord.css';
|
||||||
|
|
||||||
|
export let baseUrl: string;
|
||||||
|
export let imagesDirectoryName: string;
|
||||||
|
|
||||||
|
export let date: string = '';
|
||||||
|
export let slug: string = '';
|
||||||
|
export let title: string;
|
||||||
|
export let image: string;
|
||||||
|
export let teaserImage: string;
|
||||||
|
export let tags: string[] = [];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<article>
|
||||||
|
<div class="flex justify-center mt-4 mb-8">
|
||||||
|
<div class="w-full lg:w-[50rem] leading-[177.7%]">
|
||||||
|
<img
|
||||||
|
src="/images/{imagesDirectoryName}/{slug}/{teaserImage || image}"
|
||||||
|
alt={`${title}`}
|
||||||
|
class="max-h-[540px] rounded-tl-2xl rounded-tr-[1.3rem]"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="prose prose-img:rounded-tl-2xl prose-img:rounded-tr-[1.3rem] max-w-none text-base"
|
||||||
|
>
|
||||||
|
<p class="{tags && tags.length > 0 ? '!mb-2' : '!mb-2'} mt-8 text-base">
|
||||||
|
{formatDate(date)}
|
||||||
|
</p>
|
||||||
|
{#if tags && tags.length > 0}
|
||||||
|
<div class="flex mb-2 items-center gap-2">
|
||||||
|
{#each tags as tag}
|
||||||
|
<a
|
||||||
|
data-sveltekit-preload-data="hover"
|
||||||
|
href="/blog?{new URLSearchParams({ tag }).toString()}"
|
||||||
|
>
|
||||||
|
<span class="chip variant-ghost-surface">{tag}</span>
|
||||||
|
</a>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<style lang="postcss">
|
||||||
|
.prose :global(nav.toc) {
|
||||||
|
@apply hidden;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,82 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { isAnExternalLink } from '$lib/utils/helpers';
|
||||||
|
import type { BlogPost } from '$lib/types/blog';
|
||||||
|
|
||||||
|
export let post: BlogPost;
|
||||||
|
export let isMostRecent: boolean = false;
|
||||||
|
export let type: 'blog';
|
||||||
|
export let layout: 'row' | 'column' = 'column';
|
||||||
|
export let published: boolean = true;
|
||||||
|
export let headlineOrder: 'h3' | '' = '';
|
||||||
|
export let badge: string = '';
|
||||||
|
export let textWidth: string = '';
|
||||||
|
|
||||||
|
const generateURL = (href?: string, slug?: string) => {
|
||||||
|
if (href) return href;
|
||||||
|
return `/${type}/${slug}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
$: href = generateURL(post['href'], post.slug);
|
||||||
|
|
||||||
|
$: target = post && post['href'] && isAnExternalLink(post['href']) ? '_blank' : undefined;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<a
|
||||||
|
{href}
|
||||||
|
{target}
|
||||||
|
data-sveltekit-preload-data="hover"
|
||||||
|
class="card"
|
||||||
|
data-analytics={`{"context":"grid","variant":"preview"}`}
|
||||||
|
>
|
||||||
|
<div class="w-full text-token grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
|
<!-- Detailed -->
|
||||||
|
<a
|
||||||
|
class="card bg-gradient-to-br variant-gradient-tertiary-primary card-hover overflow-hidden"
|
||||||
|
href="/blog/{post.slug}"
|
||||||
|
>
|
||||||
|
<header>
|
||||||
|
<img
|
||||||
|
src="/images/blog/{post.slug}/{post.image}"
|
||||||
|
class="bg-black/50 w-full aspect-[21/9]"
|
||||||
|
alt="Post"
|
||||||
|
/>
|
||||||
|
</header>
|
||||||
|
<div class="p-4 space-y-4">
|
||||||
|
<h6 class="text-2" data-toc-ignore>
|
||||||
|
<div class="items-center flex gap-2">
|
||||||
|
{#if post.tags}
|
||||||
|
{#each post.tags as tag}
|
||||||
|
<span class="chip variant-ghost-surface">{tag}</span>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</h6>
|
||||||
|
<h3 class="h3" data-toc-ignore>{post.title}</h3>
|
||||||
|
<article>
|
||||||
|
<p>
|
||||||
|
<!-- cspell:disable -->
|
||||||
|
{post.excerpt}
|
||||||
|
<!-- cspell:enable -->
|
||||||
|
</p>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
<hr class="opacity-50" />
|
||||||
|
<footer class="p-4 flex justify-start items-center space-x-4">
|
||||||
|
<div class="flex-auto flex justify-between items-center">
|
||||||
|
<h6 class="font-bold" data-toc-ignore>By Matt</h6>
|
||||||
|
<small>
|
||||||
|
{#if post.date}
|
||||||
|
<span class="date text-p-small ml-macro">
|
||||||
|
{new Date(Date.parse(post.date)).toLocaleDateString(undefined, {
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'short',
|
||||||
|
day: 'numeric'
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</a>
|
|
@ -1,15 +1,16 @@
|
||||||
import type { MarkdownMetadata } from '$lib/contents/types';
|
import type { MarkdownMetadata } from '$lib/contents/types';
|
||||||
|
|
||||||
export type BlogTag = 'Projects' | 'Ideas' | 'Updates' | '';
|
export type BlogTag = 'Projects' | 'Blog' | 'Updates' | '';
|
||||||
|
|
||||||
export interface BlogPost extends MarkdownMetadata {
|
export interface BlogPost extends MarkdownMetadata {
|
||||||
|
title: string;
|
||||||
|
subtitle?: string;
|
||||||
|
tags?: BlogTag[];
|
||||||
|
modified?: string;
|
||||||
date?: string;
|
date?: string;
|
||||||
excerpt: string;
|
excerpt: string;
|
||||||
image: string;
|
image: string;
|
||||||
slug?: string;
|
slug?: string;
|
||||||
href?: string;
|
href?: string;
|
||||||
tags?: BlogTag[];
|
|
||||||
subtitle?: string;
|
|
||||||
title: string;
|
|
||||||
published: boolean;
|
published: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
/**
|
||||||
|
* Credit goes to @Xananax for providing this solution within the gist https://gist.github.com/Xananax/5dca3a1dd7070e4fdebe2927e4aeb55b
|
||||||
|
*/
|
||||||
|
import { join, basename, extname } from 'path';
|
||||||
|
|
||||||
|
export const defaults = {
|
||||||
|
extensions: ['.svelte.md', '.md', '.svx'],
|
||||||
|
dir: `$lib`,
|
||||||
|
list: []
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injects global imports in all your mdsvex files
|
||||||
|
* Specify:
|
||||||
|
* - the root dir (defaults to `src/lib`)
|
||||||
|
* - the array list of components (with extension), like `['Component.svelte']`
|
||||||
|
* - the valid extensions list as an array (defaults to `['.svelte.md', '.md', '.svx']`)
|
||||||
|
*
|
||||||
|
* If you want the component name to be different from the file name, you can specify an array
|
||||||
|
* of arrays: `['Component.svelte', ['Another', 'AnotherComp.svelte'], 'ThirdComp.svelte']`
|
||||||
|
*
|
||||||
|
* @param {Object} options options described above
|
||||||
|
* @returns a preprocessor suitable to plug into the `preprocess` key of the svelte config
|
||||||
|
*/
|
||||||
|
export const mdsvexGlobalComponents = (options = {}) => {
|
||||||
|
const { extensions, dir, list } = { ...defaults, ...options };
|
||||||
|
const extensionsRegex = new RegExp(
|
||||||
|
'(' + extensions.join('|').replace(/\./g, '\\.') + ')$',
|
||||||
|
'i'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!list || !list.length || !Array.isArray(list)) {
|
||||||
|
throw new Error(`"list" option must be an array and contain at least one element`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const imports = list
|
||||||
|
.map((entry) => {
|
||||||
|
let name = '';
|
||||||
|
if (Array.isArray(entry)) {
|
||||||
|
name = entry[0];
|
||||||
|
entry = entry[1];
|
||||||
|
}
|
||||||
|
const ext = extname(entry);
|
||||||
|
const path = join(dir, entry);
|
||||||
|
name = name || basename(entry, ext);
|
||||||
|
return `\nimport ${name} from "${path}";`;
|
||||||
|
})
|
||||||
|
.join('\n');
|
||||||
|
|
||||||
|
const preprocessor = {
|
||||||
|
script(thing) {
|
||||||
|
const { content, filename, attributes, markup } = thing;
|
||||||
|
if (!filename.match(extensionsRegex)) {
|
||||||
|
return { code: content };
|
||||||
|
}
|
||||||
|
const hasModuleContext = /^<script context="module">/.test(markup);
|
||||||
|
|
||||||
|
const isModulePass = attributes?.context === 'module';
|
||||||
|
if (!isModulePass || !hasModuleContext) {
|
||||||
|
return { code: content };
|
||||||
|
}
|
||||||
|
const isValidPass = (hasModuleContext && isModulePass) || !hasModuleContext;
|
||||||
|
if (!isValidPass) {
|
||||||
|
return { code: content };
|
||||||
|
}
|
||||||
|
return { code: `${imports}\n${content}` };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return preprocessor;
|
||||||
|
};
|
|
@ -3,22 +3,15 @@ import { visit } from 'unist-util-visit';
|
||||||
const imagesRelativeUrlPattern = '/images/';
|
const imagesRelativeUrlPattern = '/images/';
|
||||||
|
|
||||||
const visitor = (node) => {
|
const visitor = (node) => {
|
||||||
if (
|
if (node.type === 'image' && node.url.indexOf(imagesRelativeUrlPattern) > 0) {
|
||||||
node.type === 'image' &&
|
node.url = node.url.substring(node.url.indexOf(imagesRelativeUrlPattern) + ''.length);
|
||||||
node.url.indexOf(imagesRelativeUrlPattern) > 0
|
|
||||||
) {
|
|
||||||
node.url = node.url.substring(
|
|
||||||
node.url.indexOf(imagesRelativeUrlPattern) + ''.length,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default () => async (tree, vFile) => {
|
export default () => async (tree, vFile) => {
|
||||||
if (
|
if (
|
||||||
vFile.filename.indexOf('src/routes/docs/') > 0 ||
|
|
||||||
vFile.filename.indexOf('src/routes/blog/') > 0 ||
|
vFile.filename.indexOf('src/routes/blog/') > 0 ||
|
||||||
vFile.filename.indexOf('src/routes/guides/') > 0 ||
|
vFile.filename.indexOf('src/routes/projects/') > 0
|
||||||
vFile.filename.indexOf('src/routes/customers/') > 0
|
|
||||||
) {
|
) {
|
||||||
visit(tree, visitor);
|
visit(tree, visitor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
<!-- This page handles any error encountered by the site. -->
|
||||||
|
<script>
|
||||||
|
import { page } from '$app/stores';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if $page.status === 404}
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<div
|
||||||
|
class="relative mb-[3.33vh] flex h-96 w-96 items-center justify-center rounded-full bg-404"
|
||||||
|
>
|
||||||
|
<h1 class="h1 absolute text-h1 leading-[5rem]">404</h1>
|
||||||
|
</div>
|
||||||
|
<h2 class="h4 mb-x-small">You just hit a route that doesn't exist</h2>
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<h2>{$page.status}</h2>
|
||||||
|
|
||||||
|
{#if $page.error}
|
||||||
|
<p class="subhead">{$page.error.message}</p>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<p><strong>Sorry!</strong> Maybe try one of these links?</p>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/">Home</a></li>
|
||||||
|
</ul>
|
||||||
|
{/if}
|
|
@ -3,6 +3,7 @@
|
||||||
import { AppShell } from '@skeletonlabs/skeleton';
|
import { AppShell } from '@skeletonlabs/skeleton';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import MainFooter from '$lib/components/MainFooter.svelte';
|
import MainFooter from '$lib/components/MainFooter.svelte';
|
||||||
|
import MainHeader from '$lib/components/MainHeader.svelte';
|
||||||
|
|
||||||
// Floating UI for Popups
|
// Floating UI for Popups
|
||||||
import { computePosition, autoUpdate, flip, shift, offset, arrow } from '@floating-ui/dom';
|
import { computePosition, autoUpdate, flip, shift, offset, arrow } from '@floating-ui/dom';
|
||||||
|
@ -65,9 +66,8 @@
|
||||||
|
|
||||||
// Highlight JS
|
// Highlight JS
|
||||||
import hljs from 'highlight.js';
|
import hljs from 'highlight.js';
|
||||||
import 'highlight.js/styles/github-dark.css';
|
import 'highlight.js/styles/nord.css';
|
||||||
import { storeHighlightJs } from '@skeletonlabs/skeleton';
|
import { storeHighlightJs } from '@skeletonlabs/skeleton';
|
||||||
import MainHeader from '$lib/components/MainHeader.svelte';
|
|
||||||
storeHighlightJs.set(hljs);
|
storeHighlightJs.set(hljs);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
export const prerender = true;
|
||||||
|
export const trailingSlash = 'never';
|
|
@ -43,7 +43,7 @@
|
||||||
</section> -->
|
</section> -->
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import PostPreview from '$lib/components/blog/post-preview.svelte';
|
import PostPreview from '$lib/components/blog/BlogLayout.svelte';
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
import type { BlogTag } from '$lib/types/blog';
|
import type { BlogTag } from '$lib/types/blog';
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import BlogContentLayout from '$lib/components/blog/BlogLayout.svelte';
|
||||||
|
import type { PageData } from './$types';
|
||||||
|
|
||||||
|
export let data: PageData;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- <svelte:head>
|
||||||
|
<title>{data.post.title}</title>
|
||||||
|
<meta property="og:type" content="article" />
|
||||||
|
<meta property="og:title" content={data.post.title} />
|
||||||
|
</svelte:head> -->
|
||||||
|
|
||||||
|
<BlogContentLayout post={data.post}>
|
||||||
|
<svelte:component this={data.Component} />
|
||||||
|
</BlogContentLayout>
|
Loading…
Reference in New Issue