diff --git a/packages/remark-callouts/src/index.ts b/packages/remark-callouts/src/index.ts index 28c2aea52..c66d78faf 100644 --- a/packages/remark-callouts/src/index.ts +++ b/packages/remark-callouts/src/index.ts @@ -1,2 +1,3 @@ export * from "./lib/remark-callouts"; export { default } from "./lib/remark-callouts"; +export { Callout } from "./lib/Callout"; \ No newline at end of file diff --git a/packages/remark-callouts/src/lib/Callout.tsx b/packages/remark-callouts/src/lib/Callout.tsx new file mode 100644 index 000000000..215e7f780 --- /dev/null +++ b/packages/remark-callouts/src/lib/Callout.tsx @@ -0,0 +1,20 @@ +import { useRef } from "react"; + +const Callout = ({ className, children }) => { + // If it's not a foldable callout, just render it as a blockquote + if (!className.includes("callout-foldable")) { + return
{children}
; + } + + const elem = useRef(null); + + const handleClick = () => { + elem.current.classList.toggle("callout-folded"); + }; + + return ( +
{children}
+ ); +}; + +export { Callout }; \ No newline at end of file diff --git a/packages/remark-callouts/src/lib/remark-callouts.ts b/packages/remark-callouts/src/lib/remark-callouts.ts index 4924638f3..6a5429e17 100644 --- a/packages/remark-callouts/src/lib/remark-callouts.ts +++ b/packages/remark-callouts/src/lib/remark-callouts.ts @@ -113,7 +113,7 @@ export const callouts: Plugin = function (providedConfig?: Partial) { const [t, ...rest] = paragraph.children; const regex = new RegExp( - `^\\[!(?(.*?))\\][\t\f ]?(?.*?)$`, + `^\\[!(?<keyword>(.*?))\\](?<foldChar>[+-]?)[\t\f ]?(?<title>.*?)$`, "gi" ); const m = regex.exec(t.value); @@ -121,7 +121,7 @@ export const callouts: Plugin = function (providedConfig?: Partial<Config>) { // if no callout syntax, forget about it. if (!m) return; - const [key, title] = [m.groups?.keyword, m.groups?.title]; + const [key, foldChar, title] = [m.groups?.keyword, m.groups?.foldChar, m.groups?.title]; // if there's nothing inside the brackets, is it really a callout ? if (!key) return; @@ -236,12 +236,17 @@ export const callouts: Plugin = function (providedConfig?: Partial<Config>) { blockquote.children.unshift(titleNode as BlockContent); // Add classes for the callout block + const classList = [formatClassNameMap(config.classNameMaps.block)(keyword.toLowerCase())] + if (foldChar) { + classList.push('callout-foldable') + if (foldChar === '-') { + classList.push('callout-folded') + } + } blockquote.data = config.dataMaps.block({ ...blockquote.data, hProperties: { - className: formatClassNameMap(config.classNameMaps.block)( - keyword.toLowerCase() - ), + className: classList.join(" "), style: `border-left-color:${entry?.color};`, }, }); diff --git a/packages/remark-callouts/styles.css b/packages/remark-callouts/styles.css index d96092264..7b54cab2e 100644 --- a/packages/remark-callouts/styles.css +++ b/packages/remark-callouts/styles.css @@ -23,6 +23,7 @@ align-items: center; padding: 10px; gap: 10px; + position: relative; } .callout-title > strong { @@ -62,3 +63,40 @@ p:after { p:after { display: none; } + +blockquote.callout-foldable { + cursor: pointer; + display: grid; + grid-template-rows: min-content 1fr; + transition: all 0.3s ease-in-out; +} + +blockquote.callout-foldable.callout-folded { + grid-template-rows: min-content 0fr; +} + +blockquote.callout-foldable .callout-content { + overflow: hidden; + padding: 0px 10px; +} + +blockquote.callout-foldable .callout-title strong::after { + content: ""; + display: inline-block; + height: 10px; + width: 10px; + border-style: solid; + border-width: 0 3px 3px 0; + border-color: var(--tw-prose-body); + position: absolute; + top: 50%; + right: 1em; + transform: translateY(-50%) rotate(45deg); + transform-origin: center; + transition: all 0.3s ease-in-out; +} + +blockquote.callout-foldable.callout-folded .callout-title strong::after { + transform: translateY(-50%) rotate(-45deg); + transform-origin: center; +} diff --git a/packages/remark-callouts/tsconfig.lib.json b/packages/remark-callouts/tsconfig.lib.json index 18857e49b..677a24aed 100644 --- a/packages/remark-callouts/tsconfig.lib.json +++ b/packages/remark-callouts/tsconfig.lib.json @@ -7,7 +7,8 @@ "types": ["node"], "moduleResolution": "node", "esModuleInterop": true, - "forceConsistentCasingInFileNames": true + "forceConsistentCasingInFileNames": true, + "jsx": "react-jsx" }, "exclude": ["**/*.spec.ts", "**/*.test.ts"], "include": ["src/**/*.ts"]