openpanel/documentation/src/refine-theme/template-detail.tsx
2024-06-08 12:02:50 +02:00

454 lines
19 KiB
TypeScript

import React, { FC, PropsWithChildren, SVGProps } from "react";
import clsx from "clsx";
import Link from "@docusaurus/Link";
import { CommonLayout } from "@site/src/refine-theme/common-layout";
import { CommonHeader } from "@site/src/refine-theme/common-header";
import { LandingFooter } from "@site/src/refine-theme/landing-footer";
import { CommonCircleChevronRight } from "./common-circle-chevron-right";
import { ShareIcon } from "./icons/share";
import * as Icons from "@site/src/assets/integration-icons";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import remarkRehype from "remark-rehype";
import { CommonRunLocalPrompt } from "./common-run-local-prompt";
import { GithubIcon } from "./icons/github";
import { TutorialIcon } from "./icons/tutorial";
type Props = {
data: {
slug: string;
title: string;
description: string;
images: string[];
runOnYourLocalPath: string;
liveDemo: string;
github: string;
tutorial: string;
reactPlatform: string;
uiFramework: string;
dataProvider: string;
authProvider: string;
};
};
export const TemplatesDetail: FC<Props> = ({ data }) => {
return (
<CommonLayout description="Host websites and manage users with unmatched flexibility.">
<div>
<CommonHeader />
<div
className={clsx(
"w-full max-w-[592px] landing-sm:max-w-[656px] landing-md:max-w-[896px] landing-lg:max-w-[1200px]",
"px-4 landing-sm:px-0",
"mx-auto",
"flex flex-col",
"not-prose",
"mt-8 landing-lg:mt-20",
"px-6 landing-sm:px-0",
"pb-8 landing-sm:pb-12 landing-md:pb-16 landing-lg:pb-40",
)}
>
<div>
<h1
className={clsx(
"dark:text-gray-0 text-gray-900",
"text-4xl landing-sm:text-[56px] landing-sm:leading-[72px]",
"font-bold",
"px-0 landing-sm:px-8 landing-md:px-10",
"mt-6",
)}
>
{data.title}
</h1>
</div>
<div
className={clsx(
"flex",
"mt-8 landing-sm:mt-12 landing-md:mt-16",
"rounded-lg landing-md:rounded-xl landing-lg:rounded-3xl",
"-mx-4 landing-sm:-mx-0",
"landing-sm:px-4",
"aspect-[1485/736]",
)}
>
<img
className={clsx(
"rounded-lg landing-md:rounded-xl landing-lg:rounded-3xl",
"block",
"aspect-[1485/736]",
)}
src={data.images[0]}
alt={data.title}
/>
</div>
<div
className={clsx(
"flex",
"items-start",
"gap-6",
"mt-8 landing-sm:mt-12 landing-md:mt-16",
"px-0 landing-sm:pl-10 landing-md:pl-14 landing-lg:pl-10",
"px-0 landing-sm:pr-10 landing-md:pr-10 landing-lg:pr-10",
"not-prose",
)}
>
<div
className={clsx(
"max-w-full",
"flex",
"flex-col",
"gap-8 landing-sm:gap-10",
)}
>
<div
className={clsx(
"flex",
"flex-wrap",
"items-center",
"gap-4 landing-md:gap-6",
"landing-lg:pl-4",
)}
>
{data.liveDemo && (
<ProjectLink to={data.liveDemo}>
<ShareIcon width={16} height={16} />
<span
className={clsx(
"font-semibold",
"text-xs landing-md:text-base",
)}
>
Live demo
</span>
</ProjectLink>
)}
{data.tutorial && (
<ProjectLink to={data.tutorial}>
<TutorialIcon width={16} height={16} />
<span
className={clsx(
"font-semibold",
"text-xs landing-md:text-base",
)}
>
Purchase License
</span>
</ProjectLink>
)}
{data.github && (
<ProjectLink to={data.github}>
<GithubIcon width={16} height={16} />
<span
className={clsx(
"font-semibold",
"text-xs landing-md:text-base",
)}
>
Contribute on GitHub
</span>
</ProjectLink>
)}
</div>
<Integrations
svgId="mobile"
className={clsx(
"grid landing-md:hidden",
"grid-cols-2 sm:grid-cols-4",
"gap-6",
"flex-shrink-0",
)}
reactPlatform={data.reactPlatform}
uiFramework={data.uiFramework}
dataProvider={data.dataProvider}
authProvider={data.authProvider}
/>
<div
className={clsx(
"flex",
"flex-col",
"landing-lg:pl-4 landing-lg:pr-6",
)}
>
{data.runOnYourLocalPath && (
<div className={clsx("mb-2 landing-sm:mb-4")}>
<CommonRunLocalPrompt
path={data.runOnYourLocalPath}
/>
</div>
)}
<div className={clsx("not-prose")}>
<h2
className={clsx(
"text-xl landing-sm:text-2xl",
"dark:text-gray-0 text-gray-900",
"font-semibold",
)}
>
Description
</h2>
</div>
<ReactMarkdown
className={clsx(
"mt-4 landing-sm:gap-6",
"whitespace-pre-wrap",
"not-prose",
"dark:!text-gray-200 !text-gray-900",
"template-detail-markdown",
)}
remarkPlugins={[remarkGfm, remarkRehype]}
>
{data.description}
</ReactMarkdown>
</div>
</div>
<Integrations
svgId="desktop"
className={clsx(
"hidden landing-md:grid",
"grid-cols-1 landing-lg:grid-cols-2",
"landing-md:gap-10",
"pl-0 landing-lg:pl-10",
"landing-md:ml-6 landing-lg:ml-0",
"flex-shrink-0",
"justify-self-end",
)}
reactPlatform={data.reactPlatform}
uiFramework={data.uiFramework}
dataProvider={data.dataProvider}
authProvider={data.authProvider}
/>
</div>
</div>
</div>
<LandingFooter />
</CommonLayout>
);
};
const ProjectLink: FC<PropsWithChildren<{ to: string }>> = ({
to,
children,
}) => {
return (
<Link
to={to}
target="_blank"
rel="noopener noreferrer"
className={clsx(
"select-none",
"group/project-link-button",
"relative",
"w-max",
"flex",
"items-center",
"gap-1 landing-md:gap-2",
"pl-2 py-2 pr-3",
"landing-md:pl-3 landing-md:py-3 landing-md:pr-6",
"rounded-full",
"dark:bg-refine-cyan-alt/10 bg-refine-blue/10",
"dark:text-refine-cyan-alt text-refine-blue",
"hover:no-underline",
"overflow-hidden",
)}
>
{children}
<div
className={clsx(
"select-none",
"rounded-3xl",
"absolute",
"left-0",
"top-0",
"w-full",
"h-full",
"scale-[2]",
"origin-center",
"transition-[opacity,transform]",
"duration-300",
"ease-in-out",
"opacity-0",
"group-hover/project-link-button:opacity-100",
"group-hover/project-link-button:scale-100",
"pointer-events-none",
"bg-landing-copy-command-hover-bg-light dark:bg-landing-copy-command-hover-bg-dark",
)}
/>
</Link>
);
};
const Integrations = (props: {
className?: string;
svgId?: string;
reactPlatform: string;
uiFramework: string;
dataProvider: string;
authProvider: string;
}) => {
const {
reactPlatform,
uiFramework,
dataProvider,
authProvider,
className,
} = props;
return (
<div className={clsx(className)}>
<IntegrationBadge
svgId={props.svgId + "-react"}
label="Features"
integration={reactPlatform}
/>
<IntegrationBadge
svgId={props.svgId + "-ui"}
label="Limits"
integration={uiFramework}
/>
<IntegrationBadge
svgId={props.svgId + "-data"}
label="Integrations"
integration={dataProvider}
/>
<IntegrationBadge
svgId={props.svgId + "-auth"}
label="Support"
integration={authProvider}
/>
</div>
);
};
const IntegrationBadge = (props: {
svgId: string;
label: string;
integration: string;
}) => {
const Icon = integrationToIconMap?.[props.integration] || (() => null);
return (
<div className={clsx("flex", "flex-col", "gap-3", "not-prose")}>
<h6 className={clsx("text-xs", "dark:text-gray-400 text-gray-600")}>
{props.label}
</h6>
<div
className={clsx(
"flex",
"items-center",
"h-8",
"pl-2 pr-4",
"gap-2",
"rounded-full",
"border dark:border-gray-700 border-gray-200",
"w-min",
)}
>
<Icon id={props.svgId} width={16} height={16} />
<span
className={clsx(
"text-sm",
"whitespace-nowrap",
"dark:text-gray-400 text-gray-900",
)}
>
{props.integration}
</span>
</div>
</div>
);
};
const integrationToIconMap = {
Ably: (props: SVGProps<SVGSVGElement>) => <Icons.Ably {...props} />,
Airtable: (props: SVGProps<SVGSVGElement>) => <Icons.Airtable {...props} />,
"Ant Design": (props: SVGProps<SVGSVGElement>) => <Icons.Antd {...props} />,
Appwrite: (props: SVGProps<SVGSVGElement>) => <Icons.Appwrite {...props} />,
"Chakra UI": (props: SVGProps<SVGSVGElement>) => (
<Icons.Chakra {...props} />
),
Directus: (props: SVGProps<SVGSVGElement>) => <Icons.Directus {...props} />,
Dp: (props: SVGProps<SVGSVGElement>) => <Icons.Dp {...props} />,
Elide: (props: SVGProps<SVGSVGElement>) => <Icons.Elide {...props} />,
ElideGraphql: (props: SVGProps<SVGSVGElement>) => (
<Icons.ElideGraphql {...props} />
),
EntRefine: (props: SVGProps<SVGSVGElement>) => (
<Icons.EntRefine {...props} />
),
Firebase: (props: SVGProps<SVGSVGElement>) => <Icons.Firebase {...props} />,
GraphQL: (props: SVGProps<SVGSVGElement>) => <Icons.Graphql {...props} />,
Hasura: (props: SVGProps<SVGSVGElement>) => <Icons.Hasura {...props} />,
Headless: (props: SVGProps<SVGSVGElement>) => <Icons.Headless {...props} />,
"React Hook Form": (props: SVGProps<SVGSVGElement>) => (
<Icons.HookForm {...props} />
),
Hygraph: (props: SVGProps<SVGSVGElement>) => <Icons.Hygraph {...props} />,
JSONApi: (props: SVGProps<SVGSVGElement>) => <Icons.JSONApi {...props} />,
Kbar: (props: SVGProps<SVGSVGElement>) => <Icons.Kbar {...props} />,
Kinde: (props: SVGProps<SVGSVGElement>) => <Icons.Kinde {...props} />,
Mantine: (props: SVGProps<SVGSVGElement>) => <Icons.Mantine {...props} />,
Medusa: (props: SVGProps<SVGSVGElement>) => <Icons.Medusa {...props} />,
"Material UI": (props: SVGProps<SVGSVGElement>) => <Icons.Mui {...props} />,
Nest: (props: SVGProps<SVGSVGElement>) => <Icons.Nest {...props} />,
"NestJsX CRUD": (props: SVGProps<SVGSVGElement>) => (
<Icons.Nest {...props} />
),
NestQuery: (props: SVGProps<SVGSVGElement>) => (
<Icons.NestQuery {...props} />
),
"Next.js": (props: SVGProps<SVGSVGElement>) => <Icons.Nextjs {...props} />,
React: (props: SVGProps<SVGSVGElement>) => <Icons.React {...props} />,
Remix: (props: SVGProps<SVGSVGElement>) => <Icons.Remix {...props} />,
"Rest API": (props: SVGProps<SVGSVGElement>) => (
<Icons.RestWithoutText {...props} />
),
Sanity: (props: SVGProps<SVGSVGElement>) => <Icons.Sanity {...props} />,
"ShadCN UI": (props: SVGProps<SVGSVGElement>) => (
<Icons.ShadCnUI {...props} />
),
SQLite: (props: SVGProps<SVGSVGElement>) => <Icons.SQLite {...props} />,
Strapi: (props: SVGProps<SVGSVGElement>) => <Icons.Strapi {...props} />,
Supabase: (props: SVGProps<SVGSVGElement>) => <Icons.Supabase {...props} />,
TailwindCSS: (props: SVGProps<SVGSVGElement>) => (
<Icons.TailwindCss {...props} />
),
UseGenerated: (props: SVGProps<SVGSVGElement>) => (
<Icons.UseGenerated {...props} />
),
SlackIcon: (props: SVGProps<SVGSVGElement>) => (
<Icons.SlackIcon {...props} />
),
Atlassian: (props: SVGProps<SVGSVGElement>) => (
<Icons.Atlassian {...props} />
),
AuthJs: (props: SVGProps<SVGSVGElement>) => <Icons.AuthJs {...props} />,
Auth0: (props: SVGProps<SVGSVGElement>) => <Icons.Auth0 {...props} />,
AwsCognito: (props: SVGProps<SVGSVGElement>) => (
<Icons.AwsCognito {...props} />
),
AzureActiveDirectory: (props: SVGProps<SVGSVGElement>) => (
<Icons.AzureActiveDirectory {...props} />
),
Clerk: (props: SVGProps<SVGSVGElement>) => <Icons.Clerk {...props} />,
Expo: (props: SVGProps<SVGSVGElement>) => <Icons.Expo {...props} />,
Google: (props: SVGProps<SVGSVGElement>) => <Icons.Google {...props} />,
Okta: (props: SVGProps<SVGSVGElement>) => <Icons.Okta {...props} />,
MongoDB: (props: SVGProps<SVGSVGElement>) => <Icons.MongoDB {...props} />,
MsSqlServer: (props: SVGProps<SVGSVGElement>) => (
<Icons.MsSqlServer {...props} />
),
MySql: (props: SVGProps<SVGSVGElement>) => <Icons.MySql {...props} />,
PostgreSql: (props: SVGProps<SVGSVGElement>) => (
<Icons.PostgreSql {...props} />
),
Oracle: (props: SVGProps<SVGSVGElement>) => <Icons.Oracle {...props} />,
Custom: (props: SVGProps<SVGSVGElement>) => <Icons.CustomAuth {...props} />,
Vite: (props: SVGProps<SVGSVGElement>) => <Icons.Vite {...props} />,
"Nestjs-query": (props: SVGProps<SVGSVGElement>) => (
<Icons.Graphql {...props} />
),
};
export type Integration = keyof typeof integrationToIconMap;