From 5ef5bbdc4d400537c8dfec861738c140bbf39e3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Malfait?= Date: Sat, 23 Dec 2023 10:08:55 +0100 Subject: [PATCH] Marketing website POC (#3139) First website POC --- .../ObjectMetadataItemsDecorator.tsx | 9 - package.json | 3 +- packages/twenty-front/package.json | 2 +- packages/twenty-server/package.json | 2 +- packages/twenty-website/.env.example | 1 + packages/twenty-website/.eslintrc.json | 3 + packages/twenty-website/.gitignore | 36 + packages/twenty-website/README.md | 16 + packages/twenty-website/next.config.js | 4 + packages/twenty-website/package.json | 30 + .../public/images/core/logo-mini.png | Bin 0 -> 570 bytes .../public/images/core/logo.svg | 12 + .../src/app/api/github/route.ts | 8 + .../src/app/blog/[slug]/page.tsx | 4 + .../src/app/blog/list-posts.tsx | 0 packages/twenty-website/src/app/blog/page.tsx | 6 + .../src/app/components/ContentContainer.tsx | 11 + .../src/app/components/FooterNav.tsx | 106 + .../src/app/components/HeaderNav.tsx | 133 + .../src/app/components/Icons.tsx | 41 + .../src/app/components/Logo.tsx | 16 + .../src/app/emotion-root-style-registry.js | 47 + packages/twenty-website/src/app/layout.tsx | 43 + packages/twenty-website/src/app/page.tsx | 14 + .../twenty-website/src/app/releases/page.tsx | 68 + packages/twenty-website/tsconfig.json | 27 + packages/twenty-website/yarn.lock | 4717 +++++++++++++++++ yarn.lock | 966 +++- 28 files changed, 6279 insertions(+), 46 deletions(-) delete mode 100644 Users/v1b3m/Dev/GitStart/client-twenty/packages/twenty-front/src/testing/decorators/ObjectMetadataItemsDecorator.tsx create mode 100644 packages/twenty-website/.env.example create mode 100644 packages/twenty-website/.eslintrc.json create mode 100644 packages/twenty-website/.gitignore create mode 100644 packages/twenty-website/README.md create mode 100644 packages/twenty-website/next.config.js create mode 100644 packages/twenty-website/package.json create mode 100644 packages/twenty-website/public/images/core/logo-mini.png create mode 100644 packages/twenty-website/public/images/core/logo.svg create mode 100644 packages/twenty-website/src/app/api/github/route.ts create mode 100644 packages/twenty-website/src/app/blog/[slug]/page.tsx create mode 100644 packages/twenty-website/src/app/blog/list-posts.tsx create mode 100644 packages/twenty-website/src/app/blog/page.tsx create mode 100644 packages/twenty-website/src/app/components/ContentContainer.tsx create mode 100644 packages/twenty-website/src/app/components/FooterNav.tsx create mode 100644 packages/twenty-website/src/app/components/HeaderNav.tsx create mode 100644 packages/twenty-website/src/app/components/Icons.tsx create mode 100644 packages/twenty-website/src/app/components/Logo.tsx create mode 100644 packages/twenty-website/src/app/emotion-root-style-registry.js create mode 100644 packages/twenty-website/src/app/layout.tsx create mode 100644 packages/twenty-website/src/app/page.tsx create mode 100644 packages/twenty-website/src/app/releases/page.tsx create mode 100644 packages/twenty-website/tsconfig.json create mode 100644 packages/twenty-website/yarn.lock diff --git a/Users/v1b3m/Dev/GitStart/client-twenty/packages/twenty-front/src/testing/decorators/ObjectMetadataItemsDecorator.tsx b/Users/v1b3m/Dev/GitStart/client-twenty/packages/twenty-front/src/testing/decorators/ObjectMetadataItemsDecorator.tsx deleted file mode 100644 index 0eab23f8ac..0000000000 --- a/Users/v1b3m/Dev/GitStart/client-twenty/packages/twenty-front/src/testing/decorators/ObjectMetadataItemsDecorator.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { Decorator } from '@storybook/react'; - -import { ObjectMetadataItemsProvider } from '@/object-metadata/components/ObjectMetadataItemsProvider'; - -export const ObjectMetadataItemsDecorator: Decorator = (Story) => ( - - - -); diff --git a/package.json b/package.json index f3284d894b..4be8f3cdb8 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "packages/twenty-docs", "packages/twenty-server", "packages/twenty-utils", - "packages/twenty-zapier" + "packages/twenty-zapier", + "packages/twenty-website" ] }, "devDependencies": { diff --git a/packages/twenty-front/package.json b/packages/twenty-front/package.json index c05fda7752..bb86b970b7 100644 --- a/packages/twenty-front/package.json +++ b/packages/twenty-front/package.json @@ -182,4 +182,4 @@ "msw": { "workerDirectory": "public" } -} \ No newline at end of file +} diff --git a/packages/twenty-server/package.json b/packages/twenty-server/package.json index 38832a8c9a..33bf7ca2a0 100644 --- a/packages/twenty-server/package.json +++ b/packages/twenty-server/package.json @@ -154,4 +154,4 @@ "npm": "please-use-yarn", "yarn": "^4.0.2" } -} \ No newline at end of file +} diff --git a/packages/twenty-website/.env.example b/packages/twenty-website/.env.example new file mode 100644 index 0000000000..e3001b2a0e --- /dev/null +++ b/packages/twenty-website/.env.example @@ -0,0 +1 @@ +BASE_URL=http://localhost:3000 \ No newline at end of file diff --git a/packages/twenty-website/.eslintrc.json b/packages/twenty-website/.eslintrc.json new file mode 100644 index 0000000000..bffb357a71 --- /dev/null +++ b/packages/twenty-website/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "next/core-web-vitals" +} diff --git a/packages/twenty-website/.gitignore b/packages/twenty-website/.gitignore new file mode 100644 index 0000000000..fd3dbb571a --- /dev/null +++ b/packages/twenty-website/.gitignore @@ -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 diff --git a/packages/twenty-website/README.md b/packages/twenty-website/README.md new file mode 100644 index 0000000000..1601a6b33d --- /dev/null +++ b/packages/twenty-website/README.md @@ -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. + + diff --git a/packages/twenty-website/next.config.js b/packages/twenty-website/next.config.js new file mode 100644 index 0000000000..767719fc4f --- /dev/null +++ b/packages/twenty-website/next.config.js @@ -0,0 +1,4 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = {} + +module.exports = nextConfig diff --git a/packages/twenty-website/package.json b/packages/twenty-website/package.json new file mode 100644 index 0000000000..a2a51c3a8a --- /dev/null +++ b/packages/twenty-website/package.json @@ -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" + } +} diff --git a/packages/twenty-website/public/images/core/logo-mini.png b/packages/twenty-website/public/images/core/logo-mini.png new file mode 100644 index 0000000000000000000000000000000000000000..ba655d69b81193d3bb5db511797987a44e26c489 GIT binary patch literal 570 zcmV-A0>%A_P)8OKA7C;Wtx7hVl*wW@+&(s?E4v@bPBOa|N#Xt8_i%-K zZ~5d7-&2RTbGpxS&U?;17q~#;rf^fau@9Jh<-C!9ium4CO+>bUTr=hCdaw#xs|8?# z#rQT0q|<2xgTV*iX0t)PUPmkzLo^zN&34IeJRYOd>6lUJo6~GI*)xvEBgj~$K#A=OXm0cS-D)Mn4%~wl}g=WlgWhb_xslbB9RD@2(o*B zsZ=8WY&K((Bt67htro?M1awX2ndt7YP$-~MsbINWBA?Hr-|xe2x8qglR70T%r}IBbiKMG#cSu=mb0-4>eJUG#U-;c02INqS$J+!r^eBb1s*| zd_IT6;h?M3{6=_aN+1wmW)Pz*20&F+U5rneVUrD)oybm9@C>mI#99!sY&Hw0(~0x> zjNx#I!C+vR{r}&lLSPFEAq1wd4nN{Yg2f+wO+@}6v7(Xx0{@D>gsmf3-v9sr07*qo IM6N<$f*!p6$p8QV literal 0 HcmV?d00001 diff --git a/packages/twenty-website/public/images/core/logo.svg b/packages/twenty-website/public/images/core/logo.svg new file mode 100644 index 0000000000..bad18fab32 --- /dev/null +++ b/packages/twenty-website/public/images/core/logo.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/packages/twenty-website/src/app/api/github/route.ts b/packages/twenty-website/src/app/api/github/route.ts new file mode 100644 index 0000000000..21778e7399 --- /dev/null +++ b/packages/twenty-website/src/app/api/github/route.ts @@ -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); +} \ No newline at end of file diff --git a/packages/twenty-website/src/app/blog/[slug]/page.tsx b/packages/twenty-website/src/app/blog/[slug]/page.tsx new file mode 100644 index 0000000000..994520518c --- /dev/null +++ b/packages/twenty-website/src/app/blog/[slug]/page.tsx @@ -0,0 +1,4 @@ +export default async function BlogPost({ params }: { params: { slug: string } }) { + const posts = {}; + return <>Blog Post: {params.slug}; +} diff --git a/packages/twenty-website/src/app/blog/list-posts.tsx b/packages/twenty-website/src/app/blog/list-posts.tsx new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/twenty-website/src/app/blog/page.tsx b/packages/twenty-website/src/app/blog/page.tsx new file mode 100644 index 0000000000..9b360fed5d --- /dev/null +++ b/packages/twenty-website/src/app/blog/page.tsx @@ -0,0 +1,6 @@ + + +export default async function BlogHome() { + const posts = {}; + return <>Blog Home; +} \ No newline at end of file diff --git a/packages/twenty-website/src/app/components/ContentContainer.tsx b/packages/twenty-website/src/app/components/ContentContainer.tsx new file mode 100644 index 0000000000..db033a27a1 --- /dev/null +++ b/packages/twenty-website/src/app/components/ContentContainer.tsx @@ -0,0 +1,11 @@ +'use client' + +export const ContentContainer = ({children}: {children?: React.ReactNode}) => { + return ( +
{children}
+ ) +} \ No newline at end of file diff --git a/packages/twenty-website/src/app/components/FooterNav.tsx b/packages/twenty-website/src/app/components/FooterNav.tsx new file mode 100644 index 0000000000..ff325344ab --- /dev/null +++ b/packages/twenty-website/src/app/components/FooterNav.tsx @@ -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 +
+ + +
+ The #1 Open Source CRM +
+
+ + + Company + Pricing + Story + + + Resources + Documentation + Changelog + + + Other + OSS Friends + Terms of Service + Privacy Policy + + +
+
+
+ © + 2023 Twenty PBC +
+ +
+
+ ; +} diff --git a/packages/twenty-website/src/app/components/HeaderNav.tsx b/packages/twenty-website/src/app/components/HeaderNav.tsx new file mode 100644 index 0000000000..43a7cc5f96 --- /dev/null +++ b/packages/twenty-website/src/app/components/HeaderNav.tsx @@ -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 + Sign in + + + Get Started + + + ; +}; + + +const ExternalArrow = () => { + return
+ +
+ +} + +export const HeaderNav = () => { + + const isTwentyDev = false; + + return ; +}; + diff --git a/packages/twenty-website/src/app/components/Icons.tsx b/packages/twenty-website/src/app/components/Icons.tsx new file mode 100644 index 0000000000..897e9318ca --- /dev/null +++ b/packages/twenty-website/src/app/components/Icons.tsx @@ -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
+ +
+} + +export const LinkedInIcon = ({size = 'S', color = 'rgb(179, 179, 179)'}) => { + let dimension = getSize(size); + + return
+ +
; +} + +export const DiscordIcon = ({size = 'S', color = 'rgb(179, 179, 179)'}) => { + let dimension = getSize(size); + return
+ +
+} + +export const XIcon = ({size = 'S', color = 'rgb(179, 179, 179)'}) => { + let dimension = getSize(size); + return
+ +
+} \ No newline at end of file diff --git a/packages/twenty-website/src/app/components/Logo.tsx b/packages/twenty-website/src/app/components/Logo.tsx new file mode 100644 index 0000000000..1d1310f5c1 --- /dev/null +++ b/packages/twenty-website/src/app/components/Logo.tsx @@ -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 ; +}; diff --git a/packages/twenty-website/src/app/emotion-root-style-registry.js b/packages/twenty-website/src/app/emotion-root-style-registry.js new file mode 100644 index 0000000000..d7901367cd --- /dev/null +++ b/packages/twenty-website/src/app/emotion-root-style-registry.js @@ -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 ( +