Added Accordion and AccordionItem Components
This commit is contained in:
@@ -75,6 +75,12 @@ Erit. Si autem oculus tuus fuerit nequam, totum corpus tuum tenebrosum erit. Si
|
||||
|
||||
Autem introisset Capharnaum, accessit ad eum centurio, rogans eum, et dicens Domine, puer meus jacet in domo paralyticus, et male torquetur. Et ait illi Jesus Ego veniam, et curabo eum. Et respondens centurio, ait Domine, non sum dignus ut intres sub tectum meum sed tantum dic verbo, et sanabitur puer meus. Nam et ego homo sum sub potestate constitutus, habens sub me milites, et dico huic Vade, et vadit et alii Veni, et venit et servo meo [Ad eum discipuli](https://example.com/suamt/andi) Fac hoc, et facit. Audiens autem Jesus miratus est, et sequentibus se dixit Amen dico vobis, non inveni tantam fidem in Israël. Dico autem vobis, quod multi ab oriente et occidente venient, et recumbent [Qui dictus est](https://example.com/autem/etmalo) cum Abraham, et Isaac, et ==facies suas== Jacob [Modic fidei tunc surgens imperavit ventis](https://example.com/eating/adimple) in regno cælorum filii autem regni ejicientur in tenebras exteriores ibi erit fletus et stridor dentium. Et dixit Jesus centurioni Vade, et sicut credidisti, fiat tibi. Et sanatus est puer in illa hora. Et cum venisset Jesus in domum Petri, vidit socrum ejus jacentem, et febricitantem et tetigit manum ejus, et dimisit eam febris, et.
|
||||
|
||||
{% Accordion %}
|
||||
{% AccordionItem title="Lorem" defaultOpen=false %}
|
||||
Unum? Et de vestimento quid solliciti estis? Considerate lilia agri quomodo crescunt non laborant, neque nent. Dico autem vobis, quoniam nec Salomon in omni gloria sua coopertus est sicut unum ex istis. Si aut**em fœnum agri,** quod hodie est, et cras in clibanum mittitur, Deus sic vestit, quanto magis vos modicæ *fidei?* Nolite ergo solliciti esse, dicentes Quid manducabimus, aut quid bibemus, aut quo operiemur? hæc enim omnia gentes inquirunt. Scit enim Pater vester, quia his omnibus indigetis. Quærite ergo primum regnum Dei, et justitiam *aliam* ejus et hæc omnia adjicientur vobis. Nolite ergo *in via cum* solliciti.
|
||||
{% /AccordionItem %}
|
||||
{% /Accordion %}
|
||||
|
||||
#### Ubi christus nasceretur at illi dixerunt in bethlehem
|
||||
|
||||
```ruby
|
||||
|
||||
@@ -2,6 +2,9 @@ import React from 'react';
|
||||
import Markdoc from '@markdoc/markdoc';
|
||||
import type { Node } from '@markdoc/markdoc';
|
||||
|
||||
import ContentComponents from '@/components/Content';
|
||||
import SidenoteContainer from '@/components/Content/Sidenote/Container';
|
||||
|
||||
import styles from './MarkdocRenderer.module.css';
|
||||
|
||||
import { nodes } from '@/lib/markdoc/nodes';
|
||||
@@ -9,13 +12,6 @@ import { tags } from '@/lib/markdoc/tags';
|
||||
|
||||
import { collectSideNotes, hasComponents } from '@/lib/markdoc/utils';
|
||||
|
||||
import { Column } from '@/components/Content/Grid/Column';
|
||||
import { Row } from '@/components/Content/Grid/Row';
|
||||
import Sidenote from '@/components/Content/Sidenote/Item';
|
||||
import SidenoteContainer from '@/components/Content/Sidenote/Container';
|
||||
import DefinitionList from '@/components/Content/DefinitionList';
|
||||
import DefinitionItem from '@/components/Content/DefinitionList/DefinitionItem';
|
||||
|
||||
interface MarkdocRendererProps {
|
||||
content: () => Promise<{ node: Node }>;
|
||||
className?: string;
|
||||
@@ -27,14 +23,6 @@ export default async function MarkdocRenderer({
|
||||
content,
|
||||
className,
|
||||
}: MarkdocRendererProps) {
|
||||
const components = {
|
||||
Column,
|
||||
Row,
|
||||
Sidenote,
|
||||
DefinitionList,
|
||||
DefinitionItem,
|
||||
};
|
||||
|
||||
const { node } = await content();
|
||||
const errors = Markdoc.validate(node, { tags, nodes });
|
||||
|
||||
@@ -52,7 +40,9 @@ export default async function MarkdocRenderer({
|
||||
className={`${styles.wrapper} ${className} ${showMargin ? styles.hasMargin : ''}`}
|
||||
>
|
||||
<div className={`${styles.content} content`}>
|
||||
{Markdoc.renderers.react(renderable, React, { components })}
|
||||
{Markdoc.renderers.react(renderable, React, {
|
||||
components: ContentComponents,
|
||||
})}
|
||||
</div>
|
||||
<SidenoteContainer items={sidenotes} />
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
.item {
|
||||
& .summary {
|
||||
--el-summary-marker-symbol-closed: "▾";
|
||||
--el-summary-marker-symbol-open: "▾";
|
||||
--el-summary-marker-symbol-transform-open: rotate(180deg);
|
||||
|
||||
position: relative;
|
||||
|
||||
padding: var(--spacing-snug);
|
||||
|
||||
font-family: var(--el-summary-font-family);
|
||||
font-size: var(--el-summary-font-size);
|
||||
font-weight: var(--el-summary-font-weight);
|
||||
line-height: var(--el-summary-line-height);
|
||||
color: var(--el-summary-fg);
|
||||
text-transform: var(--el-summary-text-transform);
|
||||
list-style: none;
|
||||
|
||||
background: var(--el-summary-bg);
|
||||
|
||||
&::before {
|
||||
content: var(--el-summary-marker-symbol-closed);
|
||||
|
||||
position: absolute;
|
||||
right: 0;
|
||||
|
||||
font-size: 1em;
|
||||
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
}
|
||||
|
||||
& .content {
|
||||
overflow: hidden;
|
||||
display: grid;
|
||||
grid-template-rows: 0fr;
|
||||
transition: grid-template-rows 2s ease;
|
||||
|
||||
& .inner {
|
||||
min-height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&[open] {
|
||||
& .summary {
|
||||
&::before {
|
||||
content: var(--el-summary-marker-symbol-open);
|
||||
transform: var(--el-summary-marker-symbol-transform-open);
|
||||
}
|
||||
}
|
||||
|
||||
& .content {
|
||||
grid-template-rows: 1fr;
|
||||
}
|
||||
}
|
||||
}
|
||||
39
src/components/Content/Accordion/AccordionItem/index.tsx
Normal file
39
src/components/Content/Accordion/AccordionItem/index.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import styles from './AccordionItem.module.css';
|
||||
|
||||
interface AccordionItemProps {
|
||||
title: string;
|
||||
defaultOpen: boolean;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export default function AccordionItem({
|
||||
title,
|
||||
defaultOpen,
|
||||
children,
|
||||
}: AccordionItemProps) {
|
||||
const [isOpen, setIsOpen] = React.useState(defaultOpen);
|
||||
return (
|
||||
<details
|
||||
className={styles.item}
|
||||
open={isOpen}
|
||||
onToggle={(e) => setIsOpen(e.currentTarget.open)}
|
||||
>
|
||||
<summary
|
||||
className={styles.summary}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
setIsOpen(!isOpen);
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</summary>
|
||||
<div className={styles.content}>
|
||||
<div className={styles.inner}>{children}</div>
|
||||
</div>
|
||||
</details>
|
||||
);
|
||||
}
|
||||
11
src/components/Content/Accordion/index.tsx
Normal file
11
src/components/Content/Accordion/index.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import React from 'react';
|
||||
|
||||
import styles from './Accordion.module.css';
|
||||
|
||||
interface AccordionProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export default function Accordion({ children }: AccordionProps) {
|
||||
return <div className={styles.accordion}>{children}</div>;
|
||||
}
|
||||
@@ -9,7 +9,7 @@ interface ColumnProps {
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export function Column({ style, children }: ColumnProps) {
|
||||
export default function Column({ style, children }: ColumnProps) {
|
||||
return (
|
||||
<div
|
||||
className={styles.column}
|
||||
|
||||
@@ -12,7 +12,7 @@ interface RowProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export function Row({ style, children }: RowProps) {
|
||||
export default function Row({ style, children }: RowProps) {
|
||||
return (
|
||||
<div
|
||||
className={`${styles.row}`}
|
||||
|
||||
19
src/components/Content/index.ts
Normal file
19
src/components/Content/index.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import Row from '@/components/Content/Grid/Row';
|
||||
import Column from '@/components/Content/Grid/Column';
|
||||
import Sidenote from '@/components/Content/Sidenote/Item';
|
||||
import DefinitionList from '@/components/Content/DefinitionList';
|
||||
import DefinitionItem from '@/components/Content/DefinitionList/DefinitionItem';
|
||||
import Accordion from '@/components/Content/Accordion';
|
||||
import AccordionItem from '@/components/Content/Accordion/AccordionItem';
|
||||
|
||||
const ContentComponents = {
|
||||
Column,
|
||||
Row,
|
||||
Sidenote,
|
||||
DefinitionList,
|
||||
DefinitionItem,
|
||||
Accordion,
|
||||
AccordionItem,
|
||||
};
|
||||
|
||||
export default ContentComponents;
|
||||
@@ -7,6 +7,7 @@ export default collection({
|
||||
slugField: 'title',
|
||||
path: 'content/meta/*',
|
||||
format: { contentField: 'content' },
|
||||
entryLayout: 'content',
|
||||
schema: {
|
||||
...createArticleField('meta'),
|
||||
},
|
||||
|
||||
32
src/keystatic/components/general/accordion.ts
Normal file
32
src/keystatic/components/general/accordion.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { listCollapseIcon } from '@keystar/ui/icon/icons/listCollapseIcon';
|
||||
import { repeating, wrapper } from '@keystatic/core/content-components';
|
||||
import { fields } from '@keystatic/core';
|
||||
|
||||
const accordionComponents = {
|
||||
Accordion: repeating({
|
||||
label: 'Accordion',
|
||||
icon: listCollapseIcon,
|
||||
children: ['AccordionItem'],
|
||||
schema: {},
|
||||
}),
|
||||
AccordionItem: wrapper({
|
||||
label: 'Accordion Item',
|
||||
forSpecificLocations: true,
|
||||
schema: {
|
||||
title: fields.text({
|
||||
label: 'Title',
|
||||
validation: {
|
||||
length: {
|
||||
min: 1,
|
||||
},
|
||||
},
|
||||
}),
|
||||
defaultOpen: fields.checkbox({
|
||||
label: 'Open by default',
|
||||
defaultValue: false,
|
||||
}),
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
export default accordionComponents;
|
||||
@@ -2,7 +2,7 @@ import { listTreeIcon } from '@keystar/ui/icon/icons/listTreeIcon';
|
||||
import { fields } from '@keystatic/core';
|
||||
import { repeating, block } from '@keystatic/core/content-components';
|
||||
|
||||
export const definitionlistComponents = {
|
||||
const definitionlistComponents = {
|
||||
DefinitionList: repeating({
|
||||
label: 'Definition List',
|
||||
icon: listTreeIcon,
|
||||
@@ -11,6 +11,7 @@ export const definitionlistComponents = {
|
||||
}),
|
||||
DefinitionItem: block({
|
||||
label: 'Definition Item',
|
||||
forSpecificLocations: true,
|
||||
schema: {
|
||||
term: fields.text({ label: 'Term' }),
|
||||
definitions: fields.array(
|
||||
@@ -23,3 +24,5 @@ export const definitionlistComponents = {
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
export default definitionlistComponents;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { grid2X2Icon } from '@keystar/ui/icon/icons/grid2X2Icon';
|
||||
import { fields } from '@keystatic/core';
|
||||
import { repeating, wrapper } from '@keystatic/core/content-components';
|
||||
|
||||
export const gridComponents = {
|
||||
const gridComponents = {
|
||||
Row: repeating({
|
||||
label: 'Row',
|
||||
icon: grid2X2Icon,
|
||||
@@ -59,3 +59,4 @@ export const gridComponents = {
|
||||
},
|
||||
}),
|
||||
};
|
||||
export default gridComponents;
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { gridComponents } from '@/keystatic/components/general/grid';
|
||||
import { sidenoteComponents } from '@/keystatic/components/general/sidenote';
|
||||
import { definitionlistComponents } from '@/keystatic/components/general/definitionlist';
|
||||
import gridComponents from '@/keystatic/components/general/grid';
|
||||
import sidenoteComponents from '@/keystatic/components/general/sidenote';
|
||||
import definitionlistComponents from '@/keystatic/components/general/definitionlist';
|
||||
import accordionComponents from '@/keystatic/components/general/accordion';
|
||||
|
||||
export const generalComponents = {
|
||||
...gridComponents,
|
||||
...sidenoteComponents,
|
||||
...definitionlistComponents,
|
||||
...accordionComponents,
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import { panelRightDashedIcon } from '@keystar/ui/icon/icons/panelRightDashedIco
|
||||
import { fields } from '@keystatic/core';
|
||||
import { inline } from '@keystatic/core/content-components';
|
||||
|
||||
export const sidenoteComponents = {
|
||||
const sidenoteComponents = {
|
||||
Sidenote: inline({
|
||||
label: 'Sidenote',
|
||||
icon: panelRightDashedIcon,
|
||||
@@ -57,3 +57,5 @@ export const sidenoteComponents = {
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
export default sidenoteComponents;
|
||||
|
||||
@@ -58,4 +58,21 @@ export const tags: Config['tags'] = {
|
||||
},
|
||||
},
|
||||
},
|
||||
Accordion: {
|
||||
render: 'Accordion',
|
||||
children: ['tag'],
|
||||
},
|
||||
AccordionItem: {
|
||||
render: 'AccordionItem',
|
||||
attributes: {
|
||||
title: {
|
||||
type: 'String',
|
||||
required: true,
|
||||
},
|
||||
defaultOpen: {
|
||||
type: 'Boolean',
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -243,7 +243,7 @@
|
||||
--el-small-font-family: var(--font-body);
|
||||
--el-small-font-size: var(--typo-size-xs);
|
||||
|
||||
/* HR */
|
||||
/* === HR === */
|
||||
--hr-height: var(--size-3);
|
||||
--hr-margin: var(--spacing-relaxed) 0;
|
||||
--hr-color: var(--color-text-tertiary);
|
||||
@@ -254,7 +254,27 @@
|
||||
--hr-symbol-color: var(--color-text-tertiary);
|
||||
--hr-symbol-background: var(--color-surface-base);
|
||||
|
||||
/* Header */
|
||||
/* === SUMMARY === */
|
||||
--el-summary-fg: var(--color-text-inverse);
|
||||
--el-summary-bg: var(--color-surface-inverse);
|
||||
--el-summary-font-family: var(--font-mono);
|
||||
--el-summary-font-size: var(--typo-size-lg);
|
||||
--el-summary-font-weight: var(--typo-weight-black);
|
||||
--el-summary-text-transform: uppercase;
|
||||
--el-summary-line-height: var(--typo-leading-normal);
|
||||
--el-summary-marker-symbol-closed: "▾";
|
||||
--el-summary-marker-symbol-open: "▴";
|
||||
--el-summary-marker-symbol-transition-open: none;
|
||||
|
||||
/* === DETAILS === */
|
||||
--el-details-color: var(--color-text-primary);
|
||||
--el-details-font-family: var(--font-body);
|
||||
--el-details-font-size: var(--typo-size-md);
|
||||
--el-details-line-height: var(--typo-leading-normal);
|
||||
--el-details-padding: var(--spacing-snug);
|
||||
--el-details-border: var(--size-1) solid var(--color-text-secondary);
|
||||
|
||||
/* === Header === */;
|
||||
--el-header-font-size: var(--typo-size-responsive);
|
||||
--el-header-line-height: var(--typo-leading-snug);
|
||||
--el-header-paddingY: var(--spacing-snug);
|
||||
|
||||
Reference in New Issue
Block a user