@@ -11,11 +11,12 @@ | |||||
"dependencies": { | "dependencies": { | ||||
"@tesseract-design/viewfinder-base": "0.0.1", | "@tesseract-design/viewfinder-base": "0.0.1", | ||||
"@tesseract-design/viewfinder-react": "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", | |||||
"@tesseract-design/web-action-react": "0.2.0", | |||||
"@tesseract-design/web-formatted-react": "0.2.1", | |||||
"@tesseract-design/web-freeform-react": "0.2.1", | |||||
"@tesseract-design/web-navigation-react": "0.2.1", | |||||
"@theoryofnekomata/formxtra": "../../../formxtra", | |||||
"@modal-sh/iceform-next": "0.0.0", | |||||
"@types/node": "20.6.0", | "@types/node": "20.6.0", | ||||
"@types/react": "18.2.21", | "@types/react": "18.2.21", | ||||
"@types/react-dom": "18.2.7", | "@types/react-dom": "18.2.7", | ||||
@@ -25,8 +26,6 @@ | |||||
"eslint-config-next": "13.4.19", | "eslint-config-next": "13.4.19", | ||||
"next": "13.4.19", | "next": "13.4.19", | ||||
"postcss": "8.4.29", | "postcss": "8.4.29", | ||||
"react": "18.2.0", | |||||
"react-dom": "18.2.0", | |||||
"tailwindcss": "3.3.3", | "tailwindcss": "3.3.3", | ||||
"typescript": "5.2.2" | "typescript": "5.2.2" | ||||
} | } | ||||
@@ -5,6 +5,9 @@ settings: | |||||
excludeLinksFromLockfile: false | excludeLinksFromLockfile: false | ||||
dependencies: | dependencies: | ||||
'@modal-sh/iceform-next': | |||||
specifier: 0.0.0 | |||||
version: 0.0.0(next@13.4.19)(react-dom@18.2.0)(react@18.2.0) | |||||
'@tesseract-design/viewfinder-base': | '@tesseract-design/viewfinder-base': | ||||
specifier: 0.0.1 | specifier: 0.0.1 | ||||
version: 0.0.1 | version: 0.0.1 | ||||
@@ -12,20 +15,20 @@ dependencies: | |||||
specifier: 0.0.1 | specifier: 0.0.1 | ||||
version: 0.0.1(react-dom@18.2.0)(react@18.2.0) | version: 0.0.1(react-dom@18.2.0)(react@18.2.0) | ||||
'@tesseract-design/web-action-react': | '@tesseract-design/web-action-react': | ||||
specifier: ^0.2.0 | |||||
specifier: 0.2.0 | |||||
version: 0.2.0(react-dom@18.2.0)(react@18.2.0) | version: 0.2.0(react-dom@18.2.0)(react@18.2.0) | ||||
'@tesseract-design/web-formatted-react': | '@tesseract-design/web-formatted-react': | ||||
specifier: ^0.2.0 | |||||
specifier: 0.2.1 | |||||
version: 0.2.1(react-dom@18.2.0)(react@18.2.0) | version: 0.2.1(react-dom@18.2.0)(react@18.2.0) | ||||
'@tesseract-design/web-freeform-react': | '@tesseract-design/web-freeform-react': | ||||
specifier: ^0.2.0 | |||||
specifier: 0.2.1 | |||||
version: 0.2.1(react-dom@18.2.0)(react@18.2.0) | version: 0.2.1(react-dom@18.2.0)(react@18.2.0) | ||||
'@tesseract-design/web-navigation-react': | '@tesseract-design/web-navigation-react': | ||||
specifier: ^0.2.0 | |||||
specifier: 0.2.1 | |||||
version: 0.2.1(react-dom@18.2.0)(react@18.2.0) | version: 0.2.1(react-dom@18.2.0)(react@18.2.0) | ||||
'@theoryofnekomata/formxtra': | '@theoryofnekomata/formxtra': | ||||
specifier: ^1.0.3 | |||||
version: 1.0.3 | |||||
specifier: ../../../formxtra | |||||
version: link:../../../formxtra | |||||
'@types/node': | '@types/node': | ||||
specifier: 20.6.0 | specifier: 20.6.0 | ||||
version: 20.6.0 | version: 20.6.0 | ||||
@@ -53,12 +56,6 @@ dependencies: | |||||
postcss: | postcss: | ||||
specifier: 8.4.29 | specifier: 8.4.29 | ||||
version: 8.4.29 | version: 8.4.29 | ||||
react: | |||||
specifier: 18.2.0 | |||||
version: 18.2.0 | |||||
react-dom: | |||||
specifier: 18.2.0 | |||||
version: 18.2.0(react@18.2.0) | |||||
tailwindcss: | tailwindcss: | ||||
specifier: 3.3.3 | specifier: 3.3.3 | ||||
version: 3.3.3 | version: 3.3.3 | ||||
@@ -179,6 +176,23 @@ packages: | |||||
'@jridgewell/sourcemap-codec': 1.4.15 | '@jridgewell/sourcemap-codec': 1.4.15 | ||||
dev: false | dev: false | ||||
/@modal-sh/iceform-next@0.0.0(next@13.4.19)(react-dom@18.2.0)(react@18.2.0): | |||||
resolution: {integrity: sha512-/FoVjAtY0PCAPOLLN53vLjlJs3mIMmmy5r+Iqg7dp5csburzkGtLpYRpzMAVYNj4ttV0j+YaJxSBYWNtT+PaUQ==} | |||||
engines: {node: '>=12'} | |||||
peerDependencies: | |||||
next: 13.4.19 | |||||
react: ^16.8 || ^17.0 || ^18.0 | |||||
react-dom: ^16.8 || ^17.0 || ^18.0 | |||||
dependencies: | |||||
'@theoryofnekomata/formxtra': 1.0.3 | |||||
busboy: 1.6.0 | |||||
next: 13.4.19(react-dom@18.2.0)(react@18.2.0) | |||||
node-cache: 5.1.2 | |||||
react: 18.2.0 | |||||
react-dom: 18.2.0(react@18.2.0) | |||||
seroval: 0.10.4 | |||||
dev: false | |||||
/@modal-sh/react-utils@0.0.0(react-dom@18.2.0)(react@18.2.0): | /@modal-sh/react-utils@0.0.0(react-dom@18.2.0)(react@18.2.0): | ||||
resolution: {integrity: sha512-aqbD221Zhsucxnr2ZJqS2sZQbI4/xcb703GvcXLew+2zqFhZOwfRdclwTralB/TXBmrrIh3aHeOisQ+DLlmC3w==} | resolution: {integrity: sha512-aqbD221Zhsucxnr2ZJqS2sZQbI4/xcb703GvcXLew+2zqFhZOwfRdclwTralB/TXBmrrIh3aHeOisQ+DLlmC3w==} | ||||
engines: {node: '>=12'} | engines: {node: '>=12'} | ||||
@@ -826,6 +840,11 @@ packages: | |||||
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} | resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} | ||||
dev: false | dev: false | ||||
/clone@2.1.2: | |||||
resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} | |||||
engines: {node: '>=0.8'} | |||||
dev: false | |||||
/clsx@1.2.1: | /clsx@1.2.1: | ||||
resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==} | resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==} | ||||
engines: {node: '>=6'} | engines: {node: '>=6'} | ||||
@@ -2159,6 +2178,13 @@ packages: | |||||
- babel-plugin-macros | - babel-plugin-macros | ||||
dev: false | dev: false | ||||
/node-cache@5.1.2: | |||||
resolution: {integrity: sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==} | |||||
engines: {node: '>= 8.0.0'} | |||||
dependencies: | |||||
clone: 2.1.2 | |||||
dev: false | |||||
/node-releases@2.0.14: | /node-releases@2.0.14: | ||||
resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} | resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} | ||||
dev: false | dev: false | ||||
@@ -2603,6 +2629,11 @@ packages: | |||||
lru-cache: 6.0.0 | lru-cache: 6.0.0 | ||||
dev: false | dev: false | ||||
/seroval@0.10.4: | |||||
resolution: {integrity: sha512-TdaE9JkoATjKu+vjwllieX8zWyBTUVxbgWDnOsDJFfmKbM7vLSukuCXuD3pO3kkCtX4daywOW8ps2VCdPhS8/w==} | |||||
engines: {node: '>=10'} | |||||
dev: false | |||||
/set-function-length@1.2.2: | /set-function-length@1.2.2: | ||||
resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} | resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} | ||||
engines: {node: '>= 0.4'} | engines: {node: '>= 0.4'} | ||||
@@ -1,4 +1,5 @@ | |||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import * as Iceform from '@modal-sh/iceform-next'; | |||||
import {Layouts} from '@tesseract-design/viewfinder-react'; | import {Layouts} from '@tesseract-design/viewfinder-react'; | ||||
import * as WebNavigationReact from '@tesseract-design/web-navigation-react'; | import * as WebNavigationReact from '@tesseract-design/web-navigation-react'; | ||||
import * as WebFreeformReact from '@tesseract-design/web-freeform-react'; | import * as WebFreeformReact from '@tesseract-design/web-freeform-react'; | ||||
@@ -10,12 +11,14 @@ export interface ContactCtaBannerProps { | |||||
onSubmit?: React.FormEventHandler<HTMLFormElement>; | onSubmit?: React.FormEventHandler<HTMLFormElement>; | ||||
visible?: boolean; | visible?: boolean; | ||||
hasBrand?: boolean; | hasBrand?: boolean; | ||||
iceformProps?: Partial<ReturnType<typeof Iceform.useResponse>>; | |||||
} | } | ||||
export const ContactCtaBanner: React.FC<ContactCtaBannerProps> = ({ | export const ContactCtaBanner: React.FC<ContactCtaBannerProps> = ({ | ||||
onSubmit, | onSubmit, | ||||
visible: visibleProp = false, | visible: visibleProp = false, | ||||
hasBrand = false, | hasBrand = false, | ||||
iceformProps = {}, | |||||
}) => { | }) => { | ||||
const [visible, setVisible] = React.useState<boolean>(); | const [visible, setVisible] = React.useState<boolean>(); | ||||
const autofocusRef = React.useRef<HTMLInputElement>(null); | const autofocusRef = React.useRef<HTMLInputElement>(null); | ||||
@@ -76,12 +79,14 @@ export const ContactCtaBanner: React.FC<ContactCtaBannerProps> = ({ | |||||
</div> | </div> | ||||
</div> | </div> | ||||
{visible !== false && ( | {visible !== false && ( | ||||
<form | |||||
<Iceform.Form | |||||
{...iceformProps} | |||||
className="mt-8" | className="mt-8" | ||||
aria-label="Contact Form" | aria-label="Contact Form" | ||||
onSubmit={onSubmit} | onSubmit={onSubmit} | ||||
method="post" | method="post" | ||||
action="/a/contact" | action="/a/contact" | ||||
clientAction="/api/contact" | |||||
> | > | ||||
<fieldset className="contents"> | <fieldset className="contents"> | ||||
<legend className="sr-only"> | <legend className="sr-only"> | ||||
@@ -131,7 +136,7 @@ export const ContactCtaBanner: React.FC<ContactCtaBannerProps> = ({ | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</fieldset> | </fieldset> | ||||
</form> | |||||
</Iceform.Form> | |||||
)} | )} | ||||
</Layouts.Basic.ContentContainer> | </Layouts.Basic.ContentContainer> | ||||
</div> | </div> | ||||
@@ -1,4 +1,5 @@ | |||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import * as Iceform from '@modal-sh/iceform-next'; | |||||
import {Layouts} from '@tesseract-design/viewfinder-react'; | import {Layouts} from '@tesseract-design/viewfinder-react'; | ||||
import {MainLandingSection, MainLandingSectionProps} from '@/components/molecules/MainLandingSection'; | import {MainLandingSection, MainLandingSectionProps} from '@/components/molecules/MainLandingSection'; | ||||
import {MakeSection, MakeSectionProps} from '@/components/molecules/MakeSection'; | import {MakeSection, MakeSectionProps} from '@/components/molecules/MakeSection'; | ||||
@@ -17,6 +18,7 @@ export interface IndexLayoutProps { | |||||
contactVisible?: boolean; | contactVisible?: boolean; | ||||
hasMainLandingSection?: boolean; | hasMainLandingSection?: boolean; | ||||
contactHasBrand?: boolean; | contactHasBrand?: boolean; | ||||
iceformProps?: Partial<ReturnType<typeof Iceform.useResponse>> | |||||
} | } | ||||
export const IndexLayout: React.FC<IndexLayoutProps> = ({ | export const IndexLayout: React.FC<IndexLayoutProps> = ({ | ||||
@@ -28,6 +30,7 @@ export const IndexLayout: React.FC<IndexLayoutProps> = ({ | |||||
contactVisible = false, | contactVisible = false, | ||||
hasMainLandingSection = false, | hasMainLandingSection = false, | ||||
contactHasBrand = false, | contactHasBrand = false, | ||||
iceformProps, | |||||
}) => ( | }) => ( | ||||
<Layouts.Basic.Root className="contents"> | <Layouts.Basic.Root className="contents"> | ||||
<div | <div | ||||
@@ -65,6 +68,7 @@ export const IndexLayout: React.FC<IndexLayoutProps> = ({ | |||||
onSubmit={onSubmit} | onSubmit={onSubmit} | ||||
visible={contactVisible} | visible={contactVisible} | ||||
hasBrand={contactHasBrand} | hasBrand={contactHasBrand} | ||||
iceformProps={iceformProps} | |||||
/> | /> | ||||
<Footer/> | <Footer/> | ||||
</Layouts.Basic.Root> | </Layouts.Basic.Root> | ||||
@@ -0,0 +1,5 @@ | |||||
import { NextApiHandler } from 'next'; | |||||
export const receiveContactEntry: NextApiHandler = async (req, res) => { | |||||
res.status(200).json(req.body); | |||||
}; |
@@ -0,0 +1,14 @@ | |||||
import { NextPage } from 'next'; | |||||
import * as Iceform from '@modal-sh/iceform-next'; | |||||
import { receiveContactEntry } from '@/handlers/contact'; | |||||
const ActionContactPage: NextPage = () => null; | |||||
const getServerSideProps = Iceform.action.getServerSideProps({ | |||||
fn: receiveContactEntry, | |||||
}); | |||||
export { | |||||
getServerSideProps, | |||||
ActionContactPage as default, | |||||
}; |
@@ -0,0 +1,11 @@ | |||||
import * as Iceform from '@modal-sh/iceform-next'; | |||||
import { receiveContactEntry } from '@/handlers/contact'; | |||||
const handler = Iceform.action.wrapApiHandler({ fn: receiveContactEntry }); | |||||
const config = Iceform.action.getApiConfig(); | |||||
export { | |||||
config, | |||||
handler as default, | |||||
}; |
@@ -1,13 +0,0 @@ | |||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction | |||||
import type { NextApiRequest, NextApiResponse } from 'next' | |||||
type Data = { | |||||
name: string | |||||
} | |||||
export default function handler( | |||||
req: NextApiRequest, | |||||
res: NextApiResponse<Data> | |||||
) { | |||||
res.status(200).json({ name: 'John Doe' }) | |||||
} |
@@ -1,8 +1,8 @@ | |||||
import {NextPage} from 'next'; | |||||
import {useHuePulsate} from '@/hooks/effects'; | |||||
import * as config from '@/config'; | |||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import * as Iceform from '@modal-sh/iceform-next'; | |||||
import * as config from '@/config'; | |||||
import {IndexLayout} from '@/components/organisms/IndexLayout'; | import {IndexLayout} from '@/components/organisms/IndexLayout'; | ||||
import {useHuePulsate} from '@/hooks/effects'; | |||||
const IMAGE_CHOICES = [ | const IMAGE_CHOICES = [ | ||||
'/images/3cd237361eada7fd30eb96d42d55ec00.jpg', | '/images/3cd237361eada7fd30eb96d42d55ec00.jpg', | ||||
@@ -20,7 +20,18 @@ const IMAGE_CHOICES = [ | |||||
'/images/fe3050a31d3fb86accf26cc4bebec102.png', | '/images/fe3050a31d3fb86accf26cc4bebec102.png', | ||||
]; | ]; | ||||
const ContactPage: NextPage = () => { | |||||
const ContactPage: Iceform.NextPage = ({ | |||||
req, | |||||
res, | |||||
}) => { | |||||
const { | |||||
response, | |||||
loading, | |||||
...iceformProps | |||||
} = Iceform.useResponse({ | |||||
res, | |||||
}); | |||||
useHuePulsate(config.effects.huePulsate); | useHuePulsate(config.effects.huePulsate); | ||||
return ( | return ( | ||||
@@ -28,8 +39,11 @@ const ContactPage: NextPage = () => { | |||||
backgroundImages={IMAGE_CHOICES} | backgroundImages={IMAGE_CHOICES} | ||||
contactVisible | contactVisible | ||||
contactHasBrand | contactHasBrand | ||||
iceformProps={iceformProps} | |||||
/> | /> | ||||
) | ) | ||||
}; | }; | ||||
export const getServerSideProps = Iceform.destination.getServerSideProps(); | |||||
export default ContactPage; | export default ContactPage; |
@@ -4,6 +4,7 @@ import {useHuePulsate} from '@/hooks/effects'; | |||||
import {useContactForm} from '@/hooks/contact'; | import {useContactForm} from '@/hooks/contact'; | ||||
import {IndexLayout} from '@/components/organisms/IndexLayout'; | import {IndexLayout} from '@/components/organisms/IndexLayout'; | ||||
import * as config from '@/config'; | import * as config from '@/config'; | ||||
import * as Iceform from '@modal-sh/iceform-next'; | |||||
const IMAGE_CHOICES = [ | const IMAGE_CHOICES = [ | ||||
'/images/3cd237361eada7fd30eb96d42d55ec00.jpg', | '/images/3cd237361eada7fd30eb96d42d55ec00.jpg', | ||||
@@ -122,21 +123,31 @@ const featuredProjectData = [ | |||||
}, | }, | ||||
]; | ]; | ||||
const IndexPage: NextPage = () => { | |||||
const IndexPage: Iceform.NextPage = ({ | |||||
req, | |||||
res, | |||||
}) => { | |||||
const { | |||||
response, | |||||
loading, | |||||
...iceformProps | |||||
} = Iceform.useResponse({ | |||||
res, | |||||
}); | |||||
useHuePulsate(config.effects.huePulsate); | useHuePulsate(config.effects.huePulsate); | ||||
const { processContactForm } = useContactForm(); | |||||
return ( | return ( | ||||
<IndexLayout | <IndexLayout | ||||
backgroundImages={IMAGE_CHOICES} | backgroundImages={IMAGE_CHOICES} | ||||
makeSectionData={makeSectionData} | makeSectionData={makeSectionData} | ||||
envisionSectionData={envisionSectionData} | envisionSectionData={envisionSectionData} | ||||
featuredProjectData={featuredProjectData} | featuredProjectData={featuredProjectData} | ||||
onSubmit={processContactForm} | |||||
hasMainLandingSection | hasMainLandingSection | ||||
iceformProps={iceformProps} | |||||
/> | /> | ||||
); | ); | ||||
}; | }; | ||||
export const getServerSideProps = Iceform.destination.getServerSideProps(); | |||||
export default IndexPage; | export default IndexPage; |