commit 959408444141eaac7b3a5c6b0e2e98a8fcbd6c12 Author: TheoryOfNekomata Date: Thu Sep 14 18:01:40 2023 +0800 Initial commit Add files from create-next-app diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9f11b75 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea/ diff --git a/packages/web/.eslintrc.json b/packages/web/.eslintrc.json new file mode 100644 index 0000000..bffb357 --- /dev/null +++ b/packages/web/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "next/core-web-vitals" +} diff --git a/packages/web/.gitignore b/packages/web/.gitignore new file mode 100644 index 0000000..8f322f0 --- /dev/null +++ b/packages/web/.gitignore @@ -0,0 +1,35 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/packages/web/README.md b/packages/web/README.md new file mode 100644 index 0000000..965a122 --- /dev/null +++ b/packages/web/README.md @@ -0,0 +1,38 @@ +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 +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file. + +[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`. + +The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. + +This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. diff --git a/packages/web/bun.lockb b/packages/web/bun.lockb new file mode 100755 index 0000000..6122150 Binary files /dev/null and b/packages/web/bun.lockb differ diff --git a/packages/web/bunfig.toml b/packages/web/bunfig.toml new file mode 100644 index 0000000..de0d776 --- /dev/null +++ b/packages/web/bunfig.toml @@ -0,0 +1,3 @@ +[install.scopes] +"@tesseract-design" = "http://localhost:4873/" +"@modal-sh" = "http://localhost:4873/" diff --git a/packages/web/next.config.js b/packages/web/next.config.js new file mode 100644 index 0000000..a843cbe --- /dev/null +++ b/packages/web/next.config.js @@ -0,0 +1,6 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + reactStrictMode: true, +} + +module.exports = nextConfig diff --git a/packages/web/package.json b/packages/web/package.json new file mode 100644 index 0000000..a63a5ab --- /dev/null +++ b/packages/web/package.json @@ -0,0 +1,33 @@ +{ + "name": "web", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "@tesseract-design/viewfinder-base": "0.0.1", + "@tesseract-design/viewfinder-react": "0.0.1", + "@tesseract-design/web-action-react": "^0.2.0", + "@tesseract-design/web-formatted-react": "^0.2.0", + "@tesseract-design/web-freeform-react": "^0.2.0", + "@tesseract-design/web-navigation-react": "^0.2.0", + "@theoryofnekomata/formxtra": "^1.0.3", + "@types/node": "20.6.0", + "@types/react": "18.2.21", + "@types/react-dom": "18.2.7", + "autoprefixer": "10.4.15", + "clsx": "^2.0.0", + "eslint": "8.49.0", + "eslint-config-next": "13.4.19", + "next": "13.4.19", + "postcss": "8.4.29", + "react": "18.2.0", + "react-dom": "18.2.0", + "tailwindcss": "3.3.3", + "typescript": "5.2.2" + } +} diff --git a/packages/web/postcss.config.js b/packages/web/postcss.config.js new file mode 100644 index 0000000..33ad091 --- /dev/null +++ b/packages/web/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/packages/web/public/favicon.ico b/packages/web/public/favicon.ico new file mode 100644 index 0000000..718d6fe Binary files /dev/null and b/packages/web/public/favicon.ico differ diff --git a/packages/web/public/images/162cab44da8420c50900d8f11c6da6fd.jpg b/packages/web/public/images/162cab44da8420c50900d8f11c6da6fd.jpg new file mode 100644 index 0000000..be778f0 Binary files /dev/null and b/packages/web/public/images/162cab44da8420c50900d8f11c6da6fd.jpg differ diff --git a/packages/web/public/images/2626c3485668a19730c64a7ee672a214.jpg b/packages/web/public/images/2626c3485668a19730c64a7ee672a214.jpg new file mode 100644 index 0000000..1b6ad86 Binary files /dev/null and b/packages/web/public/images/2626c3485668a19730c64a7ee672a214.jpg differ diff --git a/packages/web/public/images/3cd237361eada7fd30eb96d42d55ec00.jpg b/packages/web/public/images/3cd237361eada7fd30eb96d42d55ec00.jpg new file mode 100644 index 0000000..841ae13 Binary files /dev/null and b/packages/web/public/images/3cd237361eada7fd30eb96d42d55ec00.jpg differ diff --git a/packages/web/public/images/5ace16248237a96f6dbbcc16a3c385fe.jpg b/packages/web/public/images/5ace16248237a96f6dbbcc16a3c385fe.jpg new file mode 100644 index 0000000..f1d4424 Binary files /dev/null and b/packages/web/public/images/5ace16248237a96f6dbbcc16a3c385fe.jpg differ diff --git a/packages/web/public/images/6af0fdc5eafb86f8b540e3d322c3a007.jpg b/packages/web/public/images/6af0fdc5eafb86f8b540e3d322c3a007.jpg new file mode 100644 index 0000000..1397fd9 Binary files /dev/null and b/packages/web/public/images/6af0fdc5eafb86f8b540e3d322c3a007.jpg differ diff --git a/packages/web/public/images/8f5e3d92d2da0a760b312a9387219447.jpg b/packages/web/public/images/8f5e3d92d2da0a760b312a9387219447.jpg new file mode 100644 index 0000000..2a9bd56 Binary files /dev/null and b/packages/web/public/images/8f5e3d92d2da0a760b312a9387219447.jpg differ diff --git a/packages/web/public/images/9802f260887e9044312fb7d88547fb09.jpg b/packages/web/public/images/9802f260887e9044312fb7d88547fb09.jpg new file mode 100644 index 0000000..e659559 Binary files /dev/null and b/packages/web/public/images/9802f260887e9044312fb7d88547fb09.jpg differ diff --git a/packages/web/public/images/a3a56f54a11c76f46f4392b748f3026a.png b/packages/web/public/images/a3a56f54a11c76f46f4392b748f3026a.png new file mode 100644 index 0000000..c737b57 Binary files /dev/null and b/packages/web/public/images/a3a56f54a11c76f46f4392b748f3026a.png differ diff --git a/packages/web/public/images/a96d02d8cc43cc3b9f1e77c43dfa5644.png b/packages/web/public/images/a96d02d8cc43cc3b9f1e77c43dfa5644.png new file mode 100644 index 0000000..3fa8211 Binary files /dev/null and b/packages/web/public/images/a96d02d8cc43cc3b9f1e77c43dfa5644.png differ diff --git a/packages/web/public/images/d1454662da2a4a8e77cd4c98eda6d662.png b/packages/web/public/images/d1454662da2a4a8e77cd4c98eda6d662.png new file mode 100644 index 0000000..268208d Binary files /dev/null and b/packages/web/public/images/d1454662da2a4a8e77cd4c98eda6d662.png differ diff --git a/packages/web/public/images/d69ab7f4e5747b5b8f297e4ebe9770f5.png b/packages/web/public/images/d69ab7f4e5747b5b8f297e4ebe9770f5.png new file mode 100644 index 0000000..ab609cd Binary files /dev/null and b/packages/web/public/images/d69ab7f4e5747b5b8f297e4ebe9770f5.png differ diff --git a/packages/web/public/images/e4753cf6a55db6b7ab5037ed0fd4a3fe.jpg b/packages/web/public/images/e4753cf6a55db6b7ab5037ed0fd4a3fe.jpg new file mode 100644 index 0000000..9c97432 Binary files /dev/null and b/packages/web/public/images/e4753cf6a55db6b7ab5037ed0fd4a3fe.jpg differ diff --git a/packages/web/public/images/fe3050a31d3fb86accf26cc4bebec102.png b/packages/web/public/images/fe3050a31d3fb86accf26cc4bebec102.png new file mode 100644 index 0000000..9508523 Binary files /dev/null and b/packages/web/public/images/fe3050a31d3fb86accf26cc4bebec102.png differ diff --git a/packages/web/public/next.svg b/packages/web/public/next.svg new file mode 100644 index 0000000..5174b28 --- /dev/null +++ b/packages/web/public/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/web/public/vercel.svg b/packages/web/public/vercel.svg new file mode 100644 index 0000000..d2f8422 --- /dev/null +++ b/packages/web/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/web/src/components/molecules/BackgroundGrid/index.tsx b/packages/web/src/components/molecules/BackgroundGrid/index.tsx new file mode 100644 index 0000000..f1aea84 --- /dev/null +++ b/packages/web/src/components/molecules/BackgroundGrid/index.tsx @@ -0,0 +1,75 @@ +import * as React from 'react'; + +export interface BackgroundGridProps { + level?: number; + images: string[]; + parentKey?: React.Key; +} + +export const BackgroundGrid: React.FC = ({ + level = 0, + images, + parentKey = level, +}) => { + const [values, setValues] = React.useState<(string | null)[]>(); + + React.useEffect(() => { + const newValues = []; + + for (let i = 0; i < 4; i += 1) { + if (level < 1) { + newValues.push(null); + continue; + } + + if (level < 3) { + const hasInnerGrid = Math.floor(Math.random() * 2) === 1; + if (hasInnerGrid) { + newValues.push(null); + continue; + } + } + + const randomImage = images[Math.floor(Math.random() * images.length)]; + newValues.push(randomImage); + } + + setValues(newValues); + }, []); + + return ( +
+ {values?.map((value, index) => { + if (value === null) { + return ( + + ); + + // return ( + // level < 3 + // ? ( + // + // ) + // :
+ // ); + } + + return ( +
+ ); + })} +
+ ); +} diff --git a/packages/web/src/components/molecules/Brand/index.tsx b/packages/web/src/components/molecules/Brand/index.tsx new file mode 100644 index 0000000..c3750fb --- /dev/null +++ b/packages/web/src/components/molecules/Brand/index.tsx @@ -0,0 +1,7 @@ +import * as React from 'react'; + +export const Brand = () => ( + + TheoryOfNekomata + +); diff --git a/packages/web/src/components/molecules/ContactCtaBanner/index.tsx b/packages/web/src/components/molecules/ContactCtaBanner/index.tsx new file mode 100644 index 0000000..0cb41d6 --- /dev/null +++ b/packages/web/src/components/molecules/ContactCtaBanner/index.tsx @@ -0,0 +1,124 @@ +import * as React from 'react'; +import {Layouts} from '@tesseract-design/viewfinder-react'; +import * as WebNavigationReact from '@tesseract-design/web-navigation-react'; +import * as WebFreeformReact from '@tesseract-design/web-freeform-react'; +import * as WebFormattedReact from '@tesseract-design/web-formatted-react'; +import * as WebActionReact from '@tesseract-design/web-action-react'; + +export interface ContactCtaBannerProps { + onSubmit?: React.FormEventHandler; +} + +export const ContactCtaBanner: React.FC = ({ + onSubmit, +}) => { + const [visible, setVisible] = React.useState(); + const autofocusRef = React.useRef(null); + const messageRef = React.useRef(null); + + const openContactForm: React.MouseEventHandler = (e) => { + e.preventDefault(); + setVisible(true); + window.setTimeout(() => { + autofocusRef.current?.focus(); + if (messageRef.current && messageRef.current.style.height === '0px') { + messageRef.current.style.height = '12rem'; + } + }); + }; + + React.useEffect(() => { + setVisible(false); + }, []); + + return ( +
+
+ +
+

+ + Get in touch. + +

+

+ Your message will be received via email. +

+
+ + Open Form + +
+
+ {visible !== false && ( +
+
+ + Contact Form + +
+
+ +
+
+ +
+
+ +
+
+ + Send Message + +
+
+
+
+ )} +
+
+ ); +} diff --git a/packages/web/src/components/molecules/EnvisionSection/index.tsx b/packages/web/src/components/molecules/EnvisionSection/index.tsx new file mode 100644 index 0000000..f46c2c9 --- /dev/null +++ b/packages/web/src/components/molecules/EnvisionSection/index.tsx @@ -0,0 +1,72 @@ +import * as React from 'react'; +import Link from 'next/link'; +import {Layouts} from '@tesseract-design/viewfinder-react'; +import * as WebNavigationReact from '@tesseract-design/web-navigation-react'; +import {ShowcaseItem, ShowcaseItemProps} from '@/components/molecules/ShowcaseItem'; + +interface EnvisionSectionDatum extends ShowcaseItemProps { + id: string; + url: string; +} + +export interface EnvisionSectionProps { + data: EnvisionSectionDatum[]; +} + +export const EnvisionSection: React.FC = ({ + data, +}) => ( +
+ +
+

+ + I + {' '} + + envision. + + +

+
+
Ideas
+
Methods
+
Solutions
+
+
+
+ {data.map(({ id, url, ...datum }) => ( +
+ + + +
+ ))} +
+
+
+ + Browse + +
+
+
+
+); diff --git a/packages/web/src/components/molecules/FeaturedProjectSection/index.tsx b/packages/web/src/components/molecules/FeaturedProjectSection/index.tsx new file mode 100644 index 0000000..7594f00 --- /dev/null +++ b/packages/web/src/components/molecules/FeaturedProjectSection/index.tsx @@ -0,0 +1,93 @@ +import * as React from 'react'; +import {Layouts} from '@tesseract-design/viewfinder-react'; +import * as WebNavigationReact from '@tesseract-design/web-navigation-react'; + +interface IframeShowcaseProps extends Omit, 'children'> { + type: 'iframe'; +} + +interface ImageShowcaseProps extends Omit, 'alt'> { + type: 'img'; +} + +type ShowcaseProps = IframeShowcaseProps | ImageShowcaseProps; + +interface FeaturedProjectLink { + href: string; + children: React.ReactNode; + primary?: boolean; + subtext?: React.ReactNode; +} + +export interface FeaturedProjectSectionProps { + title: string; + description: string; + links?: FeaturedProjectLink[]; + showcase: ShowcaseProps; +} + +export const FeaturedProjectSection: React.FC = ({ + title, + description, + links = [], + showcase, +}) => { + const { type: showcaseType, ...showcaseProps } = showcase; + + return ( +
+
+
+ +
+
+

{title}

+

{description}

+
+ {links.map(({ href, primary, subtext, children }) => ( +
+ + {children} + +
+ ))} +
+
+
+
+
+
+ {showcaseType === 'iframe' && ( + + )} + {showcaseType === 'img' && ( + } + className={`object-cover object-center border-0 m-0 w-full h-full block ${showcaseProps.className ?? ''}`.trim()} + alt={title} + /> + )} +
+
+ ); +}; diff --git a/packages/web/src/components/molecules/FeedItem/index.tsx b/packages/web/src/components/molecules/FeedItem/index.tsx new file mode 100644 index 0000000..c4e06e9 --- /dev/null +++ b/packages/web/src/components/molecules/FeedItem/index.tsx @@ -0,0 +1,57 @@ +import * as React from 'react'; +import {Icon, IconProps} from '@/components/molecules/Icon'; + +export interface FeedItemProps { + date: Date; + type: string; + description: string; +} + +const formatFeedItemDate = (date: Date) => { + const mm = (date.getMonth() + 1).toString().padStart(2, '0'); + const dd = date.getDate().toString().padStart(2, '0'); + + return `${mm}.${dd}`; +}; + +const FEED_ITEM_TYPE_ICONS: Record = { + code: 'git-commit', +}; + +export const FeedItem: React.FC = ({ + date, + type, + description, +}) => ( +
+
+
+
+
Date
+
+ +
+
+
+
Type
+
+ +
+
+
+
Description
+
+ {description} +
+
+
+
+
+); diff --git a/packages/web/src/components/molecules/FeedItemHeading/index.tsx b/packages/web/src/components/molecules/FeedItemHeading/index.tsx new file mode 100644 index 0000000..846a8ee --- /dev/null +++ b/packages/web/src/components/molecules/FeedItemHeading/index.tsx @@ -0,0 +1,19 @@ +import * as React from 'react'; + +export interface FeedItemHeadingProps { + children?: React.ReactNode; +} + +export const FeedItemHeading: React.FC = ({ + children, +}) => ( + + + + {children} + + + +); diff --git a/packages/web/src/components/molecules/Footer/index.tsx b/packages/web/src/components/molecules/Footer/index.tsx new file mode 100644 index 0000000..817f055 --- /dev/null +++ b/packages/web/src/components/molecules/Footer/index.tsx @@ -0,0 +1,151 @@ +import * as React from 'react'; +import {Layouts} from '@tesseract-design/viewfinder-react'; +import {Brand} from '@/components/molecules/Brand'; + +export const Footer = () => ( + +) diff --git a/packages/web/src/components/molecules/Icon/index.tsx b/packages/web/src/components/molecules/Icon/index.tsx new file mode 100644 index 0000000..8585e48 --- /dev/null +++ b/packages/web/src/components/molecules/Icon/index.tsx @@ -0,0 +1,42 @@ +import * as React from 'react'; + +const ICONS = { + 'git-commit': ( + <> + + + + + ), + 'scroll-down': ( + <> + + + + ) +}; + +export const IconDerivedElementComponent = 'svg' as const; + +export type IconDerivedElement = SVGElementTagNameMap[typeof IconDerivedElementComponent]; + +type IconName = keyof typeof ICONS; + +export interface IconProps extends React.SVGProps { + name: IconName; +} + +export const Icon = React.forwardRef(({ + name, + className, + ...etcProps +}, forwardedRef) => ( + + {ICONS[name]} + +)); diff --git a/packages/web/src/components/molecules/MainLandingSection/index.tsx b/packages/web/src/components/molecules/MainLandingSection/index.tsx new file mode 100644 index 0000000..2d44a7b --- /dev/null +++ b/packages/web/src/components/molecules/MainLandingSection/index.tsx @@ -0,0 +1,117 @@ +import * as React from 'react'; +import Link from 'next/link'; +import {Layouts} from '@tesseract-design/viewfinder-react'; +import {Brand} from '@/components/molecules/Brand'; +import {Pillar} from '@/components/molecules/Pillar'; +import {BackgroundGrid} from '@/components/molecules/BackgroundGrid'; +import {Icon} from '@/components/molecules/Icon'; + +export interface MainLandingSectionProps { + backgroundImages: string[]; +} + +export const MainLandingSection: React.FC = ({ + backgroundImages +}) => { + const scrollDown: React.MouseEventHandler = React.useCallback((event) => { + event.preventDefault(); + + const target = window.document.querySelector(event.currentTarget.getAttribute('href')!); + if (!target) { + return; + } + + target.scrollIntoView({ + behavior: 'smooth', + }); + }, []); + + return ( +
+
+
+ +
+
+
+ +
+

+ + + +

+
+
+ + + Credentials + + +
+
+ + + Portfolio + + +
+
+ + + Blog + + +
+
+ + + Services & Values + + +
+
+
+
+
+ +
+
+ ); +} diff --git a/packages/web/src/components/molecules/MakeSection/index.tsx b/packages/web/src/components/molecules/MakeSection/index.tsx new file mode 100644 index 0000000..89d086e --- /dev/null +++ b/packages/web/src/components/molecules/MakeSection/index.tsx @@ -0,0 +1,115 @@ +import * as React from 'react'; +import Link from 'next/link'; +import {Layouts} from '@tesseract-design/viewfinder-react'; +import * as WebNavigationReact from '@tesseract-design/web-navigation-react'; +import {FeedItem, FeedItemProps} from '@/components/molecules/FeedItem'; +import {FeedItemHeading} from '@/components/molecules/FeedItemHeading'; + +interface MakeSectionDatum extends FeedItemProps { + id: string; + url: string; +} + +export interface MakeSectionProps { + data: MakeSectionDatum[]; +} + +export const MakeSection: React.FC = ({ + data, +}) => { + const groupedData = data.reduce( + (grouped, datum) => ({ + ...grouped, + [datum.date.getFullYear()]: [ + ...(grouped[datum.date.getFullYear()] ?? []), + datum, + ], + }), + {} as Record, + ); + + return ( +
+
+ +
+

+ + I + {' '} + + make. + + +

+
+
Software
+
Music
+
Art
+
+
+
+ {Object.entries(groupedData).map(([year, data]) => ( +
+

+ + + {year} + + +

+
+ {data.map(({ id, ...datum }) => ( +
+ + + +
+ ))} +
+
+ ))} +
+
+
+ + Browse + +
+
+
+
+ ); +} diff --git a/packages/web/src/components/molecules/Pillar/index.tsx b/packages/web/src/components/molecules/Pillar/index.tsx new file mode 100644 index 0000000..6749ef3 --- /dev/null +++ b/packages/web/src/components/molecules/Pillar/index.tsx @@ -0,0 +1,16 @@ +import * as React from 'react'; + +export interface PillarProps { + children?: React.ReactNode; +} + +export const Pillar: React.FC = ({ + children, +}) => ( + + + + {children} + + +); diff --git a/packages/web/src/components/molecules/ShowcaseItem/index.tsx b/packages/web/src/components/molecules/ShowcaseItem/index.tsx new file mode 100644 index 0000000..2ef3bf5 --- /dev/null +++ b/packages/web/src/components/molecules/ShowcaseItem/index.tsx @@ -0,0 +1,34 @@ +import * as React from 'react'; + +export interface ShowcaseItemProps { + imageUrl?: string; + title: string; + description: string; +} + +export const ShowcaseItem: React.FC = ({ + imageUrl, + title, + description, +}) => ( +
+
+
+
+ + + {title} + + +
+
+

{title}

+

{description}

+
+
+
+); diff --git a/packages/web/src/components/organisms/IndexLayout/index.tsx b/packages/web/src/components/organisms/IndexLayout/index.tsx new file mode 100644 index 0000000..38de5b2 --- /dev/null +++ b/packages/web/src/components/organisms/IndexLayout/index.tsx @@ -0,0 +1,47 @@ +import * as React from 'react'; +import {Layouts} from '@tesseract-design/viewfinder-react'; +import {MainLandingSection, MainLandingSectionProps} from '@/components/molecules/MainLandingSection'; +import {MakeSection, MakeSectionProps} from '@/components/molecules/MakeSection'; +import {EnvisionSection, EnvisionSectionProps} from '@/components/molecules/EnvisionSection'; +import {Footer} from '@/components/molecules/Footer'; +import {FeaturedProjectSection, FeaturedProjectSectionProps} from '@/components/molecules/FeaturedProjectSection'; +import {ContactCtaBanner} from '@/components/molecules/ContactCtaBanner'; + +export interface IndexLayoutProps { + backgroundImages: MainLandingSectionProps['backgroundImages']; + makeSectionData: MakeSectionProps['data']; + envisionSectionData: EnvisionSectionProps['data']; + featuredProjectData?: FeaturedProjectSectionProps[]; + onSubmit?: React.FormEventHandler; +} + +export const IndexLayout: React.FC = ({ + backgroundImages, + makeSectionData, + envisionSectionData, + featuredProjectData = [], + onSubmit, +}) => ( + + +
+ + + {featuredProjectData.map((featuredProjectProps) => ( + + ))} + +