Compare commits
7 commits
a62087432e
...
9474e7d3f0
Author | SHA1 | Date | |
---|---|---|---|
mei (ckie) | 9474e7d3f0 | ||
mei (ckie) | b39a017918 | ||
mei (ckie) | f8db23ad7d | ||
mei (ckie) | f82f51be6f | ||
mei (ckie) | 74f52215d1 | ||
mei (ckie) | db034e7731 | ||
mei (ckie) | 21db765fed |
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
||||||
node_modules
|
node_modules
|
||||||
|
.petalpkgs
|
||||||
|
|
||||||
# Output
|
# Output
|
||||||
.output
|
.output
|
||||||
|
@ -6,6 +7,9 @@ node_modules
|
||||||
/.svelte-kit
|
/.svelte-kit
|
||||||
/build
|
/build
|
||||||
|
|
||||||
|
# Direnv cache
|
||||||
|
/.direnv
|
||||||
|
|
||||||
# OS
|
# OS
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
|
18
flake.lock
18
flake.lock
|
@ -34,10 +34,26 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"petalpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731150020,
|
||||||
|
"narHash": "sha256-mK7QbLvx6LacoEWnvaf7tjVU8sKcsqpm9PPEuVXXlb4=",
|
||||||
|
"ref": "refs/heads/main",
|
||||||
|
"rev": "09239e085e32e70fc4b947a13163f6ec10073a82",
|
||||||
|
"revCount": 707552,
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://cl.forkos.org/nixpkgs"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://cl.forkos.org/nixpkgs"
|
||||||
|
}
|
||||||
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-utils": "flake-utils",
|
"flake-utils": "flake-utils",
|
||||||
"nixpkgs": "nixpkgs"
|
"nixpkgs": "nixpkgs",
|
||||||
|
"petalpkgs": "petalpkgs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"systems": {
|
"systems": {
|
||||||
|
|
|
@ -2,9 +2,10 @@
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
flake-utils.url = "github:numtide/flake-utils";
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
petalpkgs.url = "git+https://cl.forkos.org/nixpkgs";
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, flake-utils }:
|
outputs = { self, nixpkgs, flake-utils, petalpkgs }:
|
||||||
flake-utils.lib.eachDefaultSystem (system:
|
flake-utils.lib.eachDefaultSystem (system:
|
||||||
let pkgs = import nixpkgs { inherit system; };
|
let pkgs = import nixpkgs { inherit system; };
|
||||||
in {
|
in {
|
||||||
|
@ -13,6 +14,10 @@
|
||||||
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [ pkgs.stdenv.cc.cc.lib ];
|
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [ pkgs.stdenv.cc.cc.lib ];
|
||||||
|
|
||||||
buildInputs = with pkgs; [ bun ];
|
buildInputs = with pkgs; [ bun ];
|
||||||
|
|
||||||
|
shellHook = ''
|
||||||
|
ln -sf ${petalpkgs.outPath} .petalpkgs
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
# ... and remote deployment.
|
# ... and remote deployment.
|
||||||
|
|
16
package.json
16
package.json
|
@ -13,10 +13,11 @@
|
||||||
"prepare": "husky"
|
"prepare": "husky"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sveltejs/adapter-auto": "^3.0.0",
|
"@sveltejs/adapter-node": "^5.2.9",
|
||||||
"@sveltejs/enhanced-img": "^0.3.9",
|
"@sveltejs/enhanced-img": "^0.3.9",
|
||||||
"@sveltejs/kit": "^2.5.27",
|
"@sveltejs/kit": "^2.5.27",
|
||||||
"@sveltejs/vite-plugin-svelte": "^4.0.0",
|
"@sveltejs/vite-plugin-svelte": "^4.0.0",
|
||||||
|
"@types/node": "^22.8.1",
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
"husky": "^9.1.6",
|
"husky": "^9.1.6",
|
||||||
"lint-staged": "^15.2.10",
|
"lint-staged": "^15.2.10",
|
||||||
|
@ -32,8 +33,19 @@
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
|
"mdast": "^3.0.0",
|
||||||
"moderndash": "^3.12.0",
|
"moderndash": "^3.12.0",
|
||||||
"svelte-highlight": "^7.7.0"
|
"rehype-autolink-headings": "^7.1.0",
|
||||||
|
"rehype-sanitize": "^6.0.0",
|
||||||
|
"rehype-slug-custom-id": "^2.0.0",
|
||||||
|
"rehype-stringify": "^10.0.1",
|
||||||
|
"remark": "^15.0.1",
|
||||||
|
"remark-parse": "^11.0.0",
|
||||||
|
"remark-rehype": "^11.1.1",
|
||||||
|
"svelte-highlight": "^7.7.0",
|
||||||
|
"to-vfile": "^8.0.0",
|
||||||
|
"unified": "^11.0.5",
|
||||||
|
"unist-util-flatmap": "^1.0.0"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"{package.json,*.js,src/**.{svelte,ts,js,css}}": "prettier --write --ignore-unknown"
|
"{package.json,*.js,src/**.{svelte,ts,js,css}}": "prettier --write --ignore-unknown"
|
||||||
|
|
32
src/lib/docs/index.ts
Normal file
32
src/lib/docs/index.ts
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import { readFile } from "fs/promises";
|
||||||
|
import rehypeStringify from "rehype-stringify";
|
||||||
|
import remarkParse from "remark-parse";
|
||||||
|
import remarkRehype from "remark-rehype";
|
||||||
|
import { unified } from "unified";
|
||||||
|
import rehypeSlug from "rehype-slug-custom-id";
|
||||||
|
import { join } from "path";
|
||||||
|
import { remarkInclude } from "./remark-include";
|
||||||
|
import rehypeAutolinkHeadings from "rehype-autolink-headings";
|
||||||
|
// import rehypeSanitize from "rehype-sanitize";
|
||||||
|
|
||||||
|
export async function renderToHtml(
|
||||||
|
{ base, path }: {
|
||||||
|
base: string,
|
||||||
|
path: string
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
const md = await readFile(join(base, path + ".md"), { encoding: "utf-8" });
|
||||||
|
|
||||||
|
const html = await unified()
|
||||||
|
.use(remarkParse)
|
||||||
|
.use(remarkInclude, { resolveFrom: join(base, path.split("/").slice(0, -1).join("/")) })
|
||||||
|
.use(remarkRehype)
|
||||||
|
.use(rehypeSlug, { enableCustomId: true })
|
||||||
|
.use(rehypeAutolinkHeadings)
|
||||||
|
// .use(rehypeSanitize) TODO
|
||||||
|
.use(rehypeStringify)
|
||||||
|
.process(md)
|
||||||
|
.then(vfile => vfile.toString());
|
||||||
|
|
||||||
|
return html;
|
||||||
|
}
|
68
src/lib/docs/remark-include.ts
Normal file
68
src/lib/docs/remark-include.ts
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/**
|
||||||
|
* https://github.com/hashicorp/remark-plugins
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import path from "path";
|
||||||
|
import { remark } from "remark";
|
||||||
|
import flatMap from "unist-util-flatmap";
|
||||||
|
import { readSync } from "to-vfile";
|
||||||
|
import type { Node, Root, Code } from "mdast";
|
||||||
|
import type { Plugin } from "unified";
|
||||||
|
|
||||||
|
export const remarkInclude: Plugin<[], Root> = ({ resolveFrom }: { resolveFrom: string }) => {
|
||||||
|
return (tree, file) => {
|
||||||
|
return flatMap(tree, (node: Code) => {
|
||||||
|
if (!(node.type == "code"
|
||||||
|
&& node.lang == "{=include=}"
|
||||||
|
&& node.meta !== "options"))
|
||||||
|
return [node];
|
||||||
|
|
||||||
|
// TODO: temporarily !== "options" because those are special, parsed from options.json:
|
||||||
|
// https://github.com/NixOS/nixpkgs/blob/d31617bedffa3e5fe067feba1c68b1a7f644cb4f/pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs/manual.py#L81-L102
|
||||||
|
|
||||||
|
const includes = node.value.split("\n");
|
||||||
|
|
||||||
|
return includes.flatMap(included => {
|
||||||
|
// read the file contents
|
||||||
|
const includePath = path.join(resolveFrom ?? file.dirname, included);
|
||||||
|
let includeContents;
|
||||||
|
try {
|
||||||
|
includeContents = readSync(includePath, "utf8");
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(
|
||||||
|
`The {=include=} file path at ${includePath} was not found.\n\nInclude Location: ${file.path}:${node.position.start.line}:${node.position.start.column}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we are including a ".md" or ".mdx" file, we add the contents as processed markdown
|
||||||
|
// if any other file type, they are embedded into a code block
|
||||||
|
if (includePath.match(/\.md(?:x)?$/)) {
|
||||||
|
// return the file contents in place of the @include
|
||||||
|
// (takes a couple steps because we're processing includes with remark)
|
||||||
|
const processor = remark();
|
||||||
|
// use the includeMarkdown plugin to allow recursive includes
|
||||||
|
processor.use(remarkInclude, { resolveFrom });
|
||||||
|
// Process the file contents, then return them
|
||||||
|
const ast = processor.parse(includeContents);
|
||||||
|
return processor.runSync(ast, includeContents).children;
|
||||||
|
} else {
|
||||||
|
throw new Error("noop: unused by petalpkgs");
|
||||||
|
// trim trailing newline
|
||||||
|
includeContents.contents = includeContents.contents.trim();
|
||||||
|
|
||||||
|
// return contents wrapped inside a "code" node
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
type: "code",
|
||||||
|
lang: includePath.match(/\.(\w+)$/)?.[1],
|
||||||
|
value: includeContents
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
|
@ -2,7 +2,7 @@
|
||||||
let { children } = $props();
|
let { children } = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="Layout-docs-root flex max-xl:flex-col lg:gap-2 justify-around">
|
<div class="Layout-docs-root flex max-xl:flex-col lg:gap-8 justify-around">
|
||||||
<div class="grow xl:relative">
|
<div class="grow xl:relative">
|
||||||
<nav class="mt-12 xl:absolute lg:right-0">
|
<nav class="mt-12 xl:absolute lg:right-0">
|
||||||
<ul
|
<ul
|
||||||
|
@ -17,13 +17,13 @@
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
<div class="Layout-docs-content w-[700px] max-w-[700px] text-xl">{@render children?.()}</div>
|
<div class="Layout-docs-content max-w-[740px] text-lg">{@render children?.()}</div>
|
||||||
<div class="grow"></div>
|
<div class="grow"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
:global(.Layout-docs-content p:not(.no-docs-style)) {
|
:global(.Layout-docs-content p:not(.no-docs-style)) {
|
||||||
@apply tracking-tight mb-1;
|
@apply mb-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.Layout-docs-content h1:not(.no-docs-style)) {
|
:global(.Layout-docs-content h1:not(.no-docs-style)) {
|
||||||
|
@ -33,4 +33,16 @@
|
||||||
:global(.Layout-docs-content h2:not(.no-docs-style)) {
|
:global(.Layout-docs-content h2:not(.no-docs-style)) {
|
||||||
@apply text-teal-600 text-2xl font-semibold my-1;
|
@apply text-teal-600 text-2xl font-semibold my-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:global(.Layout-docs-content h3:not(.no-docs-style)) {
|
||||||
|
@apply text-teal-600 text-xl font-semibold my-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.Layout-docs-content h4:not(.no-docs-style)) {
|
||||||
|
@apply text-teal-700 font-semibold my-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.Layout-docs-content [id]:not(.no-docs-style) > a > .icon.icon-link) {
|
||||||
|
@apply after:opacity-10 after:hover:opacity-100 after:inline-block after:font-sans after:content-['¶'] after:-ms-[1em] after:me-2 after:align-middle after:text-3xl after:text-zinc-400;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
26
src/routes/docs/petal/[...rest]/+page.server.ts
Normal file
26
src/routes/docs/petal/[...rest]/+page.server.ts
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import type { PageServerLoad } from "./$types";
|
||||||
|
import { join } from "path";
|
||||||
|
import { renderToHtml } from "$lib/docs";
|
||||||
|
import { stat } from "fs/promises";
|
||||||
|
|
||||||
|
|
||||||
|
export const load: PageServerLoad = async (event) => {
|
||||||
|
let userPath = event.params.rest;
|
||||||
|
// we shouldn't need this, but it doesn't hurt.
|
||||||
|
if (userPath.split("/").find(c => /^\.*$/.test(c)))
|
||||||
|
throw new Error("url is sus");
|
||||||
|
|
||||||
|
const base = join(process.cwd(), ".petalpkgs");
|
||||||
|
|
||||||
|
{
|
||||||
|
const isFolder = await stat(join(base, userPath))
|
||||||
|
.then(f => f.isDirectory())
|
||||||
|
.catch(() => false);
|
||||||
|
|
||||||
|
if (isFolder) userPath += "/index";
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
html: await renderToHtml({ base, path: userPath })
|
||||||
|
};
|
||||||
|
};
|
5
src/routes/docs/petal/[...rest]/+page.svelte
Normal file
5
src/routes/docs/petal/[...rest]/+page.svelte
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { page } from "$app/stores";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{@html $page.data.html}
|
|
@ -1,12 +1,9 @@
|
||||||
import adapter from "@sveltejs/adapter-auto";
|
import adapter from "@sveltejs/adapter-node";
|
||||||
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
|
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
|
||||||
|
|
||||||
/** @type {import('@sveltejs/kit').Config} */
|
/** @type {import('@sveltejs/kit').Config} */
|
||||||
const config = {
|
const config = {
|
||||||
kit: {
|
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()
|
adapter: adapter()
|
||||||
},
|
},
|
||||||
preprocess: vitePreprocess()
|
preprocess: vitePreprocess()
|
||||||
|
|
|
@ -5,8 +5,12 @@ import { defineConfig } from "vite";
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [sveltekit(), enhancedImages()],
|
plugins: [sveltekit(), enhancedImages()],
|
||||||
server: {
|
server: {
|
||||||
|
watch: {
|
||||||
|
// absurdly big
|
||||||
|
ignored: (file) => /\/(\.direnv|\.petalpkgs)$/.test(file)
|
||||||
|
},
|
||||||
fs: {
|
fs: {
|
||||||
allow: ["./tailwind.config.js"]
|
allow: ["./tailwind.config.js", "./.petalpkgs"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue