diff --git a/frontend/Dockerfile b/frontend/Dockerfile index b14906f..f9fb81d 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -13,6 +13,5 @@ COPY ./tailwind.config.ts . COPY ./tsconfig.json . COPY ./typography.ts . COPY ./src ./src -COPY ./public ./public COPY ./.env.local . CMD ["npm", "run", "dev"] diff --git a/frontend/public/next.svg b/frontend/public/next.svg deleted file mode 100644 index 5174b28..0000000 --- a/frontend/public/next.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/public/vercel.svg b/frontend/public/vercel.svg deleted file mode 100644 index d2f8422..0000000 --- a/frontend/public/vercel.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/components/Code.tsx b/frontend/src/components/Code.tsx deleted file mode 100644 index 82af1c9..0000000 --- a/frontend/src/components/Code.tsx +++ /dev/null @@ -1,384 +0,0 @@ -/** - * This file was taken from a Tailwind UI Template. - */ - -'use client'; - -import { Children, createContext, isValidElement, useContext, useEffect, useRef, useState } from 'react'; -import { Tab } from '@headlessui/react'; -import clsx from 'clsx'; -import { create } from 'zustand'; - -import { Tag } from '@/components/Tag'; - -const languageNames: Record = { - js: 'JavaScript', - ts: 'TypeScript', - javascript: 'JavaScript', - typescript: 'TypeScript', - php: 'PHP', - python: 'Python', - ruby: 'Ruby', - go: 'Go', -}; - -function getPanelTitle({ - title, - language, -}: { - title?: string - language?: string -}) { - if (title) { - return title; - } - if (language && language in languageNames) { - return languageNames[language]; - } - return 'Code'; -} - -function ClipboardIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ); -} - -function CopyButton({ code }: { code: string }) { - let [copyCount, setCopyCount] = useState(0); - let copied = copyCount > 0; - - useEffect(() => { - if (copyCount > 0) { - let timeout = setTimeout(() => setCopyCount(0), 1000); - return () => { - clearTimeout(timeout); - }; - } - }, [copyCount]); - - return ( - - ); -} - -function CodePanelHeader({ tag, label }: { tag?: string; label?: string }) { - if (!tag && !label) { - return null; - } - - return ( -
- {tag && ( -
- {tag} -
- )} - {tag && label && ( - - )} - {label && ( - {label} - )} -
- ); -} - -function CodePanel({ - children, - tag, - label, - code, -}: { - children: React.ReactNode - tag?: string - label?: string - code?: string -}) { - let child = Children.only(children); - - if (isValidElement(child)) { - tag = child.props.tag ?? tag; - label = child.props.label ?? label; - code = child.props.code ?? code; - } - - if (!code) { - throw new Error( - '`CodePanel` requires a `code` prop, or a child with a `code` prop.', - ); - } - - return ( -
- -
-
{children}
- -
-
- ); -} - -function CodeGroupHeader({ - title, - children, - selectedIndex, -}: { - title: string - children: React.ReactNode - selectedIndex: number -}) { - let hasTabs = Children.count(children) > 1; - - if (!title && !hasTabs) { - return null; - } - - return ( -
- {title && ( -

- {title} -

- )} - {hasTabs && ( - - {Children.map(children, (child, childIndex) => ( - - {getPanelTitle(isValidElement(child) ? child.props : {})} - - ))} - - )} -
- ); -} - -function CodeGroupPanels({ - children, - ...props -}: React.ComponentPropsWithoutRef) { - let hasTabs = Children.count(children) > 1; - - if (hasTabs) { - return ( - - {Children.map(children, (child) => ( - - {child} - - ))} - - ); - } - - return {children}; -} - -function usePreventLayoutShift() { - let positionRef = useRef(null); - let rafRef = useRef(); - - useEffect(() => { - return () => { - if (typeof rafRef.current !== 'undefined') { - window.cancelAnimationFrame(rafRef.current); - } - }; - }, []); - - return { - positionRef, - preventLayoutShift(callback: () => void) { - if (!positionRef.current) { - return; - } - - let initialTop = positionRef.current.getBoundingClientRect().top; - - callback(); - - rafRef.current = window.requestAnimationFrame(() => { - let newTop = - positionRef.current?.getBoundingClientRect().top ?? initialTop; - window.scrollBy(0, newTop - initialTop); - }); - }, - }; -} - -const usePreferredLanguageStore = create<{ - preferredLanguages: Array - addPreferredLanguage: (language: string) => void -}>()((set) => ({ - preferredLanguages: [], - addPreferredLanguage: (language) => - set((state) => ({ - preferredLanguages: [ - ...state.preferredLanguages.filter( - (preferredLanguage) => preferredLanguage !== language, - ), - language, - ], - })), -})); - -function useTabGroupProps(availableLanguages: Array) { - let { preferredLanguages, addPreferredLanguage } = usePreferredLanguageStore(); - let [selectedIndex, setSelectedIndex] = useState(0); - let activeLanguage = [...availableLanguages].sort( - (a, z) => preferredLanguages.indexOf(z) - preferredLanguages.indexOf(a), - )[0]; - let languageIndex = availableLanguages.indexOf(activeLanguage); - let newSelectedIndex = languageIndex === -1 ? selectedIndex : languageIndex; - if (newSelectedIndex !== selectedIndex) { - setSelectedIndex(newSelectedIndex); - } - - let { positionRef, preventLayoutShift } = usePreventLayoutShift(); - - return { - as: 'div' as const, - ref: positionRef, - selectedIndex, - onChange: (newSelectedIndex: number) => { - preventLayoutShift(() => - addPreferredLanguage(availableLanguages[newSelectedIndex]), - ); - }, - }; -} - -const CodeGroupContext = createContext(false); - -export function CodeGroup({ - children, - title, - ...props -}: React.ComponentPropsWithoutRef & { title: string }) { - let languages = - Children.map(children, (child) => - getPanelTitle(isValidElement(child) ? child.props : {}), - ) ?? []; - let tabGroupProps = useTabGroupProps(languages); - let hasTabs = Children.count(children) > 1; - - let containerClassName = - 'my-6 overflow-hidden rounded-2xl bg-zinc-900 shadow-md dark:ring-1 dark:ring-white/10'; - let header = ( - - {children} - - ); - let panels = {children}; - - return ( - - {hasTabs ? ( - -
- {header} - {panels} -
-
- ) : ( -
-
- {header} - {panels} -
-
- )} -
- ); -} - -export function Code({ - children, - ...props -}: React.ComponentPropsWithoutRef<'code'>) { - let isGrouped = useContext(CodeGroupContext); - - if (isGrouped) { - if (typeof children !== 'string') { - throw new Error( - '`Code` children must be a string when nested inside a `CodeGroup`.', - ); - } - return ; - } - - return {children}; -} - -export function Pre({ - children, - ...props -}: React.ComponentPropsWithoutRef) { - let isGrouped = useContext(CodeGroupContext); - - if (isGrouped) { - return children; - } - - return {children}; -} diff --git a/frontend/src/components/Feedback.tsx b/frontend/src/components/Feedback.tsx deleted file mode 100644 index cdc12fa..0000000 --- a/frontend/src/components/Feedback.tsx +++ /dev/null @@ -1,116 +0,0 @@ -/** - * This file was taken from a Tailwind UI Template. - */ - -'use client'; - -import { forwardRef, Fragment, useState } from 'react'; -import { Transition } from '@headlessui/react'; - -function CheckIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ); -} - -function FeedbackButton( - props: Omit, 'type' | 'className'>, -) { - return ( - -

- - ))} - - - ); -} diff --git a/frontend/src/components/Heading.tsx b/frontend/src/components/Heading.tsx deleted file mode 100644 index 7243d2c..0000000 --- a/frontend/src/components/Heading.tsx +++ /dev/null @@ -1,119 +0,0 @@ -/** - * This file was taken from a Tailwind UI Template. - */ - -'use client'; - -import { useRef } from 'react'; -import Link from 'next/link'; -import { useInView } from 'framer-motion'; - -import { Tag } from '@/components/Tag'; -import { remToPx } from '@/lib/remToPx'; - -function AnchorIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ); -} - -function Eyebrow({ tag, label }: { tag?: string; label?: string }) { - if (!tag && !label) { - return null; - } - - return ( -
- {tag && {tag}} - {tag && label && ( - - )} - {label && ( - {label} - )} -
- ); -} - -function Anchor({ - id, - inView, - children, -}: { - id: string - inView: boolean - children: React.ReactNode -}) { - return ( - - {inView && ( -
-
- -
-
- )} - {children} - - ); -} - -export function Heading({ - children, - tag, - label, - level, - anchor = true, - ...props -}: React.ComponentPropsWithoutRef<`h${Level}`> & { - id: string - tag?: string - label?: string - level?: Level - anchor?: boolean -}) { - level = level ?? (2 as Level); - let Component = `h${level}` as 'h2' | 'h3'; - let ref = useRef(null); - - let inView = useInView(ref, { - margin: `${remToPx(-3.5)}px 0px 0px 0px`, - amount: 'all', - }); - - return ( - <> - - - {anchor ? ( - - {children} - - ) : ( - children - )} - - - ); -} diff --git a/frontend/src/components/Prose.tsx b/frontend/src/components/Prose.tsx deleted file mode 100644 index 7f4a01b..0000000 --- a/frontend/src/components/Prose.tsx +++ /dev/null @@ -1,28 +0,0 @@ -/** - * This file was taken from a Tailwind UI Template. - */ - -import clsx from 'clsx'; - -export function Prose({ - as, - className, - ...props -}: Omit, 'as' | 'className'> & { - as?: T - className?: string -}) { - let Component = as ?? 'div'; - - return ( - *)` is used to select all direct children without an increase in specificity like you'd get from just `& > *` - '[html_:where(&>*)]:mx-auto [html_:where(&>*)]:max-w-2xl [html_:where(&>*)]:lg:mx-[calc(50%-min(50%,theme(maxWidth.lg)))] [html_:where(&>*)]:lg:max-w-3xl', - )} - {...props} - /> - ); -} diff --git a/frontend/src/components/Resources.tsx b/frontend/src/components/Resources.tsx deleted file mode 100644 index 6569817..0000000 --- a/frontend/src/components/Resources.tsx +++ /dev/null @@ -1,193 +0,0 @@ -/** - * This file was taken from a Tailwind UI Template. - */ - -'use client'; - -import Link from 'next/link'; -import { motion, type MotionValue, useMotionTemplate, useMotionValue } from 'framer-motion'; - -import { GridPattern } from '@/components/GridPattern'; -import { Heading } from '@/components/Heading'; -import { ChatBubbleIcon } from '@/components/icons/ChatBubbleIcon'; -import { EnvelopeIcon } from '@/components/icons/EnvelopeIcon'; -import { UserIcon } from '@/components/icons/UserIcon'; -import { UsersIcon } from '@/components/icons/UsersIcon'; - -interface Resource { - href: string; - name: string; - description: string; - icon: React.ComponentType<{ className?: string }>; - pattern: Omit< - React.ComponentPropsWithoutRef, - 'width' | 'height' | 'x' - >; -} - -const resources: Array = [ - { - href: '/contacts', - name: 'Contacts', - description: - 'Learn about the contact model and how to create, retrieve, update, delete, and list contacts.', - icon: UserIcon, - pattern: { - y: 16, - squares: [ - [0, 1], - [1, 3], - ], - }, - }, - { - href: '/conversations', - name: 'Conversations', - description: - 'Learn about the conversation model and how to create, retrieve, update, delete, and list conversations.', - icon: ChatBubbleIcon, - pattern: { - y: -6, - squares: [ - [-1, 2], - [1, 3], - ], - }, - }, - { - href: '/messages', - name: 'Messages', - description: - 'Learn about the message model and how to create, retrieve, update, delete, and list messages.', - icon: EnvelopeIcon, - pattern: { - y: 32, - squares: [ - [0, 2], - [1, 4], - ], - }, - }, - { - href: '/groups', - name: 'Groups', - description: - 'Learn about the group model and how to create, retrieve, update, delete, and list groups.', - icon: UsersIcon, - pattern: { - y: 22, - squares: [[0, 1]], - }, - }, -]; - -function ResourceIcon({ icon: Icon }: { icon: Resource['icon'] }) { - return ( -
- -
- ); -} - -function ResourcePattern({ - mouseX, - mouseY, - ...gridProps -}: Resource['pattern'] & { - mouseX: MotionValue - mouseY: MotionValue -}) { - let maskImage = useMotionTemplate`radial-gradient(180px at ${mouseX}px ${mouseY}px, white, transparent)`; - let style = { maskImage, WebkitMaskImage: maskImage }; - - return ( -
-
- -
- - - - -
- ); -} - -export function Resource({ resource }: { resource: Resource }) { - let mouseX = useMotionValue(0); - let mouseY = useMotionValue(0); - - function onMouseMove({ - currentTarget, - clientX, - clientY, - }: React.MouseEvent) { - let { left, top } = currentTarget.getBoundingClientRect(); - mouseX.set(clientX - left); - mouseY.set(clientY - top); - } - - return ( -
- -
-
- -

- - - {resource.name} - -

-

- {resource.description} -

-
-
- ); -} - -export function Resources() { - return ( -
- - Resources - -
- {resources.map((resource) => ( - - ))} -
-
- ); -}