Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 24 additions & 36 deletions content/global/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,69 +8,57 @@
"logo": "/uploads/tinaDocsLogo.svg",
"navObjects": [
{
"href": "https://tina-docs-1msuzf5j4-tinacms.vercel.app/docs",
"label": "Documentation",
"links": [
{
"link": "/getting-started",
"label": "Getting Started"
},
{
"link": "/features",
"label": "Features"
},
{
"link": "/api-reference",
"label": "API Reference"
}
],
"_template": "navDropdown"
"_template": "navLink"
},
{
"href": "/pricing",
"label": "Cloud Pricing",
"_template": "navLink"
},
{
"label": "Examples",
"label": "Community",
"links": [
{
"link": "/tinaCMS",
"label": "TinaCMS"
"link": "/showcase",
"label": "Showcase"
},
{
"link": "/EagleEye",
"label": "EagleEye"
"link": "/roadmap",
"label": "Roadmap"
},
{
"link": "/TimePro",
"label": "TimePro"
}
],
"_template": "navDropdown"
},
{
"label": "Community",
"links": [
"link": "/events",
"label": "Events"
},
{
"link": "/1",
"label": "Smashing Mag"
"link": "/docs/support",
"label": "Support"
},
{
"link": "/2",
"label": "Unity"
"link": "https://discord.com/invite/zumN63Ybpf",
"label": "Discord"
}
],
"_template": "navDropdown"
},
{
"label": "Search",
"_template": "searchBar"
"href": "/enterprise",
"label": "Enterprise",
"_template": "navLink"
},
{
"_template": "githubButton"
},
{
"label": "Book a Demo",
"variant": "outline",
"_template": "ctaButton"
"_template": "demoModal"
},
{
"label": "Get Started",
"url": "https://app.tina.io/quickstart",
"variant": "default",
"_template": "ctaButton"
}
Expand Down
22 changes: 22 additions & 0 deletions content/meeting-links/meeting-links.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"bookingCard": [
{
"name": "Oceania & Asia",
"description": "Meet with Levi 🇦🇺",
"image": "/uploads/People/levi-circle_ca5za1.png",
"url": "https://meetings-eu1.hubspot.com/levi-jackson/tinacms-demo"
},
{
"name": "Europe + USA (East) + South America",
"description": "Meet with Jean 🇫🇷 🇬🇧",
"image": "/uploads/People/jean-circle_v4aiw5.png",
"url": "https://meetings-eu1.hubspot.com/jean-thirion"
},
{
"name": "USA (West) + Pacific",
"description": "Meet with Seth 🇺🇸",
"image": "/uploads/People/seth0d.png",
"url": "https://meetings-eu1.hubspot.com/meetings/seth-daily"
}
]
}
Binary file added public/uploads/People/jean-circle_v4aiw5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/uploads/People/levi-circle_ca5za1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/uploads/People/seth0d.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 13 additions & 2 deletions src/components/layout/nav/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Image from "next/image";
import { useLayout } from "../layout-context";
import { Menu, X } from "lucide-react";
import { Button } from "../../ui/button";
import { ModalButton } from "../../ui/modalButton";
import { DropdownButton } from "../../ui/dropdownButton";
import { GitHubButton } from "../../ui/githubButton";
import { SearchBar } from "../../ui/searchBar";
Expand All @@ -14,11 +15,22 @@ const NavigationObjectRenderer = ({ navObject }: { navObject: any }) => {
const template = navObject.__typename;

switch (template) {
case "GlobalHeaderNavObjectsDemoModal":
return (
<ModalButton
variant={navObject.variant || "default"}
size="default"
modal="book-demo"
>
{navObject.label}
</ModalButton>
);

case "GlobalHeaderNavObjectsNavLink":
return (
<Link
href={navObject.href || "#"}
className="text-muted-foreground hover:text-accent-foreground block duration-150"
className="text-neutral-text hover:text-accent-foreground block duration-150"
>
<span>{navObject.label}</span>
</Link>
Expand Down Expand Up @@ -74,7 +86,6 @@ export const Header = () => {

const navObjects = header.navObjects!;


const [menuState, setMenuState] = React.useState(false);
return (
<header>
Expand Down
74 changes: 74 additions & 0 deletions src/components/modals/book-demo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { fetchMeetingLinks } from "@/src/utils/get-meeting-links";
import Image from "next/image";
import Link from "next/link";
// biome-ignore lint/correctness/noUnusedImports: <TODO>
import React, { useEffect, useState } from "react";
import { FaChevronRight } from "react-icons/fa";

interface MeetingPerson {
name: string;
description: string;
image: string;
url: string;
}

export const DemoForm = () => {
const [meetingPeople, setMeetingPeople] = useState<MeetingPerson[]>([]);

useEffect(() => {
const fetchData = async () => {
const meetingPeopleData = await fetchMeetingLinks();
console.log("meetingPeopleData", meetingPeopleData);
if (meetingPeopleData) {
setMeetingPeople(meetingPeopleData);
}
};

fetchData();
}, []);

return (
<div className="py-10 h-full flex flex-col bg-background">
<div className="flex justify-center pb-8">
<h1 className="inline-block m-0 font-ibm-plex lg:text-3xl md:text-2xl lg:leading-tight text-white">
Choose your location
</h1>
</div>
<div className="grid lg:grid-cols-3 gap-3 px-6 md:px-0 lg:px-6 grow">
{meetingPeople.map((person) => (
<div
key={person.name}
className="flex justify-center w-full items-center h-full"
>
<div className="w-full max-w-sm h-full">
<Link
href={person.url}
className="flex flex-col md:flex-row lg:flex-row w-full h-full items-center justify-between rounded-lg border border-input bg-background p-4 shadow transition transform duration-200 hover:scale-105 hover:bg-muted focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring text-white font-bold"
prefetch={false}
>
{person.image && (
<Image
src={person.image}
alt={`${person.name} Portrait`}
className="hidden md:block w-18 h-18 rounded-full lg:mr-4 md:mr-4"
width={72}
height={72}
/>
)}
<div className="grow text-center md:text-left lg:text-left">
<div className="font-medium text-lg">{person.name}</div>
<div className="text-muted-foreground text-md">
{person.description}
</div>
</div>
<div className="shrink-0">
<FaChevronRight className="h-6 w-6 text-muted-foreground" />
</div>
</Link>
</div>
</div>
))}
</div>
</div>
);
};
13 changes: 13 additions & 0 deletions src/components/ui/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export { Button, buttonVariants } from "./button";
export { ModalButton } from "./modalButton";
export { GitHubButton } from "./githubButton";
export { SearchBar } from "./searchBar";
export {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "./card";
export { Avatar, AvatarFallback, AvatarImage } from "./avatar";
133 changes: 133 additions & 0 deletions src/components/ui/modalButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import React, { useState, Fragment, useEffect } from "react";
import {
Dialog,
Transition,
TransitionChild,
DialogPanel,
} from "@headlessui/react";
import { Button, buttonVariants } from "./button";
import { DemoForm } from "../modals/book-demo";
import { cn } from "@/lib/utils";
import type { VariantProps } from "class-variance-authority";
import { X } from "lucide-react";
import { lenis } from "@/src/utils/lenis";

const MODALS = {
"book-demo": <DemoForm />,
};

export type ModalType = keyof typeof MODALS;

interface ModalButtonProps
extends React.ComponentProps<"button">,
VariantProps<typeof buttonVariants> {
modal: ModalType;
variant?:
| "default"
| "destructive"
| "outline"
| "secondary"
| "ghost"
| "link";
size?: "default" | "sm" | "lg" | "icon";
asChild?: boolean;
arrow?: boolean;
}

export const ModalButton = ({
className,
variant = "default",
size = "default",
modal,
children,
asChild = false,
arrow = false,
...props
}: ModalButtonProps) => {
const [isOpen, setIsOpen] = useState(false);

const openModal = () => setIsOpen(true);
const closeModal = () => setIsOpen(false);

useEffect(() => {
if (isOpen) {
//Hacky way to disable scroll on the background because of lenis, but lenis.stop() doesnt work.
document.body.setAttribute("data-lenis-prevent", "");
document.documentElement.setAttribute("data-lenis-prevent", "");

document.body.style.overflow = "hidden";
} else {
document.body.removeAttribute("data-lenis-prevent");
document.documentElement.removeAttribute("data-lenis-prevent");

document.body.style.overflow = "";
}

return () => {
document.body.removeAttribute("data-lenis-prevent");
document.documentElement.removeAttribute("data-lenis-prevent");
document.body.style.overflow = "";
};
}, [isOpen]);

const modalContent = MODALS[modal];

return (
<>
<Button
className={cn(className, "cursor-pointer")}
variant={variant}
size={size}
asChild={asChild}
arrow={arrow}
onClick={openModal}
{...props}
>
{children}
</Button>

<Transition appear show={isOpen} as={Fragment}>
<Dialog as="div" className="fixed inset-0 z-50 " onClose={closeModal}>
<div className="min-h-screen px-4 py-12 text-center flex flex-col items-center justify-center">
<TransitionChild
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-out duration-300"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-black/50" />
</TransitionChild>

<TransitionChild
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<DialogPanel
className="relative w-full max-w-4xl max-h-[90vh] overflow-auto text-left align-middle transition-all transform bg-white dark:bg-gray-950 shadow-xl rounded-xl"
style={{ scrollBehavior: "smooth" }}
>
<button
type="button"
className="absolute top-4 right-4 z-10 p-2 rounded-md text-gray-400 hover:text-gray-600 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
onClick={closeModal}
>
<X className="h-4 w-4 cursor-pointer" />
<span className="sr-only">Close</span>
</button>
<div className="p-6 bg-background">{modalContent}</div>
</DialogPanel>
</TransitionChild>
</div>
</Dialog>
</Transition>
</>
);
};
17 changes: 17 additions & 0 deletions src/utils/get-meeting-links.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import client from "../../tina/__generated__/client";

export const fetchMeetingLinks = async () => {
const meetingPeopleResponse = await client.queries.meetingLinks({
relativePath: "meeting-links.json",
});
const meetingPeopleData =
meetingPeopleResponse.data.meetingLinks?.bookingCard?.map(
(person: any) => ({
name: person.name || "",
description: person.description || "",
image: person.image || "",
url: person.url || "#",
})
);
return meetingPeopleData;
};
Loading