Renamed inlineComponents to richTextComponents as this is closer to what they are
This commit was merged in pull request #16.
This commit is contained in:
35
components/rich-text/block-quote.tsx
Normal file
35
components/rich-text/block-quote.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
import { TinaMarkdown, TinaMarkdownContent } from "tinacms/dist/rich-text";
|
||||
import { RichTextTemplate } from "@tinacms/schema-tools";
|
||||
import React from "react";
|
||||
|
||||
export interface BlockQuoteProps {
|
||||
children: TinaMarkdownContent;
|
||||
authorName: string;
|
||||
}
|
||||
|
||||
const BlockQuote = (props: BlockQuoteProps): React.ReactElement => (
|
||||
<div>
|
||||
<blockquote>
|
||||
<TinaMarkdown content={ props.children } />
|
||||
{ props.authorName }
|
||||
</blockquote>
|
||||
</div>);
|
||||
|
||||
export const blockQuoteSchema: RichTextTemplate = {
|
||||
name: "BlockQuote",
|
||||
label: "Block Quote",
|
||||
fields: [
|
||||
{
|
||||
name: "children",
|
||||
label: "Quote",
|
||||
type: "rich-text"
|
||||
},
|
||||
{
|
||||
name: "authorName",
|
||||
label: "Author",
|
||||
type: "string"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default BlockQuote;
|
||||
39
components/rich-text/date-time.tsx
Normal file
39
components/rich-text/date-time.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import React from "react";
|
||||
import format from "date-fns/format";
|
||||
import { RichTextTemplate } from "@tinacms/schema-tools";
|
||||
|
||||
export interface DateTimeProps {
|
||||
format?: string;
|
||||
}
|
||||
|
||||
const DateTime = (props: DateTimeProps) => {
|
||||
const dt = React.useMemo(() => {
|
||||
return new Date();
|
||||
}, []);
|
||||
|
||||
switch (props.format) {
|
||||
case "iso":
|
||||
return <span>{ format(dt, "yyyy-MM-dd") }</span>;
|
||||
case "utc":
|
||||
return <span>{ format(dt, "eee, dd MMM yyyy HH:mm:ss OOOO") }</span>;
|
||||
case "local":
|
||||
return <span>{ format(dt, "P") }</span>;
|
||||
default:
|
||||
return <span>{ format(dt, "P") }</span>;
|
||||
}
|
||||
};
|
||||
|
||||
export const dateTimeSchema: RichTextTemplate = {
|
||||
name: "DateTime",
|
||||
label: "Date & Time",
|
||||
inline: true,
|
||||
fields: [
|
||||
{
|
||||
name: "format",
|
||||
label: "Format",
|
||||
type: "string",
|
||||
options: ["utc", "iso", "local"]
|
||||
}
|
||||
] };
|
||||
|
||||
export default DateTime;
|
||||
135
components/rich-text/image.tsx
Normal file
135
components/rich-text/image.tsx
Normal file
@@ -0,0 +1,135 @@
|
||||
import { TinaMarkdownContent } from "tinacms/dist/rich-text";
|
||||
import { RichTextTemplate } from "@tinacms/schema-tools";
|
||||
import { tinaField } from "tinacms/dist/react";
|
||||
|
||||
enum imageSize {
|
||||
extraSmall = "extra-small",
|
||||
small = "small",
|
||||
medium = "medium",
|
||||
large = "large"
|
||||
}
|
||||
|
||||
enum imageDecorations {
|
||||
default = "default",
|
||||
noStyle = "no-style"
|
||||
}
|
||||
|
||||
enum imagePosition {
|
||||
left = "left",
|
||||
middle = "middle",
|
||||
right = "right"
|
||||
}
|
||||
|
||||
export interface ImageProps {
|
||||
children: TinaMarkdownContent;
|
||||
size: imageSize;
|
||||
imageUrl: string,
|
||||
decorations: imageDecorations,
|
||||
position: imagePosition,
|
||||
inline: boolean,
|
||||
alt: string
|
||||
}
|
||||
|
||||
|
||||
const Image = (props: ImageProps) => {
|
||||
const getDecorationTypeClass = (): string | undefined => {
|
||||
switch (props.decorations) {
|
||||
case imageDecorations.default:
|
||||
return "default-border";
|
||||
case imageDecorations.noStyle:
|
||||
return undefined;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const getSizeTypeClass = (): string | undefined => {
|
||||
switch (props.size) {
|
||||
case imageSize.extraSmall:
|
||||
return "xs-size";
|
||||
case imageSize.small:
|
||||
return "sm-size";
|
||||
case imageSize.medium:
|
||||
return "md-size";
|
||||
case imageSize.large:
|
||||
return "lg-size";
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const getPositionTypeClass = (): string | undefined => {
|
||||
switch (props.position) {
|
||||
case imagePosition.left:
|
||||
return (props.inline) ? "float-left mr-2" : "flex justify-start";
|
||||
case imagePosition.middle:
|
||||
return "flex justify-center";
|
||||
case imagePosition.right:
|
||||
return (props.inline) ? "float-right ml-2" : "flex justify-end";
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const getClassNameWithSpace = (className: string): string => `${ className ? ` ${ className }` : "" }`;
|
||||
|
||||
const decorationTypeClass = getDecorationTypeClass();
|
||||
|
||||
const sizeTypeClass = getSizeTypeClass();
|
||||
|
||||
const positionTypeClass = getPositionTypeClass();
|
||||
|
||||
return (<div className={ `not-prose inline-image${ getClassNameWithSpace(positionTypeClass) }` }>
|
||||
<img className={ `${ decorationTypeClass ? `${ decorationTypeClass }` : "" }${ getClassNameWithSpace(sizeTypeClass) }` }
|
||||
data-tina-field={ tinaField(props, "imageUrl") }
|
||||
alt={ props.alt }
|
||||
src={ props.imageUrl }/>
|
||||
</div>);
|
||||
};
|
||||
|
||||
export const imageSchema: RichTextTemplate = {
|
||||
name: "Image",
|
||||
label: "Advanced Image",
|
||||
ui: {
|
||||
defaultItem: {
|
||||
size: Object.values(imageSize)[0],
|
||||
decorations: Object.values(imageDecorations)[0]
|
||||
}
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: "size",
|
||||
label: "Size",
|
||||
type: "string",
|
||||
options: Object.values(imageSize)
|
||||
},
|
||||
{
|
||||
name: "position",
|
||||
label: "Position",
|
||||
type: "string",
|
||||
options: Object.values(imagePosition)
|
||||
},
|
||||
{
|
||||
name: "imageUrl",
|
||||
label: "Image",
|
||||
type: "image"
|
||||
},
|
||||
{
|
||||
name: "inline",
|
||||
label: "Inline",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "decorations",
|
||||
label: "Decorations",
|
||||
type: "string",
|
||||
options: Object.values(imageDecorations)
|
||||
},
|
||||
{
|
||||
name: "alt",
|
||||
label: "Alt",
|
||||
type: "string"
|
||||
}
|
||||
] };
|
||||
|
||||
export default Image;
|
||||
48
components/rich-text/rich-text-definitions.tsx
Normal file
48
components/rich-text/rich-text-definitions.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import { Components } from "tinacms/dist/rich-text";
|
||||
import BlockQuote, { BlockQuoteProps, blockQuoteSchema } from "./block-quote";
|
||||
import DateTime, { DateTimeProps, dateTimeSchema } from "./date-time";
|
||||
import { Prism } from "tinacms/dist/rich-text/prism";
|
||||
import React from "react";
|
||||
import Image, { ImageProps, imageSchema } from "./image";
|
||||
import { RichTextTemplate } from "@tinacms/schema-tools";
|
||||
import sanitizeHtml from "sanitize-html";
|
||||
|
||||
const HTMLInline = (props: { value: string }) => {
|
||||
const createSanitizedMarkup = (text: string) => {
|
||||
return { __html: sanitizeHtml(text, {
|
||||
allowedAttributes: {
|
||||
div: [ "class" ]
|
||||
}
|
||||
}) };
|
||||
};
|
||||
|
||||
return <span dangerouslySetInnerHTML={ createSanitizedMarkup(props.value) } />;
|
||||
};
|
||||
|
||||
const richTextComponents: Components<{
|
||||
BlockQuote: BlockQuoteProps;
|
||||
DateTime: DateTimeProps;
|
||||
Image: ImageProps;
|
||||
}> = {
|
||||
code_block: (props) => <Prism { ...props } />,
|
||||
html: HTMLInline,
|
||||
img: (props) => (
|
||||
<span className="flex items-center justify-center">
|
||||
<img src={ props.url } alt={ props.alt } />
|
||||
</span>
|
||||
),
|
||||
li: (props) => (
|
||||
<li>{ props.children }</li>
|
||||
),
|
||||
BlockQuote,
|
||||
DateTime,
|
||||
Image
|
||||
};
|
||||
|
||||
export const richTextTemplates: RichTextTemplate[] = [
|
||||
dateTimeSchema,
|
||||
blockQuoteSchema,
|
||||
imageSchema
|
||||
];
|
||||
|
||||
export default richTextComponents;
|
||||
Reference in New Issue
Block a user