f/basic-mdx-components #9
@@ -5,6 +5,7 @@ import { Hero } from "./blocks/hero";
|
||||
import { Testimonial } from "./blocks/testimonial";
|
||||
import { tinaField } from "tinacms/dist/react";
|
||||
import { Carousel } from "./blocks/carousel";
|
||||
import { ReactElement } from "react";
|
||||
|
||||
export const Blocks = (props: Omit<Page, "id" | "_sys" | "_values">) => {
|
||||
return (
|
||||
@@ -22,7 +23,15 @@ export const Blocks = (props: Omit<Page, "id" | "_sys" | "_values">) => {
|
||||
);
|
||||
};
|
||||
|
||||
const Block = (block: PageBlocks) => {
|
||||
interface PageBlockProps<T = PageBlocks> {
|
||||
data: T
|
||||
}
|
||||
|
||||
export type PageBlockFunction<T = PageBlocks> = ({
|
||||
data
|
||||
}: PageBlockProps<T>) => ReactElement;
|
||||
|
||||
const Block = (block: PageBlocks): ReactElement<PageBlockProps, PageBlockFunction> => {
|
||||
switch (block.__typename) {
|
||||
case "PageBlocksContent":
|
||||
return <Content data={ block } />;
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
import * as React from "react";
|
||||
import { Section } from "../util/section";
|
||||
import { PageBlocksCarousel } from "../../tina/__generated__/types";
|
||||
import { PageBlocks, PageBlocksCarousel, PageBlocksMutation } from "../../tina/__generated__/types";
|
||||
import { Anchoring, anchoringSchema } from "../util/anchoring";
|
||||
import { Template } from "tinacms";
|
||||
import { PageBlockFunction } from "../blocks-renderer";
|
||||
|
||||
export const Carousel = ({ data }: { data: PageBlocksCarousel }) => {
|
||||
/**
|
||||
* Section carousel used for the main page but can be used everywhere
|
||||
* @param {PageBlocksCarousel} data The data from the carousel
|
||||
* @constructor
|
||||
*/
|
||||
export const Carousel: PageBlockFunction<PageBlocksCarousel> = ({ data }) => {
|
||||
return (
|
||||
<Section>
|
||||
<div className="carousel flex w-[100%] items-end justify-center" style={ { backgroundImage: `url(${ data?.images?.[0] })` } }>
|
||||
|
||||
@@ -2,22 +2,35 @@ import React from "react";
|
||||
import { Container } from "../util/container";
|
||||
import { Section } from "../util/section";
|
||||
import { TinaMarkdown } from "tinacms/dist/rich-text";
|
||||
import type { Template, TinaTemplate } from "tinacms";
|
||||
import type { Template } from "tinacms";
|
||||
import { PageBlocksContent } from "../../tina/__generated__/types";
|
||||
import { tinaField } from "tinacms/dist/react";
|
||||
import { PageBlockFunction } from "../blocks-renderer";
|
||||
import inlineComponents, { richTextTemplates } from "../inline/inline-definitions";
|
||||
import sanitizeHtml from "sanitize-html";
|
||||
|
||||
export const Content = ({ data }: { data: PageBlocksContent }) => {
|
||||
const HTMLInline = (props: { value: string }) => {
|
||||
const createSanitizedMarkup = (text: string) => {
|
||||
return { __html: sanitizeHtml(text, {
|
||||
allowedAttributes: {
|
||||
div: [ "class" ]
|
||||
}
|
||||
}) };
|
||||
};
|
||||
|
||||
return <span dangerouslySetInnerHTML={ createSanitizedMarkup(props.value) } />;
|
||||
};
|
||||
|
||||
export const Content: PageBlockFunction<PageBlocksContent> = ({ data }) => {
|
||||
return (
|
||||
<Section color={ data.color }>
|
||||
<Section>
|
||||
<Container
|
||||
className={ `prose prose-lg ${
|
||||
data.color === "primary" ? "prose-primary" : "dark:prose-dark"
|
||||
}` }
|
||||
className={ "prose default-text-color" }
|
||||
data-tina-field={ tinaField(data, "body") }
|
||||
size="large"
|
||||
width="medium"
|
||||
size="small"
|
||||
width="large"
|
||||
>
|
||||
<TinaMarkdown content={ data.body } />
|
||||
<TinaMarkdown components={ { ...inlineComponents, html: props => <HTMLInline { ...props } /> } } content={ data.body } />
|
||||
</Container>
|
||||
</Section>
|
||||
);
|
||||
@@ -34,19 +47,12 @@ export const contentBlockSchema: Template = {
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
|
||||
type: "rich-text",
|
||||
label: "Body",
|
||||
name: "body"
|
||||
},
|
||||
{
|
||||
type: "string",
|
||||
label: "Color",
|
||||
name: "color",
|
||||
options: [
|
||||
{ label: "Default", value: "default" },
|
||||
{ label: "Tint", value: "tint" },
|
||||
{ label: "Primary", value: "primary" }
|
||||
]
|
||||
name: "body",
|
||||
templates: richTextTemplates,
|
||||
isBody: true
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
} from "../../tina/__generated__/types";
|
||||
import { tinaField } from "tinacms/dist/react";
|
||||
import { Template } from "tinacms";
|
||||
import { PageBlockFunction } from "../blocks-renderer";
|
||||
|
||||
export const Feature = ({
|
||||
featuresColor,
|
||||
@@ -49,7 +50,7 @@ export const Feature = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const Features = ({ data }: { data: PageBlocksFeatures }) => {
|
||||
export const Features: PageBlockFunction<PageBlocksFeatures> = ({ data }) => {
|
||||
return (
|
||||
<Section color={ data.color }>
|
||||
<Container
|
||||
|
||||
@@ -3,22 +3,12 @@ import { Actions } from "../util/actions";
|
||||
import { Container } from "../util/container";
|
||||
import { Section } from "../util/section";
|
||||
import { TinaMarkdown } from "tinacms/dist/rich-text";
|
||||
import type { Template, TinaTemplate } from "tinacms";
|
||||
import type { Template } from "tinacms";
|
||||
import { PageBlocksHero } from "../../tina/__generated__/types";
|
||||
import { tinaField } from "tinacms/dist/react";
|
||||
import { PageBlockFunction } from "../blocks-renderer";
|
||||
|
||||
export const Hero = ({ data }: { data: PageBlocksHero }) => {
|
||||
const headlineColorClasses = {
|
||||
blue: "from-blue-400 to-blue-600",
|
||||
teal: "from-teal-400 to-teal-600",
|
||||
green: "from-green-400 to-green-600",
|
||||
red: "from-red-400 to-red-600",
|
||||
pink: "from-pink-400 to-pink-600",
|
||||
purple: "from-purple-400 to-purple-600",
|
||||
orange: "from-orange-300 to-orange-600",
|
||||
yellow: "from-yellow-400 to-yellow-600"
|
||||
};
|
||||
|
||||
export const Hero: PageBlockFunction<PageBlocksHero> = ({ data }) => {
|
||||
return (
|
||||
<Section color={ data.color }>
|
||||
<Container
|
||||
|
||||
45
components/blocks/main-title.tsx
Normal file
45
components/blocks/main-title.tsx
Normal file
@@ -0,0 +1,45 @@
|
||||
import React from "react";
|
||||
import { Container } from "../util/container";
|
||||
import { Section } from "../util/section";
|
||||
import { TinaMarkdown } from "tinacms/dist/rich-text";
|
||||
import type { Template } from "tinacms";
|
||||
import { PageBlocksContent } from "../../tina/__generated__/types";
|
||||
import { tinaField } from "tinacms/dist/react";
|
||||
import { PageBlockFunction } from "../blocks-renderer";
|
||||
import inlineComponents, { richTextTemplates } from "../inline/inline-definitions";
|
||||
|
||||
export const MainTitle: PageBlockFunction<PageBlocksContent> = ({ data }) => {
|
||||
return (
|
||||
<Section>
|
||||
<Container
|
||||
className={ "" }
|
||||
data-tina-field={ tinaField(data, "body") }
|
||||
size="large"
|
||||
width="medium"
|
||||
>
|
||||
<TinaMarkdown components={ inlineComponents } content={ data.body } />
|
||||
</Container>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
export const mainTitleBlockSchema: Template = {
|
||||
name: "mainTitle",
|
||||
label: "Main title",
|
||||
ui: {
|
||||
previewSrc: "/blocks/content.png",
|
||||
defaultItem: {
|
||||
body: "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec odio. Quisque volutpat mattis eros. Nullam malesuada erat ut turpis. Suspendisse urna nibh, viverra non, semper suscipit, posuere a, pede."
|
||||
}
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
|
||||
type: "rich-text",
|
||||
label: "Body",
|
||||
name: "body",
|
||||
templates: richTextTemplates,
|
||||
isBody: true
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -4,8 +4,9 @@ import { Section } from "../util/section";
|
||||
import type { Template } from "tinacms";
|
||||
import { PageBlocksTestimonial } from "../../tina/__generated__/types";
|
||||
import { tinaField } from "tinacms/dist/react";
|
||||
import { PageBlockFunction } from "../blocks-renderer";
|
||||
|
||||
export const Testimonial = ({ data }: { data: PageBlocksTestimonial }) => {
|
||||
export const Testimonial: PageBlockFunction<PageBlocksTestimonial> = ({ data }) => {
|
||||
return (
|
||||
<Section color={ data.color }>
|
||||
<Container size="large">
|
||||
|
||||
34
components/inline/block-quote.tsx
Normal file
34
components/inline/block-quote.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import { TinaMarkdown, TinaMarkdownContent } from "tinacms/dist/rich-text";
|
||||
import { RichTextTemplate } from "@tinacms/schema-tools";
|
||||
|
||||
export interface BlockQuoteProps {
|
||||
children: TinaMarkdownContent;
|
||||
authorName: string;
|
||||
}
|
||||
|
||||
const BlockQuote = (props: BlockQuoteProps) => (
|
||||
<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;
|
||||
40
components/inline/date-time.tsx
Normal file
40
components/inline/date-time.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import React from "react";
|
||||
import format from "date-fns/format";
|
||||
import { Template } from "tinacms";
|
||||
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;
|
||||
120
components/inline/image.tsx
Normal file
120
components/inline/image.tsx
Normal file
@@ -0,0 +1,120 @@
|
||||
import { TinaMarkdownContent } from "tinacms/dist/rich-text";
|
||||
import { RichTextTemplate } from "@tinacms/schema-tools";
|
||||
import { tinaField } from "tinacms/dist/react";
|
||||
|
||||
enum imageSize {
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
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.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 "float-left mr-2";
|
||||
case imagePosition.middle:
|
||||
return "flex justify-center";
|
||||
case imagePosition.right:
|
||||
return "float-right ml-2";
|
||||
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") }
|
||||
src={ props.imageUrl }/>
|
||||
</div>);
|
||||
};
|
||||
|
||||
export const imageSchema: RichTextTemplate = {
|
||||
name: "Image",
|
||||
label: "Image",
|
||||
inline: true,
|
||||
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: "decorations",
|
||||
label: "Decorations",
|
||||
type: "string",
|
||||
options: Object.values(imageDecorations)
|
||||
}
|
||||
] };
|
||||
|
||||
export default Image;
|
||||
35
components/inline/inline-definitions.tsx
Normal file
35
components/inline/inline-definitions.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
import { Components } from "tinacms/dist/rich-text";
|
||||
import BlockQuote, { BlockQuoteProps, blockQuoteSchema } from "./block-quote";
|
||||
import DateTime, { DateTimeProps, dateTimeSchema } from "./date-time";
|
||||
import NewsletterSignup, { NewsletterSignupProps, newsletterSignupSchema } from "./newsletter-signup";
|
||||
import { Prism } from "tinacms/dist/rich-text/prism";
|
||||
import React from "react";
|
||||
import Image, { ImageProps, imageSchema } from "./image";
|
||||
import { RichTextTemplate } from "@tinacms/schema-tools";
|
||||
|
||||
const inlineComponents: Components<{
|
||||
BlockQuote: BlockQuoteProps;
|
||||
DateTime: DateTimeProps;
|
||||
NewsletterSignup: NewsletterSignupProps;
|
||||
Image: ImageProps;
|
||||
}> = {
|
||||
code_block: (props) => <Prism { ...props } />,
|
||||
BlockQuote,
|
||||
DateTime,
|
||||
NewsletterSignup,
|
||||
img: (props) => (
|
||||
<span className="flex items-center justify-center">
|
||||
<img src={ props.url } alt={ props.alt } />
|
||||
</span>
|
||||
),
|
||||
Image
|
||||
};
|
||||
|
||||
export const richTextTemplates: RichTextTemplate[] = [
|
||||
dateTimeSchema,
|
||||
blockQuoteSchema,
|
||||
newsletterSignupSchema,
|
||||
imageSchema
|
||||
];
|
||||
|
||||
export default inlineComponents;
|
||||
83
components/inline/newsletter-signup.tsx
Normal file
83
components/inline/newsletter-signup.tsx
Normal file
@@ -0,0 +1,83 @@
|
||||
import { TinaMarkdown, TinaMarkdownContent } from "tinacms/dist/rich-text";
|
||||
import React from "react";
|
||||
import format from "date-fns/format";
|
||||
import { RichTextTemplate } from "@tinacms/schema-tools";
|
||||
|
||||
export interface NewsletterSignupProps {
|
||||
placeholder: string;
|
||||
buttonText: string;
|
||||
children: TinaMarkdownContent;
|
||||
disclaimer?: TinaMarkdownContent;
|
||||
}
|
||||
|
||||
const NewsletterSignup = (props: NewsletterSignupProps) => (
|
||||
<div className="bg-white">
|
||||
<div className="max-w-7xl mx-auto py-8 px-4 sm:px-6 lg:px-8">
|
||||
<div className="">
|
||||
<TinaMarkdown content={ props.children } />
|
||||
</div>
|
||||
<div className="mt-8 ">
|
||||
<form className="sm:flex">
|
||||
<label htmlFor="email-address" className="sr-only">
|
||||
Email address
|
||||
</label>
|
||||
<input
|
||||
id="email-address"
|
||||
name="email-address"
|
||||
type="email"
|
||||
autoComplete="email"
|
||||
required
|
||||
className="w-full px-5 py-3 border border-gray-300 shadow-sm placeholder-gray-400 focus:ring-1 focus:ring-teal-500 focus:border-teal-500 sm:max-w-xs rounded-md"
|
||||
placeholder={ props.placeholder }
|
||||
/>
|
||||
<div className="mt-3 rounded-md shadow sm:mt-0 sm:ml-3 sm:flex-shrink-0">
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full flex items-center justify-center py-3 px-5 border border-transparent text-base font-medium rounded-md text-white bg-teal-600 hover:bg-teal-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-teal-500"
|
||||
>
|
||||
{ props.buttonText }
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<div className="mt-3 text-sm text-gray-500">
|
||||
{ props.disclaimer && <TinaMarkdown content={ props.disclaimer } /> }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const newsletterSignupSchema: RichTextTemplate = {
|
||||
name: "NewsletterSignup",
|
||||
label: "Newsletter Sign Up",
|
||||
fields: [
|
||||
{
|
||||
name: "children",
|
||||
label: "CTA",
|
||||
type: "rich-text"
|
||||
},
|
||||
{
|
||||
name: "placeholder",
|
||||
label: "Placeholder",
|
||||
type: "string"
|
||||
},
|
||||
{
|
||||
name: "buttonText",
|
||||
label: "Button Text",
|
||||
type: "string"
|
||||
},
|
||||
{
|
||||
name: "disclaimer",
|
||||
label: "Disclaimer",
|
||||
type: "rich-text"
|
||||
}
|
||||
],
|
||||
ui: {
|
||||
defaultItem: {
|
||||
placeholder: "Enter your email",
|
||||
buttonText: "Notify Me"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default NewsletterSignup;
|
||||
@@ -28,7 +28,7 @@ export const Layout = ({
|
||||
/>
|
||||
</Head>
|
||||
<div
|
||||
className={ "min-h-screen flex flex-col font-nunito" }
|
||||
className={ "min-h-screen flex flex-col" }
|
||||
>
|
||||
<Header data={ data?.header } />
|
||||
<div className="flex-1 text-gray-800 bg-gradient-to-br from-white to-gray-50 dark:from-gray-900 dark:to-gray-1000 flex flex-col">
|
||||
|
||||
@@ -16,116 +16,11 @@ import { Container } from "../util/container";
|
||||
import { Section } from "../util/section";
|
||||
import format from "date-fns/format";
|
||||
import { TinaMarkdown } from "tinacms/dist/rich-text";
|
||||
import { Prism } from "tinacms/dist/rich-text/prism";
|
||||
import type { TinaMarkdownContent, Components } from "tinacms/dist/rich-text";
|
||||
import { PostType } from "../../pages/posts/[filename]";
|
||||
import { tinaField } from "tinacms/dist/react";
|
||||
|
||||
const components: Components<{
|
||||
BlockQuote: {
|
||||
children: TinaMarkdownContent;
|
||||
authorName: string;
|
||||
};
|
||||
DateTime: {
|
||||
format?: string;
|
||||
};
|
||||
NewsletterSignup: {
|
||||
placeholder: string;
|
||||
buttonText: string;
|
||||
children: TinaMarkdownContent;
|
||||
disclaimer?: TinaMarkdownContent;
|
||||
};
|
||||
}> = {
|
||||
code_block: (props) => <Prism { ...props } />,
|
||||
BlockQuote: (props: {
|
||||
children: TinaMarkdownContent;
|
||||
authorName: string;
|
||||
}) => {
|
||||
return (
|
||||
<div>
|
||||
<blockquote>
|
||||
<TinaMarkdown content={ props.children } />
|
||||
{ props.authorName }
|
||||
</blockquote>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
DateTime: (props) => {
|
||||
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>;
|
||||
}
|
||||
},
|
||||
NewsletterSignup: (props) => {
|
||||
return (
|
||||
<div className="bg-white">
|
||||
<div className="max-w-7xl mx-auto py-8 px-4 sm:px-6 lg:px-8">
|
||||
<div className="">
|
||||
<TinaMarkdown content={ props.children } />
|
||||
</div>
|
||||
<div className="mt-8 ">
|
||||
<form className="sm:flex">
|
||||
<label htmlFor="email-address" className="sr-only">
|
||||
Email address
|
||||
</label>
|
||||
<input
|
||||
id="email-address"
|
||||
name="email-address"
|
||||
type="email"
|
||||
autoComplete="email"
|
||||
required
|
||||
className="w-full px-5 py-3 border border-gray-300 shadow-sm placeholder-gray-400 focus:ring-1 focus:ring-teal-500 focus:border-teal-500 sm:max-w-xs rounded-md"
|
||||
placeholder={ props.placeholder }
|
||||
/>
|
||||
<div className="mt-3 rounded-md shadow sm:mt-0 sm:ml-3 sm:flex-shrink-0">
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full flex items-center justify-center py-3 px-5 border border-transparent text-base font-medium rounded-md text-white bg-teal-600 hover:bg-teal-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-teal-500"
|
||||
>
|
||||
{ props.buttonText }
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<div className="mt-3 text-sm text-gray-500">
|
||||
{ props.disclaimer && <TinaMarkdown content={ props.disclaimer } /> }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
img: (props) => (
|
||||
<span className="flex items-center justify-center">
|
||||
<img src={ props.url } alt={ props.alt } />
|
||||
</span>
|
||||
)
|
||||
};
|
||||
import inlineComponents from "../inline/inline-definitions";
|
||||
|
||||
export const Post = (props: PostType) => {
|
||||
const titleColorClasses = {
|
||||
blue: "from-blue-400 to-blue-600 dark:from-blue-300 dark:to-blue-500",
|
||||
teal: "from-teal-400 to-teal-600 dark:from-teal-300 dark:to-teal-500",
|
||||
green: "from-green-400 to-green-600",
|
||||
red: "from-red-400 to-red-600",
|
||||
pink: "from-pink-300 to-pink-500",
|
||||
purple:
|
||||
"from-purple-400 to-purple-600 dark:from-purple-300 dark:to-purple-500",
|
||||
orange:
|
||||
"from-orange-300 to-orange-600 dark:from-orange-200 dark:to-orange-500",
|
||||
yellow:
|
||||
"from-yellow-400 to-yellow-500 dark:from-yellow-300 dark:to-yellow-500"
|
||||
};
|
||||
|
||||
const date = new Date(props.date);
|
||||
let formattedDate = "";
|
||||
if (!isNaN(date.getTime())) {
|
||||
@@ -202,7 +97,7 @@ export const Post = (props: PostType) => {
|
||||
data-tina-field={ tinaField(props, "_body") }
|
||||
className="prose dark:prose-dark w-full max-w-none"
|
||||
>
|
||||
<TinaMarkdown components={ components } content={ props._body } />
|
||||
<TinaMarkdown components={ inlineComponents } content={ props._body } />
|
||||
</div>
|
||||
</Container>
|
||||
</Section>
|
||||
|
||||
@@ -8,7 +8,12 @@ interface AnchoringProps {
|
||||
linkTo?: string // Default: #main-page
|
||||
}
|
||||
|
||||
export const Anchoring = (props: AnchoringProps) => {
|
||||
/**
|
||||
* Made to be used with the carousel
|
||||
* @param {AnchoringProps} props Props for the anchoring.
|
||||
* @return {ReactElement} The function component
|
||||
*/
|
||||
export const Anchoring: React.FC<AnchoringProps> = (props) => {
|
||||
const [opacity, setOpacity] = useState(1);
|
||||
const anchoringRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ export const Container = ({
|
||||
const widthClass = {
|
||||
small: "max-w-4xl",
|
||||
medium: "max-w-5xl",
|
||||
large: "max-w-7xl",
|
||||
large: "container-large",
|
||||
custom: ""
|
||||
};
|
||||
|
||||
|
||||
@@ -30,10 +30,5 @@
|
||||
"twitter": "/",
|
||||
"instagram": "/"
|
||||
}
|
||||
},
|
||||
"theme": {
|
||||
"color": "blue",
|
||||
"font": "sans",
|
||||
"darkMode": "system"
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,14 @@
|
||||
title: About
|
||||
blocks:
|
||||
- body: >
|
||||

|
||||
|
||||
Je suis **psychopraticienne en art-thérapie** et mon approche est issue de
|
||||
la **psychologie intégrative**, autrement dit, je m’intéresse à l’ensemble
|
||||
de la personne : sa personnalité, son évolution dans ses différents
|
||||
environnements (familial, professionnel, amical) et son fonctionnement à
|
||||
la fois émotionnel, affectif, comportemental, cognitif et relationnel.
|
||||
<Image size="medium" decorations="default" position="right"
|
||||
imageUrl="/uploads/photo.jpg" /> Je suis **psychopraticienne en
|
||||
art-thérapie** et mon approche est issue de la **psychologie
|
||||
intégrative**, autrement dit, je m’intéresse à l’ensemble de la personne :
|
||||
sa personnalité, son évolution dans ses différents environnements
|
||||
(familial, professionnel, amical) et son fonctionnement à la fois
|
||||
émotionnel, affectif, comportemental, cognitif et relationnel.
|
||||
|
||||
|
||||
Ainsi, je m’adapte à vous en assemblant différentes techniques issues de
|
||||
@@ -80,8 +81,13 @@ blocks:
|
||||
Maintenant, c’est à votre tour de vous présenter à moi, si vous le
|
||||
souhaitez, n’hésitez pas à me **contacter** par **téléphone, par mail ou
|
||||
via les réseaux sociaux** !
|
||||
color: default
|
||||
_template: content
|
||||
url: aboutt
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -9,6 +9,43 @@ blocks:
|
||||
text: Découvrez-en plus !
|
||||
linkTo: main-page
|
||||
_template: carousel
|
||||
- body: >
|
||||
<div class="not-prose text-center text-4xl">
|
||||
<h1>Découvrez la PsychARThérapie,</h1>
|
||||
<h1>Quand l’art dévoile ce qui se cache en vous !</h1>
|
||||
</div>
|
||||
|
||||
|
||||
<Image size="medium" decorations="default" position="middle"
|
||||
imageUrl="/uploads/etoile.jpg" />
|
||||
|
||||
|
||||
PsychARThérapie est l’alliance entre la psychologie intégrative et
|
||||
l’art-thérapie, autrement dit, en tant que psychopraticienne en
|
||||
art-thérapie, je m’adapte à vos besoins, à votre rythme, pour vous
|
||||
accompagner vers là où vous souhaitez aller.
|
||||
|
||||
|
||||
Les médiations artistiques (peinture, dessin, écriture, photographie) vont
|
||||
pouvoir vous aider à accéder à votre but par le jeu, la création, l’image,
|
||||
le symbole, et un tout nouveau moyen d’expression, votre propre langage.
|
||||
|
||||
|
||||
Voulez-vous être accompagné/soutenu lors d’un événement difficile à gérer
|
||||
pour vous ?
|
||||
|
||||
|
||||
Voulez-vous découvrir l’artiste qui sommeille en vous et qui veut recréer
|
||||
son histoire ?
|
||||
|
||||
|
||||
Voulez-vous explorer vos capacités, vos ressources intérieures grâce à
|
||||
l’art-thérapie ?
|
||||
|
||||
|
||||
Tentez l’expérience et entrez dans votre espace de création et de liberté
|
||||
!
|
||||
_template: content
|
||||
- headline: Welcome to the Tina Starter
|
||||
text: >
|
||||
This project is set up to show you the basics of working with Tina. You're
|
||||
@@ -63,6 +100,7 @@ blocks:
|
||||
author: Phil Karlton
|
||||
color: primary
|
||||
_template: testimonial
|
||||
url: home
|
||||
---
|
||||
|
||||
|
||||
@@ -79,3 +117,68 @@ blocks:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ excerpt: >
|
||||
vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla
|
||||
facilities morbi tempus.
|
||||
author: content/authors/pedro.md
|
||||
date: "2021-07-03T20:30:00.000Z"
|
||||
date: 2021-07-03T20:30:00.000Z
|
||||
---
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus.
|
||||
<DateTime format="iso" /> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus.
|
||||
|
||||
16
package.json
16
package.json
@@ -11,19 +11,20 @@
|
||||
"bullshit:build": "tinacms dev -c \"next build\""
|
||||
},
|
||||
"devDependencies": {
|
||||
"@svgr/webpack": "^6.3.1",
|
||||
"@tinacms/cli": "^1.5.14",
|
||||
"@svgr/webpack": "^8.0.1",
|
||||
"@tinacms/cli": "^1.5.29",
|
||||
"@types/js-cookie": "^3.0.0",
|
||||
"@types/node": "^16.11.7",
|
||||
"@types/react": "^17.0.35",
|
||||
"@types/sanitize-html": "^2.9.0",
|
||||
"@types/styled-components": "^5.1.15",
|
||||
"@typescript-eslint/eslint-plugin": "^5.20.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.60.0",
|
||||
"@typescript-eslint/parser": "^6.5.0",
|
||||
"autoprefixer": "^10.4.0",
|
||||
"autoprefixer": "^10.4.7",
|
||||
"eslint": "^8.13.0",
|
||||
"eslint-plugin-react": "^7.33.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"postcss": "^8.3.11",
|
||||
"postcss": "^8.4.21",
|
||||
"postcss-import": "^14.0.2",
|
||||
"postcss-nesting": "^10.1.0"
|
||||
},
|
||||
@@ -35,10 +36,11 @@
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-icons": "^4.2.0",
|
||||
"sanitize-html": "^2.11.0",
|
||||
"sass": "^1.66.1",
|
||||
"styled-jsx": "^3.2.5",
|
||||
"tailwindcss": "^3.2.4",
|
||||
"tinacms": "^1.5.6",
|
||||
"tailwindcss": "^3.3.2",
|
||||
"tinacms": "^1.5.20",
|
||||
"typescript": "^4.5.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ export default function HomePage(
|
||||
|
||||
export const getStaticProps = async ({ params }) => {
|
||||
const tinaProps = await client.queries.contentQuery({
|
||||
relativePath: `${ params.filename }.md`
|
||||
relativePath: `${ params.filename }.mdx`
|
||||
});
|
||||
const props = {
|
||||
...tinaProps,
|
||||
|
||||
BIN
public/uploads/etoile.jpg
Normal file
BIN
public/uploads/etoile.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 336 KiB |
@@ -3,6 +3,7 @@
|
||||
@import "header";
|
||||
@import "anchoring";
|
||||
@import "carousel";
|
||||
@import "image";
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@@ -18,8 +19,20 @@ html {
|
||||
scroll-padding-top: var(--header-Height);
|
||||
}
|
||||
|
||||
.container-large {
|
||||
max-width: 75rem;
|
||||
}
|
||||
|
||||
.default-text-color {
|
||||
color: var(--primaryColor);
|
||||
--tw-prose-bold: #124498;
|
||||
}
|
||||
|
||||
.font {
|
||||
font-family: 'Questrial', sans-serif;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Questrial', sans-serif;
|
||||
background-color: var(--body-BackgroundColor);
|
||||
|
||||
}
|
||||
15
styles/image.scss
Normal file
15
styles/image.scss
Normal file
@@ -0,0 +1,15 @@
|
||||
.inline-image {
|
||||
.default-border {
|
||||
border: var(--primaryColor) solid .25rem;
|
||||
border-radius: 1rem;
|
||||
}
|
||||
.sm-size {
|
||||
max-height: 15rem;
|
||||
}
|
||||
.md-size {
|
||||
max-height: 25rem;
|
||||
}
|
||||
.lg-size {
|
||||
max-height: 40rem;
|
||||
}
|
||||
}
|
||||
@@ -106,7 +106,7 @@ module.exports = {
|
||||
DEFAULT: {
|
||||
css: {
|
||||
pre: {
|
||||
color: theme("colors.gray.700"),
|
||||
color: "var(--primaryColor)",
|
||||
backgroundColor: theme("colors.gray.100"),
|
||||
lineHeight: 1.5
|
||||
},
|
||||
@@ -157,9 +157,9 @@ module.exports = {
|
||||
},
|
||||
dark: {
|
||||
css: {
|
||||
color: theme("colors.gray.200"),
|
||||
color: "var(--primaryColor)",
|
||||
"[class~=\"lead\"]": { color: theme("colors.gray.400") },
|
||||
a: { color: theme("colors.gray.100") },
|
||||
a: { color: "var(--primaryColor)" },
|
||||
strong: { color: theme("colors.gray.100") },
|
||||
"ul > li::before": { backgroundColor: theme("colors.gray.700") },
|
||||
hr: { borderColor: theme("colors.gray.800") },
|
||||
@@ -177,11 +177,11 @@ module.exports = {
|
||||
},
|
||||
"a code": { color: theme("colors.gray.100") },
|
||||
pre: {
|
||||
color: theme("colors.gray.200"),
|
||||
color: "var(--primaryColor)",
|
||||
backgroundColor: theme("colors.gray.900")
|
||||
},
|
||||
thead: {
|
||||
color: theme("colors.gray.100"),
|
||||
color: "var(--primaryColor)",
|
||||
borderBottomColor: theme("colors.gray.700")
|
||||
},
|
||||
"tbody tr": { borderBottomColor: theme("colors.gray.800") }
|
||||
@@ -189,31 +189,31 @@ module.exports = {
|
||||
},
|
||||
primary: {
|
||||
css: {
|
||||
color: theme("colors.gray.50"),
|
||||
color: "var(--primaryColor)",
|
||||
"[class~=\"lead\"]": { color: theme("colors.gray.400") },
|
||||
a: { color: theme("colors.gray.100") },
|
||||
strong: { color: theme("colors.gray.100") },
|
||||
a: { color: "var(--primaryColor)" },
|
||||
strong: { color: "var(--primaryColor)" },
|
||||
"ul > li::before": { backgroundColor: theme("colors.gray.700") },
|
||||
hr: { borderColor: theme("colors.gray.800") },
|
||||
blockquote: {
|
||||
color: theme("colors.gray.100"),
|
||||
borderLeftColor: theme("colors.gray.800")
|
||||
},
|
||||
h1: { color: theme("colors.gray.100") },
|
||||
h2: { color: theme("colors.gray.100") },
|
||||
h3: { color: theme("colors.gray.100") },
|
||||
h4: { color: theme("colors.gray.100") },
|
||||
h1: { color: "var(--primaryColor)" },
|
||||
h2: { color: "var(--primaryColor)" },
|
||||
h3: { color: "var(--primaryColor)" },
|
||||
h4: { color: "var(--primaryColor)" },
|
||||
code: {
|
||||
color: theme("colors.gray.100"),
|
||||
backgroundColor: "rgba(0,0,0,0.15)"
|
||||
},
|
||||
"a code": { color: theme("colors.gray.100") },
|
||||
pre: {
|
||||
color: theme("colors.gray.200"),
|
||||
color: "var(--primaryColor)",
|
||||
backgroundColor: "rgba(0,0,0,0.15)"
|
||||
},
|
||||
thead: {
|
||||
color: theme("colors.gray.100"),
|
||||
color: "var(--primaryColor)",
|
||||
borderBottomColor: theme("colors.gray.700")
|
||||
},
|
||||
"tbody tr": { borderBottomColor: theme("colors.gray.800") }
|
||||
|
||||
@@ -6,6 +6,7 @@ import { testimonialBlockSchema } from "../components/blocks/testimonial";
|
||||
import { carouselBlockSchema } from "../components/blocks/carousel";
|
||||
import { headerSchema } from "../components/layout/header";
|
||||
import { footerSchema } from "../components/layout/footer/footer";
|
||||
import { richTextTemplates } from "../components/inline/inline-definitions";
|
||||
|
||||
const config = defineConfig({
|
||||
clientId: process.env.NEXT_PUBLIC_TINA_CLIENT_ID!,
|
||||
@@ -15,12 +16,12 @@ const config = defineConfig({
|
||||
process.env.HEAD!, // Netlify branch env
|
||||
token: process.env.TINA_TOKEN!,
|
||||
media: {
|
||||
// If you wanted cloudinary do this
|
||||
// loadCustomStore: async () => {
|
||||
// const pack = await import("next-tinacms-cloudinary");
|
||||
// return pack.TinaCloudCloudinaryMediaStore;
|
||||
// },
|
||||
// this is the config for the tina cloud media store
|
||||
// If you wanted cloudinary do this
|
||||
// loadCustomStore: async () => {
|
||||
// const pack = await import("next-tinacms-cloudinary");
|
||||
// return pack.TinaCloudCloudinaryMediaStore;
|
||||
// },
|
||||
// this is the config for the tina cloud media store
|
||||
tina: {
|
||||
publicFolder: "public",
|
||||
mediaRoot: "uploads"
|
||||
@@ -79,69 +80,7 @@ const config = defineConfig({
|
||||
type: "rich-text",
|
||||
label: "Body",
|
||||
name: "_body",
|
||||
templates: [
|
||||
{
|
||||
name: "DateTime",
|
||||
label: "Date & Time",
|
||||
inline: true,
|
||||
fields: [
|
||||
{
|
||||
name: "format",
|
||||
label: "Format",
|
||||
type: "string",
|
||||
options: ["utc", "iso", "local"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "BlockQuote",
|
||||
label: "Block Quote",
|
||||
fields: [
|
||||
{
|
||||
name: "children",
|
||||
label: "Quote",
|
||||
type: "rich-text"
|
||||
},
|
||||
{
|
||||
name: "authorName",
|
||||
label: "Author",
|
||||
type: "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "NewsletterSignup",
|
||||
label: "Newsletter Sign Up",
|
||||
fields: [
|
||||
{
|
||||
name: "children",
|
||||
label: "CTA",
|
||||
type: "rich-text"
|
||||
},
|
||||
{
|
||||
name: "placeholder",
|
||||
label: "Placeholder",
|
||||
type: "string"
|
||||
},
|
||||
{
|
||||
name: "buttonText",
|
||||
label: "Button Text",
|
||||
type: "string"
|
||||
},
|
||||
{
|
||||
name: "disclaimer",
|
||||
label: "Disclaimer",
|
||||
type: "rich-text"
|
||||
}
|
||||
],
|
||||
ui: {
|
||||
defaultItem: {
|
||||
placeholder: "Enter your email",
|
||||
buttonText: "Notify Me"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
templates: richTextTemplates,
|
||||
isBody: true
|
||||
}
|
||||
]
|
||||
@@ -183,15 +122,14 @@ const config = defineConfig({
|
||||
label: "Pages",
|
||||
name: "page",
|
||||
path: "content/pages",
|
||||
format: "mdx",
|
||||
ui: {
|
||||
router: ({ document }) => {
|
||||
router: ({ document, collection }) => {
|
||||
if (document._sys.filename === "home") {
|
||||
return "/";
|
||||
}
|
||||
if (document._sys.filename === "about") {
|
||||
return "/about";
|
||||
}
|
||||
return undefined;
|
||||
|
||||
return `/${ document._sys.filename }`;
|
||||
}
|
||||
},
|
||||
fields: [
|
||||
@@ -214,11 +152,9 @@ const config = defineConfig({
|
||||
},
|
||||
templates: [
|
||||
heroBlockSchema,
|
||||
// @ts-ignore
|
||||
featureBlockSchema,
|
||||
contentBlockSchema,
|
||||
testimonialBlockSchema,
|
||||
// @ts-ignore
|
||||
carouselBlockSchema
|
||||
]
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user