Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
msconstantino committed Oct 24, 2024
0 parents commit 3b62675
Show file tree
Hide file tree
Showing 20 changed files with 5,629 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CONTENTSTACK_API_KEY=''
CONTENTSTACK_DELIVERY_TOKEN=''
CONTENTSTACK_ENVIRONMENT='preview'
CONTENTSTACK_PREVIEW_TOKEN=''
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

/node_modules
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).

## Getting Started

First, run the development server:

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file.
11 changes: 11 additions & 0 deletions app/components/Footer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default function Footer() {

{/* ----- EXAMPLE OF HARDCODED COMPONENT ----- */}
return (
<footer className="bg-white mt-8 px-6 py-12">
<p className="text-center text-xs leading-5 text-gray-500">
&copy; 2024 Contentstack Inc. All rights reserved.
</p>
</footer>
);
}
34 changes: 34 additions & 0 deletions app/components/Hero.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
export default function Hero({ content }) {
return (
<div className="bg-black">
<div className="relative isolate overflow-hidden">

{/* ----- BACKGROUND IMAGE FROM CONTENTSTACK ----- */}
<img src={content?.background_image?.url} className="absolute inset-0 -z-10 h-full w-full object-cover object-center opacity-75"/>
<div className="mx-auto max-w-2xl py-32 sm:py-48 lg:py-56 ">
<div className="text-center">

{/* ----- HEADER & TEXT FROM CONTENTSTACK ----- */}
<h5 className="text-5xl font-bold text-center tracking-widest text-white leading-relaxed" {...content?.$?.title}>
{content.title}
</h5>

<p className="mx-5 mt-8 font-normal text-lg leading-8 text-left text-white tracking-wide" {...content?.$?.text}>
{content.text}
</p>

<div className="mt-10 flex items-center justify-center gap-x-6">
<button
type="button"
className="rounded-md px-8 py-4 text-md tracking-widest uppercase font-bold shadow-sm ring-1 ring-inset ring-gray-300 text-gray-700 bg-gray-50 hover:text-white hover:bg-gray-700 hover:ring-0"
{...content?.cta.$?.title}
>
{content.cta.title}
</button>
</div>
</div>
</div>
</div>
</div>
);
}
22 changes: 22 additions & 0 deletions app/components/ImageGallery.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export default function ImageGallery({ content }) {
return (
<div className="max-w-7xl mx-auto mt-8 mb-8 px-8">
<div className="flex flex-col md:grid md:grid-cols-2 lg:grid-cols-3 gap-8 auto-rows-fr">

{/* ----- ITTERATING OVER ARRAY OF IMAGES COMING FROM CONTENTSTACK ----- */}
{content.gallery_item.map((item, index) => (
<div key={index} className="relative">
<a href={item.page.length > 0 ? item.page[0].url : "#"}>
<div className="bg-cover bg-bottom aspect-h-1 aspect-w-1 flex items-center justify-center" {...item?.$?.image}>
<img src={item.image.url} className="object-cover" />
</div>
</a>
<p className="pointer-events-none mt-2 block truncate text-sm font-medium text-gray-900" {...item?.$?.header}>
{item.header}
</p>
</div>
))}
</div>
</div>
);
}
135 changes: 135 additions & 0 deletions app/components/NavBar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
"use client";
import { useState, useEffect } from "react";
import Stack, { onEntryChange } from "../../lib/index";
import { Dialog } from "@headlessui/react";
import {
Bars3Icon,
XMarkIcon,
InformationCircleIcon,
} from "@heroicons/react/24/outline";

export default function NavBar() {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
const [entry, setEntry] = useState({});
const [loading, SetLoading] = useState(true);

const getContent = async () => {
const entry = await Stack.getElementByTypeWtihRefs(
"menu",
[""]
);
console.log("header:", entry[0][0]);
setEntry(entry[0][0]);
SetLoading(false);
};

useEffect(() => {
onEntryChange(getContent);
}, []);

if (loading) {
return;
}

return (
<header className="bg-white shadow-md">
<nav className="flex items-center justify-between p-6 lg:px-8">
<div className="flex lg:flex-1">
<a href="/" className="-m-1.5 p-1.5">

{/* ----- LOGO IMAGE SERVED FROM CONTENTSTACK ----- */}
<img
className="h-8 w-auto"
src={entry?.logo?.url}
alt=""
{...entry?.$?.logo}
/>

</a>
</div>
<div className="flex lg:hidden">
<button
type="button" className="-m-2.5 inline-flex items-center justify-center rounded-md p-2.5 text-gray-700"
onClick={() => setMobileMenuOpen(true)}
>
<Bars3Icon className="h-6 w-6" aria-hidden="true" />
</button>
</div>
<div className="hidden lg:flex lg:gap-x-12">

{/* ----- ITTERATE OVER ARRAY FROM CONTENTSTACK ----- */}
{entry.menu_items?.map((item) => (
<a
key={item.menu_item.title}
href={item.menu_item.href}
className="text-sm font-semibold leading-6 text-gray-900"
{...item?.menu_item?.$?.title}
>
{item.menu_item.title}
</a>
))}

</div>
<div className="hidden lg:flex lg:flex-1 lg:justify-end">
<a
href="https://www.contentstack.com/docs/developers"
target="__blank"
>
<InformationCircleIcon
className="h-6 w-6 flex-none text-neutral-800"
/>
</a>
</div>
</nav>
<Dialog
as="div"
className="lg:hidden"
open={mobileMenuOpen}
onClose={setMobileMenuOpen}
>
<div className="fixed inset-0 z-10" />
<Dialog.Panel className="fixed inset-y-0 right-0 z-10 w-full overflow-y-auto bg-white px-6 py-6 sm:max-w-sm sm:ring-1 sm:ring-gray-900/10">
<div className="flex items-center justify-between">

{/* ----- LOGO FROM CONTENTSTACK FOR MOBILE MENU ----- */}
<a href="#" className="-m-1.5 p-1.5">
<img className="h-8 w-auto" src={entry?.logo?.url} alt="" />
</a>
<button
type="button"
className="-m-2.5 rounded-md p-2.5 text-gray-700"
onClick={() => setMobileMenuOpen(false)}
>
<XMarkIcon className="h-6 w-6" aria-hidden="true" />
</button>
</div>
<div className="mt-6 flow-root">
<div className="-my-6 ">
<div className="space-y-2 py-6">

{/* ----- ITTERATE OVER ARRAY FROM CONTENTSTACK FOR MOBILE MENU ----- */}
{entry?.menu_item?.map((item) => (
<a
key={item.title}
href={item.href}
className="-mx-3 block rounded-lg px-3 py-2 text-base font-semibold leading-7 text-gray-900 hover:bg-gray-50"
{...item?.$?.title}
>
{item.title}
</a>
))}
<a
key={"docs"}
href="https://www.contentstack.com/docs/developers"
className="-mx-3 block rounded-lg px-3 py-2 text-base font-semibold leading-7 text-gray-900 hover:bg-gray-50"
>
Documentation
</a>
</div>
</div>
</div>
</Dialog.Panel>
</Dialog>
</header>
);
}
74 changes: 74 additions & 0 deletions app/components/TextBlock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import {
GlobeEuropeAfricaIcon,
SunIcon,
CurrencyEuroIcon,
} from "@heroicons/react/20/solid";

export default function TextBlock({ content }) {
function icon() {
if (content.icon == "Globe") {
return (
<GlobeEuropeAfricaIcon
className="h-10 w-10 flex-none text-cyan-600"
aria-hidden="true"
{...content?.$?.icon}
/>
);
} else if (content.icon == "Sun") {
return (
<SunIcon
className="h-10 w-10 flex-none text-cyan-600"
aria-hidden="true"
{...content?.$?.icon}
/>
);
} else if (content.icon == "Euro") {
return (
<CurrencyEuroIcon
className="h-10 w-10 flex-none text-cyan-600"
aria-hidden="true"
{...content?.$?.icon}
/>
);
} else if (content.icon == "None") {
return <></>;
}
}

return (
<div className="bg-white">
<div className="px-6 py-24 sm:px-6 sm:py-32 lg:px-8">
<div className="mx-auto max-w-2xl text-center">
<dt className="flex items-center gap-x-3 text-base font-semibold text-gray-900 justify-center">
{/* ----- ICON COMING FROM SELECT MENU IN CONTENTSTACK ----- */}
{icon()}
</dt>

<h5
className="mt-8 text-2xl font-bold text-center tracking-widest text-neutral-700"
{...content?.$?.header}
>
{content.header}
</h5>

<p
className="mx-5 mt-8 font-normal text-left leading-8 text-gray-700 text-block whitespace-pre-line"
{...content?.$?.text}
>
{content.multi}
</p>

<div className="mt-10 flex items-center justify-center gap-x-6">
<button
type="button"
className="rounded-md px-8 py-4 text-md tracking-widest uppercase font-bold text-cyan-600 shadow-sm ring-2 ring-inset ring-cyan-600 hover:text-white hover:bg-cyan-600"
{...content?.cta[0].$?.title}
>
<a href={content.cta[0].href}>{content.cta[0].title}</a>
</button>
</div>
</div>
</div>
</div>
);
}
3 changes: 3 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
19 changes: 19 additions & 0 deletions app/layout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Inter } from "next/font/google";
import "./globals.css";


const inter = Inter({ subsets: ["latin"] });

export const metadata = {
title: "Contentstack Dev Starter",
// description: "Generated by create next app",
icons: [{rel: 'icon', url: '/favicon.ico'}]
};

export default function RootLayout({ children }) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
</html>
);
}
50 changes: 50 additions & 0 deletions app/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"use client";
import { useState, useEffect } from "react";
import Stack, { onEntryChange } from "../lib/index";
import Footer from "./components/Footer";
import TextBlock from "./components/TextBlock";
import Hero from "./components/Hero";
import NavBar from "./components/NavBar";
import ImageGallery from "./components/ImageGallery";

export default function Home({ params }) {
const [entry, setEntry] = useState({});
const [loading, SetLoading] = useState(true);

const getContent = async () => {
const entry = await Stack.getElementByTypeWtihRefs(
"home_page",
["hero_banner", "page_content.image_gallery.gallery_item.page"]
);
// console.log("homepage:", entry[0][0]);
setEntry(entry[0][0]);
SetLoading(false);
};

useEffect(() => {
onEntryChange(getContent);
}, []);

if (loading) {
return;
}

return (
<>
<NavBar />

<Hero content={entry.hero_banner[0]} />

{entry.page_content?.map((item, index) => {
if (item.hasOwnProperty("text_block")) {
return <TextBlock key={index} content={item.text_block} />;
}
if (item.hasOwnProperty("image_gallery")) {
return <ImageGallery key={index} content={item.image_gallery} />;
}
})}

<Footer />
</>
);
}
Loading

0 comments on commit 3b62675

Please sign in to comment.