[examples/openspending] - openspending v0.2 (#907)
* [examples/openspending] - openspending v0.2 * [examples/openspending][m] - fix build * [examples/openspending][xs] - fix build * [examples/openspending][xs] - add prebuild step * [examples/openspending][m] - fix requested by demenech * [examples/openspending][sm] - remove links + fix bug
This commit is contained in:
111
examples/openspending/lib/computeFields.ts
Normal file
111
examples/openspending/lib/computeFields.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
// This file is a temporary replacement for legacy contentlayer's computeFields + default fields values
|
||||
import { remark } from "remark";
|
||||
import stripMarkdown, { Options } from "strip-markdown";
|
||||
|
||||
import { defaultConfig as siteConfig } from '@flowershow/core'
|
||||
|
||||
// TODO return type
|
||||
const sluggify = (urlPath: string) => {
|
||||
return urlPath.replace(/^(.+?\/)*/, "");
|
||||
};
|
||||
|
||||
const computeFields = async ({
|
||||
frontMatter,
|
||||
urlPath,
|
||||
filePath,
|
||||
source,
|
||||
}: {
|
||||
frontMatter: Record<string, any>;
|
||||
urlPath: string;
|
||||
filePath: string;
|
||||
source: string;
|
||||
}) => {
|
||||
// Fields with corresponding config options
|
||||
// TODO see _app.tsx
|
||||
const showEditLink =
|
||||
frontMatter.showEditLink ?? siteConfig.showEditLink ?? false;
|
||||
// TODO take config into accout
|
||||
const showLinkPreviews =
|
||||
frontMatter.showLinkPreviews ?? siteConfig.showLinkPreviews ?? false;
|
||||
const showToc = frontMatter.showToc ?? siteConfig.showToc ?? false;
|
||||
const showSidebar =
|
||||
frontMatter.showSidebar ?? siteConfig.showSidebar ?? false;
|
||||
|
||||
// Computed fields
|
||||
// const title = frontMatter.title ?? (await extractTitle(source));
|
||||
const title = frontMatter.title ?? null;
|
||||
const description =
|
||||
frontMatter.description ?? (await extractDescription(source));
|
||||
const date = frontMatter.date ?? frontMatter.created ?? null;
|
||||
const layout = (() => {
|
||||
if (frontMatter.layout) return frontMatter.layout;
|
||||
if (urlPath.startsWith("blog/")) return "blog";
|
||||
// if (urlPath.startsWith("docs/")) return "docs";
|
||||
return "docs"; // TODO default layout from config?
|
||||
})();
|
||||
|
||||
// TODO Temporary, should probably be a column in the database
|
||||
const slug = sluggify(urlPath);
|
||||
// TODO take into accout include/exclude fields in config
|
||||
const isDraft = frontMatter.isDraft ?? false;
|
||||
|
||||
return {
|
||||
...frontMatter,
|
||||
title,
|
||||
description,
|
||||
date,
|
||||
layout,
|
||||
slug,
|
||||
urlPath, // extra for blogs index page; temporary here
|
||||
isDraft,
|
||||
showEditLink,
|
||||
showLinkPreviews,
|
||||
showToc,
|
||||
showSidebar,
|
||||
};
|
||||
};
|
||||
|
||||
const extractTitle = async (source: string) => {
|
||||
const heading = source.trim().match(/^#\s+(.*)/);
|
||||
if (heading) {
|
||||
const title = heading[1]
|
||||
// replace wikilink with only text value
|
||||
.replace(/\[\[([\S]*?)]]/, "$1");
|
||||
|
||||
const stripTitle = await remark().use(stripMarkdown).process(title);
|
||||
return stripTitle.toString().trim();
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const extractDescription = async (source: string) => {
|
||||
const content = source
|
||||
// remove commented lines
|
||||
.replace(/{\/\*.*\*\/}/g, "")
|
||||
// remove import statements
|
||||
.replace(
|
||||
/^import\s*(?:\{\s*[\w\s,\n]+\s*\})?(\s*(\w+))?\s*from\s*("|')[^"]+("|');?$/gm,
|
||||
""
|
||||
)
|
||||
// remove youtube links
|
||||
.replace(/^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.?be)\/.+$/gm, "")
|
||||
// replace wikilinks with only text
|
||||
.replace(/([^!])\[\[(\S*?)\]]/g, "$1$2")
|
||||
// remove wikilink images
|
||||
.replace(/!\[[\S]*?]]/g, "");
|
||||
|
||||
// remove markdown formatting
|
||||
const stripped = await remark()
|
||||
.use(stripMarkdown, {
|
||||
remove: ["heading", "blockquote", "list", "image", "html", "code"],
|
||||
} as Options)
|
||||
.process(content);
|
||||
|
||||
if (stripped.value) {
|
||||
const description: string = stripped.value.toString().slice(0, 200);
|
||||
return description + "...";
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export default computeFields;
|
||||
105
examples/openspending/lib/markdown.mjs
Normal file
105
examples/openspending/lib/markdown.mjs
Normal file
@@ -0,0 +1,105 @@
|
||||
import matter from "gray-matter";
|
||||
import mdxmermaid from "mdx-mermaid";
|
||||
import { h } from "hastscript";
|
||||
import remarkCallouts from "@flowershow/remark-callouts";
|
||||
import remarkEmbed from "@flowershow/remark-embed";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import remarkMath from "remark-math";
|
||||
import remarkSmartypants from "remark-smartypants";
|
||||
import remarkToc from "remark-toc";
|
||||
import remarkWikiLink from "@flowershow/remark-wiki-link";
|
||||
import rehypeAutolinkHeadings from "rehype-autolink-headings";
|
||||
import rehypeKatex from "rehype-katex";
|
||||
import rehypeSlug from "rehype-slug";
|
||||
import rehypePrismPlus from "rehype-prism-plus";
|
||||
|
||||
import { serialize } from "next-mdx-remote/serialize";
|
||||
|
||||
/**
|
||||
* Parse a markdown or MDX file to an MDX source form + front matter data
|
||||
*
|
||||
* @source: the contents of a markdown or mdx file
|
||||
* @format: used to indicate to next-mdx-remote which format to use (md or mdx)
|
||||
* @returns: { mdxSource: mdxSource, frontMatter: ...}
|
||||
*/
|
||||
const parse = async function (source, format, scope) {
|
||||
const { content, data, excerpt } = matter(source, {
|
||||
excerpt: (file, options) => {
|
||||
// Generate an excerpt for the file
|
||||
file.excerpt = file.content.split("\n\n")[0];
|
||||
},
|
||||
});
|
||||
|
||||
const mdxSource = await serialize(
|
||||
{ value: content, path: format },
|
||||
{
|
||||
// Optionally pass remark/rehype plugins
|
||||
mdxOptions: {
|
||||
remarkPlugins: [
|
||||
remarkEmbed,
|
||||
remarkGfm,
|
||||
[remarkSmartypants, { quotes: false, dashes: "oldschool" }],
|
||||
remarkMath,
|
||||
remarkCallouts,
|
||||
remarkWikiLink,
|
||||
[
|
||||
remarkToc,
|
||||
{
|
||||
heading: "Table of contents",
|
||||
tight: true,
|
||||
},
|
||||
],
|
||||
[mdxmermaid, {}],
|
||||
],
|
||||
rehypePlugins: [
|
||||
rehypeSlug,
|
||||
[
|
||||
rehypeAutolinkHeadings,
|
||||
{
|
||||
properties: { className: 'heading-link' },
|
||||
test(element) {
|
||||
return (
|
||||
["h2", "h3", "h4", "h5", "h6"].includes(element.tagName) &&
|
||||
element.properties?.id !== "table-of-contents" &&
|
||||
element.properties?.className !== "blockquote-heading"
|
||||
);
|
||||
},
|
||||
content() {
|
||||
return [
|
||||
h(
|
||||
"svg",
|
||||
{
|
||||
xmlns: "http:www.w3.org/2000/svg",
|
||||
fill: "#ab2b65",
|
||||
viewBox: "0 0 20 20",
|
||||
className: "w-5 h-5",
|
||||
},
|
||||
[
|
||||
h("path", {
|
||||
fillRule: "evenodd",
|
||||
clipRule: "evenodd",
|
||||
d: "M9.493 2.853a.75.75 0 00-1.486-.205L7.545 6H4.198a.75.75 0 000 1.5h3.14l-.69 5H3.302a.75.75 0 000 1.5h3.14l-.435 3.148a.75.75 0 001.486.205L7.955 14h2.986l-.434 3.148a.75.75 0 001.486.205L12.456 14h3.346a.75.75 0 000-1.5h-3.14l.69-5h3.346a.75.75 0 000-1.5h-3.14l.435-3.147a.75.75 0 00-1.486-.205L12.045 6H9.059l.434-3.147zM8.852 7.5l-.69 5h2.986l.69-5H8.852z",
|
||||
}),
|
||||
]
|
||||
),
|
||||
];
|
||||
},
|
||||
},
|
||||
],
|
||||
[rehypeKatex, { output: "mathml" }],
|
||||
[rehypePrismPlus, { ignoreMissing: true }],
|
||||
],
|
||||
format,
|
||||
},
|
||||
scope,
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
mdxSource: mdxSource,
|
||||
frontMatter: data,
|
||||
excerpt,
|
||||
};
|
||||
};
|
||||
|
||||
export default parse;
|
||||
24
examples/openspending/lib/mddb.ts
Normal file
24
examples/openspending/lib/mddb.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { MarkdownDB } from "@flowershow/markdowndb";
|
||||
// import config from "./markdowndb.config.js";
|
||||
|
||||
// TODO get this path from markdowndb.config.js or something
|
||||
const dbPath = "markdown.db";
|
||||
//
|
||||
// if (!config.dbPath)
|
||||
// throw new Error("Invalid/Missing path in markdowndb.config.js");
|
||||
// }
|
||||
//
|
||||
// const dbPath = config.dbPath;
|
||||
// OR
|
||||
// const dbOptions = config.dbOptions;
|
||||
|
||||
const client = new MarkdownDB({
|
||||
client: "sqlite3",
|
||||
connection: {
|
||||
filename: dbPath,
|
||||
},
|
||||
});
|
||||
|
||||
const clientPromise = client.init();
|
||||
|
||||
export default clientPromise;
|
||||
Reference in New Issue
Block a user