Skip to content

Commit 8bcf89e

Browse files
Merge pull request #28 from tinacms/meeting-fixes
2 parents 3ea73e3 + 42a5879 commit 8bcf89e

File tree

15 files changed

+388
-41
lines changed

15 files changed

+388
-41
lines changed

content/global/index.json

Lines changed: 24 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,69 +8,57 @@
88
"logo": "/uploads/tinaDocsLogo.svg",
99
"navObjects": [
1010
{
11+
"href": "https://tina-docs-1msuzf5j4-tinacms.vercel.app/docs",
1112
"label": "Documentation",
12-
"links": [
13-
{
14-
"link": "/getting-started",
15-
"label": "Getting Started"
16-
},
17-
{
18-
"link": "/features",
19-
"label": "Features"
20-
},
21-
{
22-
"link": "/api-reference",
23-
"label": "API Reference"
24-
}
25-
],
26-
"_template": "navDropdown"
13+
"_template": "navLink"
14+
},
15+
{
16+
"href": "/pricing",
17+
"label": "Cloud Pricing",
18+
"_template": "navLink"
2719
},
2820
{
29-
"label": "Examples",
21+
"label": "Community",
3022
"links": [
3123
{
32-
"link": "/tinaCMS",
33-
"label": "TinaCMS"
24+
"link": "/showcase",
25+
"label": "Showcase"
3426
},
3527
{
36-
"link": "/EagleEye",
37-
"label": "EagleEye"
28+
"link": "/roadmap",
29+
"label": "Roadmap"
3830
},
3931
{
40-
"link": "/TimePro",
41-
"label": "TimePro"
42-
}
43-
],
44-
"_template": "navDropdown"
45-
},
46-
{
47-
"label": "Community",
48-
"links": [
32+
"link": "/events",
33+
"label": "Events"
34+
},
4935
{
50-
"link": "/1",
51-
"label": "Smashing Mag"
36+
"link": "/docs/support",
37+
"label": "Support"
5238
},
5339
{
54-
"link": "/2",
55-
"label": "Unity"
40+
"link": "https://discord.com/invite/zumN63Ybpf",
41+
"label": "Discord"
5642
}
5743
],
5844
"_template": "navDropdown"
5945
},
6046
{
61-
"label": "Search",
62-
"_template": "searchBar"
47+
"href": "/enterprise",
48+
"label": "Enterprise",
49+
"_template": "navLink"
6350
},
6451
{
6552
"_template": "githubButton"
6653
},
6754
{
6855
"label": "Book a Demo",
6956
"variant": "outline",
70-
"_template": "ctaButton"
57+
"_template": "demoModal"
7158
},
7259
{
7360
"label": "Get Started",
61+
"url": "https://app.tina.io/quickstart",
7462
"variant": "default",
7563
"_template": "ctaButton"
7664
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"bookingCard": [
3+
{
4+
"name": "Oceania & Asia",
5+
"description": "Meet with Levi 🇦🇺",
6+
"image": "/uploads/People/levi-circle_ca5za1.png",
7+
"url": "https://meetings-eu1.hubspot.com/levi-jackson/tinacms-demo"
8+
},
9+
{
10+
"name": "Europe + USA (East) + South America",
11+
"description": "Meet with Jean 🇫🇷 🇬🇧",
12+
"image": "/uploads/People/jean-circle_v4aiw5.png",
13+
"url": "https://meetings-eu1.hubspot.com/jean-thirion"
14+
},
15+
{
16+
"name": "USA (West) + Pacific",
17+
"description": "Meet with Seth 🇺🇸",
18+
"image": "/uploads/People/seth0d.png",
19+
"url": "https://meetings-eu1.hubspot.com/meetings/seth-daily"
20+
}
21+
]
22+
}
2.19 MB
Loading
83.5 KB
Loading

public/uploads/People/seth0d.png

37.5 KB
Loading

src/components/layout/nav/header.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Image from "next/image";
66
import { useLayout } from "../layout-context";
77
import { Menu, X } from "lucide-react";
88
import { Button } from "../../ui/button";
9+
import { ModalButton } from "../../ui/modalButton";
910
import { DropdownButton } from "../../ui/dropdownButton";
1011
import { GitHubButton } from "../../ui/githubButton";
1112
import { SearchBar } from "../../ui/searchBar";
@@ -14,11 +15,22 @@ const NavigationObjectRenderer = ({ navObject }: { navObject: any }) => {
1415
const template = navObject.__typename;
1516

1617
switch (template) {
18+
case "GlobalHeaderNavObjectsDemoModal":
19+
return (
20+
<ModalButton
21+
variant={navObject.variant || "default"}
22+
size="default"
23+
modal="book-demo"
24+
>
25+
{navObject.label}
26+
</ModalButton>
27+
);
28+
1729
case "GlobalHeaderNavObjectsNavLink":
1830
return (
1931
<Link
2032
href={navObject.href || "#"}
21-
className="text-muted-foreground hover:text-accent-foreground block duration-150"
33+
className="text-neutral-text hover:text-accent-foreground block duration-150"
2234
>
2335
<span>{navObject.label}</span>
2436
</Link>
@@ -74,7 +86,6 @@ export const Header = () => {
7486

7587
const navObjects = header.navObjects!;
7688

77-
7889
const [menuState, setMenuState] = React.useState(false);
7990
return (
8091
<header>
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { fetchMeetingLinks } from "@/src/utils/get-meeting-links";
2+
import Image from "next/image";
3+
import Link from "next/link";
4+
// biome-ignore lint/correctness/noUnusedImports: <TODO>
5+
import React, { useEffect, useState } from "react";
6+
import { FaChevronRight } from "react-icons/fa";
7+
8+
interface MeetingPerson {
9+
name: string;
10+
description: string;
11+
image: string;
12+
url: string;
13+
}
14+
15+
export const DemoForm = () => {
16+
const [meetingPeople, setMeetingPeople] = useState<MeetingPerson[]>([]);
17+
18+
useEffect(() => {
19+
const fetchData = async () => {
20+
const meetingPeopleData = await fetchMeetingLinks();
21+
console.log("meetingPeopleData", meetingPeopleData);
22+
if (meetingPeopleData) {
23+
setMeetingPeople(meetingPeopleData);
24+
}
25+
};
26+
27+
fetchData();
28+
}, []);
29+
30+
return (
31+
<div className="py-10 h-full flex flex-col bg-background">
32+
<div className="flex justify-center pb-8">
33+
<h1 className="inline-block m-0 font-ibm-plex lg:text-3xl md:text-2xl lg:leading-tight text-white">
34+
Choose your location
35+
</h1>
36+
</div>
37+
<div className="grid lg:grid-cols-3 gap-3 px-6 md:px-0 lg:px-6 grow">
38+
{meetingPeople.map((person) => (
39+
<div
40+
key={person.name}
41+
className="flex justify-center w-full items-center h-full"
42+
>
43+
<div className="w-full max-w-sm h-full">
44+
<Link
45+
href={person.url}
46+
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"
47+
prefetch={false}
48+
>
49+
{person.image && (
50+
<Image
51+
src={person.image}
52+
alt={`${person.name} Portrait`}
53+
className="hidden md:block w-18 h-18 rounded-full lg:mr-4 md:mr-4"
54+
width={72}
55+
height={72}
56+
/>
57+
)}
58+
<div className="grow text-center md:text-left lg:text-left">
59+
<div className="font-medium text-lg">{person.name}</div>
60+
<div className="text-muted-foreground text-md">
61+
{person.description}
62+
</div>
63+
</div>
64+
<div className="shrink-0">
65+
<FaChevronRight className="h-6 w-6 text-muted-foreground" />
66+
</div>
67+
</Link>
68+
</div>
69+
</div>
70+
))}
71+
</div>
72+
</div>
73+
);
74+
};

src/components/ui/index.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export { Button, buttonVariants } from "./button";
2+
export { ModalButton } from "./modalButton";
3+
export { GitHubButton } from "./githubButton";
4+
export { SearchBar } from "./searchBar";
5+
export {
6+
Card,
7+
CardContent,
8+
CardDescription,
9+
CardFooter,
10+
CardHeader,
11+
CardTitle,
12+
} from "./card";
13+
export { Avatar, AvatarFallback, AvatarImage } from "./avatar";

src/components/ui/modalButton.tsx

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
import React, { useState, Fragment, useEffect } from "react";
2+
import {
3+
Dialog,
4+
Transition,
5+
TransitionChild,
6+
DialogPanel,
7+
} from "@headlessui/react";
8+
import { Button, buttonVariants } from "./button";
9+
import { DemoForm } from "../modals/book-demo";
10+
import { cn } from "@/lib/utils";
11+
import type { VariantProps } from "class-variance-authority";
12+
import { X } from "lucide-react";
13+
import { lenis } from "@/src/utils/lenis";
14+
15+
const MODALS = {
16+
"book-demo": <DemoForm />,
17+
};
18+
19+
export type ModalType = keyof typeof MODALS;
20+
21+
interface ModalButtonProps
22+
extends React.ComponentProps<"button">,
23+
VariantProps<typeof buttonVariants> {
24+
modal: ModalType;
25+
variant?:
26+
| "default"
27+
| "destructive"
28+
| "outline"
29+
| "secondary"
30+
| "ghost"
31+
| "link";
32+
size?: "default" | "sm" | "lg" | "icon";
33+
asChild?: boolean;
34+
arrow?: boolean;
35+
}
36+
37+
export const ModalButton = ({
38+
className,
39+
variant = "default",
40+
size = "default",
41+
modal,
42+
children,
43+
asChild = false,
44+
arrow = false,
45+
...props
46+
}: ModalButtonProps) => {
47+
const [isOpen, setIsOpen] = useState(false);
48+
49+
const openModal = () => setIsOpen(true);
50+
const closeModal = () => setIsOpen(false);
51+
52+
useEffect(() => {
53+
if (isOpen) {
54+
//Hacky way to disable scroll on the background because of lenis, but lenis.stop() doesnt work.
55+
document.body.setAttribute("data-lenis-prevent", "");
56+
document.documentElement.setAttribute("data-lenis-prevent", "");
57+
58+
document.body.style.overflow = "hidden";
59+
} else {
60+
document.body.removeAttribute("data-lenis-prevent");
61+
document.documentElement.removeAttribute("data-lenis-prevent");
62+
63+
document.body.style.overflow = "";
64+
}
65+
66+
return () => {
67+
document.body.removeAttribute("data-lenis-prevent");
68+
document.documentElement.removeAttribute("data-lenis-prevent");
69+
document.body.style.overflow = "";
70+
};
71+
}, [isOpen]);
72+
73+
const modalContent = MODALS[modal];
74+
75+
return (
76+
<>
77+
<Button
78+
className={cn(className, "cursor-pointer")}
79+
variant={variant}
80+
size={size}
81+
asChild={asChild}
82+
arrow={arrow}
83+
onClick={openModal}
84+
{...props}
85+
>
86+
{children}
87+
</Button>
88+
89+
<Transition appear show={isOpen} as={Fragment}>
90+
<Dialog as="div" className="fixed inset-0 z-50 " onClose={closeModal}>
91+
<div className="min-h-screen px-4 py-12 text-center flex flex-col items-center justify-center">
92+
<TransitionChild
93+
as={Fragment}
94+
enter="ease-out duration-300"
95+
enterFrom="opacity-0"
96+
enterTo="opacity-100"
97+
leave="ease-out duration-300"
98+
leaveFrom="opacity-100"
99+
leaveTo="opacity-0"
100+
>
101+
<div className="fixed inset-0 bg-black/50" />
102+
</TransitionChild>
103+
104+
<TransitionChild
105+
as={Fragment}
106+
enter="ease-out duration-300"
107+
enterFrom="opacity-0 scale-95"
108+
enterTo="opacity-100 scale-100"
109+
leave="ease-in duration-200"
110+
leaveFrom="opacity-100 scale-100"
111+
leaveTo="opacity-0 scale-95"
112+
>
113+
<DialogPanel
114+
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"
115+
style={{ scrollBehavior: "smooth" }}
116+
>
117+
<button
118+
type="button"
119+
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"
120+
onClick={closeModal}
121+
>
122+
<X className="h-4 w-4 cursor-pointer" />
123+
<span className="sr-only">Close</span>
124+
</button>
125+
<div className="p-6 bg-background">{modalContent}</div>
126+
</DialogPanel>
127+
</TransitionChild>
128+
</div>
129+
</Dialog>
130+
</Transition>
131+
</>
132+
);
133+
};

src/utils/get-meeting-links.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import client from "../../tina/__generated__/client";
2+
3+
export const fetchMeetingLinks = async () => {
4+
const meetingPeopleResponse = await client.queries.meetingLinks({
5+
relativePath: "meeting-links.json",
6+
});
7+
const meetingPeopleData =
8+
meetingPeopleResponse.data.meetingLinks?.bookingCard?.map(
9+
(person: any) => ({
10+
name: person.name || "",
11+
description: person.description || "",
12+
image: person.image || "",
13+
url: person.url || "#",
14+
})
15+
);
16+
return meetingPeopleData;
17+
};

0 commit comments

Comments
 (0)