lint: updates lint rules for no-unused-vars
This commit is contained in:
parent
16497edd46
commit
2e7eaccde8
@ -1,3 +1,23 @@
|
|||||||
{
|
{
|
||||||
"extends": "next/core-web-vitals"
|
"parser": "@typescript-eslint/parser",
|
||||||
}
|
"plugins": [
|
||||||
|
"@typescript-eslint"
|
||||||
|
],
|
||||||
|
"extends": [
|
||||||
|
"next/core-web-vitals"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"@typescript-eslint/no-unused-vars": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"args": "all",
|
||||||
|
"argsIgnorePattern": "^_",
|
||||||
|
"caughtErrors": "all",
|
||||||
|
"caughtErrorsIgnorePattern": "^_",
|
||||||
|
"destructuredArrayIgnorePattern": "^_",
|
||||||
|
"varsIgnorePattern": "^_",
|
||||||
|
"ignoreRestSiblings": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
export default function Error({
|
export default function Error({
|
||||||
error,
|
error,
|
||||||
reset,
|
|
||||||
}: {
|
}: {
|
||||||
error: Error & { digest?: string };
|
error: Error & { digest?: string };
|
||||||
reset: () => void;
|
reset: () => void;
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
import { readMD } from "@/actions/readMD";
|
import { readMD } from "@/actions/readMD";
|
||||||
import { TTCMD } from "@/components/ttcmd";
|
|
||||||
import { readFile } from "fs/promises";
|
|
||||||
import { Suspense } from "react";
|
import { Suspense } from "react";
|
||||||
import { HomeClient } from "./client";
|
import { HomeClient } from "./client";
|
||||||
import { MDSkeletonLoader } from "@/components/loader";
|
import { MDSkeletonLoader } from "@/components/loader";
|
||||||
|
@ -4,7 +4,6 @@ import {
|
|||||||
PropsWithChildren,
|
PropsWithChildren,
|
||||||
SetStateAction,
|
SetStateAction,
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
|
||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { bulkRound } from "../../utils/bulkRound";
|
import { bulkRound } from "../../utils/bulkRound";
|
||||||
@ -24,7 +23,7 @@ interface IProps {
|
|||||||
setHover: Dispatch<SetStateAction<boolean>>;
|
setHover: Dispatch<SetStateAction<boolean>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
type position = { top: number; left: number; width?: number };
|
type position = { top: number; left: number; width?: number; };
|
||||||
|
|
||||||
export const PoppableContent: FC<PropsWithChildren<IProps>> = (
|
export const PoppableContent: FC<PropsWithChildren<IProps>> = (
|
||||||
{
|
{
|
||||||
@ -35,7 +34,6 @@ export const PoppableContent: FC<PropsWithChildren<IProps>> = (
|
|||||||
spacing = 10,
|
spacing = 10,
|
||||||
setHover,
|
setHover,
|
||||||
isClosing,
|
isClosing,
|
||||||
isClosed,
|
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
const [popRef, setPopRef] = useState<HTMLDivElement>();
|
const [popRef, setPopRef] = useState<HTMLDivElement>();
|
||||||
@ -52,7 +50,7 @@ export const PoppableContent: FC<PropsWithChildren<IProps>> = (
|
|||||||
relHeight: number,
|
relHeight: number,
|
||||||
popWidth: number,
|
popWidth: number,
|
||||||
popHeight: number,
|
popHeight: number,
|
||||||
edge: edge,
|
_edge: edge,
|
||||||
align: alignment,
|
align: alignment,
|
||||||
): position => {
|
): position => {
|
||||||
const pos = {
|
const pos = {
|
||||||
|
@ -1,13 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import {
|
import { FC, PropsWithChildren, ReactNode, useCallback, useState } from "react";
|
||||||
FC,
|
|
||||||
PropsWithChildren,
|
|
||||||
ReactNode,
|
|
||||||
useCallback,
|
|
||||||
useEffect,
|
|
||||||
useState,
|
|
||||||
} from "react";
|
|
||||||
import { PoppableContent } from "./poppable-content";
|
import { PoppableContent } from "./poppable-content";
|
||||||
import { useDebounce } from "../../../hooks/useDebounce";
|
import { useDebounce } from "../../../hooks/useDebounce";
|
||||||
|
|
||||||
|
@ -3,48 +3,14 @@ import Link from "next/link";
|
|||||||
import { Fragment } from "react";
|
import { Fragment } from "react";
|
||||||
import { Poppable } from "../poppables/components/poppable";
|
import { Poppable } from "../poppables/components/poppable";
|
||||||
import { Accordion, AccordionContent } from "../accordion";
|
import { Accordion, AccordionContent } from "../accordion";
|
||||||
import { metadata } from "@/app/layout";
|
|
||||||
|
|
||||||
type SearchFunction = (s: string, start: number, end: number) => {
|
export const TokenRenderers = new Map<string, TokenRenderer<any>>();
|
||||||
start: number;
|
|
||||||
end: number;
|
|
||||||
text: string;
|
|
||||||
lastIndex: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
type TokenIdentifier<M> = {
|
|
||||||
rx: RegExp;
|
|
||||||
parse: (s: string) => Token<M>;
|
|
||||||
search?: SearchFunction;
|
|
||||||
};
|
|
||||||
|
|
||||||
type TokenIdentifierMap = Map<
|
|
||||||
string,
|
|
||||||
TokenIdentifier<any>
|
|
||||||
>;
|
|
||||||
|
|
||||||
export const TokenRenderers = new Map<
|
|
||||||
string,
|
|
||||||
TokenRenderer<any>
|
|
||||||
>();
|
|
||||||
|
|
||||||
type IdentifierRegistration = <N = Record<string, string>>(
|
|
||||||
type: string,
|
|
||||||
match: RegExp,
|
|
||||||
parseFunction: (s: string, rx: RegExp) => IdentifiedToken<N>,
|
|
||||||
renderFunction: TokenRenderer<N>,
|
|
||||||
openTagRx?: RegExp,
|
|
||||||
closeTagRx?: RegExp,
|
|
||||||
) => void;
|
|
||||||
|
|
||||||
export function buildIdentifierMap(): [
|
export function buildIdentifierMap(): [
|
||||||
TokenIdentifierMap,
|
TokenIdentifierMap,
|
||||||
IdentifierRegistration,
|
IdentifierRegistration,
|
||||||
] {
|
] {
|
||||||
const TokenIdentifiers = new Map<
|
const TokenIdentifiers = new Map<string, TokenIdentifier<any>>();
|
||||||
string,
|
|
||||||
TokenIdentifier<any>
|
|
||||||
>();
|
|
||||||
|
|
||||||
function registerIdentifier<M>(
|
function registerIdentifier<M>(
|
||||||
type: string,
|
type: string,
|
||||||
@ -79,7 +45,7 @@ export function buildIdentifierMap(): [
|
|||||||
|
|
||||||
return { ...token, ...identifiedToken } as Token<M>;
|
return { ...token, ...identifiedToken } as Token<M>;
|
||||||
},
|
},
|
||||||
search: (openTagRx && closeTagRx)
|
search: openTagRx && closeTagRx
|
||||||
? (s, start, end) => {
|
? (s, start, end) => {
|
||||||
return search(
|
return search(
|
||||||
s,
|
s,
|
||||||
@ -120,8 +86,11 @@ export const buildOnlyDefaultElements = () => {
|
|||||||
/(?<!\/)(?:\[\])+\n+((?:.|\n)*?)\n+\/\[\]/g,
|
/(?<!\/)(?:\[\])+\n+((?:.|\n)*?)\n+\/\[\]/g,
|
||||||
(s) => {
|
(s) => {
|
||||||
const rx = /((?:\[\])+)\n+([\s\S]*)\n+\/\[\]/;
|
const rx = /((?:\[\])+)\n+([\s\S]*)\n+\/\[\]/;
|
||||||
const [_, columns, content] = s.match(rx) ||
|
const [_, columns, content] = s.match(rx) || [
|
||||||
["", "..", "Unable to parse grid"];
|
"",
|
||||||
|
"..",
|
||||||
|
"Unable to parse grid",
|
||||||
|
];
|
||||||
return {
|
return {
|
||||||
content,
|
content,
|
||||||
raw: s,
|
raw: s,
|
||||||
@ -133,7 +102,7 @@ export const buildOnlyDefaultElements = () => {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
(token) => {
|
(token) => {
|
||||||
const { content, children, metadata, uuid } = token;
|
const { children, metadata } = token;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@ -141,11 +110,7 @@ export const buildOnlyDefaultElements = () => {
|
|||||||
} as React.CSSProperties}
|
} as React.CSSProperties}
|
||||||
className="grid grid-cols-dynamic gap-x-8 gap-y-6 mb-6"
|
className="grid grid-cols-dynamic gap-x-8 gap-y-6 mb-6"
|
||||||
>
|
>
|
||||||
{children?.map((c) => (
|
{children?.map((c) => <div key={c.uuid}>{c.render(c)}</div>)}
|
||||||
<div key={c.uuid}>
|
|
||||||
{c.render(c)}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -173,17 +138,14 @@ export const buildOnlyDefaultElements = () => {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
(token) => {
|
(token) => {
|
||||||
const { children, metadata, uuid } = token;
|
const { children, metadata } = token;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-block={!!metadata.isBlock}
|
data-block={!!metadata.isBlock}
|
||||||
className="data-[block=false]:card mb-6"
|
className="data-[block=false]:card mb-6"
|
||||||
>
|
>
|
||||||
{children?.map((e) => (
|
{children?.map((e) => <Fragment key={e.uuid}>{e.render(e)}
|
||||||
<Fragment key={e.uuid}>
|
</Fragment>)}
|
||||||
{e.render(e)}
|
|
||||||
</Fragment>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -192,22 +154,26 @@ export const buildOnlyDefaultElements = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// fenced code block
|
// fenced code block
|
||||||
registerIdentifier("code", /`{3}\n+((?:.|\n)*?)\n+`{3}/g, (s, rx) => {
|
registerIdentifier(
|
||||||
return {
|
"code",
|
||||||
content: s.match(new RegExp(rx, ""))?.at(1) ||
|
/`{3}\n+((?:.|\n)*?)\n+`{3}/g,
|
||||||
"Unable to parse code",
|
(s, rx) => {
|
||||||
raw: s,
|
return {
|
||||||
metadata: {},
|
content: s.match(new RegExp(rx, ""))?.at(1) || "Unable to parse code",
|
||||||
uuid: crypto.randomUUID(),
|
raw: s,
|
||||||
rendersContentOnly,
|
metadata: {},
|
||||||
};
|
uuid: crypto.randomUUID(),
|
||||||
}, (token) => {
|
rendersContentOnly,
|
||||||
return (
|
};
|
||||||
<pre className="whitespace-pre-wrap bg-black/20 p-2 rounded-md">
|
},
|
||||||
{token.content}
|
(token) => {
|
||||||
</pre>
|
return (
|
||||||
);
|
<pre className="whitespace-pre-wrap bg-black/20 p-2 rounded-md">
|
||||||
});
|
{token.content}
|
||||||
|
</pre>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// list
|
// list
|
||||||
registerIdentifier(
|
registerIdentifier(
|
||||||
@ -215,20 +181,18 @@ export const buildOnlyDefaultElements = () => {
|
|||||||
/^\s*-\s([\s\S]*?)\n\n/gm,
|
/^\s*-\s([\s\S]*?)\n\n/gm,
|
||||||
(s, rx) => {
|
(s, rx) => {
|
||||||
return {
|
return {
|
||||||
content: s.match(new RegExp(rx, ""))?.at(1) ||
|
content: s.match(new RegExp(rx, ""))?.at(1) || "Unable to parse list",
|
||||||
"Unable to parse list",
|
|
||||||
raw: s,
|
raw: s,
|
||||||
metadata: {
|
metadata: {
|
||||||
initialDepth:
|
initialDepth:
|
||||||
s.replace("\n", "").split("-").at(0)?.length.toString() ||
|
s.replace("\n", "").split("-").at(0)?.length.toString() || "1",
|
||||||
"1",
|
|
||||||
},
|
},
|
||||||
uuid: crypto.randomUUID(),
|
uuid: crypto.randomUUID(),
|
||||||
rendersChildrenOnly,
|
rendersChildrenOnly,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
(token) => {
|
(token) => {
|
||||||
const { children, metadata, uuid } = token;
|
const { children, metadata } = token;
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ul
|
<ul
|
||||||
@ -237,10 +201,7 @@ export const buildOnlyDefaultElements = () => {
|
|||||||
>
|
>
|
||||||
{children?.map((c) => {
|
{children?.map((c) => {
|
||||||
return (
|
return (
|
||||||
<li
|
<li key={c.uuid} data-depth={metadata.initialDepth}>
|
||||||
key={c.uuid}
|
|
||||||
data-depth={metadata.initialDepth}
|
|
||||||
>
|
|
||||||
{c.children?.map((c: Token<any>) => (
|
{c.children?.map((c: Token<any>) => (
|
||||||
<Fragment key={c.uuid}>{c.render(c)}</Fragment>
|
<Fragment key={c.uuid}>{c.render(c)}</Fragment>
|
||||||
))}
|
))}
|
||||||
@ -264,19 +225,15 @@ export const buildOnlyDefaultElements = () => {
|
|||||||
raw: s,
|
raw: s,
|
||||||
metadata: {
|
metadata: {
|
||||||
initialDepth:
|
initialDepth:
|
||||||
s.replace("\n", "").split("-").at(0)?.length.toString() ||
|
s.replace("\n", "").split("-").at(0)?.length.toString() || "1",
|
||||||
"1",
|
|
||||||
},
|
},
|
||||||
uuid: crypto.randomUUID(),
|
uuid: crypto.randomUUID(),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
(token) => {
|
(token) => {
|
||||||
const { children, metadata, uuid } = token;
|
const { children, metadata } = token;
|
||||||
return (
|
return (
|
||||||
<li
|
<li data-depth={metadata.initialDepth} className="ml-2">
|
||||||
data-depth={metadata.initialDepth}
|
|
||||||
className="ml-2"
|
|
||||||
>
|
|
||||||
{children?.map((c) => (
|
{children?.map((c) => (
|
||||||
<Fragment key={c.uuid}>
|
<Fragment key={c.uuid}>
|
||||||
(c.render(c))
|
(c.render(c))
|
||||||
@ -288,104 +245,120 @@ export const buildOnlyDefaultElements = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// heading
|
// heading
|
||||||
registerIdentifier("heading", /^#+\s(.*?)$/gm, (s, rx) => {
|
registerIdentifier(
|
||||||
const content = s.match(new RegExp(rx, ""))?.at(1) ||
|
"heading",
|
||||||
"Unable to parse heading";
|
/^#+\s(.*?)$/gm,
|
||||||
return {
|
(s, rx) => {
|
||||||
content: content,
|
const content = s.match(new RegExp(rx, ""))?.at(1) ||
|
||||||
raw: s,
|
"Unable to parse heading";
|
||||||
metadata: {
|
return {
|
||||||
strength: s.match(/#/g)?.length.toString() || "1",
|
content: content,
|
||||||
id: generateId(content, usedIds),
|
raw: s,
|
||||||
},
|
metadata: {
|
||||||
uuid: crypto.randomUUID(),
|
strength: s.match(/#/g)?.length.toString() || "1",
|
||||||
rendersContentOnly,
|
id: generateId(content, usedIds),
|
||||||
};
|
},
|
||||||
}, (token) => {
|
uuid: crypto.randomUUID(),
|
||||||
return (
|
rendersContentOnly,
|
||||||
<div
|
};
|
||||||
// id={generateId(token.raw, usedIds)}
|
},
|
||||||
data-strength={token.metadata.strength}
|
(token) => {
|
||||||
className={`
|
return (
|
||||||
|
<div
|
||||||
|
// id={generateId(token.raw, usedIds)}
|
||||||
|
data-strength={token.metadata.strength}
|
||||||
|
className={`
|
||||||
font-bold
|
font-bold
|
||||||
data-[strength="1"]:text-4xl
|
data-[strength="1"]:text-4xl
|
||||||
data-[strength="2"]:text-3xl
|
data-[strength="2"]:text-3xl
|
||||||
data-[strength="3"]:text-2xl
|
data-[strength="3"]:text-2xl
|
||||||
`}
|
`}
|
||||||
>
|
|
||||||
{token.content}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// image
|
|
||||||
registerIdentifier("image", /\!\[(.*?)\]\((.*?)\)/g, (s, rx) => {
|
|
||||||
const [_, title, src] = s.match(new RegExp(rx, ""))!;
|
|
||||||
|
|
||||||
return {
|
|
||||||
// content: inline,
|
|
||||||
content: title.trim(),
|
|
||||||
raw: s,
|
|
||||||
metadata: {
|
|
||||||
src,
|
|
||||||
},
|
|
||||||
uuid: crypto.randomUUID(),
|
|
||||||
rendersContentOnly,
|
|
||||||
};
|
|
||||||
}, (token) => {
|
|
||||||
const { metadata } = token;
|
|
||||||
metadata.src = metadata.src as string;
|
|
||||||
if (metadata.src.startsWith("<svg")) {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
dangerouslySetInnerHTML={{
|
|
||||||
__html: sanitize(metadata.src, {
|
|
||||||
USE_PROFILES: { svg: true },
|
|
||||||
}),
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
|
{token.content}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
// eslint-disable-next-line @next/next/no-img-element
|
);
|
||||||
return <img src={metadata.src} alt={token.content} />;
|
|
||||||
});
|
// image
|
||||||
|
registerIdentifier(
|
||||||
|
"image",
|
||||||
|
/\!\[(.*?)\]\((.*?)\)/g,
|
||||||
|
(s, rx) => {
|
||||||
|
const [_, title, src] = s.match(new RegExp(rx, ""))!;
|
||||||
|
|
||||||
|
return {
|
||||||
|
// content: inline,
|
||||||
|
content: title.trim(),
|
||||||
|
raw: s,
|
||||||
|
metadata: {
|
||||||
|
src,
|
||||||
|
},
|
||||||
|
uuid: crypto.randomUUID(),
|
||||||
|
rendersContentOnly,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
(token) => {
|
||||||
|
const { metadata } = token;
|
||||||
|
metadata.src = metadata.src as string;
|
||||||
|
if (metadata.src.startsWith("<svg")) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: sanitize(metadata.src, {
|
||||||
|
USE_PROFILES: { svg: true },
|
||||||
|
}),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line @next/next/no-img-element
|
||||||
|
return <img src={metadata.src} alt={token.content} />;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// anchor
|
// anchor
|
||||||
registerIdentifier("anchor", /(?<![\!^])\[(.*?)\]\((.*?)\)/g, (s, rx) => {
|
registerIdentifier(
|
||||||
let preset, [_, title, href] = s.match(new RegExp(rx, ""))!;
|
"anchor",
|
||||||
const match = title.match(/`{3}(cta|button)?(.*)/);
|
/(?<![\!^])\[(.*?)\]\((.*?)\)/g,
|
||||||
|
(s, rx) => {
|
||||||
|
let preset,
|
||||||
|
[_, title, href] = s.match(new RegExp(rx, ""))!;
|
||||||
|
const match = title.match(/`{3}(cta|button)?(.*)/);
|
||||||
|
|
||||||
if (match) {
|
if (match) {
|
||||||
[_, preset, title] = match;
|
[_, preset, title] = match;
|
||||||
}
|
}
|
||||||
|
|
||||||
const classes = {
|
const classes = {
|
||||||
button: "btn-primary inline-block",
|
button: "btn-primary inline-block",
|
||||||
cta: "btn-secondary inline-block uppercase",
|
cta: "btn-secondary inline-block uppercase",
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
content: title.trim(),
|
content: title.trim(),
|
||||||
raw: s,
|
raw: s,
|
||||||
metadata: {
|
metadata: {
|
||||||
href,
|
href,
|
||||||
classes: classes[preset as keyof typeof classes],
|
classes: classes[preset as keyof typeof classes],
|
||||||
},
|
},
|
||||||
uuid: crypto.randomUUID(),
|
uuid: crypto.randomUUID(),
|
||||||
rendersContentOnly,
|
rendersContentOnly,
|
||||||
};
|
};
|
||||||
}, (token) => {
|
},
|
||||||
const { metadata } = token;
|
(token) => {
|
||||||
return (
|
const { metadata } = token;
|
||||||
<Link
|
return (
|
||||||
className={metadata.classes ||
|
<Link
|
||||||
"dark:text-primary-600 underline dark:no-underline"}
|
className={metadata.classes ||
|
||||||
href={metadata.href}
|
"dark:text-primary-600 underline dark:no-underline"}
|
||||||
>
|
href={metadata.href}
|
||||||
{token.content}
|
>
|
||||||
</Link>
|
{token.content}
|
||||||
);
|
</Link>
|
||||||
});
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// inline-code
|
// inline-code
|
||||||
registerIdentifier(
|
registerIdentifier(
|
||||||
@ -411,70 +384,75 @@ export const buildOnlyDefaultElements = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// bold
|
// bold
|
||||||
registerIdentifier("bold", /\*{2}(.*?)\*{2}/g, (s, rx) => {
|
registerIdentifier(
|
||||||
return {
|
"bold",
|
||||||
content: s.match(new RegExp(rx, "i"))?.at(1) ||
|
/\*{2}(.*?)\*{2}/g,
|
||||||
"Unable to parse bold",
|
(s, rx) => {
|
||||||
raw: s,
|
return {
|
||||||
metadata: {},
|
content: s.match(new RegExp(rx, "i"))?.at(1) || "Unable to parse bold",
|
||||||
uuid: crypto.randomUUID(),
|
raw: s,
|
||||||
rendersContentOnly,
|
metadata: {},
|
||||||
};
|
uuid: crypto.randomUUID(),
|
||||||
}, (token) => {
|
rendersContentOnly,
|
||||||
return (
|
};
|
||||||
<span className="font-bold">
|
},
|
||||||
{token.content}
|
(token) => {
|
||||||
</span>
|
return <span className="font-bold">{token.content}</span>;
|
||||||
);
|
},
|
||||||
});
|
);
|
||||||
|
|
||||||
// italic
|
// italic
|
||||||
registerIdentifier("italic", /(?<!\*)\*([^\*]+?)\*(?!\*)/g, (s, rx) => {
|
registerIdentifier(
|
||||||
return {
|
"italic",
|
||||||
content: s.match(new RegExp(rx, "i"))?.at(1) ||
|
/(?<!\*)\*([^\*]+?)\*(?!\*)/g,
|
||||||
"Unable to parse italic",
|
(s, rx) => {
|
||||||
raw: s,
|
return {
|
||||||
metadata: {},
|
content: s.match(new RegExp(rx, "i"))?.at(1) ||
|
||||||
uuid: crypto.randomUUID(),
|
"Unable to parse italic",
|
||||||
rendersContentOnly,
|
raw: s,
|
||||||
};
|
metadata: {},
|
||||||
}, (token) => {
|
uuid: crypto.randomUUID(),
|
||||||
return (
|
rendersContentOnly,
|
||||||
<span className="italic">
|
};
|
||||||
{token.content}
|
},
|
||||||
</span>
|
(token) => {
|
||||||
);
|
return <span className="italic">{token.content}</span>;
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// popover
|
// popover
|
||||||
registerIdentifier("popover", /\^\[(.*?)\]\<<(.*?)\>>/g, (s, rx) => {
|
registerIdentifier(
|
||||||
const [_, title, content] = s.match(new RegExp(rx, ""))!;
|
"popover",
|
||||||
|
/\^\[(.*?)\]\<<(.*?)\>>/g,
|
||||||
|
(s, rx) => {
|
||||||
|
const [_, title, content] = s.match(new RegExp(rx, ""))!;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content,
|
content,
|
||||||
raw: s,
|
raw: s,
|
||||||
metadata: { title },
|
metadata: { title },
|
||||||
uuid: crypto.randomUUID(),
|
uuid: crypto.randomUUID(),
|
||||||
rendersContentOnly,
|
rendersContentOnly,
|
||||||
};
|
};
|
||||||
}, (token) => {
|
},
|
||||||
const { children, metadata, uuid } = token;
|
(token) => {
|
||||||
return (
|
const { children, metadata, uuid } = token;
|
||||||
<Poppable
|
return (
|
||||||
content={children?.map((c) => (
|
<Poppable
|
||||||
<Fragment key={uuid}>{c.render(c)}</Fragment>
|
content={children?.map((c) => (
|
||||||
)) ||
|
<Fragment key={uuid}>{c.render(c)}</Fragment>
|
||||||
token.content}
|
)) || token.content}
|
||||||
preferredAlign="centered"
|
preferredAlign="centered"
|
||||||
preferredEdge="bottom"
|
preferredEdge="bottom"
|
||||||
className="cursor-pointer mx-2"
|
className="cursor-pointer mx-2"
|
||||||
>
|
>
|
||||||
<span className="border-b-2 border-dotted border-white">
|
<span className="border-b-2 border-dotted border-white">
|
||||||
{metadata.title}
|
{metadata.title}
|
||||||
</span>
|
</span>
|
||||||
</Poppable>
|
</Poppable>
|
||||||
);
|
);
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
registerIdentifier(
|
registerIdentifier(
|
||||||
"accordion",
|
"accordion",
|
||||||
@ -490,17 +468,13 @@ export const buildOnlyDefaultElements = () => {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
(token) => {
|
(token) => {
|
||||||
const { children, metadata, uuid } = token;
|
const { children, metadata } = token;
|
||||||
return (
|
return (
|
||||||
<div className="bg-black/20 p-1 accordion">
|
<div className="bg-black/20 p-1 accordion">
|
||||||
<Accordion
|
<Accordion title={metadata.title || "Expand"}>
|
||||||
title={metadata.title || "Expand"}
|
|
||||||
>
|
|
||||||
<AccordionContent>
|
<AccordionContent>
|
||||||
{children?.map((e, i) => (
|
{children?.map((e) => (
|
||||||
<Fragment key={e.uuid}>
|
<Fragment key={e.uuid}>{e.render(e)}</Fragment>
|
||||||
{e.render(e)}
|
|
||||||
</Fragment>
|
|
||||||
))}
|
))}
|
||||||
</AccordionContent>
|
</AccordionContent>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
@ -509,169 +483,193 @@ export const buildOnlyDefaultElements = () => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
registerIdentifier("p", /(?<=\n\n)([\s\S]*?)(?=\n\n)/g, (s) => {
|
registerIdentifier(
|
||||||
return {
|
"p",
|
||||||
content: s.replace("\n", " "),
|
/(?<=\n\n)([\s\S]*?)(?=\n\n)/g,
|
||||||
raw: s,
|
(s) => {
|
||||||
metadata: {},
|
return {
|
||||||
uuid: crypto.randomUUID(),
|
content: s.replace("\n", " "),
|
||||||
};
|
raw: s,
|
||||||
}, (token) => {
|
metadata: {},
|
||||||
const { children, uuid } = token;
|
uuid: crypto.randomUUID(),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
(token) => {
|
||||||
|
const { children } = token;
|
||||||
|
|
||||||
debugger;
|
debugger;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p">
|
<div className="p">
|
||||||
{children?.map((e) => {
|
{children?.map((e) => {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
return (
|
return <Fragment key={e.uuid}>{e.render(e)}</Fragment>;
|
||||||
<Fragment key={e.uuid}>
|
})}
|
||||||
{e.render(e)}
|
</div>
|
||||||
</Fragment>
|
);
|
||||||
);
|
},
|
||||||
})}
|
);
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
registerIdentifier("hr", /^-{3,}$/gm, (s, rx) => {
|
registerIdentifier(
|
||||||
return {
|
"hr",
|
||||||
content: s,
|
/^-{3,}$/gm,
|
||||||
raw: s,
|
(s) => {
|
||||||
metadata: {},
|
return {
|
||||||
uuid: crypto.randomUUID(),
|
content: s,
|
||||||
rendersContentOnly,
|
raw: s,
|
||||||
};
|
metadata: {},
|
||||||
}, (token) => {
|
uuid: crypto.randomUUID(),
|
||||||
return <div className="w-full border-b border-mixed-500 my-3"></div>;
|
rendersContentOnly,
|
||||||
});
|
};
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
return <div className="w-full border-b border-mixed-500 my-3"></div>;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
registerIdentifier("comment", /<!--[\s\S]+?-->/g, (s, rx) => {
|
registerIdentifier(
|
||||||
return {
|
"comment",
|
||||||
content: "",
|
/<!--[\s\S]+?-->/g,
|
||||||
metadata: { comment: s },
|
(s) => {
|
||||||
raw: "",
|
return {
|
||||||
uuid: crypto.randomUUID(),
|
content: "",
|
||||||
rendersContentOnly,
|
metadata: { comment: s },
|
||||||
};
|
raw: "",
|
||||||
}, (token) => {
|
uuid: crypto.randomUUID(),
|
||||||
return <></>;
|
rendersContentOnly,
|
||||||
});
|
};
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
return <></>;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
registerIdentifier("frontmatter", /^---([\s\S]*?)---/g, (s, rx) => {
|
registerIdentifier(
|
||||||
return {
|
"frontmatter",
|
||||||
content: "",
|
/^---([\s\S]*?)---/g,
|
||||||
metadata: {
|
(s, rx) => {
|
||||||
frontmatterString: s.match(rx)?.at(0) || "",
|
return {
|
||||||
},
|
content: "",
|
||||||
raw: "",
|
metadata: {
|
||||||
uuid: "frontmatter",
|
frontmatterString: s.match(rx)?.at(0) || "",
|
||||||
};
|
},
|
||||||
}, (token) => {
|
raw: "",
|
||||||
return <>{token.raw}</>;
|
uuid: "frontmatter",
|
||||||
});
|
};
|
||||||
|
},
|
||||||
|
(token) => {
|
||||||
|
return <>{token.raw}</>;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
registerIdentifier("table", /^\|\s[\s\S]*?\|(?=(\n\n)|$)/g, (s, rx) => {
|
registerIdentifier(
|
||||||
const rowSections = s.split(/^\|[|-\s]+\|$/gm).map((s) =>
|
"table",
|
||||||
s.split("\n").filter((r) => !!r).map((r) =>
|
/^\|\s[\s\S]*?\|(?=(\n\n)|$)/g,
|
||||||
r.split("|").map((c) => c.trim()).filter((c) => !!c)
|
(s) => {
|
||||||
)
|
const rowSections = s.split(/^\|[|-\s]+\|$/gm).map((s) =>
|
||||||
);
|
s
|
||||||
|
.split("\n")
|
||||||
|
.filter((r) => !!r)
|
||||||
|
.map((r) =>
|
||||||
|
r
|
||||||
|
.split("|")
|
||||||
|
.map((c) => c.trim())
|
||||||
|
.filter((c) => !!c)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
let headerRows: string[][] = [],
|
let headerRows: string[][] = [],
|
||||||
bodyRows: string[][] = [],
|
bodyRows: string[][] = [],
|
||||||
footerRows: string[][] = [];
|
footerRows: string[][] = [];
|
||||||
|
|
||||||
switch (rowSections.length) {
|
switch (rowSections.length) {
|
||||||
case 1:
|
case 1:
|
||||||
bodyRows = rowSections[0];
|
bodyRows = rowSections[0];
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
headerRows = rowSections[0];
|
headerRows = rowSections[0];
|
||||||
bodyRows = rowSections[1];
|
bodyRows = rowSections[1];
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
headerRows = rowSections[0];
|
headerRows = rowSections[0];
|
||||||
bodyRows = rowSections[1];
|
bodyRows = rowSections[1];
|
||||||
footerRows = rowSections[3];
|
footerRows = rowSections[3];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxColumns = Math.max(
|
const maxColumns = Math.max(
|
||||||
...[...headerRows, ...bodyRows, ...footerRows].map((r) => r.length),
|
...[...headerRows, ...bodyRows, ...footerRows].map((r) => r.length),
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: s,
|
content: s,
|
||||||
raw: s,
|
raw: s,
|
||||||
metadata: {
|
metadata: {
|
||||||
headerRows: headerRows,
|
headerRows: headerRows,
|
||||||
bodyRows: bodyRows,
|
bodyRows: bodyRows,
|
||||||
footerRows: footerRows,
|
footerRows: footerRows,
|
||||||
columns: maxColumns,
|
columns: maxColumns,
|
||||||
},
|
},
|
||||||
uuid: crypto.randomUUID(),
|
uuid: crypto.randomUUID(),
|
||||||
};
|
};
|
||||||
}, (t) => {
|
},
|
||||||
const { headerRows, bodyRows, footerRows, columns } = t.metadata;
|
(t) => {
|
||||||
|
const { headerRows, bodyRows, footerRows, columns } = t.metadata;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<table className="md-table">
|
<table className="md-table">
|
||||||
{!!headerRows && (
|
{!!headerRows && (
|
||||||
<thead>
|
<thead>
|
||||||
{headerRows.map((r, i) => (
|
{headerRows.map((r, i) => (
|
||||||
<tr key={r.join() + i}>
|
<tr key={r.join() + i}>
|
||||||
{r.concat(Array(columns - r.length).fill("")).map((c) => {
|
{r.concat(Array(columns - r.length).fill("")).map((c) => {
|
||||||
const child = t.children?.find((child) => child.raw === c);
|
const child = t.children?.find((child) => child.raw === c);
|
||||||
return (
|
return (
|
||||||
<th key={r.join() + i + c}>
|
<th key={r.join() + i + c}>
|
||||||
{child?.render(child) ||
|
{child?.render(child) || c}
|
||||||
c}
|
</th>
|
||||||
</th>
|
);
|
||||||
);
|
})}
|
||||||
})}
|
</tr>
|
||||||
</tr>
|
))}
|
||||||
))}
|
</thead>
|
||||||
</thead>
|
)}
|
||||||
)}
|
{!!bodyRows && (
|
||||||
{!!bodyRows && (
|
<tbody>
|
||||||
<tbody>
|
{bodyRows.map((r, i) => (
|
||||||
{bodyRows.map((r, i) => (
|
<tr key={r.join() + i}>
|
||||||
<tr key={r.join() + i}>
|
{r.concat(Array(columns - r.length).fill("")).map((c) => {
|
||||||
{r.concat(Array(columns - r.length).fill("")).map((c) => {
|
const child = t.children?.find((child) => child.raw === c);
|
||||||
const child = t.children?.find((child) => child.raw === c);
|
return (
|
||||||
return (
|
<td key={r.join() + i + c}>
|
||||||
<td key={r.join() + i + c}>
|
{child?.render(child) || c}
|
||||||
{child?.render(child) ||
|
</td>
|
||||||
c}
|
);
|
||||||
</td>
|
})}
|
||||||
);
|
</tr>
|
||||||
})}
|
))}
|
||||||
</tr>
|
</tbody>
|
||||||
))}
|
)}
|
||||||
</tbody>
|
{!!footerRows && (
|
||||||
)}
|
<tfoot>
|
||||||
{!!footerRows && (
|
{footerRows.map((r, i) => (
|
||||||
<tfoot>
|
<tr key={r.join() + i}>
|
||||||
{footerRows.map((r, i) => (
|
{r.concat(Array(columns - r.length).fill("")).map((c) => {
|
||||||
<tr key={r.join() + i}>
|
const child = t.children?.find((child) => child.raw === c);
|
||||||
{r.concat(Array(columns - r.length).fill("")).map((c) => {
|
return (
|
||||||
const child = t.children?.find((child) => child.raw === c);
|
<td key={r.join() + i + c}>
|
||||||
return (
|
{child?.render(child) || c}
|
||||||
<td key={r.join() + i + c}>
|
</td>
|
||||||
{child?.render(child) ||
|
);
|
||||||
c}
|
})}
|
||||||
</td>
|
</tr>
|
||||||
);
|
))}
|
||||||
})}
|
</tfoot>
|
||||||
</tr>
|
)}
|
||||||
))}
|
</table>
|
||||||
</tfoot>
|
);
|
||||||
)}
|
},
|
||||||
</table>
|
);
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return TokenIdentifiers;
|
return TokenIdentifiers;
|
||||||
};
|
};
|
||||||
@ -694,14 +692,16 @@ function findMatchingClosedParenthesis(
|
|||||||
const openingMatch = openRegex.exec(str);
|
const openingMatch = openRegex.exec(str);
|
||||||
const closingMatch = closedRegex.exec(str);
|
const closingMatch = closedRegex.exec(str);
|
||||||
|
|
||||||
if ((openingMatch && !closingMatch)) {
|
if (openingMatch && !closingMatch) {
|
||||||
throw Error("Things have gone horribly wrong");
|
throw Error("Things have gone horribly wrong");
|
||||||
}
|
}
|
||||||
|
|
||||||
// if ((!openingMatch && closingMatch) || (!openingMatch && !closingMatch)) break;
|
// if ((!openingMatch && closingMatch) || (!openingMatch && !closingMatch)) break;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
openingMatch && closingMatch && openingMatch.index < closingMatch.index
|
openingMatch &&
|
||||||
|
closingMatch &&
|
||||||
|
openingMatch.index < closingMatch.index
|
||||||
) {
|
) {
|
||||||
openings++;
|
openings++;
|
||||||
lastOpeningSuccessIndex = openingMatch.index + openingMatch[0].length;
|
lastOpeningSuccessIndex = openingMatch.index + openingMatch[0].length;
|
||||||
@ -758,10 +758,11 @@ function search(
|
|||||||
|
|
||||||
// Finds a unique id for things like headings
|
// Finds a unique id for things like headings
|
||||||
function generateId(t: string, usedIds: string[]) {
|
function generateId(t: string, usedIds: string[]) {
|
||||||
let id = t.toLowerCase().replace(/[^a-z\s]/ig, "").trim().replaceAll(
|
let id = t
|
||||||
" ",
|
.toLowerCase()
|
||||||
"-",
|
.replace(/[^a-z\s]/gi, "")
|
||||||
);
|
.trim()
|
||||||
|
.replaceAll(" ", "-");
|
||||||
let idNum = 1;
|
let idNum = 1;
|
||||||
while (usedIds.includes(id)) {
|
while (usedIds.includes(id)) {
|
||||||
id = id.replace(/-[0-9]+$/g, "");
|
id = id.replace(/-[0-9]+$/g, "");
|
||||||
|
@ -118,7 +118,7 @@ function isAcceptableChild(parentType: string, childType: string): boolean {
|
|||||||
return acceptableChildren ? acceptableChildren.includes(childType) : true;
|
return acceptableChildren ? acceptableChildren.includes(childType) : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Occasionally, some P blocks start exactly at the same point as another block (a side effect of needing to exclude preceding linebreaks from the regex while also having the only clear delineation being those linebreaks) so we just remove those P blocks so that when searching for a parent, it doesn't need to figure out if the P block is valid or not. This doesn't cause issues during rendering since each block handles its own container element
|
// Occasionally, some P blocks start exactly at the same point as another block (a side effect of needing to exclude preceding line-breaks from the regex while also having the only clear delineation being those line-breaks) so we just remove those P blocks so that when searching for a parent, it doesn't need to figure out if the P block is valid or not. This doesn't cause issues during rendering since each block handles its own container element
|
||||||
function filterOverlappingPBlocks(blocks: TokenMarker[]): TokenMarker[] {
|
function filterOverlappingPBlocks(blocks: TokenMarker[]): TokenMarker[] {
|
||||||
return blocks.filter((block) => {
|
return blocks.filter((block) => {
|
||||||
if (block.type !== "p") {
|
if (block.type !== "p") {
|
||||||
|
@ -16,14 +16,15 @@
|
|||||||
"react-dom": "^18"
|
"react-dom": "^18"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^5",
|
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^18",
|
"@types/react": "^18",
|
||||||
"@types/react-dom": "^18",
|
"@types/react-dom": "^18",
|
||||||
"autoprefixer": "^10.0.1",
|
"autoprefixer": "^10.0.1",
|
||||||
|
"eslint": "^8",
|
||||||
|
"eslint-config-next": "14.1.0",
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
"tailwindcss": "^3.3.0",
|
"tailwindcss": "^3.3.0",
|
||||||
"eslint": "^8",
|
"typescript": "^5",
|
||||||
"eslint-config-next": "14.1.0"
|
"typescript-eslint": "^7.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
28
types.d.ts
vendored
28
types.d.ts
vendored
@ -26,3 +26,31 @@ type TokenMarker<M = Record<string, string>> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type FrontMatter = Record<string, string>;
|
type FrontMatter = Record<string, string>;
|
||||||
|
|
||||||
|
type SearchFunction = (
|
||||||
|
s: string,
|
||||||
|
start: number,
|
||||||
|
end: number,
|
||||||
|
) => {
|
||||||
|
start: number;
|
||||||
|
end: number;
|
||||||
|
text: string;
|
||||||
|
lastIndex: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type TokenIdentifier<M> = {
|
||||||
|
rx: RegExp;
|
||||||
|
parse: (s: string) => Token<M>;
|
||||||
|
search?: SearchFunction;
|
||||||
|
};
|
||||||
|
|
||||||
|
type TokenIdentifierMap = Map<string, TokenIdentifier<any>>;
|
||||||
|
|
||||||
|
type IdentifierRegistration = <N = Record<string, string>>(
|
||||||
|
type: string,
|
||||||
|
match: RegExp,
|
||||||
|
parseFunction: (s: string, rx: RegExp) => IdentifiedToken<N>,
|
||||||
|
renderFunction: TokenRenderer<N>,
|
||||||
|
openTagRx?: RegExp,
|
||||||
|
closeTagRx?: RegExp,
|
||||||
|
) => void;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user