diff --git a/apps/ligo-virgo/package.json b/apps/ligo-virgo/package.json index e8a18e071c..270901439f 100644 --- a/apps/ligo-virgo/package.json +++ b/apps/ligo-virgo/package.json @@ -10,6 +10,7 @@ "keywords": [], "author": "AFFiNE ", "dependencies": { + "@emotion/babel-plugin": "^11.10.2", "@mui/icons-material": "^5.8.4" }, "devDependencies": { diff --git a/apps/venus/package.json b/apps/venus/package.json index 87065b9d79..1d8a1287bb 100644 --- a/apps/venus/package.json +++ b/apps/venus/package.json @@ -7,6 +7,7 @@ "keywords": [], "author": "DarkSky ", "dependencies": { + "@emotion/babel-plugin": "^11.10.2", "@emotion/react": "^11.10.0", "@emotion/styled": "^11.10.0", "@mui/joy": "^5.0.0-alpha.42", diff --git a/apps/venus/src/app/AboutUs.tsx b/apps/venus/src/app/AboutUs.tsx index 18eea69853..193f87be0f 100644 --- a/apps/venus/src/app/AboutUs.tsx +++ b/apps/venus/src/app/AboutUs.tsx @@ -10,7 +10,7 @@ export const AboutUs = () => { return ( <> - + (({ width }) => ({ - position: 'relative', - width: '24em', - height: '128px', - transform: 'translateY(-8px)', - overflowY: 'hidden', - '@media (max-width: 1024px)': { - width, - height: '48px', - transform: 'translateY(0)', - }, - '& .scroll-element': { - width: 'inherit', - height: 'inherit', - position: 'absolute', - left: '0%', - top: '0%', - lineHeight: '96px', - '@media (max-width: 1024px)': { - lineHeight: '32px', - }, - }, - '& .scroll-element.active': { - animation: 'primary 500ms linear infinite', - }, - '.primary.active': { - animation: 'primary 500ms linear infinite', - }, - '.secondary.active': { - animation: 'secondary 500ms linear infinite', - }, - '@keyframes primary': { - from: { - top: '0%', - }, - to: { - top: '-100%', - }, - }, - '@keyframes secondary': { - from: { - top: '100%', - }, - to: { - top: '0%', - }, - }, -})); - -const _alternatives = ['Notion', 'Miro', 'Monday']; -const _alternativesSize = [8, 6, 10]; - -const Product = () => { - const [idx, setIdx] = useState(0); - const [last, current] = useMemo( - () => [ - _alternatives[idx], - _alternatives[idx + 1] ? _alternatives[idx + 1] : _alternatives[0], - ], - [idx] - ); - const maxWidth = useMemo(() => _alternativesSize[idx], [idx]); - const [active, setActive] = useState(false); - const matches = useMediaQuery('(max-width: 1024px)'); - - useEffect(() => { - const handle = setInterval(() => { - setActive(true); - setTimeout( - () => { - setIdx(idx => (_alternatives[idx + 1] ? idx + 1 : 0)); - setActive(false); - }, - matches ? 450 : 380 - ); - }, 2000); - return () => clearInterval(handle); - }, [matches]); - - return ( - - - - {last} - - - - - {current} - - - - ); -}; - -const AFFiNEOnline = (props: { center?: boolean; flat?: boolean }) => { - const matches = useMediaQuery('(max-width: 1024px)'); - const { t } = useTranslation(); - return ( - - ); -}; - -export function App() { - const matches = useMediaQuery('(max-width: 1024px)'); - const navigate = useNavigate(); - const { t, i18n } = useTranslation(); - - const changeLanguage = (event: any) => { - i18n.changeLanguage(event); - }; - return ( - <> - - - - - {t('Open Source')}, - - - {t('Privacy First')} - - - - - - - - {t('Alternative')} - - - - - - - {t('description1.part1')} - - - - - - - - - - - - - - - - - - {t('description1.part2')} - - - - - - - {t('description1.part3')} - - - {t('description1.part4')} - - - - - - - - {t('description2.part1')} - - - {t('description2.part2')} - - - {t('description2.part3')} - - - - - - - - - - - - - - {t('description3.part1')} - - - {t('description3.part2')} - - - {t('description3.part3')} - - - {t('description3.part4')} - - - - - - - - - - - - - {t('description4.part1')} - - - {t('description4.part2')} - - - {t('description4.part3')} - - - - - - - - - - - ); -} diff --git a/apps/venus/src/app/IndexPage/Alternatives.tsx b/apps/venus/src/app/IndexPage/Alternatives.tsx new file mode 100644 index 0000000000..17403e01c9 --- /dev/null +++ b/apps/venus/src/app/IndexPage/Alternatives.tsx @@ -0,0 +1,153 @@ +import { Box, Typography } from '@mui/joy'; +import { styled } from '@mui/joy/styles'; +import clsx from 'clsx'; +import { useEffect, useMemo, useState } from 'react'; +// eslint-disable-next-line no-restricted-imports +import { useMediaQuery } from '@mui/material'; + +const Alternatives = styled(Box)<{ width: string }>(({ width }) => ({ + position: 'relative', + width: '20em', + height: '128px', + transform: 'translateY(-8px)', + overflowY: 'hidden', + '@media (max-width: 1024px)': { + width, + height: '48px', + transform: 'translateY(0)', + }, + '& .scroll-element': { + width: 'inherit', + height: 'inherit', + position: 'absolute', + left: '0', + top: '0', + paddingTop: '22px', + lineHeight: '96px', + '@media (max-width: 1024px)': { + lineHeight: '32px', + }, + }, + '& .scroll-element.active': { + animation: 'primary 500ms linear infinite', + }, + '.primary.active': { + animation: 'primary 500ms linear infinite', + }, + '.secondary.active': { + animation: 'secondary 500ms linear infinite', + }, + '@keyframes primary': { + from: { + top: '0%', + }, + to: { + top: '-100%', + }, + }, + '@keyframes secondary': { + from: { + top: '100%', + }, + to: { + top: '0%', + }, + }, +})); + +const _alternatives = ['Notion', 'Miro', 'Monday']; +const _alternativesSize = [8, 6, 10]; + +export const AlternativesProduct = () => { + const [idx, setIdx] = useState(0); + const [last, current] = useMemo( + () => [ + _alternatives[idx], + _alternatives[idx + 1] ? _alternatives[idx + 1] : _alternatives[0], + ], + [idx] + ); + const maxWidth = useMemo(() => _alternativesSize[idx], [idx]); + const [active, setActive] = useState(false); + const matches = useMediaQuery('(max-width: 1024px)'); + + useEffect(() => { + const handle = setInterval(() => { + setActive(true); + setTimeout( + () => { + setIdx(idx => (_alternatives[idx + 1] ? idx + 1 : 0)); + setActive(false); + }, + matches ? 450 : 380 + ); + }, 2000); + return () => clearInterval(handle); + }, [matches]); + + return ( + + + + {last} + + + + + {current} + + + + ); +}; diff --git a/apps/venus/src/app/IndexPage/FunctionTabs.tsx b/apps/venus/src/app/IndexPage/FunctionTabs.tsx new file mode 100644 index 0000000000..7a87df1ddd --- /dev/null +++ b/apps/venus/src/app/IndexPage/FunctionTabs.tsx @@ -0,0 +1,200 @@ +import { Box, Grid, Typography } from '@mui/joy'; +import { useState } from 'react'; +// eslint-disable-next-line no-restricted-imports +import { Paper, Slide, Tab, Tabs, useMediaQuery } from '@mui/material'; +import { useTranslation } from 'react-i18next'; +import { AFFiNEImage } from '../common'; +import ShapeImage from './shape.png'; +import TaskImage from './task.png'; + +export const FunctionTabs = () => { + const matches = useMediaQuery('(max-width: 1024px)'); + const { t } = useTranslation(); + const [tab, selectTab] = useState(0); + return ( + + selectTab(value)} + centered + > + + + + + + + + + {t('description2.part1')} + + + {t('description2.part2')} + + + {t('description2.part3')} + + + + + + + + + + + + + + + + {t('description3.part1')} + + + {t('description3.part2')} + + + {t('description3.part3')} + + + {t('description3.part4')} + + + + + + + + + + + + ); +}; diff --git a/apps/venus/src/app/IndexPage/IndexPage.tsx b/apps/venus/src/app/IndexPage/IndexPage.tsx new file mode 100644 index 0000000000..71e26402e8 --- /dev/null +++ b/apps/venus/src/app/IndexPage/IndexPage.tsx @@ -0,0 +1,292 @@ +/* eslint-disable max-lines */ +/* eslint-disable @typescript-eslint/naming-convention */ +import { useTranslation } from 'react-i18next'; + +import { Box, Button, Grid, Typography } from '@mui/joy'; +import { LogoIcon } from '@toeverything/components/icons'; +// eslint-disable-next-line no-restricted-imports +import { useMediaQuery } from '@mui/material'; + +import { AFFiNEFooter, AFFiNEHeader, AFFiNEImage } from '../common'; +import { GitHub } from '../Icons'; +import { AlternativesProduct } from './Alternatives'; +import CollaborationImage from './collaboration.png'; +import { FunctionTabs } from './FunctionTabs'; +import PageImage from './page.png'; + +const AFFiNEOnline = (props: { center?: boolean; flat?: boolean }) => { + const matches = useMediaQuery('(max-width: 1024px)'); + const { t } = useTranslation(); + return ( + + ); +}; + +export function IndexPage() { + const matches = useMediaQuery('(max-width: 1024px)'); + const { t } = useTranslation(); + + return ( + <> + + + + + {t('Open Source')}, + + + {t('Privacy First')} + + + + + + + + {t('Alternative')} + + + + + + + {t('description1.part1')} + + + + + + + + + + + + + + + + + + {t('description1.part2')} + + + + + + + {t('description1.part3')} + + + {t('description1.part4')} + + + + + + + + {t('description4.part1')} + + + {t('description4.part2')} + + + {t('description4.part3')} + + + + + + + + + + + ); +} diff --git a/apps/venus/src/app/collaboration.png b/apps/venus/src/app/IndexPage/collaboration.png similarity index 100% rename from apps/venus/src/app/collaboration.png rename to apps/venus/src/app/IndexPage/collaboration.png diff --git a/apps/venus/src/app/IndexPage/index.ts b/apps/venus/src/app/IndexPage/index.ts new file mode 100644 index 0000000000..b36af73081 --- /dev/null +++ b/apps/venus/src/app/IndexPage/index.ts @@ -0,0 +1 @@ +export { IndexPage } from './IndexPage'; diff --git a/apps/venus/src/app/page.png b/apps/venus/src/app/IndexPage/page.png similarity index 100% rename from apps/venus/src/app/page.png rename to apps/venus/src/app/IndexPage/page.png diff --git a/apps/venus/src/app/shape.png b/apps/venus/src/app/IndexPage/shape.png similarity index 100% rename from apps/venus/src/app/shape.png rename to apps/venus/src/app/IndexPage/shape.png diff --git a/apps/venus/src/app/task.png b/apps/venus/src/app/IndexPage/task.png similarity index 100% rename from apps/venus/src/app/task.png rename to apps/venus/src/app/IndexPage/task.png diff --git a/apps/venus/src/app/common/Header.tsx b/apps/venus/src/app/common/Header.tsx index a1fb6aa995..1c48b71ae8 100644 --- a/apps/venus/src/app/common/Header.tsx +++ b/apps/venus/src/app/common/Header.tsx @@ -6,82 +6,141 @@ import { Button, Grid } from '@mui/joy'; import Option from '@mui/joy/Option'; import Select from '@mui/joy/Select'; // eslint-disable-next-line no-restricted-imports -import { useMediaQuery } from '@mui/material'; +import GitHubIcon from '@mui/icons-material/GitHub'; +// eslint-disable-next-line no-restricted-imports +import { styled, useMediaQuery } from '@mui/material'; +import AFFiNETextLogo from './affine-text-logo.png'; +import { HoverMenu } from './HoverMenu'; import { options } from '../i18n'; -import { GitHub } from '../Icons'; export const AFFiNEHeader = () => { const matches = useMediaQuery('(max-width: 1024px)'); const navigate = useNavigate(); - const { i18n } = useTranslation(); + const { i18n, t } = useTranslation(); const changeLanguage = (event: any) => { i18n.changeLanguage(event); }; const matchesIPAD = useMediaQuery('(max-width: 768px)'); return ( - - - - - - - + /> + + + + + + + + { + window.open(href); + }} + /> - + ); }; + +const Container = styled(Grid)({ + position: 'fixed', + top: 0, + left: '50%', + transform: 'translateX(-50%)', + width: '100%', + paddingTop: '1em', + backgroundColor: '#fff', + zIndex: 1500, + maxWidth: '1440px', + margin: 'auto', + marginTop: '0 !important', +}); + +const StyledImage = styled('img')({ + height: '24px', + marginRight: '16px', + cursor: 'pointer', +}); diff --git a/apps/venus/src/app/common/HoverMenu.tsx b/apps/venus/src/app/common/HoverMenu.tsx new file mode 100644 index 0000000000..d7bcded3ee --- /dev/null +++ b/apps/venus/src/app/common/HoverMenu.tsx @@ -0,0 +1,73 @@ +import Button from '@mui/joy/Button'; +// eslint-disable-next-line no-restricted-imports +import { styled, Tooltip, type TooltipProps } from '@mui/material'; + +interface HoverMenuProps { + title: string; + options: Array<{ title: string; value: string }>; + onSelect: (value: string) => void; +} + +export function HoverMenu({ title, options, onSelect }: HoverMenuProps) { + return ( + + {options.map(option => { + return ( + { + onSelect(option.value); + }} + > + {option.title} + + ); + })} + + } + > + + + ); +} + +const StyledTooltip = styled(({ className, ...props }: TooltipProps) => ( + +))(({ theme }) => ({ + '& .MuiTooltip-tooltip': { + backgroundColor: 'white', + boxShadow: theme.shadows[4], + color: '#272930', + zIndex: '1500', + }, +})); + +const ListItem = styled('a')({ + display: 'block', + fontSize: '16px', + lineHeight: '32px', + padding: '5px', + cursor: 'pointer', + borderRadius: '4px', + color: '#272930', + textDecoration: 'none', + + '&:hover': { + color: '#131418', + backgroundColor: '#eeeff0', + }, +}); diff --git a/apps/venus/src/app/common/affine-text-logo.png b/apps/venus/src/app/common/affine-text-logo.png new file mode 100644 index 0000000000..a136ab17fa Binary files /dev/null and b/apps/venus/src/app/common/affine-text-logo.png differ diff --git a/apps/venus/src/app/i18n/resources/en.json b/apps/venus/src/app/i18n/resources/en.json index 2cffda93bd..789a577584 100644 --- a/apps/venus/src/app/i18n/resources/en.json +++ b/apps/venus/src/app/i18n/resources/en.json @@ -1,8 +1,11 @@ { "translation": { "Blog": "Blog", - "AboutUs": "About AboutUs", + "AboutUs": "About Us", "Open Source": "Open Source", + "Docs": "Docs", + "Feedback": "Feedback", + "ContactUs": "Contact Us", "Privacy First": "Privacy First", "Alternative": "Alternative", "Check GitHub": "Check GitHub", diff --git a/apps/venus/src/app/i18n/resources/zh.json b/apps/venus/src/app/i18n/resources/zh.json index ca0a060072..9a3e51a2ca 100644 --- a/apps/venus/src/app/i18n/resources/zh.json +++ b/apps/venus/src/app/i18n/resources/zh.json @@ -4,9 +4,12 @@ "AboutUs": "关于我们", "Open Source": "开源", "Privacy First": "隐私第一", + "Docs": "文档", + "Feedback": "反馈", + "ContactUs": "联系我们", "Alternative": "的另一种选择", "Check GitHub": "GitHub中查看", - "Try it Online": "在线上试试", + "Try it Online": "在线试用", "description1": { "part1": "Affine是面向专业人士的下一代协同知识库", "part2": "它不仅仅是一个文档、白板和表格的集合。", diff --git a/apps/venus/src/app/index.tsx b/apps/venus/src/app/index.tsx index 8464ca5b4a..6064cef415 100644 --- a/apps/venus/src/app/index.tsx +++ b/apps/venus/src/app/index.tsx @@ -4,7 +4,7 @@ import { Container } from '@mui/joy'; import { CssVarsProvider } from '@mui/joy/styles'; import { AboutUs } from './AboutUs'; -import { App } from './App'; +import { IndexPage } from './IndexPage'; const VenusContainer = () => { return ( @@ -30,7 +30,7 @@ export function VenusRoutes() { }> } /> - } /> + } /> ); diff --git a/libs/components/account/src/login/Firebase.tsx b/libs/components/account/src/login/Firebase.tsx index f976ef8a84..8bf8ca5630 100644 --- a/libs/components/account/src/login/Firebase.tsx +++ b/libs/components/account/src/login/Firebase.tsx @@ -25,9 +25,9 @@ const GoogleIcon = () => ( = { dockerfile: () => StreamLanguage.define(dockerFile), r: () => StreamLanguage.define(r), }; -const DEFAULT_LANG = 'javascript'; +const DEFAULT_LANG = 'markdown'; const CodeBlock = styled('div')(({ theme }) => ({ backgroundColor: '#F2F5F9', padding: '8px 24px', @@ -142,10 +142,13 @@ export const CodeView = ({ block, editor }: CreateCodeView) => { const langType: string = block.getProperty('lang'); const [extensions, setExtensions] = useState(); const codeMirror = useRef(); - useOnSelect(block.id, (_is_select: boolean) => { + const focusCode = () => { if (codeMirror.current) { codeMirror?.current?.view?.focus(); } + }; + useOnSelect(block.id, (_is_select: boolean) => { + focusCode(); }); const onChange = (value: string) => { block.setProperty('text', { @@ -158,6 +161,9 @@ export const CodeView = ({ block, editor }: CreateCodeView) => { }; useEffect(() => { handleLangChange(langType ? langType : DEFAULT_LANG); + setTimeout(() => { + focusCode(); + }, 100); }, []); const copyCode = () => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cc6501e0a8..86d16f5efc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -194,11 +194,13 @@ importers: apps/ligo-virgo: specifiers: + '@emotion/babel-plugin': ^11.10.2 '@mui/icons-material': ^5.8.4 firebase: ^9.9.3 mini-css-extract-plugin: ^2.6.1 webpack: ^5.74.0 dependencies: + '@emotion/babel-plugin': 11.10.2 '@mui/icons-material': 5.8.4 devDependencies: firebase: 9.9.3 @@ -213,6 +215,7 @@ importers: apps/venus: specifiers: + '@emotion/babel-plugin': ^11.10.2 '@emotion/react': ^11.10.0 '@emotion/styled': ^11.10.0 '@mdx-js/loader': ^2.1.3 @@ -227,6 +230,7 @@ importers: react-i18next: ^11.18.4 webpack: ^5.74.0 dependencies: + '@emotion/babel-plugin': 11.10.2 '@emotion/react': 11.10.0 '@emotion/styled': 11.10.0_@emotion+react@11.10.0 '@mui/joy': 5.0.0-alpha.42_72v32ofbtgpmxm7mhvtx474vfu @@ -2681,8 +2685,8 @@ packages: tslib: 2.4.0 dev: false - /@emotion/babel-plugin/11.10.0: - resolution: {integrity: sha512-xVnpDAAbtxL1dsuSelU5A7BnY/lftws0wUexNJZTPsvX/1tM4GZJbclgODhvW4E+NH7E5VFcH0bBn30NvniPJA==} + /@emotion/babel-plugin/11.10.2: + resolution: {integrity: sha512-xNQ57njWTFVfPAc3cjfuaPdsgLp5QOSuRsj9MA6ndEhH/AzuZM86qIQzt6rq+aGBwj3n5/TkLmU5lhAfdRmogA==} peerDependencies: '@babel/core': ^7.0.0 peerDependenciesMeta: @@ -2811,7 +2815,7 @@ packages: optional: true dependencies: '@babel/runtime': 7.18.6 - '@emotion/babel-plugin': 11.10.0 + '@emotion/babel-plugin': 11.10.2 '@emotion/cache': 11.10.1 '@emotion/serialize': 1.1.0 '@emotion/utils': 1.2.0 @@ -2938,7 +2942,7 @@ packages: optional: true dependencies: '@babel/runtime': 7.18.6 - '@emotion/babel-plugin': 11.10.0 + '@emotion/babel-plugin': 11.10.2 '@emotion/is-prop-valid': 1.2.0 '@emotion/react': 11.10.0 '@emotion/serialize': 1.1.0 @@ -7417,10 +7421,8 @@ packages: indent-string: 4.0.0 dev: true - /ajv-formats/2.1.1_ajv@8.11.0: + /ajv-formats/2.1.1: resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} - peerDependencies: - ajv: ^8.0.0 peerDependenciesMeta: ajv: optional: true @@ -16987,7 +16989,7 @@ packages: dependencies: '@types/json-schema': 7.0.11 ajv: 8.11.0 - ajv-formats: 2.1.1_ajv@8.11.0 + ajv-formats: 2.1.1 ajv-keywords: 5.1.0_ajv@8.11.0 dev: true