Marketing website POC (#3139)

First website POC
This commit is contained in:
Félix Malfait 2023-12-23 10:08:55 +01:00 committed by GitHub
parent 68a6250757
commit 5ef5bbdc4d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 6279 additions and 46 deletions

View File

@ -1,9 +0,0 @@
import { Decorator } from '@storybook/react';
import { ObjectMetadataItemsProvider } from '@/object-metadata/components/ObjectMetadataItemsProvider';
export const ObjectMetadataItemsDecorator: Decorator = (Story) => (
<ObjectMetadataItemsProvider>
<Story />
</ObjectMetadataItemsProvider>
);

View File

@ -15,7 +15,8 @@
"packages/twenty-docs",
"packages/twenty-server",
"packages/twenty-utils",
"packages/twenty-zapier"
"packages/twenty-zapier",
"packages/twenty-website"
]
},
"devDependencies": {

View File

@ -182,4 +182,4 @@
"msw": {
"workerDirectory": "public"
}
}
}

View File

@ -154,4 +154,4 @@
"npm": "please-use-yarn",
"yarn": "^4.0.2"
}
}
}

View File

@ -0,0 +1 @@
BASE_URL=http://localhost:3000

View File

@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}

36
packages/twenty-website/.gitignore vendored Normal file
View File

@ -0,0 +1,36 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz
# 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

View File

@ -0,0 +1,16 @@
This is a [Next.js](https://nextjs.org/) project.
## Getting Started
First, run the development server:
```bash
yarn 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.tsx`. The page auto-updates as you edit the file.

View File

@ -0,0 +1,4 @@
/** @type {import('next').NextConfig} */
const nextConfig = {}
module.exports = nextConfig

View File

@ -0,0 +1,30 @@
{
"name": "twenty-website",
"version": "0.2.2",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@tabler/icons-react": "^2.44.0",
"next": "14.0.4",
"next-mdx-remote": "^4.4.1",
"react": "^18",
"react-dom": "^18",
"remark-behead": "^3.1.0",
"remark-gfm": "^3.0.1"
},
"devDependencies": {
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"eslint": "^8",
"eslint-config-next": "14.0.4",
"typescript": "^5"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 570 B

View File

@ -0,0 +1,12 @@
<svg width="136" height="136" viewBox="0 0 136 136" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_2343_96406)">
<path d="M136 2.28882e-05H0L0.000144482 136H136V2.28882e-05ZM27.27 50.6401C27.27 43.2101 33.3 37.1801 40.73 37.1801H66.64C67.02 37.1801 67.37 37.4101 67.53 37.7601C67.69 38.1101 67.62 38.5201 67.36 38.8101L61.68 44.9801C60.69 46.0501 59.3 46.6701 57.84 46.6701H40.8C38.57 46.6701 36.76 48.4801 36.76 50.7101V60.8901C36.76 62.2001 35.7 63.2601 34.39 63.2601H29.65C28.34 63.2601 27.28 62.2001 27.28 60.8901V50.6401H27.27ZM107.88 85.3601C107.88 92.7901 101.85 98.82 94.42 98.82H83.41C75.98 98.82 69.95 92.7901 69.95 85.3601V66.0901C69.95 64.7801 70.44 63.5201 71.33 62.5501L77.75 55.5801C78.02 55.2901 78.44 55.1901 78.82 55.3301C79.19 55.4801 79.44 55.83 79.44 56.23V85.3001C79.44 87.5301 81.25 89.3401 83.48 89.3401H94.36C96.59 89.3401 98.4 87.5301 98.4 85.3001V50.7101C98.4 48.4801 96.59 46.6701 94.36 46.6701H81.71C80.26 46.6701 78.88 47.2801 77.89 48.3401L40.16 89.3401H62.83C64.14 89.3401 65.2 90.4001 65.2 91.7101V96.4501C65.2 97.7601 64.14 98.82 62.83 98.82H32.28C29.51 98.82 27.26 96.5701 27.26 93.8001V91.29C27.26 90.03 27.73 88.8201 28.59 87.8901L70.89 41.9401C73.69 38.9001 77.62 37.1801 81.75 37.1801H94.41C101.84 37.1801 107.87 43.2101 107.87 50.6401V85.3601H107.88Z" fill="black"/>
<path d="M27.27 50.6401C27.27 43.2101 33.3 37.1801 40.73 37.1801H66.64C67.02 37.1801 67.37 37.4101 67.53 37.7601C67.69 38.1101 67.62 38.5201 67.36 38.8101L61.68 44.9801C60.69 46.0501 59.3 46.6701 57.84 46.6701H40.8C38.57 46.6701 36.76 48.4801 36.76 50.7101V60.8901C36.76 62.2001 35.7 63.2601 34.39 63.2601H29.65C28.34 63.2601 27.28 62.2001 27.28 60.8901V50.6401H27.27Z" fill="white"/>
<path d="M107.88 85.3601C107.88 92.7901 101.85 98.82 94.42 98.82H83.41C75.98 98.82 69.95 92.7901 69.95 85.3601V66.0901C69.95 64.7801 70.44 63.5201 71.33 62.5501L77.75 55.5801C78.02 55.2901 78.44 55.1901 78.82 55.3301C79.19 55.4801 79.44 55.83 79.44 56.23V85.3001C79.44 87.5301 81.25 89.3401 83.48 89.3401H94.36C96.59 89.3401 98.4 87.5301 98.4 85.3001V50.7101C98.4 48.4801 96.59 46.6701 94.36 46.6701H81.71C80.26 46.6701 78.88 47.2801 77.89 48.3401L40.16 89.3401H62.83C64.14 89.3401 65.2 90.4001 65.2 91.7101V96.4501C65.2 97.7601 64.14 98.82 62.83 98.82H32.28C29.51 98.82 27.26 96.5701 27.26 93.8001V91.29C27.26 90.03 27.73 88.8201 28.59 87.8901L70.89 41.9401C73.69 38.9001 77.62 37.1801 81.75 37.1801H94.41C101.84 37.1801 107.87 43.2101 107.87 50.6401V85.3601H107.88Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_2343_96406">
<rect width="136" height="136" rx="16" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,8 @@
import {NextRequest, NextResponse} from "next/server";
export async function GET (request: NextRequest){
const response = await fetch('https://api.github.com/repos/twentyhq/twenty/releases');
const data = await response.json();
return NextResponse.json(data);
}

View File

@ -0,0 +1,4 @@
export default async function BlogPost({ params }: { params: { slug: string } }) {
const posts = {};
return <>Blog Post: {params.slug}</>;
}

View File

@ -0,0 +1,6 @@
export default async function BlogHome() {
const posts = {};
return <>Blog Home</>;
}

View File

@ -0,0 +1,11 @@
'use client'
export const ContentContainer = ({children}: {children?: React.ReactNode}) => {
return (
<div style={{
width: '600px',
display: 'flex',
flexDirection: 'column',
}}>{children}</div>
)
}

View File

@ -0,0 +1,106 @@
'use client'
import styled from '@emotion/styled'
import { Logo } from './Logo';
import { DiscordIcon, GithubIcon, LinkedInIcon, XIcon } from "./Icons";
const FooterContainer = styled.div`
padding: 64px 96px 64px 96px;
display: flex;
flex-direction: column;
color: rgb(129, 129, 129);
gap: 32px;
`;
const LeftSideFooter = styled.div`
width: 36Opx;
display: flex;
flex-direction: column;
gap: 16px;`;
const RightSideFooter = styled.div`
display: flex;
justify-content: space-between;`;
const RightSideFooterColumn = styled.div`
width: 160px;
display: flex;
flex-direction: column;
gap: 8px;
`;
const RightSideFooterLink = styled.a`
color: rgb(129, 129, 129);
text-decoration: none;
&:hover {
text-decoration: underline;
color: #000;
}`;
const RightSideFooterColumnTitle = styled.div`
font-size: 20px;
font-weight: 500;
color: #000;
`;
export const FooterNav = () => {
return <FooterContainer>
<div style={{ width: '100%', display: 'flex', flexDirection: 'row', justifyContent:'space-between'}}>
<LeftSideFooter>
<Logo />
<div>
The #1 Open Source CRM
</div>
</LeftSideFooter>
<RightSideFooter>
<RightSideFooterColumn>
<RightSideFooterColumnTitle>Company</RightSideFooterColumnTitle>
<RightSideFooterLink href='/'>Pricing</RightSideFooterLink>
<RightSideFooterLink href='/'>Story</RightSideFooterLink>
</RightSideFooterColumn>
<RightSideFooterColumn>
<RightSideFooterColumnTitle>Resources</RightSideFooterColumnTitle>
<RightSideFooterLink href='https://docs.twenty.com'>Documentation</RightSideFooterLink>
<RightSideFooterLink href='/releases'>Changelog</RightSideFooterLink>
</RightSideFooterColumn>
<RightSideFooterColumn>
<RightSideFooterColumnTitle>Other</RightSideFooterColumnTitle>
<RightSideFooterLink href='/oss-friends'>OSS Friends</RightSideFooterLink>
<RightSideFooterLink href='/legal/terms'>Terms of Service</RightSideFooterLink>
<RightSideFooterLink href='/legal/privacy'>Privacy Policy</RightSideFooterLink>
</RightSideFooterColumn>
</RightSideFooter>
</div>
<div style={{
width: '100%',
display: 'flex',
flexDirection: 'row',
justifyContent:'space-between',
borderTop: '1px solid rgb(179, 179, 179)',
paddingTop: '32px'
}}>
<div>
<span style={{fontFamily: "Inter, sans-serif"}}>©</span>
2023 Twenty PBC
</div>
<div style={{ display: 'flex', flexDirection: 'row', justifyContent:'space-between', gap:'10px'}}>
<a href="https://x.com/twentycrm" target="_blank">
<XIcon size='M'/>
</a>
<a href="https://github.com/twentyhq/twenty" target="_blank">
<GithubIcon size='M'/>
</a>
<a href="https://www.linkedin.com/company/twenty" target="_blank">
<LinkedInIcon size='M'/>
</a>
<a href="https://discord.gg/UfGNZJfAG6" target="_blank">
<DiscordIcon size='M' />
</a>
</div>
</div>
</FooterContainer>
;
}

View File

@ -0,0 +1,133 @@
'use client'
import styled from '@emotion/styled'
import { Logo } from './Logo';
import { IBM_Plex_Mono } from 'next/font/google';
import { GithubIcon } from './Icons';
const IBMPlexMono = IBM_Plex_Mono({
weight: '500',
subsets: ['latin'],
display: 'swap',
});
const Nav = styled.nav`
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-between;
align-items: center;
overflow: visible;
padding: 12px 16px 12px 16px;
position: relative;
border-color: rgba(20, 20, 20, 0.08);
transform-origin: 50% 50% 0px;
border-bottom: 1px solid var(--Borders-Light, #F1F1F1);
`;
const LinkList = styled.div`
display:flex;
flex-direction: row;
`;
const ListItem = styled.a`
color: rgb(71, 71, 71);
text-decoration: none;
display: flex;
gap: 4px;
align-items: center;
border-radius: 8px;
height: 40px;
padding-left: 16px;
padding-right: 16px;
&:hover {
background-color: #F1F1F1;
}
`;
const LogoContainer = styled.div`
display: flex;
align-items: center;
gap: 8px;
width:202px;`;
const LogoAddon = styled.div`
font-size: 12px;
font-style: normal;
font-weight: 500;
line-height: 150%;
`;
const StyledButton = styled.div`
display: flex;
height: 40px;
padding-left: 16px;
padding-right: 16px;
align-items: center;
background-color: #000;
color: #fff;
border-radius: 8px;
font-weight: 500;
border: none;
outline: inherit;
cursor: pointer;
`;
const CallToActionContainer = styled.div`
display: flex;
align-items: center;
gap: 16px;
a {
text-decoration: none;
}
`;
const LinkNextToCTA = styled.a`
display: flex;
align-items: center;
color: rgb(71, 71, 71);
span {
text-decoration: underline;
}`;
const CallToAction = () => {
return <CallToActionContainer>
<LinkNextToCTA href="https://github.com/twentyhq/twenty">Sign in</LinkNextToCTA>
<a href="#">
<StyledButton>
Get Started
</StyledButton>
</a>
</CallToActionContainer>;
};
const ExternalArrow = () => {
return <div style={{width:'14px', height:'14px', fill: 'rgb(179, 179, 179)'}}>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" focusable="false" color="rgb(179, 179, 179)"><g color="rgb(179, 179, 179)" ><path d="M200,64V168a8,8,0,0,1-16,0V83.31L69.66,197.66a8,8,0,0,1-11.32-11.32L172.69,72H88a8,8,0,0,1,0-16H192A8,8,0,0,1,200,64Z"></path></g></svg>
</div>
}
export const HeaderNav = () => {
const isTwentyDev = false;
return <Nav>
<LogoContainer>
<Logo />
{isTwentyDev && <LogoAddon className={IBMPlexMono.className}>for Developers</LogoAddon>}
</LogoContainer>
<LinkList>
<ListItem href="/pricing">Pricing</ListItem>
<ListItem href="/story">Story</ListItem>
<ListItem href="http://docs.twenty.com">Docs <ExternalArrow /></ListItem>
<ListItem href="http://docs.twenty.com"><GithubIcon color='rgb(71,71,71)' /> 5.7k <ExternalArrow /></ListItem>
</LinkList>
<CallToAction />
</Nav>;
};

View File

@ -0,0 +1,41 @@
const getSize = size => {
switch(size) {
case 'S':
return '14px';
case 'M':
return '24px';
case 'L':
return '48px';
default:
return '14px';
}
};
export const GithubIcon = ({size = 'S', color = 'rgb(179, 179, 179)'}) => {
let dimension = getSize(size);
return <div style={{width: dimension, height: dimension}}>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14 14"><path d="M 6.979 0 C 3.12 0 0 3.143 0 7.031 C 0 10.139 1.999 12.77 4.772 13.701 C 5.119 13.771 5.246 13.55 5.246 13.364 C 5.246 13.201 5.234 12.642 5.234 12.06 C 3.293 12.479 2.889 11.222 2.889 11.222 C 2.577 10.407 2.114 10.197 2.114 10.197 C 1.479 9.767 2.161 9.767 2.161 9.767 C 2.866 9.813 3.235 10.488 3.235 10.488 C 3.859 11.559 4.865 11.257 5.269 11.07 C 5.327 10.616 5.512 10.302 5.708 10.127 C 4.16 9.964 2.531 9.359 2.531 6.658 C 2.531 5.89 2.808 5.262 3.247 4.773 C 3.178 4.598 2.935 3.876 3.316 2.91 C 3.316 2.91 3.906 2.724 5.234 3.632 C 5.803 3.478 6.39 3.4 6.979 3.399 C 7.568 3.399 8.169 3.481 8.724 3.632 C 10.053 2.724 10.642 2.91 10.642 2.91 C 11.023 3.876 10.781 4.598 10.711 4.773 C 11.162 5.262 11.428 5.89 11.428 6.658 C 11.428 9.359 9.799 9.953 8.239 10.127 C 8.493 10.349 8.712 10.768 8.712 11.431 C 8.712 12.374 8.701 13.131 8.701 13.363 C 8.701 13.55 8.828 13.771 9.175 13.701 C 11.948 12.77 13.947 10.139 13.947 7.031 C 13.958 3.143 10.827 0 6.979 0 Z" fill={color}></path></svg>
</div>
}
export const LinkedInIcon = ({size = 'S', color = 'rgb(179, 179, 179)'}) => {
let dimension = getSize(size);
return <div style={{width: dimension, height: dimension}}>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" focusable="false" color={color} ><g color={color}><path d="M216,24H40A16,16,0,0,0,24,40V216a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V40A16,16,0,0,0,216,24Zm0,192H40V40H216V216ZM96,112v64a8,8,0,0,1-16,0V112a8,8,0,0,1,16,0Zm88,28v36a8,8,0,0,1-16,0V140a20,20,0,0,0-40,0v36a8,8,0,0,1-16,0V112a8,8,0,0,1,15.79-1.78A36,36,0,0,1,184,140ZM100,84A12,12,0,1,1,88,72,12,12,0,0,1,100,84Z" fill={color}></path></g></svg>
</div>;
}
export const DiscordIcon = ({size = 'S', color = 'rgb(179, 179, 179)'}) => {
let dimension = getSize(size);
return <div style={{width: dimension, height: dimension}}>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" focusable="false" color={color} ><g color={color}><path d="M104,140a12,12,0,1,1-12-12A12,12,0,0,1,104,140Zm60-12a12,12,0,1,0,12,12A12,12,0,0,0,164,128Zm74.45,64.9-67,29.71a16.17,16.17,0,0,1-21.71-9.1l-8.11-22q-6.72.45-13.63.46t-13.63-.46l-8.11,22a16.18,16.18,0,0,1-21.71,9.1l-67-29.71a15.93,15.93,0,0,1-9.06-18.51L38,58A16.07,16.07,0,0,1,51,46.14l36.06-5.93a16.22,16.22,0,0,1,18.26,11.88l3.26,12.84Q118.11,64,128,64t19.4.93l3.26-12.84a16.21,16.21,0,0,1,18.26-11.88L205,46.14A16.07,16.07,0,0,1,218,58l29.53,116.38A15.93,15.93,0,0,1,238.45,192.9ZM232,178.28,202.47,62s0,0-.08,0L166.33,56a.17.17,0,0,0-.17,0l-2.83,11.14c5,.94,10,2.06,14.83,3.42A8,8,0,0,1,176,86.31a8.09,8.09,0,0,1-2.16-.3A172.25,172.25,0,0,0,128,80a172.25,172.25,0,0,0-45.84,6,8,8,0,1,1-4.32-15.4c4.82-1.36,9.78-2.48,14.82-3.42L89.83,56s0,0-.12,0h0L53.61,61.93a.17.17,0,0,0-.09,0L24,178.33,91,208a.23.23,0,0,0,.22,0L98,189.72a173.2,173.2,0,0,1-20.14-4.32A8,8,0,0,1,82.16,170,171.85,171.85,0,0,0,128,176a171.85,171.85,0,0,0,45.84-6,8,8,0,0,1,4.32,15.41A173.2,173.2,0,0,1,158,189.72L164.75,208a.22.22,0,0,0,.21,0Z" fill={color}></path></g></svg>
</div>
}
export const XIcon = ({size = 'S', color = 'rgb(179, 179, 179)'}) => {
let dimension = getSize(size);
return <div style={{width: dimension, height: dimension}}>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" focusable="false" color={color} ><g color={color}><path d="M104,140a12,12,0,1,1-12-12A12,12,0,0,1,104,140Zm60-12a12,12,0,1,0,12,12A12,12,0,0,0,164,128Zm74.45,64.9-67,29.71a16.17,16.17,0,0,1-21.71-9.1l-8.11-22q-6.72.45-13.63.46t-13.63-.46l-8.11,22a16.18,16.18,0,0,1-21.71,9.1l-67-29.71a15.93,15.93,0,0,1-9.06-18.51L38,58A16.07,16.07,0,0,1,51,46.14l36.06-5.93a16.22,16.22,0,0,1,18.26,11.88l3.26,12.84Q118.11,64,128,64t19.4.93l3.26-12.84a16.21,16.21,0,0,1,18.26-11.88L205,46.14A16.07,16.07,0,0,1,218,58l29.53,116.38A15.93,15.93,0,0,1,238.45,192.9ZM232,178.28,202.47,62s0,0-.08,0L166.33,56a.17.17,0,0,0-.17,0l-2.83,11.14c5,.94,10,2.06,14.83,3.42A8,8,0,0,1,176,86.31a8.09,8.09,0,0,1-2.16-.3A172.25,172.25,0,0,0,128,80a172.25,172.25,0,0,0-45.84,6,8,8,0,1,1-4.32-15.4c4.82-1.36,9.78-2.48,14.82-3.42L89.83,56s0,0-.12,0h0L53.61,61.93a.17.17,0,0,0-.09,0L24,178.33,91,208a.23.23,0,0,0,.22,0L98,189.72a173.2,173.2,0,0,1-20.14-4.32A8,8,0,0,1,82.16,170,171.85,171.85,0,0,0,128,176a171.85,171.85,0,0,0,45.84-6,8,8,0,0,1,4.32,15.41A173.2,173.2,0,0,1,158,189.72L164.75,208a.22.22,0,0,0,.21,0Z" fill={color}></path></g></svg>
</div>
}

View File

@ -0,0 +1,16 @@
import styled from "@emotion/styled";
const Link = styled.a`
display:block;
image-rendering: pixelated;
flex-shrink: 0;
background-size: 100% 100%;
border-radius: 8px;
height: 40px;
width: 40px;
background-image: url("images/core/logo.svg");
opacity: 1;`;
export const Logo = () => {
return <Link href="/" />;
};

View File

@ -0,0 +1,47 @@
'use client'
import { CacheProvider } from '@emotion/react'
import createCache from '@emotion/cache'
import { useServerInsertedHTML } from 'next/navigation'
import { useState } from 'react'
export default function RootStyleRegistry({ children }) {
const [{ cache, flush }] = useState(() => {
const cache = createCache({ key: 'emotion-cache' })
cache.compat = true
const prevInsert = cache.insert
let inserted = []
cache.insert = (...args) => {
const serialized = args[1]
if (cache.inserted[serialized.name] === undefined) {
inserted.push(serialized.name)
}
return prevInsert(...args)
}
const flush = () => {
const prevInserted = inserted
inserted = []
return prevInserted
}
return { cache, flush }
})
useServerInsertedHTML(() => {
const names = flush()
if (names.length === 0) return null
let styles = ''
for (const name of names) {
styles += cache.inserted[name]
}
return (
<style
data-emotion={`${cache.key} ${names.join(' ')}`}
dangerouslySetInnerHTML={{
__html: styles,
}}
/>
)
})
return <CacheProvider value={cache}>{children}</CacheProvider>
}

View File

@ -0,0 +1,43 @@
import type { Metadata } from 'next'
import { Gabarito } from 'next/font/google'
import EmotionRootStyleRegistry from './emotion-root-style-registry'
import styled from '@emotion/styled'
import { HeaderNav } from './components/HeaderNav'
import { FooterNav } from './components/FooterNav'
export const metadata: Metadata = {
title: 'Twenty.dev',
description: 'Twenty for Developer',
icons: '/favicon.ico',
}
const gabarito = Gabarito({
weight: ['400', '500'],
subsets: ['latin'],
display: 'swap',
})
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en" className={gabarito.className}>
<body style={{
margin: 0,
WebkitFontSmoothing: "antialiased",
MozOsxFontSmoothing: "grayscale"
}}>
<EmotionRootStyleRegistry>
<HeaderNav />
<div style={{display: 'flex', flexDirection: 'column', alignItems: 'center'}}>
{children}
</div>
<FooterNav />
</EmotionRootStyleRegistry>
</body>
</html>
)
}

View File

@ -0,0 +1,14 @@
import Image from 'next/image'
import { ContentContainer } from './components/ContentContainer'
export default function Home() {
return (
<ContentContainer>
<div style={{ minHeight: '60vh', marginTop: '50px' }}>
Part of the website is built directly with Framer, including the homepage. <br />
We use Clouflare to split the traffic between the two sites.
</div>
</ContentContainer>
)
}

View File

@ -0,0 +1,68 @@
import { GetStaticProps } from 'next'
import { MDXRemote } from 'next-mdx-remote/rsc'
import { compileMDX } from 'next-mdx-remote/rsc'
import gfm from 'remark-gfm';
import { ContentContainer } from '../components/ContentContainer';
import { visit } from 'unist-util-visit';
import remarkBehead from 'remark-behead';
interface Release {
id: number;
name: string;
body: string;
}
const Home = async () => {
const res = await fetch(`${process.env.BASE_URL}/api/github`);
const data: Release[] = await res.json();
const releases = await Promise.all(
data.map(async (release) => {
let mdxSource;
try {
mdxSource = await compileMDX({
source: release.body,
options: {
mdxOptions: {
remarkPlugins: [
gfm,
[remarkBehead, { depth: 2 }],
],
}
},
});
mdxSource = mdxSource.content;
} catch(error) {
console.error('An error occurred during MDX rendering:', error);
mdxSource = `<p>Oops! Something went wrong.</p> ${error}`;;
}
return {
id: release.id,
name: release.name,
body: mdxSource,
};
})
);
return (
<ContentContainer>
<h1>Releases</h1>
{releases.map(release => (
<div key={release.id}
style={{
padding: '24px 0px 24px 0px',
borderBottom: '1px solid #ccc',
}}>
<h2>{release.name}</h2>
<div>{release.body}</div>
</div>
))}
</ContentContainer>
)
}
export default Home;

View File

@ -0,0 +1,27 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "src/app/emotion-root-style-registry.js"],
"exclude": ["node_modules"]
}

File diff suppressed because it is too large Load Diff

966
yarn.lock

File diff suppressed because it is too large Load Diff