<Button>-component (#480)

-`<Button/>` component
- Uses `next/link` + `<a/>` if you supply a `href` otherwise `<button/>`
- Add UI sandbox
- Change the `event-types/index` to use a query param for deciding if modal is open or not
This commit is contained in:
Alex Johansson 2021-08-23 14:45:25 +02:00 committed by GitHub
parent ce64080160
commit a77a15056a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 251 additions and 83 deletions

View file

@ -1,32 +1,37 @@
import React from "react"; import React from "react";
import * as DialogPrimitive from "@radix-ui/react-dialog"; import * as DialogPrimitive from "@radix-ui/react-dialog";
export function Dialog({ children, ...props }) { type DialogProps = React.ComponentProps<typeof DialogPrimitive["Root"]>;
export function Dialog(props: DialogProps) {
const { children, ...other } = props;
return ( return (
<DialogPrimitive.Root {...props}> <DialogPrimitive.Root {...other}>
<DialogPrimitive.Overlay className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" /> <DialogPrimitive.Overlay className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
{children} {children}
</DialogPrimitive.Root> </DialogPrimitive.Root>
); );
} }
type DialogContentProps = React.ComponentProps<typeof DialogPrimitive["Content"]>;
export const DialogContent = React.forwardRef(({ children, ...props }, forwardedRef) => ( export const DialogContent = React.forwardRef<HTMLDivElement, DialogContentProps>(
<DialogPrimitive.Content ({ children, ...props }, forwardedRef) => (
{...props} <DialogPrimitive.Content
className="fixed bg-white min-w-[360px] rounded top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 text-left overflow-hidden shadow-xl sm:align-middle sm:max-w-lg sm:w-full p-6" {...props}
ref={forwardedRef}> className="min-w-[360px] fixed left-1/2 top-1/2 p-6 text-left bg-white rounded shadow-xl overflow-hidden -translate-x-1/2 -translate-y-1/2 sm:align-middle sm:w-full sm:max-w-lg"
{children} ref={forwardedRef}>
</DialogPrimitive.Content> {children}
)); </DialogPrimitive.Content>
)
);
export function DialogHeader({ title, subtitle }: { title: string; subtitle: string }) { export function DialogHeader({ title, subtitle }: { title: string; subtitle: string }) {
return ( return (
<div className="mb-8"> <div className="mb-8">
<h3 className="text-lg leading-6 font-bold text-gray-900" id="modal-title"> <h3 className="text-gray-900 text-lg font-bold leading-6" id="modal-title">
{title} {title}
</h3> </h3>
<div> <div>
<p className="text-sm text-gray-400">{subtitle}</p> <p className="text-gray-400 text-sm">{subtitle}</p>
</div> </div>
</div> </div>
); );

View file

@ -1,26 +1,111 @@
export default function Button(props) { import classNames from "@lib/classNames";
return ( import Link, { LinkProps } from "next/link";
<button type="submit" className="btn btn-primary dark:btn-white"> import React from "react";
{!props.loading && props.children}
{props.loading && ( type HTMLAnchorProps = React.AnchorHTMLAttributes<HTMLAnchorElement>;
<svg type HTMLButtonProps = React.ButtonHTMLAttributes<HTMLButtonProps>;
className="animate-spin mx-4 h-5 w-5 text-white"
xmlns="http://www.w3.org/2000/svg" type SVGComponent = React.FunctionComponent<React.SVGProps<SVGSVGElement>>;
fill="none"
viewBox="0 0 24 24"> export type ButtonProps = {
<circle color?: "primary" | "secondary" | "minimal";
className="opacity-25" size?: "base" | "sm" | "lg";
cx="12" loading?: boolean;
cy="12" disabled?: boolean;
r="10" onClick?: (event: React.MouseEvent<HTMLElement, MouseEvent>) => void;
stroke="currentColor" StartIcon?: SVGComponent;
strokeWidth="4"></circle> EndIcon?: SVGComponent;
<path } & ((Omit<HTMLAnchorProps, "href"> & { href: LinkProps["href"] }) | (HTMLButtonProps & { href?: never }));
className="opacity-75"
fill="currentColor" export const Button = function Button(props: ButtonProps) {
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> const {
</svg> loading = false,
color = "primary",
size = "base",
StartIcon,
EndIcon,
// attributes propagated from `HTMLAnchorProps` or `HTMLButtonProps`
...passThroughProps
} = props;
// Buttons are **always** disabled if we're in a `loading` state
const disabled = props.disabled || loading;
// If pass an `href`-attr is passed it's `<a>`, otherwise it's a `<button />`
const isLink = typeof props.href !== "undefined";
const elementType = isLink ? "a" : "button";
const element = React.createElement(
elementType,
{
...passThroughProps,
disabled,
className: classNames(
// base styles independent what type of button it is
"inline-flex items-center relative",
// different styles depending on size
size === "sm" && "px-3 py-2 text-sm leading-4 font-medium rounded-sm",
size === "base" && "px-3 py-2 text-sm font-medium rounded-sm",
size === "lg" && "px-4 py-2 text-base font-medium rounded-sm",
// different styles depending on color
color === "primary" &&
(disabled
? "border border-transparent bg-gray-400 text-white"
: "border border-transparent text-white bg-neutral-900 hover:bg-neutral-800 hover:shadow-md focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-neutral-900"),
color === "secondary" &&
(disabled
? "border border-gray-200 text-gray-400 bg-white"
: "border border-gray-300 text-gray-700 bg-white hover:bg-gray-50 hover:text-gray-900 hover:shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-neutral-900"),
color === "minimal" &&
(disabled
? "text-gray-400 bg-transparent"
: "text-gray-700 bg-transparent hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:bg-gray-100 focus:ring-neutral-500"),
// set not-allowed cursor if disabled
disabled && "cursor-not-allowed",
props.className
),
// if we click a disabled button, we prevent going through the click handler
onClick: disabled
? (e: React.MouseEvent<HTMLElement, MouseEvent>) => {
e.preventDefault();
}
: props.onClick,
},
<>
{StartIcon && <StartIcon className="inline w-5 h-5 mr-2 -ml-1" />}
{props.children}
{loading && (
<div className="absolute transform -translate-x-1/2 -translate-y-1/2 top-1/2 left-1/2">
<svg
className={classNames(
"w-5 h-5 mx-4 animate-spin",
color === "primary" ? "text-white" : "text-black"
)}
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24">
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"></circle>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
</div>
)} )}
</button> {EndIcon && <EndIcon className="inline w-5 h-5 ml-2 -mr-1" />}
</>
); );
} return props.href ? (
<Link passHref href={props.href}>
{element}
</Link>
) : (
element
);
};

View file

@ -1,3 +1,3 @@
export default function classNames(...classes) { export default function classNames(...classes: unknown[]) {
return classes.filter(Boolean).join(" "); return classes.filter(Boolean).join(" ");
} }

View file

@ -40,7 +40,7 @@
"lodash.debounce": "^4.0.8", "lodash.debounce": "^4.0.8",
"lodash.merge": "^4.6.2", "lodash.merge": "^4.6.2",
"lodash.throttle": "^4.1.1", "lodash.throttle": "^4.1.1",
"next": "^10.2.0", "next": "^10.2.3",
"next-auth": "^3.28.0", "next-auth": "^3.28.0",
"next-transpile-modules": "^8.0.0", "next-transpile-modules": "^8.0.0",
"nodemailer": "^6.6.3", "nodemailer": "^6.6.3",

View file

@ -1,6 +1,7 @@
import { Dialog, DialogClose, DialogContent, DialogTrigger } from "@components/Dialog"; import { Dialog, DialogClose, DialogContent } from "@components/Dialog";
import { Tooltip } from "@components/Tooltip";
import Loader from "@components/Loader"; import Loader from "@components/Loader";
import { Tooltip } from "@components/Tooltip";
import { Button } from "@components/ui/Button";
import { Menu, Transition } from "@headlessui/react"; import { Menu, Transition } from "@headlessui/react";
import { import {
ClockIcon, ClockIcon,
@ -12,6 +13,7 @@ import {
UserIcon, UserIcon,
} from "@heroicons/react/solid"; } from "@heroicons/react/solid";
import classNames from "@lib/classNames"; import classNames from "@lib/classNames";
import showToast from "@lib/notification";
import { getSession, useSession } from "next-auth/client"; import { getSession, useSession } from "next-auth/client";
import Head from "next/head"; import Head from "next/head";
import Link from "next/link"; import Link from "next/link";
@ -19,7 +21,6 @@ import { useRouter } from "next/router";
import React, { Fragment, useRef } from "react"; import React, { Fragment, useRef } from "react";
import Shell from "../../components/Shell"; import Shell from "../../components/Shell";
import prisma from "../../lib/prisma"; import prisma from "../../lib/prisma";
import showToast from "@lib/notification";
export default function Availability({ user, types }) { export default function Availability({ user, types }) {
const [session, loading] = useSession(); const [session, loading] = useSession();
@ -30,6 +31,8 @@ export default function Availability({ user, types }) {
const descriptionRef = useRef<HTMLTextAreaElement>(); const descriptionRef = useRef<HTMLTextAreaElement>();
const lengthRef = useRef<HTMLInputElement>(); const lengthRef = useRef<HTMLInputElement>();
const dialogOpen = router.query.new === "1";
async function createEventTypeHandler(event) { async function createEventTypeHandler(event) {
event.preventDefault(); event.preventDefault();
@ -69,14 +72,23 @@ export default function Availability({ user, types }) {
} }
const CreateNewEventDialog = () => ( const CreateNewEventDialog = () => (
<Dialog> <Dialog
<DialogTrigger className="py-2 px-4 mt-6 border border-transparent rounded-sm shadow-sm text-sm font-medium text-white bg-neutral-900 hover:bg-neutral-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900"> open={dialogOpen}
<PlusIcon className="w-5 h-5 mr-1 inline" /> onOpenChange={(isOpen) => {
const newQuery = {
...router.query,
};
delete newQuery["new"];
if (!isOpen) {
router.push({ pathname: router.pathname, query: newQuery });
}
}}>
<Button className="mt-2" StartIcon={PlusIcon} href={{ query: { ...router.query, new: "1" } }}>
New event type New event type
</DialogTrigger> </Button>
<DialogContent> <DialogContent>
<div className="mb-8"> <div className="mb-8">
<h3 className="text-lg leading-6 font-bold text-gray-900" id="modal-title"> <h3 className="text-lg font-bold leading-6 text-gray-900" id="modal-title">
Add a new event type Add a new event type
</h3> </h3>
<div> <div>
@ -97,7 +109,7 @@ export default function Availability({ user, types }) {
name="title" name="title"
id="title" id="title"
required required
className="shadow-sm focus:ring-neutral-900 focus:border-neutral-900 block w-full sm:text-sm border-gray-300 rounded-sm" className="block w-full border-gray-300 rounded-sm shadow-sm focus:border-neutral-900 focus:ring-neutral-900 sm:text-sm"
placeholder="Quick Chat" placeholder="Quick Chat"
/> />
</div> </div>
@ -108,7 +120,7 @@ export default function Availability({ user, types }) {
</label> </label>
<div className="mt-1"> <div className="mt-1">
<div className="flex rounded-sm shadow-sm"> <div className="flex rounded-sm shadow-sm">
<span className="inline-flex items-center px-3 rounded-l-md border border-r-0 border-gray-300 bg-gray-50 text-gray-500 sm:text-sm"> <span className="inline-flex items-center px-3 text-gray-500 border border-r-0 border-gray-300 bg-gray-50 rounded-l-md sm:text-sm">
{location.hostname}/{user.username}/ {location.hostname}/{user.username}/
</span> </span>
<input <input
@ -117,7 +129,7 @@ export default function Availability({ user, types }) {
name="slug" name="slug"
id="slug" id="slug"
required required
className="flex-1 block w-full focus:ring-neutral-900 focus:border-neutral-900 min-w-0 rounded-none rounded-r-md sm:text-sm border-gray-300" className="flex-1 block w-full min-w-0 border-gray-300 rounded-none focus:border-neutral-900 rounded-r-md focus:ring-neutral-900 sm:text-sm"
/> />
</div> </div>
</div> </div>
@ -131,7 +143,7 @@ export default function Availability({ user, types }) {
ref={descriptionRef} ref={descriptionRef}
name="description" name="description"
id="description" id="description"
className="shadow-sm focus:ring-neutral-900 focus:border-neutral-900 block w-full sm:text-sm border-gray-300 rounded-sm" className="block w-full border-gray-300 rounded-sm shadow-sm focus:border-neutral-900 focus:ring-neutral-900 sm:text-sm"
placeholder="A quick video meeting."></textarea> placeholder="A quick video meeting."></textarea>
</div> </div>
</div> </div>
@ -139,17 +151,17 @@ export default function Availability({ user, types }) {
<label htmlFor="length" className="block text-sm font-medium text-gray-700"> <label htmlFor="length" className="block text-sm font-medium text-gray-700">
Length Length
</label> </label>
<div className="mt-1 relative rounded-sm shadow-sm"> <div className="relative mt-1 rounded-sm shadow-sm">
<input <input
ref={lengthRef} ref={lengthRef}
type="number" type="number"
name="length" name="length"
id="length" id="length"
required required
className="focus:ring-neutral-900 focus:border-neutral-900 block w-full pr-20 sm:text-sm border-gray-300 rounded-sm" className="block w-full pr-20 border-gray-300 rounded-sm focus:border-neutral-900 focus:ring-neutral-900 sm:text-sm"
placeholder="15" placeholder="15"
/> />
<div className="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 text-sm"> <div className="absolute inset-y-0 right-0 flex items-center pr-3 text-sm text-gray-400">
minutes minutes
</div> </div>
</div> </div>
@ -159,7 +171,7 @@ export default function Availability({ user, types }) {
<button type="submit" className="btn btn-primary"> <button type="submit" className="btn btn-primary">
Continue Continue
</button> </button>
<DialogClose as="button" className="btn btn-white mx-2"> <DialogClose as="button" className="mx-2 btn btn-white">
Cancel Cancel
</DialogClose> </DialogClose>
</div> </div>
@ -178,44 +190,44 @@ export default function Availability({ user, types }) {
heading="Event Types" heading="Event Types"
subtitle="Create events to share for people to book on your calendar." subtitle="Create events to share for people to book on your calendar."
CTA={types.length !== 0 && <CreateNewEventDialog />}> CTA={types.length !== 0 && <CreateNewEventDialog />}>
<div className="bg-white border border-gray-200 rounded-sm overflow-hidden -mx-4 sm:mx-0"> <div className="-mx-4 overflow-hidden bg-white border border-gray-200 rounded-sm sm:mx-0">
<ul className="divide-y divide-neutral-200"> <ul className="divide-y divide-neutral-200">
{types.map((type) => ( {types.map((type) => (
<li key={type.id}> <li key={type.id}>
<div className="hover:bg-neutral-50"> <div className="hover:bg-neutral-50">
<div className="px-4 py-4 flex items-center sm:px-6"> <div className="flex items-center px-4 py-4 sm:px-6">
<Link href={"/event-types/" + type.id}> <Link href={"/event-types/" + type.id}>
<a className="min-w-0 flex-1 sm:flex sm:items-center sm:justify-between"> <a className="flex-1 min-w-0 sm:flex sm:items-center sm:justify-between">
<span className="truncate "> <span className="truncate">
<div className="flex text-sm"> <div className="flex text-sm">
<p className="font-medium text-neutral-900 truncate">{type.title}</p> <p className="font-medium truncate text-neutral-900">{type.title}</p>
{type.hidden && ( {type.hidden && (
<span className="ml-2 inline-flex items-center px-1.5 py-0.5 rounded-sm text-xs font-medium bg-yellow-100 text-yellow-800"> <span className="inline-flex items-center ml-2 px-1.5 py-0.5 text-yellow-800 text-xs font-medium bg-yellow-100 rounded-sm">
Hidden Hidden
</span> </span>
)} )}
</div> </div>
<div className="mt-2 flex space-x-4"> <div className="flex mt-2 space-x-4">
<div className="flex items-center text-sm text-neutral-500"> <div className="flex items-center text-sm text-neutral-500">
<ClockIcon <ClockIcon
className="flex-shrink-0 mr-1.5 h-4 w-4 text-neutral-400" className="flex-shrink-0 mr-1.5 w-4 h-4 text-neutral-400"
aria-hidden="true" aria-hidden="true"
/> />
<p>{type.length}m</p> <p>{type.length}m</p>
</div> </div>
<div className="flex items-center text-sm text-neutral-500"> <div className="flex items-center text-sm text-neutral-500">
<UserIcon <UserIcon
className="flex-shrink-0 mr-1.5 h-4 w-4 text-neutral-400" className="flex-shrink-0 mr-1.5 w-4 h-4 text-neutral-400"
aria-hidden="true" aria-hidden="true"
/> />
<p>1-on-1</p> <p>1-on-1</p>
</div> </div>
<div className="flex items-center text-sm text-neutral-500"> <div className="flex items-center text-sm text-neutral-500">
<InformationCircleIcon <InformationCircleIcon
className="flex-shrink-0 mr-1.5 h-4 w-4 text-neutral-400" className="flex-shrink-0 mr-1.5 w-4 h-4 text-neutral-400"
aria-hidden="true" aria-hidden="true"
/> />
<div className="max-w-32 sm:max-w-full truncate"> <div className="truncate max-w-32 sm:max-w-full">
{type.description.substring(0, 100)} {type.description.substring(0, 100)}
</div> </div>
</div> </div>
@ -224,15 +236,15 @@ export default function Availability({ user, types }) {
</a> </a>
</Link> </Link>
<div className="hidden sm:flex mt-4 flex-shrink-0 sm:mt-0 sm:ml-5"> <div className="flex-shrink-0 hidden mt-4 sm:flex sm:ml-5 sm:mt-0">
<div className="flex overflow-hidden space-x-5"> <div className="flex space-x-5 overflow-hidden">
<Tooltip content="Preview"> <Tooltip content="Preview">
<a <a
href={"/" + session.user.username + "/" + type.slug} href={"/" + session.user.username + "/" + type.slug}
target="_blank" target="_blank"
rel="noreferrer" rel="noreferrer"
className="group cursor-pointer text-neutral-400 p-2 border border-transparent hover:border-gray-200"> className="p-2 border border-transparent cursor-pointer group text-neutral-400 hover:border-gray-200">
<ExternalLinkIcon className="group-hover:text-black w-5 h-5" /> <ExternalLinkIcon className="w-5 h-5 group-hover:text-black" />
</a> </a>
</Tooltip> </Tooltip>
@ -244,20 +256,20 @@ export default function Availability({ user, types }) {
window.location.hostname + "/" + session.user.username + "/" + type.slug window.location.hostname + "/" + session.user.username + "/" + type.slug
); );
}} }}
className="group text-neutral-400 p-2 border border-transparent hover:border-gray-200"> className="p-2 border border-transparent group text-neutral-400 hover:border-gray-200">
<LinkIcon className="group-hover:text-black w-5 h-5" /> <LinkIcon className="w-5 h-5 group-hover:text-black" />
</button> </button>
</Tooltip> </Tooltip>
</div> </div>
</div> </div>
<div className="flex sm:hidden ml-5 flex-shrink-0"> <div className="flex flex-shrink-0 ml-5 sm:hidden">
<Menu as="div" className="inline-block text-left"> <Menu as="div" className="inline-block text-left">
{({ open }) => ( {({ open }) => (
<> <>
<div> <div>
<Menu.Button className="text-neutral-400 mt-1 p-2 border border-transparent hover:border-gray-200"> <Menu.Button className="p-2 mt-1 border border-transparent text-neutral-400 hover:border-gray-200">
<span className="sr-only">Open options</span> <span className="sr-only">Open options</span>
<DotsHorizontalIcon className="h-5 w-5" aria-hidden="true" /> <DotsHorizontalIcon className="w-5 h-5" aria-hidden="true" />
</Menu.Button> </Menu.Button>
</div> </div>
@ -272,7 +284,7 @@ export default function Availability({ user, types }) {
leaveTo="transform opacity-0 scale-95"> leaveTo="transform opacity-0 scale-95">
<Menu.Items <Menu.Items
static static
className="origin-top-right absolute right-0 mt-2 w-56 rounded-sm shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none divide-y divide-neutral-100"> className="absolute right-0 w-56 mt-2 origin-top-right bg-white divide-y rounded-sm shadow-lg focus:outline-none divide-neutral-100 ring-1 ring-black ring-opacity-5">
<div className="py-1"> <div className="py-1">
<Menu.Item> <Menu.Item>
{({ active }) => ( {({ active }) => (
@ -285,7 +297,7 @@ export default function Availability({ user, types }) {
"group flex items-center px-4 py-2 text-sm font-medium" "group flex items-center px-4 py-2 text-sm font-medium"
)}> )}>
<ExternalLinkIcon <ExternalLinkIcon
className="mr-3 h-4 w-4 text-neutral-400 group-hover:text-neutral-500" className="w-4 h-4 mr-3 text-neutral-400 group-hover:text-neutral-500"
aria-hidden="true" aria-hidden="true"
/> />
Preview Preview
@ -307,10 +319,10 @@ export default function Availability({ user, types }) {
}} }}
className={classNames( className={classNames(
active ? "bg-neutral-100 text-neutral-900" : "text-neutral-700", active ? "bg-neutral-100 text-neutral-900" : "text-neutral-700",
"group flex items-center px-4 py-2 text-sm w-full font-medium" "group flex items-center px-4 py-2 w-full text-sm font-medium"
)}> )}>
<LinkIcon <LinkIcon
className="mr-3 h-4 w-4 text-neutral-400 group-hover:text-neutral-500" className="w-4 h-4 mr-3 text-neutral-400 group-hover:text-neutral-500"
aria-hidden="true" aria-hidden="true"
/> />
Copy link to event Copy link to event
@ -326,7 +338,7 @@ export default function Availability({ user, types }) {
{/* "group flex items-center px-4 py-2 text-sm font-medium"*/} {/* "group flex items-center px-4 py-2 text-sm font-medium"*/}
{/* )}>*/} {/* )}>*/}
{/* <DuplicateIcon*/} {/* <DuplicateIcon*/}
{/* className="mr-3 h-4 w-4 text-neutral-400 group-hover:text-neutral-500"*/} {/* className="w-4 h-4 mr-3 text-neutral-400 group-hover:text-neutral-500"*/}
{/* aria-hidden="true"*/} {/* aria-hidden="true"*/}
{/* />*/} {/* />*/}
{/* Duplicate*/} {/* Duplicate*/}
@ -344,7 +356,7 @@ export default function Availability({ user, types }) {
{/* "group flex items-center px-4 py-2 text-sm font-medium"*/} {/* "group flex items-center px-4 py-2 text-sm font-medium"*/}
{/* )}>*/} {/* )}>*/}
{/* <TrashIcon*/} {/* <TrashIcon*/}
{/* className="mr-3 h-5 w-5 text-red-400 group-hover:text-red-700"*/} {/* className="w-5 h-5 mr-3 text-red-400 group-hover:text-red-700"*/}
{/* aria-hidden="true"*/} {/* aria-hidden="true"*/}
{/* />*/} {/* />*/}
{/* Delete*/} {/* Delete*/}
@ -367,7 +379,7 @@ export default function Availability({ user, types }) {
{types.length === 0 && ( {types.length === 0 && (
<div className="md:py-20"> <div className="md:py-20">
<svg <svg
className="w-1/2 md:w-32 mx-auto block mb-4" className="block w-1/2 mx-auto mb-4 md:w-32"
viewBox="0 0 132 132" viewBox="0 0 132 132"
fill="none" fill="none"
xmlns="http://www.w3.org/2000/svg"> xmlns="http://www.w3.org/2000/svg">
@ -604,7 +616,7 @@ export default function Availability({ user, types }) {
</clipPath> </clipPath>
</defs> </defs>
</svg> </svg>
<div className="text-center block md:max-w-screen-sm mx-auto"> <div className="block mx-auto text-center md:max-w-screen-sm">
<h3 className="mt-2 text-xl font-bold text-neutral-900">Create your first event type</h3> <h3 className="mt-2 text-xl font-bold text-neutral-900">Create your first event type</h3>
<p className="mt-1 text-md text-neutral-600"> <p className="mt-1 text-md text-neutral-600">
Event types enable you to share links that show available times on your calendar and allow Event types enable you to share links that show available times on your calendar and allow

66
pages/sandbox/Button.tsx Normal file
View file

@ -0,0 +1,66 @@
import { Button, ButtonProps } from "@components/ui/Button";
import { PlusIcon } from "@heroicons/react/solid";
import Head from "next/head";
import React from "react";
export default function ButtonPage() {
const list: ButtonProps[] = [
// primary
{ color: "primary" },
{ color: "primary", disabled: true },
{ color: "primary", disabled: true, loading: true },
// secondary
{ color: "secondary" },
{ color: "secondary", disabled: true },
{ color: "secondary", disabled: true, loading: true },
// minimal
{ color: "minimal" },
{ color: "minimal", disabled: true },
{ color: "minimal", disabled: true, loading: true },
// sizes
{ color: "primary", size: "sm" },
{ color: "primary", size: "base" },
{ color: "primary", size: "lg" },
// href
{ href: "/staging" },
{ href: "/staging", disabled: true },
{ StartIcon: PlusIcon },
{ EndIcon: PlusIcon },
];
return (
<>
<Head>
<meta name="googlebot" content="noindex" />
</Head>
<div className="p-4 bg-gray-200">
<h1>Button component</h1>
<div className="flex flex-col">
{list.map((props, index) => (
<div key={index} className="p-2 m-2 bg-white">
<h3>
<code>
{JSON.stringify(
props,
(key, value) => {
if (key.includes("Icon")) {
return "..";
}
return value;
},
2
)}
</code>
</h3>
<Button {...props}>Button text</Button>
</div>
))}
</div>
</div>
</>
);
}

View file

@ -4804,7 +4804,7 @@ next-transpile-modules@^8.0.0:
enhanced-resolve "^5.7.0" enhanced-resolve "^5.7.0"
escalade "^3.1.1" escalade "^3.1.1"
next@^10.2.0: next@^10.2.3:
version "10.2.3" version "10.2.3"
resolved "https://registry.npmjs.org/next/-/next-10.2.3.tgz#5aa058a63626338cea91c198fda8f2715c058394" resolved "https://registry.npmjs.org/next/-/next-10.2.3.tgz#5aa058a63626338cea91c198fda8f2715c058394"
integrity sha512-dkM1mIfnORtGyzw/Yme8RdqNxlCMZyi4Lqj56F01/yHbe1ZtOaJ0cyqqRB4RGiPhjGGh0319f8ddjDyO1605Ow== integrity sha512-dkM1mIfnORtGyzw/Yme8RdqNxlCMZyi4Lqj56F01/yHbe1ZtOaJ0cyqqRB4RGiPhjGGh0319f8ddjDyO1605Ow==