diff --git a/app/(pages)/(components)/footer/footer.module.scss b/app/(pages)/(components)/footer/footer.module.scss index 66e3be15..927f638b 100644 --- a/app/(pages)/(components)/footer/footer.module.scss +++ b/app/(pages)/(components)/footer/footer.module.scss @@ -1,4 +1,5 @@ .footer { display: flex; justify-content: space-between; + padding: var(--layout-margin); } diff --git a/app/(pages)/(components)/navigation/index.js b/app/(pages)/(components)/navigation/index.js index 95300042..28004ade 100644 --- a/app/(pages)/(components)/navigation/index.js +++ b/app/(pages)/(components)/navigation/index.js @@ -8,6 +8,7 @@ import s from './navigation.module.scss' const LINKS = [ { href: '/', label: 'home' }, { href: '/r3f', label: 'r3f' }, + { href: '/storyblok', label: 'storyblok' }, ] export function Navigation() { diff --git a/app/(pages)/(components)/navigation/navigation.module.scss b/app/(pages)/(components)/navigation/navigation.module.scss index f0012ab6..46cfa962 100644 --- a/app/(pages)/(components)/navigation/navigation.module.scss +++ b/app/(pages)/(components)/navigation/navigation.module.scss @@ -3,6 +3,8 @@ flex-direction: column; position: fixed; z-index: 2; + top: var(--layout-margin); + left: var(--layout-margin); .title { display: inline-flex; diff --git a/app/(pages)/wrapper/index.js b/app/(pages)/(components)/wrapper/index.js similarity index 85% rename from app/(pages)/wrapper/index.js rename to app/(pages)/(components)/wrapper/index.js index 8dea1aad..cc89522b 100644 --- a/app/(pages)/wrapper/index.js +++ b/app/(pages)/(components)/wrapper/index.js @@ -1,8 +1,8 @@ import cn from 'clsx' import { Lenis } from 'components/lenis' import { Canvas } from 'libs/webgl/components/canvas' -import { Footer } from '../(components)/footer' -import { Navigation } from '../(components)/navigation' +import { Footer } from '../footer' +import { Navigation } from '../navigation' import s from './wrapper.module.scss' export function Wrapper({ diff --git a/app/(pages)/wrapper/wrapper.module.scss b/app/(pages)/(components)/wrapper/wrapper.module.scss similarity index 81% rename from app/(pages)/wrapper/wrapper.module.scss rename to app/(pages)/(components)/wrapper/wrapper.module.scss index c6087024..12cf27ab 100644 --- a/app/(pages)/wrapper/wrapper.module.scss +++ b/app/(pages)/(components)/wrapper/wrapper.module.scss @@ -8,5 +8,7 @@ .main { flex-grow: 1; position: relative; + display: flex; + flex-direction: column; } } diff --git a/app/(pages)/home/home.module.scss b/app/(pages)/home/home.module.scss index 8555cf68..fc34cc7b 100644 --- a/app/(pages)/home/home.module.scss +++ b/app/(pages)/home/home.module.scss @@ -1,5 +1,5 @@ .page { text-transform: uppercase; font-family: var(--font-ibm-plex-mono); - padding: desktop-vw(16px); + padding: var(--layout-margin); } diff --git a/app/(pages)/home/page.js b/app/(pages)/home/page.js index e58b84a5..1897c781 100644 --- a/app/(pages)/home/page.js +++ b/app/(pages)/home/page.js @@ -1,13 +1,10 @@ -import { TheatreProjectProvider } from 'libs/theatre' -import { Wrapper } from '../wrapper' +import { Wrapper } from '../(components)/wrapper' import s from './home.module.scss' export default function Home() { return ( - - - {/* content */} - - + + {/* content */} + ) } diff --git a/app/(pages)/r3f/page.js b/app/(pages)/r3f/page.js index d857063d..62d13cc0 100644 --- a/app/(pages)/r3f/page.js +++ b/app/(pages)/r3f/page.js @@ -1,11 +1,11 @@ import { TheatreProjectProvider } from 'libs/theatre' -import { Wrapper } from '../wrapper' +import { Wrapper } from '../(components)/wrapper' import { Box } from './(components)/box' import s from './r3f.module.scss' export default function Home() { return ( - + diff --git a/app/(pages)/r3f/r3f.module.scss b/app/(pages)/r3f/r3f.module.scss index 8555cf68..fc34cc7b 100644 --- a/app/(pages)/r3f/r3f.module.scss +++ b/app/(pages)/r3f/r3f.module.scss @@ -1,5 +1,5 @@ .page { text-transform: uppercase; font-family: var(--font-ibm-plex-mono); - padding: desktop-vw(16px); + padding: var(--layout-margin); } diff --git a/app/(pages)/storyblok/(component)/tutorial/index.js b/app/(pages)/storyblok/(component)/tutorial/index.js new file mode 100644 index 00000000..d5c69c37 --- /dev/null +++ b/app/(pages)/storyblok/(component)/tutorial/index.js @@ -0,0 +1,44 @@ +'use client' + +import { useStoryblokContext } from 'libs/storyblok/context' +import s from './tutorial.module.scss' + +export function Tutorial() { + const { story } = useStoryblokContext() + + return ( +
+

{story.content?.title}

+ +
+ + # MacOS +
+ brew install mkcert +
+ + # Windows +
+ choco install mkcert +
+
+
+ + + mkcert -install +
+ mkcert localhost +
+ npm run dev:storyblok +
+ + + # update .env +
+ STORYBLOK_PREVIEW_ACCESS_TOKEN +
+ STORYBLOK_PUBLIC_ACCESS_TOKEN +
+
+ ) +} diff --git a/app/(pages)/storyblok/(component)/tutorial/tutorial.module.scss b/app/(pages)/storyblok/(component)/tutorial/tutorial.module.scss new file mode 100644 index 00000000..2d7c1d53 --- /dev/null +++ b/app/(pages)/storyblok/(component)/tutorial/tutorial.module.scss @@ -0,0 +1,22 @@ +.tutorial { + display: flex; + flex-direction: column; + align-items: center; + gap: var(--layout-columns-gap); + + .title { + text-align: center; + } + + .codes { + display: flex; + gap: var(--layout-columns-gap); + } + + code { + padding: desktop-vw(8px); + border: 1px solid var(--theme-secondary); + border-radius: desktop-vw(8px); + display: inline-block; + } +} diff --git a/app/(pages)/storyblok/page.js b/app/(pages)/storyblok/page.js new file mode 100644 index 00000000..46e2557b --- /dev/null +++ b/app/(pages)/storyblok/page.js @@ -0,0 +1,21 @@ +import { storyblokApi } from 'libs/storyblok' +import { StoryblokContextProvider } from 'libs/storyblok/context' +import { Wrapper } from '../(components)/wrapper' +import { Tutorial } from './(component)/tutorial' +import s from './storyblok.module.scss' + +export default async function Storyblok() { + const { data } = await storyblokApi.get('cdn/stories/home', { + version: process.env.NODE_ENV === 'development' ? 'draft' : 'published', + }) + + return ( + + +
+ +
+
+
+ ) +} diff --git a/app/(pages)/storyblok/storyblok.module.scss b/app/(pages)/storyblok/storyblok.module.scss new file mode 100644 index 00000000..8a2f7e75 --- /dev/null +++ b/app/(pages)/storyblok/storyblok.module.scss @@ -0,0 +1,11 @@ +.page { + text-transform: uppercase; + font-family: var(--font-ibm-plex-mono); + + .inner { + display: flex; + align-items: center; + justify-content: center; + flex-grow: 1; + } +} diff --git a/app/(pages)/tina/(components)/hero.js b/app/(pages)/tina/(components)/hero.js deleted file mode 100644 index 18cd8f0d..00000000 --- a/app/(pages)/tina/(components)/hero.js +++ /dev/null @@ -1,16 +0,0 @@ -'use client' - -import { useTinaContext } from 'tina/tina-provider' -import { tinaField } from 'tinacms/dist/react' - -export const Hero = () => { - const { hero: data } = useTinaContext() - - if (!data) return - - return ( -

- {data.firstFold.title} -

- ) -} diff --git a/app/(pages)/tina/(components)/section.js b/app/(pages)/tina/(components)/section.js deleted file mode 100644 index 15998da0..00000000 --- a/app/(pages)/tina/(components)/section.js +++ /dev/null @@ -1,16 +0,0 @@ -'use client' - -import { useTinaContext } from 'tina/tina-provider' -import { tinaField } from 'tinacms/dist/react' - -export const Section = () => { - const { sections: data } = useTinaContext() - - if (!data) return - - return ( -

- {data.firstSection.title} -

- ) -} diff --git a/app/(pages)/tina/page.js b/app/(pages)/tina/page.js deleted file mode 100644 index f48a3b30..00000000 --- a/app/(pages)/tina/page.js +++ /dev/null @@ -1,64 +0,0 @@ -import { client } from 'tina/__generated__/client' -import { TinaProvider } from 'tina/tina-provider' -import { Wrapper } from '../wrapper' -import { Hero } from './(components)/hero' -import { Section } from './(components)/section' -import s from './tina.module.scss' - -const pageId = 'home' -const indexable = false //TODO: change when going live - -export default async function TinaHome() { - const [pageData] = await Promise.all([ - client.queries[pageId]({ - relativePath: `${pageId}.md`, - }), - ]) - - return ( - - - -
- - - ) -} - -export async function generateMetadata() { - const [metadata] = await Promise.all([ - client.queries['getHomeMetadata']({ - relativePath: `${pageId}.md`, - }), - ]) - - const cmsMetadata = metadata?.data[pageId]?.global?.find(({ __typename }) => - __typename.toLowerCase().includes('metadata'), - ) - - if (!cmsMetadata) return {} - - return { - ...cmsMetadata, - openGraph: cmsMetadata.openGraph - ? { - images: [ - { - url: cmsMetadata.openGraph, - width: 1200, - height: 630, - alt: cmsMetadata.title, - }, - ], - } - : null, - robots: { - index: indexable, - follow: indexable, - googleBot: { - index: indexable, - follow: indexable, - }, - }, - } -} diff --git a/app/(pages)/tina/templates/[slug]/page.js b/app/(pages)/tina/templates/[slug]/page.js deleted file mode 100644 index 295eacef..00000000 --- a/app/(pages)/tina/templates/[slug]/page.js +++ /dev/null @@ -1,79 +0,0 @@ -export const dynamic = 'force-dynamic' - -import { Wrapper } from 'app/(pages)/wrapper' -import { isEmptyArray } from 'libs/utils' -import { notFound } from 'next/navigation' -import { client } from 'tina/__generated__/client' -import { TinaProvider } from 'tina/tina-provider' -import { Hero } from '../../(components)/hero' -import { Section } from '../../(components)/section' -import s from '../../tina.module.scss' - -const pageId = 'templatesConnection' -const indexable = false //TODO: change when going live - -export default async function Templates({ params }) { - const [pageData] = await Promise.all([ - client.queries[pageId]({ - filter: { slug: { eq: params.slug } }, - }), - ]) - - if (isEmptyArray(pageData.data[pageId].edges)) return notFound() - - return ( - - - -
- - - ) -} - -export const dynamicParams = true - -export async function generateStaticParams() { - const { data } = await client.queries[pageId]() - const paths = data[pageId].edges.map(({ node }) => ({ slug: node.slug })) - - return paths -} - -export async function generateMetadata({ params }) { - const [metadata] = await Promise.all([ - client.queries['getTemplatesMetadata']({ - filter: { slug: { eq: params.slug } }, - }), - ]) - - const cmsMetadata = metadata?.data[pageId]?.edges[0]?.node?.global?.find( - ({ __typename }) => __typename.toLowerCase().includes('metadata'), - ) - - if (!cmsMetadata) return {} - - return { - ...cmsMetadata, - openGraph: cmsMetadata.openGraph - ? { - images: [ - { - url: cmsMetadata.openGraph, - width: 1200, - height: 630, - alt: cmsMetadata.title, - }, - ], - } - : null, - robots: { - index: indexable, - follow: indexable, - googleBot: { - index: indexable, - follow: indexable, - }, - }, - } -} diff --git a/app/(pages)/tina/tina.module.scss b/app/(pages)/tina/tina.module.scss deleted file mode 100644 index 8555cf68..00000000 --- a/app/(pages)/tina/tina.module.scss +++ /dev/null @@ -1,5 +0,0 @@ -.page { - text-transform: uppercase; - font-family: var(--font-ibm-plex-mono); - padding: desktop-vw(16px); -} diff --git a/components/console/index.js b/components/console/index.js new file mode 100644 index 00000000..44dc8f6c --- /dev/null +++ b/components/console/index.js @@ -0,0 +1,5 @@ +'use client' + +export default function Console({ log }) { + console.log(log) +} diff --git a/components/scrollbar/index.js b/components/scrollbar/index.js index cb077482..db28984a 100644 --- a/components/scrollbar/index.js +++ b/components/scrollbar/index.js @@ -1,3 +1,5 @@ +'use client' + import { useRect } from '@studio-freight/hamo' import { useLenis } from '@studio-freight/react-lenis' import { mapRange } from 'libs/maths' diff --git a/components/split-text/index.js b/components/split-text/index.js index 362447cb..0cae1d3d 100644 --- a/components/split-text/index.js +++ b/components/split-text/index.js @@ -1,6 +1,7 @@ +'use client' + import { useRect } from '@studio-freight/hamo' import { gsap } from 'gsap' -// import { SplitText as GSAPSplitText } from 'gsap/dist/SplitText' import { SplitText as GSAPSplitText } from 'gsap/dist/SplitText' import { forwardRef, @@ -12,7 +13,9 @@ import { } from 'react' import s from './split-text.module.scss' -gsap.registerPlugin(GSAPSplitText) +if (typeof window !== 'undefined') { + gsap.registerPlugin(GSAPSplitText) +} export const SplitText = forwardRef(function SplitText( { children, className, type }, @@ -29,6 +32,9 @@ export const SplitText = forwardRef(function SplitText( const splitted = new GSAPSplitText(elementRef.current, { tag: 'span', type, + linesClass: 'line', + wordsClass: 'word', + charsClass: 'char', }) setSplitted(splitted) @@ -40,17 +46,15 @@ export const SplitText = forwardRef(function SplitText( const render = useMemo( () => ( - - - - {children} - - - {children} - + + + {children} + + + {children} ), diff --git a/create-certs.sh b/create-certs.sh new file mode 100644 index 00000000..9a0aa607 --- /dev/null +++ b/create-certs.sh @@ -0,0 +1,6 @@ +# MacOS + +brew install mkcert +mkcert -install +mkcert localhost + diff --git a/libs/storyblok/context.js b/libs/storyblok/context.js new file mode 100644 index 00000000..d6fb5a59 --- /dev/null +++ b/libs/storyblok/context.js @@ -0,0 +1,71 @@ +'use client' + +// https://www.storyblok.com/docs/Guides/storyblok-latest-js?utm_source=github.com&utm_medium=readme&utm_campaign=storyblok-js + +import { useRouter, useSearchParams } from 'next/navigation' +import Script from 'next/script' +import { + Suspense, + createContext, + useCallback, + useContext, + useState, +} from 'react' + +export const StoryblokContext = createContext({}) + +export function useStoryblokContext() { + return useContext(StoryblokContext) +} + +const BRIDGE_URL = '//app.storyblok.com/f/storyblok-v2-latest.js' + +function StoryblokBridge({ onLoad }) { + const searchParams = useSearchParams() + const isLiveEditing = searchParams.has('_storyblok') + + return ( + isLiveEditing && ( +