Linted the whole project with eslint

This commit was merged in pull request #3.
This commit is contained in:
2023-08-31 19:42:15 +02:00
parent cbc4d839d0
commit 7be98e1793
29 changed files with 2931 additions and 1686 deletions

View File

@@ -3,320 +3,229 @@ import { contentBlockSchema } from "../components/blocks/content";
import { featureBlockSchema } from "../components/blocks/features";
import { heroBlockSchema } from "../components/blocks/hero";
import { testimonialBlockSchema } from "../components/blocks/testimonial";
import { ColorPickerInput } from "./fields/color";
import {carouselBlockSchema} from "../components/blocks/carousel";
import { carouselBlockSchema } from "../components/blocks/carousel";
import { headerSchema } from "../components/layout/header";
import { footerSchema } from "../components/layout/footer/footer";
const config = defineConfig({
clientId: process.env.NEXT_PUBLIC_TINA_CLIENT_ID!,
branch:
clientId: process.env.NEXT_PUBLIC_TINA_CLIENT_ID!,
branch:
process.env.NEXT_PUBLIC_TINA_BRANCH! || // custom branch env override
process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_REF! || // Vercel branch env
process.env.HEAD!, // Netlify branch env
token: process.env.TINA_TOKEN!,
media: {
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
tina: {
publicFolder: "public",
mediaRoot: "uploads",
tina: {
publicFolder: "public",
mediaRoot: "uploads"
}
},
},
build: {
publicFolder: "public", // The public asset folder for your framework
outputFolder: "admin", // within the public folder
},
schema: {
collections: [
{
label: "Blog Posts",
name: "post",
path: "content/posts",
format: "mdx",
ui: {
router: ({ document }) => {
return `/posts/${document._sys.filename}`;
},
},
fields: [
{
type: "string",
label: "Title",
name: "title",
isTitle: true,
required: true,
},
{
type: "image",
name: "heroImg",
label: "Hero Image",
},
{
type: "rich-text",
label: "Excerpt",
name: "excerpt",
},
{
type: "reference",
label: "Author",
name: "author",
collections: ["author"],
},
{
type: "datetime",
label: "Posted Date",
name: "date",
ui: {
dateFormat: "MMMM DD YYYY",
timeFormat: "hh:mm A",
build: {
publicFolder: "public", // The public asset folder for your framework
outputFolder: "admin" // within the public folder
},
schema: {
collections: [
{
label: "Blog Posts",
name: "post",
path: "content/posts",
format: "mdx",
ui: {
router: ({ document }) => {
return `/posts/${ document._sys.filename }`;
}
},
fields: [
{
type: "string",
label: "Title",
name: "title",
isTitle: true,
required: true
},
{
type: "image",
name: "heroImg",
label: "Hero Image"
},
{
type: "rich-text",
label: "Excerpt",
name: "excerpt"
},
{
type: "reference",
label: "Author",
name: "author",
collections: ["author"]
},
{
type: "datetime",
label: "Posted Date",
name: "date",
ui: {
dateFormat: "MMMM DD YYYY",
timeFormat: "hh:mm A"
}
},
{
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"
}
}
}
],
isBody: true
}
]
},
},
{
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",
},
],
{
label: "Global",
name: "global",
path: "content/global",
format: "json",
ui: {
defaultItem: {
placeholder: "Enter your email",
buttonText: "Notify Me",
},
},
},
],
isBody: true,
},
],
},
{
label: "Global",
name: "global",
path: "content/global",
format: "json",
ui: {
global: true,
},
fields: [
{
type: "object",
label: "Header",
name: "header",
fields: [
{
type: "string",
label: "Page Title",
name: "pageTitle",
},
{
type: "string",
label: "Title",
name: "title",
},
{
type: "string",
label: "Subtitle",
name: "subtitle",
},
{
type: "image",
label: "Logo",
name: "logoSrc"
},
{
type: "object",
label: "Nav Links",
name: "nav",
list: true,
ui: {
itemProps: (item) => {
return { label: item?.label };
},
defaultItem: {
href: "home",
label: "Home",
external: false
},
global: true
},
fields: [
{
type: "string",
label: "Link",
name: "href",
},
{
type: "string",
label: "Label",
name: "label",
},
{
type: "boolean",
label: "External",
name: "external",
}
],
},
],
},
{
type: "object",
label: "Footer",
name: "footer",
fields: [
{
type: "object",
label: "Social Links",
name: "social",
headerSchema,
footerSchema
]
},
{
label: "Authors",
name: "author",
path: "content/authors",
format: "md",
fields: [
{
type: "string",
label: "Facebook",
name: "facebook",
},
{
type: "string",
label: "Twitter",
name: "twitter",
},
{
type: "string",
label: "Instagram",
name: "instagram",
},
{
type: "string",
label: "Github",
name: "github",
},
],
},
],
},
],
},
{
label: "Authors",
name: "author",
path: "content/authors",
format: "md",
fields: [
{
type: "string",
label: "Name",
name: "name",
isTitle: true,
required: true,
},
{
type: "image",
label: "Avatar",
name: "avatar",
},
],
},
{
label: "Pages",
name: "page",
path: "content/pages",
ui: {
router: ({ document }) => {
if (document._sys.filename === "home") {
return `/`;
}
if (document._sys.filename === "about") {
return `/about`;
}
return undefined;
},
},
fields: [
{
type: "string",
label: "Title",
name: "title",
description:
{
type: "string",
label: "Name",
name: "name",
isTitle: true,
required: true
},
{
type: "image",
label: "Avatar",
name: "avatar"
}
]
},
{
label: "Pages",
name: "page",
path: "content/pages",
ui: {
router: ({ document }) => {
if (document._sys.filename === "home") {
return "/";
}
if (document._sys.filename === "about") {
return "/about";
}
return undefined;
}
},
fields: [
{
type: "string",
label: "Title",
name: "title",
description:
"The title of the page. This is used to display the title in the CMS",
isTitle: true,
required: true,
},
{
type: "object",
list: true,
name: "blocks",
label: "Sections",
ui: {
visualSelector: true,
},
templates: [
heroBlockSchema,
// @ts-ignore
featureBlockSchema,
contentBlockSchema,
testimonialBlockSchema,
// @ts-ignore
carouselBlockSchema
],
},
],
},
],
},
isTitle: true,
required: true
},
{
type: "object",
list: true,
name: "blocks",
label: "Sections",
ui: {
visualSelector: true
},
templates: [
heroBlockSchema,
// @ts-ignore
featureBlockSchema,
contentBlockSchema,
testimonialBlockSchema,
// @ts-ignore
carouselBlockSchema
]
}
]
}
]
}
});
export default config;

View File

@@ -2,51 +2,51 @@ import * as React from "react";
import { wrapFieldsWithMeta } from "tinacms";
export const colorOptions = [
"blue",
"teal",
"green",
"yellow",
"orange",
"red",
"pink",
"purple",
"white",
"blue",
"teal",
"green",
"yellow",
"orange",
"red",
"pink",
"purple",
"white"
];
export const ColorPickerInput = wrapFieldsWithMeta(({ input }) => {
const inputClasses = {
blue: "bg-blue-500 border-blue-600",
teal: "bg-teal-500 border-teal-600",
green: "bg-green-500 border-green-600",
yellow: "bg-yellow-500 border-yellow-600",
orange: "bg-orange-500 border-orange-600",
red: "bg-red-500 border-red-600",
pink: "bg-pink-500 border-pink-600",
purple: "bg-purple-500 border-purple-600",
white: "bg-white border-gray-150",
};
const inputClasses = {
blue: "bg-blue-500 border-blue-600",
teal: "bg-teal-500 border-teal-600",
green: "bg-green-500 border-green-600",
yellow: "bg-yellow-500 border-yellow-600",
orange: "bg-orange-500 border-orange-600",
red: "bg-red-500 border-red-600",
pink: "bg-pink-500 border-pink-600",
purple: "bg-purple-500 border-purple-600",
white: "bg-white border-gray-150"
};
return (
<>
<input type="text" id={input.name} className="hidden" {...input} />
<div className="flex gap-2 flex-wrap">
{colorOptions.map((color) => {
return (
<button
className={`w-9 h-9 rounded-full shadow border ${
inputClasses[color]
} ${
input.value === color
? "ring-[3px] ring-offset-2 ring-blue-400"
: ""
}`}
onClick={() => {
input.onChange(color);
}}
></button>
);
})}
</div>
</>
);
return (
<>
<input type="text" id={ input.name } className="hidden" { ...input } />
<div className="flex gap-2 flex-wrap">
{ colorOptions.map((color) => {
return (
<button
className={ `w-9 h-9 rounded-full shadow border ${
inputClasses[color]
} ${
input.value === color
? "ring-[3px] ring-offset-2 ring-blue-400"
: ""
}` }
onClick={ () => {
input.onChange(color);
} }
/>
);
}) }
</div>
</>
);
});

View File

@@ -6,129 +6,128 @@ import { Icon, IconOptions } from "../../components/util/icon";
import { BiChevronRight } from "react-icons/bi";
const parseIconName = (name: string) => {
const splitName = name.split(/(?=[A-Z])/);
if (splitName.length > 1) {
return splitName.slice(1).join(" ");
} else {
const splitName = name.split(/(?=[A-Z])/);
if (splitName.length > 1) {
return splitName.slice(1).join(" ");
}
return name;
}
};
export const IconPickerInput = wrapFieldsWithMeta(({ input }) => {
const [filter, setFilter] = React.useState("");
const filteredBlocks = React.useMemo(() => {
return Object.keys(IconOptions).filter((name) => {
return name.toLowerCase().includes(filter.toLowerCase());
});
}, [filter]);
const [filter, setFilter] = React.useState("");
const filteredBlocks = React.useMemo(() => {
return Object.keys(IconOptions).filter((name) => {
return name.toLowerCase().includes(filter.toLowerCase());
});
}, [filter]);
const inputLabel = Object.keys(IconOptions).includes(input.value)
? parseIconName(input.value)
: "Select Icon";
const InputIcon = IconOptions[input.value] ? IconOptions[input.value] : null;
const inputLabel = Object.keys(IconOptions).includes(input.value)
? parseIconName(input.value)
: "Select Icon";
const InputIcon = IconOptions[input.value] ? IconOptions[input.value] : null;
return (
<div className="relative z-[1000]">
<input type="text" id={input.name} className="hidden" {...input} />
<Popover>
{({ open }) => (
<>
<Popover.Button as={"span"}>
<Button
className={`text-sm h-11 px-4 ${InputIcon ? "h-11" : "h-10"}`}
size="custom"
rounded="full"
variant={open ? "secondary" : "white"}
>
{InputIcon && (
<InputIcon className="w-7 mr-1 h-auto fill-current text-blue-500" />
)}
{inputLabel}
{!InputIcon && (
<BiChevronRight className="w-5 h-auto fill-current opacity-70 ml-1" />
)}
</Button>
</Popover.Button>
<div
className="absolute w-full min-w-[192px] max-w-2xl -bottom-2 left-0 translate-y-full"
style={{ zIndex: 1000 }}
>
<Transition
enter="transition duration-150 ease-out"
enterFrom="transform opacity-0 -translate-y-2"
enterTo="transform opacity-100 translate-y-0"
leave="transition duration-75 ease-in"
leaveFrom="transform opacity-100 translate-y-0"
leaveTo="transform opacity-0 -translate-y-2"
>
<Popover.Panel className="relative overflow-hidden rounded-lg shadow-lg bg-white border border-gray-150 z-50">
{({ close }) => (
<div className="max-h-[24rem] flex flex-col w-full h-full">
<div className="bg-gray-50 p-2 border-b border-gray-100 z-10 shadow-sm">
<input
type="text"
className="bg-white text-sm rounded-sm border border-gray-100 shadow-inner py-1.5 px-2.5 w-full block placeholder-gray-200"
onClick={(event: any) => {
event.stopPropagation();
event.preventDefault();
}}
value={filter}
onChange={(event: any) => {
setFilter(event.target.value);
}}
placeholder="Filter..."
/>
</div>
{filteredBlocks.length === 0 && (
<span className="relative text-center text-xs px-2 py-3 text-gray-300 bg-gray-50 italic">
return (
<div className="relative z-[1000]">
<input type="text" id={ input.name } className="hidden" { ...input } />
<Popover>
{ ({ open }) => (
<>
<Popover.Button as={ "span" }>
<Button
className={ `text-sm h-11 px-4 ${ InputIcon ? "h-11" : "h-10" }` }
size="custom"
rounded="full"
variant={ open ? "secondary" : "white" }
>
{ InputIcon && (
<InputIcon className="w-7 mr-1 h-auto fill-current text-blue-500" />
) }
{ inputLabel }
{ !InputIcon && (
<BiChevronRight className="w-5 h-auto fill-current opacity-70 ml-1" />
) }
</Button>
</Popover.Button>
<div
className="absolute w-full min-w-[192px] max-w-2xl -bottom-2 left-0 translate-y-full"
style={ { zIndex: 1000 } }
>
<Transition
enter="transition duration-150 ease-out"
enterFrom="transform opacity-0 -translate-y-2"
enterTo="transform opacity-100 translate-y-0"
leave="transition duration-75 ease-in"
leaveFrom="transform opacity-100 translate-y-0"
leaveTo="transform opacity-0 -translate-y-2"
>
<Popover.Panel className="relative overflow-hidden rounded-lg shadow-lg bg-white border border-gray-150 z-50">
{ ({ close }) => (
<div className="max-h-[24rem] flex flex-col w-full h-full">
<div className="bg-gray-50 p-2 border-b border-gray-100 z-10 shadow-sm">
<input
type="text"
className="bg-white text-sm rounded-sm border border-gray-100 shadow-inner py-1.5 px-2.5 w-full block placeholder-gray-200"
onClick={ (event: any) => {
event.stopPropagation();
event.preventDefault();
} }
value={ filter }
onChange={ (event: any) => {
setFilter(event.target.value);
} }
placeholder="Filter..."
/>
</div>
{ filteredBlocks.length === 0 && (
<span className="relative text-center text-xs px-2 py-3 text-gray-300 bg-gray-50 italic">
No matches found
</span>
)}
{filteredBlocks.length > 0 && (
<div className="w-full grid grid-cols-6 auto-rows-auto p-2 overflow-y-auto">
<button
className="relative rounded-lg text-center text-xs py-2 px-3 flex-1 outline-none transition-all ease-out duration-150 hover:text-blue-500 focus:text-blue-500 focus:bg-gray-50 hover:bg-gray-50"
key={"clear-input"}
onClick={() => {
input.onChange("");
setFilter("");
close();
}}
>
<GoCircleSlash className="w-6 h-auto text-gray-200" />
</button>
{filteredBlocks.map((name) => {
return (
<button
className="relative flex items-center justify-center rounded-lg text-center text-xs py-2 px-3 flex-1 outline-none transition-all ease-out duration-150 hover:text-blue-500 focus:text-blue-500 focus:bg-gray-50 hover:bg-gray-50"
key={name}
onClick={() => {
input.onChange(name);
setFilter("");
close();
}}
>
<Icon
data={{
name: name,
size: "custom",
color: "blue",
}}
className="w-7 h-auto"
/>
</button>
);
})}
</span>
) }
{ filteredBlocks.length > 0 && (
<div className="w-full grid grid-cols-6 auto-rows-auto p-2 overflow-y-auto">
<button
className="relative rounded-lg text-center text-xs py-2 px-3 flex-1 outline-none transition-all ease-out duration-150 hover:text-blue-500 focus:text-blue-500 focus:bg-gray-50 hover:bg-gray-50"
key={ "clear-input" }
onClick={ () => {
input.onChange("");
setFilter("");
close();
} }
>
<GoCircleSlash className="w-6 h-auto text-gray-200" />
</button>
{ filteredBlocks.map((name) => {
return (
<button
className="relative flex items-center justify-center rounded-lg text-center text-xs py-2 px-3 flex-1 outline-none transition-all ease-out duration-150 hover:text-blue-500 focus:text-blue-500 focus:bg-gray-50 hover:bg-gray-50"
key={ name }
onClick={ () => {
input.onChange(name);
setFilter("");
close();
} }
>
<Icon
data={ {
name: name,
size: "custom",
color: "blue"
} }
className="w-7 h-auto"
/>
</button>
);
}) }
</div>
) }
</div>
) }
</Popover.Panel>
</Transition>
</div>
)}
</div>
)}
</Popover.Panel>
</Transition>
</div>
</>
)}
</Popover>
</div>
);
</>
) }
</Popover>
</div>
);
});