Merge branch 'master' into feat/client-app

This commit is contained in:
linonetwo
2023-02-09 22:39:08 +08:00
176 changed files with 10442 additions and 2571 deletions

48
.github/CLA.md vendored Normal file
View File

@@ -0,0 +1,48 @@
<!-- To indicate your agreement, simply edit this file and submit a pull request. -->
# AFFiNE Contributor License Agreement
To clarify the intellectual property license granted with contributions from any person or entity, AFFiNE must have on file a signed Contributor License Agreement ("CLA") from each contributor, indicating agreement with the license terms below. This agreement is for your protection as a contributor as well as the protection of the AFFiNE and its users; it does not change your rights to use your own contributions for any other purpose.
You accept and agree to the following terms and conditions for your past, present and future contributions submitted to AFFiNE. You should sign this agreement before submitting your first contribution. Except for the license granted herein to AFFiNE and recipients of software distributed by AFFiNE, You reserve all right, title, and interest in and to Your Contributions.
1. Parties.
(a) "AFFiNE" refers to the project's operator, TOEVERYTHING PTE. LTD registered in Republic of Singapore.
(b) "You" (or "Your") means the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with AFFiNE.
2. Definitions. "Contribution" shall mean any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to AFFiNE for inclusion in, or documentation of, any of the products owned or managed by AFFiNE (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to AFFiNE or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, AFFiNE for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution".
3. Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to AFFiNE and to recipients of software distributed by AFFiNE a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to use, copy, reproduce, prepare derivative works of, distribute, sublicense, and publicly perform and display the Contribution and such derivative works on any licensing terms, including without limitation open source licenses and binary, proprietary, or commercial licenses.
4. Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to AFFiNE and to recipients of software distributed by AFFiNE a perpetual, irrevocable, non-exclusive, worldwide, no-charge, royalty-free patent license to make, have made, use, sell, offer to sell, import, and otherwise transfer your Contribution in whole or in part, alone or in combination with or included in any product, work or materials arising out of the project to which your contribution was submitted, and to sublicense these same rights to third parties through multiple levels of sublicensees or other licensing arrangements.
5. Except as set out above, You keep all right, title, and interest in your contribution. The rights that you grant to AFFiNE under these terms are effective on the date you first submitted a contribution to AFFiNE, even if your submission took place before the date you sign these terms.
6. You promise that:
- Each of Your Contributions is Your original work and that you are legally entitled to grant the above license.
- Each of Your Contributions does not to the best of your knowledge violate any third party's copyrights, trademarks, patents, or other intellectual property rights;
- Your Contribution submissions include complete details of any third-party license or other restriction (including, but not limited to, related patents and trademarks) of which you are personally aware and which are associated with any part of Your Contributions.
- If You are an individual and if your employer(s) has rights to intellectual property that you create that includes your Contributions, you represent that you have received permission to make Contributions on behalf of that employer, that your employer has waived such rights for your Contributions to AFFiNE, or that your employer has executed a separate Corporate CLA with AFFiNE.
7. You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
8. You agree to notify AFFiNE of any facts or circumstances of which you become aware that would make these representations inaccurate in any respect.
9. This Agreement will be governed by the laws of Republic of Singapore without reference to conflict of laws principles.
## List of Contributors
The below-signed are contributors to a code repository that is part of the project named "AFFiNE". Each below-signed contributor has read, understand and agrees to the terms above in the section within this document entitled "AFFiNE Contributor License Agreement" as of the date beside their real name (or entity name) and GitHub account name.
---
<!--
Example:
- Dark Sky, @darkskygit, 2022/07/22
-->
- Dark Sky, @darkskygit, 2022/07/22

1
.gitignore vendored
View File

@@ -48,6 +48,7 @@ Thumbs.db
.next .next
out/ out/
storybook-static
module-resolve.js module-resolve.js
module-resolve.cjs module-resolve.cjs

View File

@@ -89,6 +89,8 @@ Before we tell you how to get started with AFFiNE, we'd like to shamelessly plug
Calling all developers, testers, tech writers and more! Contributions of all types are more than welcome, you can read more in [docs/types-of-contributions.md](docs/types-of-contributions.md). If you are interested in contributing code, read our [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) and feel free to check out our GitHub issues to get stuck in to show us what you’re made of. Calling all developers, testers, tech writers and more! Contributions of all types are more than welcome, you can read more in [docs/types-of-contributions.md](docs/types-of-contributions.md). If you are interested in contributing code, read our [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) and feel free to check out our GitHub issues to get stuck in to show us what you’re made of.
**Before you start contributing, please make sure you have read and accepted our [Contributor License Agreement]. To indicate your agreement, simply edit this file and submit a pull request.**
For **bug reports**, **feature requests** and other **suggestions** you can also [create a new issue](https://github.com/toeverything/AFFiNE/issues/new/choose) and choose the most appropiate template for your feedback. For **bug reports**, **feature requests** and other **suggestions** you can also [create a new issue](https://github.com/toeverything/AFFiNE/issues/new/choose) and choose the most appropiate template for your feedback.
For **translation** and **language support** you can visit our [i18n General Space](https://community.affine.pro/c/i18n-general). For **translation** and **language support** you can visit our [i18n General Space](https://community.affine.pro/c/i18n-general).
@@ -197,15 +199,15 @@ Thanks a lot to the community for providing such powerful and simple libraries,
## Self-Host ## Self-Host
Get started with Docker and deploy your own feature-rich, restriction-free deployment of AFFiNE - check the [latest packages](https://github.com/toeverything/AFFiNE/pkgs/container/affine-self-hosted). Get started with Docker and deploy your own feature-rich, restriction-free deployment of AFFiNE - check the [latest packages].
## Hiring ## Hiring
Some amazing companies including AFFiNE are looking for developers! Are you interested in helping build with AFFiNE and/or its partners? Check out some of the latest [jobs available](./docs/jobs/summary.md). Some amazing companies including AFFiNE are looking for developers! Are you interested in helping build with AFFiNE and/or its partners? Check out some of the latest [jobs available].
## Upgrading ## Upgrading
For upgrading information please see our [update page](https://affine.pro/blog?tag=Release%20Note). For upgrading information please see our [update page].
## Feature Request ## Feature Request
@@ -213,8 +215,20 @@ For feature request please see https://community.affine.pro/c/feature-requests/
## Is it awesome? ## Is it awesome?
[These people](https://twitter.com/AffineOfficial/followers) seem to like it. [These people] seem to like it.
## Building
See [BUILDING.md] for instructions on how to build AFFiNE from source code.
## License ## License
See [LICENSE](/LICENSE) for details. See [LICENSE] for details.
[license]: ./LICENSE
[building.md]: ./docs/BUILDING.md
[these people]: https://twitter.com/AffineOfficial/followers
[update page]: https://affine.pro/blog?tag=Release%20Note
[jobs available]: ./docs/jobs/summary.md
[latest packages]: https://github.com/toeverything/AFFiNE/pkgs/container/affine-self-hosted
[contributor license agreement]: https://github.com/toeverything/affine/edit/master/.github/CLA.md

55
docs/BUILDING.md Normal file
View File

@@ -0,0 +1,55 @@
# Building AFFiNE
## Table of Contents
- [Prerequisites](#prerequisites)
- [Setup Environment](#setup-environment)
- [Play with Playground](#play-with-playground)
- [Testing](#testing)
## Prerequisites
We suggest develop our product under node.js LTS(Long-term support) version
### Option 1: Manually install node.js
install [Node LTS version](https://nodejs.org/en/download)
> Up to now, the major node.js version is 18.x
### Option 2: Use node version manager
install [nvm](https://github.com/nvm-sh/nvm)
```sh
nvm install --lts
nvm use --lts
```
## Setup Environment
```sh
# install dependencies
pnpm install
```
## Play with Playground
```sh
pnpm dev
```
The playground page should work at [http://localhost:8080/](http://localhost:8080/)
## Testing
Adding test cases is strongly encouraged when you contribute new features and bug fixes.
We use [Playwright](https://playwright.dev/) for E2E test, and [vitest](https://vitest.dev/) for unit test.
To test locally, please make sure browser binaries are already installed via `npx playwright install`. Then there are multi commands to choose from:
```sh
# run tests in headless mode in another terminal window
pnpm test
```

View File

@@ -11,6 +11,7 @@
"dev:local": "pnpm --filter=!@affine/app build && cross-env NODE_API_SERVER=local pnpm --filter @affine/app dev", "dev:local": "pnpm --filter=!@affine/app build && cross-env NODE_API_SERVER=local pnpm --filter @affine/app dev",
"build": " pnpm --filter=!@affine/app build && pnpm --filter!=@affine/datacenter -r build", "build": " pnpm --filter=!@affine/app build && pnpm --filter!=@affine/datacenter -r build",
"build:client": " pnpm --filter=@affine/client-app build:app", "build:client": " pnpm --filter=@affine/client-app build:app",
"build:storybook": " pnpm -r build-storybook",
"export": "pnpm --filter @affine/app export", "export": "pnpm --filter @affine/app export",
"start": "pnpm --filter @affine/app start", "start": "pnpm --filter @affine/app start",
"lint": "pnpm --filter @affine/app lint", "lint": "pnpm --filter @affine/app lint",
@@ -33,7 +34,6 @@
"@typescript-eslint/eslint-plugin": "^5.47.0", "@typescript-eslint/eslint-plugin": "^5.47.0",
"@typescript-eslint/parser": "^5.47.0", "@typescript-eslint/parser": "^5.47.0",
"concurrently": "^7.6.0", "concurrently": "^7.6.0",
"babel-plugin-istanbul": "^6.1.1",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"eslint": "^8.30.0", "eslint": "^8.30.0",
"eslint-config-next": "12.3.1", "eslint-config-next": "12.3.1",

View File

@@ -1,28 +0,0 @@
const plugins = [];
if (process.env.NODE_ENV === 'development' || process.env.COVERAGE === 'true') {
console.log(
'Detected development environment. Instrumenting code for coverage.'
);
plugins.push('istanbul');
}
plugins.push([
'@emotion',
{
// See https://emotion.sh/docs/@emotion/babel-plugin
importMap: {
'@/styles': {
styled: {
canonicalImport: ['@emotion/styled', 'default'],
styledBaseImport: ['@/styles', 'styled'],
},
},
},
},
]);
module.exports = {
presets: ['next/babel'],
plugins,
};

View File

@@ -11,8 +11,8 @@ const EDITOR_VERSION = enableDebugLocal
const profileTarget = { const profileTarget = {
ac: '100.85.73.88:12001', ac: '100.85.73.88:12001',
dev: '100.77.180.48:11001', dev: '100.84.105.99:11001',
test: '100.77.180.48:11001', test: '100.84.105.99:11001',
stage: '', stage: '',
pro: 'http://pathfinder.affine.pro', pro: 'http://pathfinder.affine.pro',
local: '127.0.0.1:3000', local: '127.0.0.1:3000',
@@ -47,6 +47,7 @@ const nextConfig = {
COMMIT_HASH: getCommitHash(), COMMIT_HASH: getCommitHash(),
EDITOR_VERSION, EDITOR_VERSION,
}, },
transpilePackages: ['@affine/component'],
webpack: config => { webpack: config => {
config.experiments = { ...config.experiments, topLevelAwait: true }; config.experiments = { ...config.experiments, topLevelAwait: true };
config.resolve.alias['yjs'] = require.resolve('yjs'); config.resolve.alias['yjs'] = require.resolve('yjs');

View File

@@ -9,21 +9,22 @@
"lint": "next lint" "lint": "next lint"
}, },
"dependencies": { "dependencies": {
"@affine/component": "workspace:*",
"@affine/datacenter": "workspace:*", "@affine/datacenter": "workspace:*",
"@affine/i18n": "workspace:*", "@affine/i18n": "workspace:*",
"@blocksuite/blocks": "0.4.0-alpha.2", "@blocksuite/blocks": "0.4.0-alpha.2",
"@blocksuite/editor": "0.4.0-alpha.2", "@blocksuite/editor": "0.4.0-alpha.2",
"@blocksuite/icons": "^2.0.2", "@blocksuite/icons": "^2.0.2",
"@blocksuite/store": "0.4.0-alpha.2", "@blocksuite/store": "0.4.0-alpha.2",
"@emotion/css": "^11.10.0", "@emotion/css": "^11.10.5",
"@emotion/react": "^11.10.4", "@emotion/react": "^11.10.5",
"@emotion/server": "^11.10.0", "@emotion/server": "^11.10.0",
"@emotion/styled": "^11.10.4", "@emotion/styled": "^11.10.5",
"@fontsource/poppins": "^4.5.10", "@fontsource/poppins": "^4.5.10",
"@fontsource/space-mono": "^4.5.10", "@fontsource/space-mono": "^4.5.10",
"@mui/base": "^5.0.0-alpha.87", "@mui/base": "=5.0.0-alpha.101",
"@mui/icons-material": "^5.10.9", "@mui/icons-material": "=5.10.9",
"@mui/material": "^5.8.6", "@mui/material": "=5.8.6",
"@toeverything/pathfinder-logger": "workspace:@affine/logger@*", "@toeverything/pathfinder-logger": "workspace:@affine/logger@*",
"cmdk": "^0.1.20", "cmdk": "^0.1.20",
"css-spring": "^4.1.0", "css-spring": "^4.1.0",
@@ -39,7 +40,6 @@
"yjs": "^13.5.45" "yjs": "^13.5.45"
}, },
"devDependencies": { "devDependencies": {
"@emotion/babel-plugin": "^11.10.5",
"@types/node": "18.7.18", "@types/node": "18.7.18",
"@types/react": "18.0.20", "@types/react": "18.0.20",
"@types/react-dom": "18.0.6", "@types/react-dom": "18.0.6",

View File

@@ -1,6 +1,6 @@
import { NotFoundTitle, PageContainer } from './styles'; import { NotFoundTitle, PageContainer } from './styles';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
import { Button } from '@/ui/button'; import { Button } from '@affine/component';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
export const NotfoundPage = () => { export const NotfoundPage = () => {
const { t } = useTranslation(); const { t } = useTranslation();

View File

@@ -1,4 +1,4 @@
import { styled } from '@/styles'; import { styled } from '@affine/component';
export const PageContainer = styled('div')(({ theme }) => { export const PageContainer = styled('div')(({ theme }) => {
return { return {

View File

@@ -1,4 +1,4 @@
import { Modal, ModalCloseButton, ModalWrapper } from '@/ui/modal'; import { Modal, ModalCloseButton, ModalWrapper } from '@affine/component';
import { import {
LogoIcon, LogoIcon,
DocIcon, DocIcon,

View File

@@ -1,4 +1,4 @@
import { absoluteCenter, displayFlex, styled } from '@/styles'; import { absoluteCenter, displayFlex, styled } from '@affine/component';
export const StyledBigLink = styled('a')(({ theme }) => { export const StyledBigLink = styled('a')(({ theme }) => {
return { return {

View File

@@ -1,13 +1,13 @@
import { styled } from '@/styles'; import { styled } from '@affine/component';
import { Modal, ModalWrapper, ModalCloseButton } from '@/ui/modal'; import { Modal, ModalWrapper, ModalCloseButton } from '@affine/component';
import { Button } from '@/ui/button'; import { Button } from '@affine/component';
import { useState } from 'react'; import { useState } from 'react';
import Input from '@/ui/input'; import { Input } from '@affine/component';
import { KeyboardEvent } from 'react'; import { KeyboardEvent } from 'react';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
import { useWorkspaceHelper } from '@/hooks/use-workspace-helper'; import { useWorkspaceHelper } from '@/hooks/use-workspace-helper';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { toast } from '@/ui/toast'; import { toast } from '@affine/component';
interface ModalProps { interface ModalProps {
open: boolean; open: boolean;

View File

@@ -1,7 +1,7 @@
import { styled } from '@/styles'; import { styled } from '@affine/component';
import { Modal, ModalWrapper, ModalCloseButton } from '@/ui/modal'; import { Modal, ModalWrapper, ModalCloseButton } from '@affine/component';
import { Button } from '@/ui/button'; import { Button } from '@affine/component';
import Input from '@/ui/input'; import { Input } from '@affine/component';
import { useState } from 'react'; import { useState } from 'react';
interface LoginModalProps { interface LoginModalProps {

View File

@@ -14,8 +14,8 @@ import {
UndoIcon, UndoIcon,
RedoIcon, RedoIcon,
} from './Icons'; } from './Icons';
import { MuiSlide } from '@/ui/mui'; import { MuiSlide } from '@affine/component';
import { Tooltip } from '@/ui/tooltip'; import { Tooltip } from '@affine/component';
import useCurrentPageMeta from '@/hooks/use-current-page-meta'; import useCurrentPageMeta from '@/hooks/use-current-page-meta';
import { useAppState } from '@/providers/app-state-provider'; import { useAppState } from '@/providers/app-state-provider';
import useHistoryUpdated from '@/hooks/use-history-update'; import useHistoryUpdated from '@/hooks/use-history-update';

View File

@@ -1,4 +1,4 @@
import { styled, displayFlex } from '@/styles'; import { styled, displayFlex } from '@affine/component';
export const StyledEdgelessToolbar = styled.div(({ theme }) => ({ export const StyledEdgelessToolbar = styled.div(({ theme }) => ({
height: '320px', height: '320px',

View File

@@ -1,4 +1,4 @@
import { displayFlex, keyframes, styled } from '@/styles'; import { displayFlex, keyframes, styled } from '@affine/component';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
import spring, { toString } from 'css-spring'; import spring, { toString } from 'css-spring';

View File

@@ -3,7 +3,7 @@ import type { Page, Workspace } from '@blocksuite/store';
import '@blocksuite/blocks'; import '@blocksuite/blocks';
import { EditorContainer } from '@blocksuite/editor'; import { EditorContainer } from '@blocksuite/editor';
import exampleMarkdown from '@/templates/Welcome-to-AFFiNE-Alpha-Downhills.md'; import exampleMarkdown from '@/templates/Welcome-to-AFFiNE-Alpha-Downhills.md';
import { styled } from '@/styles'; import { styled } from '@affine/component';
const StyledEditorContainer = styled('div')(() => { const StyledEditorContainer = styled('div')(() => {
return { return {
@@ -59,7 +59,6 @@ export const Editor = ({ page, workspace, setEditor }: Props) => {
} }
setEditor(editor); setEditor(editor);
document.title = page.meta.title || 'Untitled';
return ret; return ret;
}, [workspace, page, setEditor]); }, [workspace, page, setEditor]);

View File

@@ -1,11 +1,11 @@
import { styled } from '@/styles'; import { styled } from '@affine/component';
import { Modal, ModalWrapper } from '@/ui/modal'; import { Modal, ModalWrapper } from '@affine/component';
import { Button, IconButton } from '@/ui/button'; import { Button, IconButton } from '@affine/component';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
import { useAppState } from '@/providers/app-state-provider'; import { useAppState } from '@/providers/app-state-provider';
import { useState } from 'react'; import { useState } from 'react';
import router from 'next/router'; import router from 'next/router';
import { toast } from '@/ui/toast'; import { toast } from '@affine/component';
import { CloseIcon } from '@blocksuite/icons'; import { CloseIcon } from '@blocksuite/icons';
interface EnableWorkspaceModalProps { interface EnableWorkspaceModalProps {
open: boolean; open: boolean;

View File

@@ -1,4 +1,4 @@
import { Button } from '@/ui/button'; import { Button } from '@affine/component';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
import { useState } from 'react'; import { useState } from 'react';
import { EnableWorkspaceModal } from './EnableWorkspaceModal'; import { EnableWorkspaceModal } from './EnableWorkspaceModal';

View File

@@ -1,6 +1,6 @@
import { Button } from '@/ui/button'; import { Button } from '@affine/component';
import { FC, useRef, ChangeEvent, ReactElement } from 'react'; import { FC, useRef, ChangeEvent, ReactElement } from 'react';
import { styled } from '@/styles'; import { styled } from '@affine/component';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
interface Props { interface Props {
uploadType?: string; uploadType?: string;

View File

@@ -5,7 +5,7 @@ import {
StyledTitle, StyledTitle,
StyledTitleWrapper, StyledTitleWrapper,
} from './styles'; } from './styles';
import { Content } from '@/ui/layout'; import { Content } from '@affine/component';
import { useAppState } from '@/providers/app-state-provider'; import { useAppState } from '@/providers/app-state-provider';
import EditorModeSwitch from '@/components/editor-mode-switch'; import EditorModeSwitch from '@/components/editor-mode-switch';
import QuickSearchButton from './QuickSearchButton'; import QuickSearchButton from './QuickSearchButton';

View File

@@ -1,8 +1,8 @@
import React from 'react'; import React from 'react';
import { IconButton, IconButtonProps } from '@/ui/button'; import { IconButton, IconButtonProps } from '@affine/component';
import { ArrowDownIcon } from '@blocksuite/icons'; import { ArrowDownIcon } from '@blocksuite/icons';
import { useModal } from '@/providers/GlobalModalProvider'; import { useModal } from '@/providers/GlobalModalProvider';
import { styled } from '@/styles'; import { styled } from '@affine/component';
const StyledIconButtonWithAnimate = styled(IconButton)(({ theme }) => { const StyledIconButtonWithAnimate = styled(IconButton)(({ theme }) => {
return { return {

View File

@@ -1,5 +1,5 @@
import { Menu, MenuItem } from '@/ui/menu'; import { Menu, MenuItem } from '@affine/component';
import { IconButton } from '@/ui/button'; import { IconButton } from '@affine/component';
import { import {
EdgelessIcon, EdgelessIcon,
ExportIcon, ExportIcon,
@@ -15,7 +15,7 @@ import { useAppState } from '@/providers/app-state-provider';
import { usePageHelper } from '@/hooks/use-page-helper'; import { usePageHelper } from '@/hooks/use-page-helper';
import { useConfirm } from '@/providers/ConfirmProvider'; import { useConfirm } from '@/providers/ConfirmProvider';
import useCurrentPageMeta from '@/hooks/use-current-page-meta'; import useCurrentPageMeta from '@/hooks/use-current-page-meta';
import { toast } from '@/ui/toast'; import { toast } from '@affine/component';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
const PopoverContent = () => { const PopoverContent = () => {
const { editor } = useAppState(); const { editor } = useAppState();
@@ -37,12 +37,12 @@ const PopoverContent = () => {
onClick={() => { onClick={() => {
toggleFavoritePage(id); toggleFavoritePage(id);
toast( toast(
favorite ? t('Removed from Favourites') : t('Added to Favourites') favorite ? t('Removed from Favorites') : t('Added to Favorites')
); );
}} }}
icon={favorite ? <FavouritedIcon /> : <FavouritesIcon />} icon={favorite ? <FavouritedIcon /> : <FavouritesIcon />}
> >
{favorite ? t('Remove from favourites') : t('Add to favourites')} {favorite ? t('Remove from favorites') : t('Add to favorites')}
</MenuItem> </MenuItem>
<MenuItem <MenuItem
icon={mode === 'page' ? <EdgelessIcon /> : <PaperIcon />} icon={mode === 'page' ? <EdgelessIcon /> : <PaperIcon />}

View File

@@ -1,7 +1,7 @@
import { CloudUnsyncedIcon } from '@blocksuite/icons'; import { CloudUnsyncedIcon } from '@blocksuite/icons';
import { useModal } from '@/providers/GlobalModalProvider'; import { useModal } from '@/providers/GlobalModalProvider';
import { useAppState } from '@/providers/app-state-provider'; import { useAppState } from '@/providers/app-state-provider';
import { IconButton } from '@/ui/button'; import { IconButton } from '@affine/component';
// Temporary solution to use this component, since the @blocksuite/icons has not been published yet // Temporary solution to use this component, since the @blocksuite/icons has not been published yet
const DefaultSyncIcon = () => { const DefaultSyncIcon = () => {

View File

@@ -1,4 +1,4 @@
import { Button } from '@/ui/button'; import { Button } from '@affine/component';
import { usePageHelper } from '@/hooks/use-page-helper'; import { usePageHelper } from '@/hooks/use-page-helper';
import { useAppState } from '@/providers/app-state-provider'; import { useAppState } from '@/providers/app-state-provider';
import { useConfirm } from '@/providers/ConfirmProvider'; import { useConfirm } from '@/providers/ConfirmProvider';

View File

@@ -1,4 +1,4 @@
import { displayFlex, keyframes, styled } from '@/styles'; import { displayFlex, keyframes, styled } from '@affine/component';
import { CSSProperties } from 'react'; import { CSSProperties } from 'react';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore

View File

@@ -1,4 +1,4 @@
import { displayFlex, styled } from '@/styles'; import { displayFlex, styled } from '@affine/component';
export const StyledHeaderContainer = styled.div<{ hasWarning: boolean }>( export const StyledHeaderContainer = styled.div<{ hasWarning: boolean }>(
({ hasWarning }) => { ({ hasWarning }) => {

View File

@@ -6,8 +6,8 @@ import {
StyledTransformIcon, StyledTransformIcon,
} from './style'; } from './style';
import { CloseIcon, ContactIcon, HelpIcon, KeyboardIcon } from './Icons'; import { CloseIcon, ContactIcon, HelpIcon, KeyboardIcon } from './Icons';
import { MuiGrow } from '@/ui/mui'; import { MuiGrow } from '@affine/component';
import { Tooltip } from '@/ui/tooltip'; import { Tooltip } from '@affine/component';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
import { useModal } from '@/providers/GlobalModalProvider'; import { useModal } from '@/providers/GlobalModalProvider';
import { useTheme } from '@/providers/ThemeProvider'; import { useTheme } from '@/providers/ThemeProvider';

View File

@@ -1,4 +1,4 @@
import { displayFlex, styled } from '@/styles'; import { displayFlex, styled } from '@affine/component';
export const StyledIsland = styled('div')(({ theme }) => { export const StyledIsland = styled('div')(({ theme }) => {
return { return {

View File

@@ -1,13 +1,13 @@
import { Modal, ModalWrapper, ModalCloseButton } from '@/ui/modal'; import { Modal, ModalWrapper, ModalCloseButton } from '@affine/component';
import { StyledButtonWrapper, StyledTitle } from './styles'; import { StyledButtonWrapper, StyledTitle } from './styles';
import { Button } from '@/ui/button'; import { Button } from '@affine/component';
import { Content, FlexWrapper } from '@/ui/layout'; import { Content, FlexWrapper } from '@affine/component';
import Loading from '@/components/loading'; import Loading from '@/components/loading';
import { usePageHelper } from '@/hooks/use-page-helper'; import { usePageHelper } from '@/hooks/use-page-helper';
import { useAppState } from '@/providers/app-state-provider'; import { useAppState } from '@/providers/app-state-provider';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
// import { Tooltip } from '@/ui/tooltip'; // import { Tooltip } from '@affine/component';
type ImportModalProps = { type ImportModalProps = {
open: boolean; open: boolean;
onClose: () => void; onClose: () => void;

View File

@@ -1,4 +1,4 @@
import { styled } from '@/styles'; import { styled } from '@affine/component';
export const StyledTitle = styled.div(({ theme }) => { export const StyledTitle = styled.div(({ theme }) => {
return { return {

View File

@@ -1,4 +1,4 @@
import { styled } from '@/styles'; import { styled } from '@affine/component';
import Loading from './Loading'; import Loading from './Loading';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';

View File

@@ -1,4 +1,4 @@
import { styled } from '@/styles'; import { styled } from '@affine/component';
// Inspired by https://codepen.io/graphilla/pen/rNvBMYY // Inspired by https://codepen.io/graphilla/pen/rNvBMYY
export const StyledLoadingWrapper = styled('div', { export const StyledLoadingWrapper = styled('div', {

View File

@@ -1,6 +1,6 @@
import { positionAbsolute, styled } from '@/styles'; import { positionAbsolute, styled } from '@affine/component';
import { Modal, ModalWrapper, ModalCloseButton } from '@/ui/modal'; import { Modal, ModalWrapper, ModalCloseButton } from '@affine/component';
import { Button } from '@/ui/button'; import { Button } from '@affine/component';
import { useAppState } from '@/providers/app-state-provider'; import { useAppState } from '@/providers/app-state-provider';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
import { GoogleIcon } from './GoogleIcon'; import { GoogleIcon } from './GoogleIcon';

View File

@@ -1,6 +1,6 @@
import { styled } from '@/styles'; import { styled } from '@affine/component';
import { Modal, ModalWrapper, ModalCloseButton } from '@/ui/modal'; import { Modal, ModalWrapper, ModalCloseButton } from '@affine/component';
import { Button } from '@/ui/button'; import { Button } from '@affine/component';
import { Check, UnCheck } from './icon'; import { Check, UnCheck } from './icon';
import { useState } from 'react'; import { useState } from 'react';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';

View File

@@ -1,5 +1,5 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import Modal, { ModalCloseButton, ModalWrapper } from '@/ui/modal'; import { Modal, ModalCloseButton, ModalWrapper } from '@affine/component';
import getIsMobile from '@/utils/get-is-mobile'; import getIsMobile from '@/utils/get-is-mobile';
import { StyledButton, StyledContent, StyledTitle } from './styles'; import { StyledButton, StyledContent, StyledTitle } from './styles';
import bg from './bg.png'; import bg from './bg.png';

View File

@@ -1,4 +1,4 @@
import { displayFlex, styled } from '@/styles'; import { displayFlex, styled } from '@affine/component';
export const StyledTitle = styled.div(() => { export const StyledTitle = styled.div(() => {
return { return {

View File

@@ -1,7 +1,7 @@
import localizedFormat from 'dayjs/plugin/localizedFormat'; import localizedFormat from 'dayjs/plugin/localizedFormat';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { PageMeta } from '@/providers/app-state-provider'; import { PageMeta } from '@/providers/app-state-provider';
import { TableCell } from '@/ui/table'; import { TableCell } from '@affine/component';
import React from 'react'; import React from 'react';
dayjs.extend(localizedFormat); dayjs.extend(localizedFormat);

View File

@@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { Empty } from '@/ui/empty'; import { Empty } from '@affine/component';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
export const PageListEmpty = (props: { listType?: string }) => { export const PageListEmpty = (props: { listType?: string }) => {
const { listType } = props; const { listType } = props;
@@ -12,7 +12,7 @@ export const PageListEmpty = (props: { listType?: string }) => {
sx={{ marginTop: '100px', marginBottom: '30px' }} sx={{ marginTop: '100px', marginBottom: '30px' }}
/> />
{listType === 'all' && <p>{t('emptyAllPages')}</p>} {listType === 'all' && <p>{t('emptyAllPages')}</p>}
{listType === 'favorite' && <p>{t('emptyFavourite')}</p>} {listType === 'favorite' && <p>{t('emptyFavorite')}</p>}
{listType === 'trash' && <p>{t('emptyTrash')}</p>} {listType === 'trash' && <p>{t('emptyTrash')}</p>}
</div> </div>
); );

View File

@@ -1,8 +1,8 @@
import { useConfirm } from '@/providers/ConfirmProvider'; import { useConfirm } from '@/providers/ConfirmProvider';
import { PageMeta } from '@/providers/app-state-provider'; import { PageMeta } from '@/providers/app-state-provider';
import { Menu, MenuItem } from '@/ui/menu'; import { Menu, MenuItem } from '@affine/component';
import { FlexWrapper } from '@/ui/layout'; import { FlexWrapper } from '@affine/component';
import { IconButton } from '@/ui/button'; import { IconButton } from '@affine/component';
import { import {
MoreVerticalIcon, MoreVerticalIcon,
RestoreIcon, RestoreIcon,
@@ -12,7 +12,7 @@ import {
OpenInNewIcon, OpenInNewIcon,
TrashIcon, TrashIcon,
} from '@blocksuite/icons'; } from '@blocksuite/icons';
import { toast } from '@/ui/toast'; import { toast } from '@affine/component';
import { usePageHelper } from '@/hooks/use-page-helper'; import { usePageHelper } from '@/hooks/use-page-helper';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
export const OperationCell = ({ pageMeta }: { pageMeta: PageMeta }) => { export const OperationCell = ({ pageMeta }: { pageMeta: PageMeta }) => {
@@ -27,12 +27,12 @@ export const OperationCell = ({ pageMeta }: { pageMeta: PageMeta }) => {
onClick={() => { onClick={() => {
toggleFavoritePage(id); toggleFavoritePage(id);
toast( toast(
favorite ? t('Removed from Favourites') : t('Added to Favourites') favorite ? t('Removed from Favorites') : t('Added to Favorites')
); );
}} }}
icon={favorite ? <FavouritedIcon /> : <FavouritesIcon />} icon={favorite ? <FavouritedIcon /> : <FavouritesIcon />}
> >
{favorite ? t('Remove from favourites') : t('Add to favourites')} {favorite ? t('Remove from favorites') : t('Add to favorites')}
</MenuItem> </MenuItem>
<MenuItem <MenuItem
onClick={() => { onClick={() => {

View File

@@ -11,17 +11,23 @@ import {
StyledTitleLink, StyledTitleLink,
StyledTitleWrapper, StyledTitleWrapper,
} from './styles'; } from './styles';
import { Table, TableBody, TableCell, TableHead, TableRow } from '@/ui/table'; import {
Table,
TableBody,
TableCell,
TableHead,
TableRow,
} from '@affine/component';
import { OperationCell, TrashOperationCell } from './OperationCell'; import { OperationCell, TrashOperationCell } from './OperationCell';
import Empty from './Empty'; import Empty from './Empty';
import { Content } from '@/ui/layout'; import { Content } from '@affine/component';
import React from 'react'; import React from 'react';
import DateCell from '@/components/page-list/DateCell'; import DateCell from '@/components/page-list/DateCell';
import { IconButton } from '@/ui/button'; import { IconButton } from '@affine/component';
import { Tooltip } from '@/ui/tooltip'; import { Tooltip } from '@affine/component';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { useAppState } from '@/providers/app-state-provider'; import { useAppState } from '@/providers/app-state-provider';
import { toast } from '@/ui/toast'; import { toast } from '@affine/component';
import { usePageHelper } from '@/hooks/use-page-helper'; import { usePageHelper } from '@/hooks/use-page-helper';
import { useTheme } from '@/providers/ThemeProvider'; import { useTheme } from '@/providers/ThemeProvider';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
@@ -35,7 +41,7 @@ const FavoriteTag = ({
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<Tooltip <Tooltip
content={favorite ? t('Favourited') : t('Favourite')} content={favorite ? t('Favorited') : t('Favorite')}
placement="top-start" placement="top-start"
> >
<IconButton <IconButton
@@ -45,7 +51,7 @@ const FavoriteTag = ({
e.stopPropagation(); e.stopPropagation();
toggleFavoritePage(id); toggleFavoritePage(id);
toast( toast(
favorite ? t('Removed from Favourites') : t('Added to Favourites') favorite ? t('Removed from Favorites') : t('Added to Favorites')
); );
}} }}
style={{ style={{
@@ -54,7 +60,7 @@ const FavoriteTag = ({
className={favorite ? '' : 'favorite-button'} className={favorite ? '' : 'favorite-button'}
> >
{favorite ? ( {favorite ? (
<FavouritedIcon data-testid="favourited-icon" /> <FavouritedIcon data-testid="favorited-icon" />
) : ( ) : (
<FavouritesIcon /> <FavouritesIcon />
)} )}
@@ -100,6 +106,7 @@ export const PageList = ({
{pageList.map((pageMeta, index) => { {pageList.map((pageMeta, index) => {
return ( return (
<StyledTableRow <StyledTableRow
data-testid="page-list-item"
key={`${pageMeta.id}-${index}`} key={`${pageMeta.id}-${index}`}
onClick={() => { onClick={() => {
if (isPublic) { if (isPublic) {

View File

@@ -1,5 +1,5 @@
import { displayFlex, styled } from '@/styles'; import { displayFlex, styled } from '@affine/component';
import { TableRow } from '@/ui/table'; import { TableRow } from '@affine/component';
export const StyledTableContainer = styled.div(() => { export const StyledTableContainer = styled.div(() => {
return { return {

View File

@@ -22,7 +22,7 @@ export const useSwitchToConfig = (
icon: AllPagesIcon, icon: AllPagesIcon,
}, },
{ {
title: t('Favourites'), title: t('Favorites'),
href: currentWorkspaceId href: currentWorkspaceId
? `/workspace/${currentWorkspaceId}/favorite` ? `/workspace/${currentWorkspaceId}/favorite`
: '', : '',

View File

@@ -1,4 +1,4 @@
import { Modal, ModalWrapper } from '@/ui/modal'; import { Modal, ModalWrapper } from '@affine/component';
import { import {
StyledContent, StyledContent,
StyledModalHeader, StyledModalHeader,
@@ -40,7 +40,6 @@ export const QuickSearch = ({ open, onClose }: TransitionsModalProps) => {
// Add ‘⌘+K’ shortcut keys as switches // Add ‘⌘+K’ shortcut keys as switches
useEffect(() => { useEffect(() => {
if (router.pathname.startsWith('/404')) { if (router.pathname.startsWith('/404')) {
triggerQuickSearchModal(false);
return; return;
} }
const down = (e: KeyboardEvent) => { const down = (e: KeyboardEvent) => {
@@ -59,7 +58,7 @@ export const QuickSearch = ({ open, onClose }: TransitionsModalProps) => {
document.addEventListener('keydown', down, { capture: true }); document.addEventListener('keydown', down, { capture: true });
return () => return () =>
document.removeEventListener('keydown', down, { capture: true }); document.removeEventListener('keydown', down, { capture: true });
}, [open, router.pathname, triggerQuickSearchModal]); }, [open, router, triggerQuickSearchModal]);
useEffect(() => { useEffect(() => {
if (router.pathname.startsWith('/public-workspace')) { if (router.pathname.startsWith('/public-workspace')) {
@@ -68,6 +67,12 @@ export const QuickSearch = ({ open, onClose }: TransitionsModalProps) => {
return setIsPublic(false); return setIsPublic(false);
} }
}, [router]); }, [router]);
useEffect(() => {
if (router.pathname.startsWith('/404')) {
return onClose();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return ( return (
<Modal <Modal

View File

@@ -1,4 +1,4 @@
import { displayFlex, styled } from '@/styles'; import { displayFlex, styled } from '@affine/component';
export const StyledContent = styled('div')(({ theme }) => { export const StyledContent = styled('div')(({ theme }) => {
return { return {
@@ -13,7 +13,7 @@ export const StyledContent = styled('div')(({ theme }) => {
letterSpacing: '0.06em', letterSpacing: '0.06em',
'[cmdk-group-heading]': { '[cmdk-group-heading]': {
margin: '5px 16px', margin: '5px 16px',
fontSize: theme.font.sm, fontSize: theme.font.base,
fontWeight: '500', fontWeight: '500',
}, },
'[aria-selected="true"]': { '[aria-selected="true"]': {
@@ -28,7 +28,7 @@ export const StyledJumpTo = styled('div')(({ theme }) => {
...displayFlex('center', 'start'), ...displayFlex('center', 'start'),
flexDirection: 'column', flexDirection: 'column',
padding: '10px 10px 10px 0', padding: '10px 10px 10px 0',
fontSize: theme.font.sm, fontSize: theme.font.base,
strong: { strong: {
fontWeight: '500', fontWeight: '500',
marginBottom: '10px', marginBottom: '10px',
@@ -41,7 +41,7 @@ export const StyledNotFound = styled('div')(({ theme }) => {
...displayFlex('center', 'center'), ...displayFlex('center', 'center'),
flexDirection: 'column', flexDirection: 'column',
padding: '5px 16px', padding: '5px 16px',
fontSize: theme.font.sm, fontSize: theme.font.base,
span: { span: {
width: '100%', width: '100%',
fontWeight: '500', fontWeight: '500',
@@ -75,7 +75,7 @@ export const StyledInputContent = styled('div')(({ theme }) => {
export const StyledShortcut = styled('div')(({ theme }) => { export const StyledShortcut = styled('div')(({ theme }) => {
return { return {
color: theme.colors.placeHolderColor, color: theme.colors.placeHolderColor,
fontSize: theme.font.sm, fontSize: theme.font.base,
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
}; };
}); });
@@ -109,7 +109,7 @@ export const StyledModalDivider = styled('div')(({ theme }) => {
export const StyledModalFooter = styled('div')(({ theme }) => { export const StyledModalFooter = styled('div')(({ theme }) => {
return { return {
fontSize: theme.font.sm, fontSize: theme.font.base,
lineHeight: '22px', lineHeight: '22px',
marginBottom: '8px', marginBottom: '8px',
textAlign: 'center', textAlign: 'center',
@@ -127,7 +127,7 @@ export const StyledModalFooterContent = styled.button(({ theme }) => {
return { return {
width: '612px', width: '612px',
height: '32px', height: '32px',
fontSize: theme.font.sm, fontSize: theme.font.base,
lineHeight: '22px', lineHeight: '22px',
textAlign: 'center', textAlign: 'center',
...displayFlex('center', 'center'), ...displayFlex('center', 'center'),
@@ -144,7 +144,7 @@ export const StyledListItem = styled.button(({ theme }) => {
return { return {
width: '612px', width: '612px',
height: '32px', height: '32px',
fontSize: theme.font.sm, fontSize: theme.font.base,
color: 'inherit', color: 'inherit',
paddingLeft: '12px', paddingLeft: '12px',
borderRadius: '5px', borderRadius: '5px',

View File

@@ -13,8 +13,8 @@ import {
useWindowsKeyboardShortcuts, useWindowsKeyboardShortcuts,
useWinMarkdownShortcuts, useWinMarkdownShortcuts,
} from '@/components/shortcuts-modal/config'; } from '@/components/shortcuts-modal/config';
import { MuiSlide } from '@/ui/mui'; import { MuiSlide } from '@affine/component';
import { ModalCloseButton } from '@/ui/modal'; import { ModalCloseButton } from '@affine/component';
import { getUaHelper } from '@/utils'; import { getUaHelper } from '@/utils';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
type ModalProps = { type ModalProps = {

View File

@@ -1,4 +1,4 @@
import { displayFlex, styled } from '@/styles'; import { displayFlex, styled } from '@affine/component';
export const StyledShortcutsModal = styled.div(({ theme }) => ({ export const StyledShortcutsModal = styled.div(({ theme }) => ({
width: '288px', width: '288px',

View File

@@ -1,4 +1,4 @@
import { styled } from '@/styles'; import { styled } from '@affine/component';
export const StyledPage = styled('div')(({ theme }) => { export const StyledPage = styled('div')(({ theme }) => {
return { return {

View File

@@ -1,11 +1,11 @@
import { CloudInsyncIcon, LogOutIcon } from '@blocksuite/icons'; import { CloudInsyncIcon, LogOutIcon } from '@blocksuite/icons';
import { FlexWrapper } from '@/ui/layout'; import { FlexWrapper } from '@affine/component';
import { WorkspaceAvatar } from '@/components/workspace-avatar'; import { WorkspaceAvatar } from '@/components/workspace-avatar';
import { IconButton } from '@/ui/button'; import { IconButton } from '@affine/component';
import { useAppState } from '@/providers/app-state-provider'; import { useAppState } from '@/providers/app-state-provider';
import { StyledFooter, StyleUserInfo, StyledSignInButton } from './styles'; import { StyledFooter, StyleUserInfo, StyledSignInButton } from './styles';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
import { Tooltip } from '@/ui/tooltip'; import { Tooltip } from '@affine/component';
export const Footer = ({ export const Footer = ({
onLogin, onLogin,
onLogout, onLogout,

View File

@@ -1,9 +1,9 @@
import { LOCALES } from '@affine/i18n'; import { LOCALES } from '@affine/i18n';
import { styled } from '@/styles'; import { styled } from '@affine/component';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
import { ArrowDownIcon } from '@blocksuite/icons'; import { ArrowDownIcon } from '@blocksuite/icons';
import { Button } from '@/ui/button'; import { Button } from '@affine/component';
import { Menu, MenuItem } from '@/ui/menu'; import { Menu, MenuItem } from '@affine/component';
const LanguageMenuContent = () => { const LanguageMenuContent = () => {
const { i18n } = useTranslation(); const { i18n } = useTranslation();

View File

@@ -10,7 +10,7 @@ import { WorkspaceUnit } from '@affine/datacenter';
import { useAppState } from '@/providers/app-state-provider'; import { useAppState } from '@/providers/app-state-provider';
import { StyleWorkspaceInfo, StyleWorkspaceTitle, StyledCard } from './styles'; import { StyleWorkspaceInfo, StyleWorkspaceTitle, StyledCard } from './styles';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
import { FlexWrapper } from '@/ui/layout'; import { FlexWrapper } from '@affine/component';
const WorkspaceType = ({ workspaceData }: { workspaceData: WorkspaceUnit }) => { const WorkspaceType = ({ workspaceData }: { workspaceData: WorkspaceUnit }) => {
const { user } = useAppState(); const { user } = useAppState();

View File

@@ -1,9 +1,9 @@
import { Modal, ModalWrapper, ModalCloseButton } from '@/ui/modal'; import { Modal, ModalWrapper, ModalCloseButton } from '@affine/component';
import { FlexWrapper } from '@/ui/layout'; import { FlexWrapper } from '@affine/component';
import { useState } from 'react'; import { useState } from 'react';
import { CreateWorkspaceModal } from '../create-workspace'; import { CreateWorkspaceModal } from '../create-workspace';
import { Tooltip } from '@/ui/tooltip'; import { Tooltip } from '@affine/component';
import { AddIcon, HelpCenterIcon } from '@blocksuite/icons'; import { AddIcon, HelpCenterIcon } from '@blocksuite/icons';
@@ -71,6 +71,7 @@ export const WorkspaceModal = ({ open, onClose }: WorkspaceModalProps) => {
<LanguageMenu /> <LanguageMenu />
<StyledSplitLine /> <StyledSplitLine />
<ModalCloseButton <ModalCloseButton
data-testid="close-workspace-modal"
onClick={() => { onClick={() => {
onClose(); onClose();
}} }}

View File

@@ -1,5 +1,10 @@
import { displayFlex, displayInlineFlex, styled, textEllipsis } from '@/styles'; import {
import { Button } from '@/ui/button'; displayFlex,
displayInlineFlex,
styled,
textEllipsis,
} from '@affine/component';
import { Button } from '@affine/component';
export const StyledSplitLine = styled.div(({ theme }) => { export const StyledSplitLine = styled.div(({ theme }) => {
return { return {

View File

@@ -1,7 +1,7 @@
import { WorkspaceUnit } from '@affine/datacenter'; import { WorkspaceUnit } from '@affine/datacenter';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
import { Wrapper } from '@/ui/layout'; import { Wrapper } from '@affine/component';
import { Button } from '@/ui/button'; import { Button } from '@affine/component';
export const ExportPage = ({ workspace }: { workspace: WorkspaceUnit }) => { export const ExportPage = ({ workspace }: { workspace: WorkspaceUnit }) => {
const { t } = useTranslation(); const { t } = useTranslation();
console.log(workspace); console.log(workspace);

View File

@@ -1,12 +1,12 @@
import { useState } from 'react'; import { useState } from 'react';
import { Button } from '@/ui/button'; import { Button } from '@affine/component';
import Input from '@/ui/input'; import { Input } from '@affine/component';
import { toast } from '@/ui/toast'; import { toast } from '@affine/component';
import { WorkspaceUnit } from '@affine/datacenter'; import { WorkspaceUnit } from '@affine/datacenter';
import { useWorkspaceHelper } from '@/hooks/use-workspace-helper'; import { useWorkspaceHelper } from '@/hooks/use-workspace-helper';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
import { EnableWorkspaceButton } from '../enable-workspace'; import { EnableWorkspaceButton } from '../enable-workspace';
import { Wrapper, Content, FlexWrapper } from '@/ui/layout'; import { Wrapper, Content, FlexWrapper } from '@affine/component';
export const PublishPage = ({ workspace }: { workspace: WorkspaceUnit }) => { export const PublishPage = ({ workspace }: { workspace: WorkspaceUnit }) => {
const shareUrl = window.location.host + '/public-workspace/' + workspace.id; const shareUrl = window.location.host + '/public-workspace/' + workspace.id;
const { publishWorkspace } = useWorkspaceHelper(); const { publishWorkspace } = useWorkspaceHelper();

View File

@@ -9,7 +9,7 @@ import { useTranslation, Trans } from '@affine/i18n';
import { WorkspaceUnitAvatar } from '@/components/workspace-avatar'; import { WorkspaceUnitAvatar } from '@/components/workspace-avatar';
import { EnableWorkspaceButton } from '../enable-workspace'; import { EnableWorkspaceButton } from '../enable-workspace';
import { useAppState } from '@/providers/app-state-provider'; import { useAppState } from '@/providers/app-state-provider';
import { FlexWrapper, Content, Wrapper } from '@/ui/layout'; import { FlexWrapper, Content, Wrapper } from '@affine/component';
// // FIXME: Temporary solution, since the @blocksuite/icons is broken // // FIXME: Temporary solution, since the @blocksuite/icons is broken
// const ActiveIcon = () => { // const ActiveIcon = () => {

View File

@@ -1,9 +1,9 @@
import { StyledInput, StyledProviderInfo, StyledAvatar } from './style'; import { StyledInput, StyledProviderInfo, StyledAvatar } from './style';
import { StyledSettingKey, StyledRow } from '../style'; import { StyledSettingKey, StyledRow } from '../style';
import { FlexWrapper, Content } from '@/ui/layout'; import { FlexWrapper, Content } from '@affine/component';
import { useState } from 'react'; import { useState } from 'react';
import { Button } from '@/ui/button'; import { Button } from '@affine/component';
import { useAppState } from '@/providers/app-state-provider'; import { useAppState } from '@/providers/app-state-provider';
import { WorkspaceDelete } from './delete'; import { WorkspaceDelete } from './delete';
import { WorkspaceLeave } from './leave'; import { WorkspaceLeave } from './leave';
@@ -18,7 +18,7 @@ import { Upload } from '@/components/file-upload';
export const GeneralPage = ({ workspace }: { workspace: WorkspaceUnit }) => { export const GeneralPage = ({ workspace }: { workspace: WorkspaceUnit }) => {
const [showDelete, setShowDelete] = useState<boolean>(false); const [showDelete, setShowDelete] = useState<boolean>(false);
const [showLeave, setShowLeave] = useState<boolean>(false); const [showLeave, setShowLeave] = useState<boolean>(false);
const [workspaceName, setWorkspaceName] = useState<string>(workspace.name); const [workspaceName, setWorkspaceName] = useState<string>(workspace?.name);
const { currentWorkspace, isOwner } = useAppState(); const { currentWorkspace, isOwner } = useAppState();
const { updateWorkspace } = useWorkspaceHelper(); const { updateWorkspace } = useWorkspaceHelper();
const { t } = useTranslation(); const { t } = useTranslation();
@@ -33,7 +33,6 @@ export const GeneralPage = ({ workspace }: { workspace: WorkspaceUnit }) => {
currentWorkspace && currentWorkspace &&
(await updateWorkspace({ avatarBlob: blob }, currentWorkspace)); (await updateWorkspace({ avatarBlob: blob }, currentWorkspace));
}; };
if (!workspace) { if (!workspace) {
return null; return null;
} }
@@ -42,22 +41,30 @@ export const GeneralPage = ({ workspace }: { workspace: WorkspaceUnit }) => {
<> <>
<StyledRow> <StyledRow>
<StyledSettingKey>{t('Workspace Avatar')}</StyledSettingKey> <StyledSettingKey>{t('Workspace Avatar')}</StyledSettingKey>
<StyledAvatar> <StyledAvatar disabled={!isOwner}>
<Upload {isOwner ? (
accept="image/gif,image/jpeg,image/jpg,image/png,image/svg" <Upload
fileChange={fileChange} accept="image/gif,image/jpeg,image/jpg,image/png,image/svg"
> fileChange={fileChange}
<> >
<div className="camera-icon"> <>
<CameraIcon></CameraIcon> <div className="camera-icon">
</div> <CameraIcon></CameraIcon>
<WorkspaceUnitAvatar </div>
size={72} <WorkspaceUnitAvatar
name={workspace.name} size={72}
workspaceUnit={workspace} name={workspace.name}
/> workspaceUnit={workspace}
</> />
</Upload> </>
</Upload>
) : (
<WorkspaceUnitAvatar
size={72}
name={workspace.name}
workspaceUnit={workspace}
/>
)}
</StyledAvatar> </StyledAvatar>
</StyledRow> </StyledRow>

View File

@@ -1,6 +1,6 @@
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import Modal from '@/ui/modal'; import { Modal } from '@affine/component';
import Input from '@/ui/input'; import { Input } from '@affine/component';
import { import {
StyledModalHeader, StyledModalHeader,
StyledTextContent, StyledTextContent,
@@ -10,8 +10,8 @@ import {
StyledWorkspaceName, StyledWorkspaceName,
} from './style'; } from './style';
import { useState } from 'react'; import { useState } from 'react';
import { ModalCloseButton } from '@/ui/modal'; import { ModalCloseButton } from '@affine/component';
import { Button } from '@/ui/button'; import { Button } from '@affine/component';
import { WorkspaceUnit } from '@affine/datacenter'; import { WorkspaceUnit } from '@affine/datacenter';
import { Trans, useTranslation } from '@affine/i18n'; import { Trans, useTranslation } from '@affine/i18n';

View File

@@ -1,4 +1,4 @@
import { styled } from '@/styles'; import { styled } from '@affine/component';
export const StyledModalWrapper = styled('div')(({ theme }) => { export const StyledModalWrapper = styled('div')(({ theme }) => {
return { return {

View File

@@ -1,12 +1,12 @@
import Modal from '@/ui/modal'; import { Modal } from '@affine/component';
import { import {
StyledModalHeader, StyledModalHeader,
StyledTextContent, StyledTextContent,
StyledModalWrapper, StyledModalWrapper,
StyledButtonContent, StyledButtonContent,
} from './style'; } from './style';
import { ModalCloseButton } from '@/ui/modal'; import { ModalCloseButton } from '@affine/component';
import { Button } from '@/ui/button'; import { Button } from '@affine/component';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
import { useWorkspaceHelper } from '@/hooks/use-workspace-helper'; import { useWorkspaceHelper } from '@/hooks/use-workspace-helper';
// import { getDataCenter } from '@affine/datacenter'; // import { getDataCenter } from '@affine/datacenter';

View File

@@ -1,4 +1,4 @@
import { styled } from '@/styles'; import { styled } from '@affine/component';
export const StyledModalWrapper = styled('div')(({ theme }) => { export const StyledModalWrapper = styled('div')(({ theme }) => {
return { return {

View File

@@ -1,5 +1,5 @@
import { styled } from '@/styles'; import { styled } from '@affine/component';
import Input from '@/ui/input'; import { Input } from '@affine/component';
export const StyledInput = styled(Input)(({ theme }) => { export const StyledInput = styled(Input)(({ theme }) => {
return { return {
@@ -19,26 +19,29 @@ export const StyledProviderInfo = styled('p')(({ theme }) => {
}; };
}); });
export const StyledAvatar = styled('div')(() => { export const StyledAvatar = styled('div')(
return { ({ disabled }: { disabled: boolean }) => {
position: 'relative', return {
cursor: 'pointer', position: 'relative',
':hover': { marginRight: '20px',
'.camera-icon': { cursor: disabled ? 'default' : 'pointer',
display: 'block', ':hover': {
'.camera-icon': {
display: 'block',
},
}, },
}, '.camera-icon': {
'.camera-icon': { position: 'absolute',
position: 'absolute', display: 'none',
display: 'none', width: '100%',
width: '100%', height: '100%',
height: '100%', borderRadius: '50%',
borderRadius: '50%', backgroundColor: 'rgba(60, 61, 63, 0.5)',
backgroundColor: 'rgba(60, 61, 63, 0.5)', top: 0,
top: 0, left: 0,
left: 0, textAlign: 'center',
textAlign: 'center', lineHeight: '72px',
lineHeight: '72px', },
}, };
}; }
}); );

View File

@@ -1,10 +1,10 @@
import { EmailIcon } from '@blocksuite/icons'; import { EmailIcon } from '@blocksuite/icons';
import { styled } from '@/styles'; import { styled } from '@affine/component';
import { Modal, ModalWrapper, ModalCloseButton } from '@/ui/modal'; import { Modal, ModalWrapper, ModalCloseButton } from '@affine/component';
import { Button } from '@/ui/button'; import { Button } from '@affine/component';
import Input from '@/ui/input'; import { Input } from '@affine/component';
import { useState } from 'react'; import { useState } from 'react';
import { MuiAvatar } from '@/ui/mui'; import { MuiAvatar } from '@affine/component';
import useMembers from '@/hooks/use-members'; import useMembers from '@/hooks/use-members';
import { User } from '@affine/datacenter'; import { User } from '@affine/datacenter';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';

View File

@@ -12,19 +12,19 @@ import {
StyledMoreVerticalButton, StyledMoreVerticalButton,
StyledMemberContainer, StyledMemberContainer,
} from './style'; } from './style';
import { Wrapper } from '@/ui/layout'; import { Wrapper } from '@affine/component';
import { MoreVerticalIcon, EmailIcon, TrashIcon } from '@blocksuite/icons'; import { MoreVerticalIcon, EmailIcon, TrashIcon } from '@blocksuite/icons';
import { useState } from 'react'; import { useState } from 'react';
import { Button, IconButton } from '@/ui/button'; import { Button, IconButton } from '@affine/component';
import { InviteMemberModal } from './InviteMemberModal'; import { InviteMemberModal } from './InviteMemberModal';
import { Menu, MenuItem } from '@/ui/menu'; import { Menu, MenuItem } from '@affine/component';
import { Empty } from '@/ui/empty'; import { Empty } from '@affine/component';
import { WorkspaceUnit } from '@affine/datacenter'; import { WorkspaceUnit } from '@affine/datacenter';
import { useConfirm } from '@/providers/ConfirmProvider'; import { useConfirm } from '@/providers/ConfirmProvider';
import { toast } from '@/ui/toast'; import { toast } from '@affine/component';
import useMembers from '@/hooks/use-members'; import useMembers from '@/hooks/use-members';
import Loading from '@/components/loading'; import Loading from '@/components/loading';
import { FlexWrapper } from '@/ui/layout'; import { FlexWrapper } from '@affine/component';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
import { EnableWorkspaceButton } from '@/components/enable-workspace'; import { EnableWorkspaceButton } from '@/components/enable-workspace';

View File

@@ -1,5 +1,5 @@
import { styled } from '@/styles'; import { styled } from '@affine/component';
import { MuiAvatar } from '@/ui/mui'; import { MuiAvatar } from '@affine/component';
export const StyledMemberTitleContainer = styled('li')(() => { export const StyledMemberTitleContainer = styled('li')(() => {
return { return {

View File

@@ -1,5 +1,5 @@
import { styled } from '@/styles'; import { styled } from '@affine/component';
import { FlexWrapper } from '@/ui/layout'; import { FlexWrapper } from '@affine/component';
export const StyledSettingContainer = styled('div')(() => { export const StyledSettingContainer = styled('div')(() => {
return { return {
display: 'flex', display: 'flex',

View File

@@ -1,5 +1,5 @@
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
import { styled } from '@/styles'; import { styled } from '@affine/component';
import { WorkspaceItemWrapper, WorkspaceItemContent } from './styles'; import { WorkspaceItemWrapper, WorkspaceItemContent } from './styles';
interface ListItemProps { interface ListItemProps {

View File

@@ -1,5 +1,5 @@
import { useModal } from '@/providers/GlobalModalProvider'; import { useModal } from '@/providers/GlobalModalProvider';
import { styled } from '@/styles'; import { styled } from '@affine/component';
import { AffineIcon } from '../../icons/Icons'; import { AffineIcon } from '../../icons/Icons';
import { import {
WorkspaceItemAvatar, WorkspaceItemAvatar,

View File

@@ -1,5 +1,5 @@
import { MuiAvatar } from '@/ui/mui'; import { MuiAvatar } from '@affine/component';
import { styled } from '@/styles'; import { styled } from '@affine/component';
export const WorkspaceItemWrapper = styled('div')(({ theme }) => ({ export const WorkspaceItemWrapper = styled('div')(({ theme }) => ({
display: 'flex', display: 'flex',

View File

@@ -1,6 +1,6 @@
import { MuiAvatar } from '@/ui/mui'; import { MuiAvatar } from '@affine/component';
import { styled } from '@/styles'; import { styled } from '@affine/component';
import { StyledPopperContainer } from '@/ui/shared/Container'; import { StyledPopperContainer } from '@affine/component';
export const SelectorWrapper = styled('div')({ export const SelectorWrapper = styled('div')({
width: '100%', width: '100%',

View File

@@ -21,11 +21,11 @@ import {
SettingsIcon, SettingsIcon,
} from '@blocksuite/icons'; } from '@blocksuite/icons';
import Link from 'next/link'; import Link from 'next/link';
import { MuiCollapse } from '@/ui/mui'; import { MuiCollapse } from '@affine/component';
import { Tooltip } from '@/ui/tooltip'; import { Tooltip } from '@affine/component';
import { useModal } from '@/providers/GlobalModalProvider'; import { useModal } from '@/providers/GlobalModalProvider';
import { useAppState } from '@/providers/app-state-provider'; import { useAppState } from '@/providers/app-state-provider';
import { IconButton } from '@/ui/button'; import { IconButton } from '@affine/component';
import useLocalStorage from '@/hooks/use-local-storage'; import useLocalStorage from '@/hooks/use-local-storage';
import { usePageHelper } from '@/hooks/use-page-helper'; import { usePageHelper } from '@/hooks/use-page-helper';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
@@ -125,13 +125,14 @@ export const WorkSpaceSliderBar = () => {
</StyledListItem> </StyledListItem>
<Link href={{ pathname: paths.all }}> <Link href={{ pathname: paths.all }}>
<StyledListItem active={router.asPath === paths.all}> <StyledListItem active={router.asPath === paths.all}>
<AllPagesIcon /> <span>{t('All pages')}</span> <AllPagesIcon />
<span data-testid="all-pages">{t('All pages')}</span>
</StyledListItem> </StyledListItem>
</Link> </Link>
<StyledListItem active={router.asPath === paths.favorite}> <StyledListItem active={router.asPath === paths.favorite}>
<StyledLink href={{ pathname: paths.favorite }}> <StyledLink href={{ pathname: paths.favorite }}>
<FavouritesIcon /> <FavouritesIcon />
{t('Favourites')} {t('Favorites')}
</StyledLink> </StyledLink>
<IconButton <IconButton
darker={true} darker={true}

View File

@@ -1,4 +1,4 @@
import { displayFlex, styled, textEllipsis } from '@/styles'; import { displayFlex, styled, textEllipsis } from '@affine/component';
import Link from 'next/link'; import Link from 'next/link';
export const StyledSliderBar = styled.div<{ show: boolean }>( export const StyledSliderBar = styled.div<{ show: boolean }>(

View File

@@ -1,5 +1,13 @@
import NotfoundPage from '@/components/404'; import NotfoundPage from '@/components/404';
import Head from 'next/head';
export default function Custom404() { export default function Custom404() {
return <NotfoundPage></NotfoundPage>; return (
<>
<Head>
<title>404 - AFFiNE</title>
</Head>
<NotfoundPage></NotfoundPage>
</>
);
} }

View File

@@ -50,6 +50,7 @@ const App = ({ Component, pageProps }: AppPropsWithLayout) => {
sizes="180x180" sizes="180x180"
href="/icons/apple-touch-icon.png" href="/icons/apple-touch-icon.png"
/> />
<title>AFFiNE</title>
</Head> </Head>
<Logger /> <Logger />
<ProviderComposer <ProviderComposer

View File

@@ -1,67 +0,0 @@
import { displayFlex, styled } from '@/styles';
import Loading from '@/components/loading';
import Modal from '@/ui/modal';
import { useState } from 'react';
import { Button } from '@/ui/button';
import { FavouritedIcon } from '@blocksuite/icons';
import { toast } from '@/ui/toast';
export const StyledHeader = styled('div')({
height: '60px',
width: '100vw',
...displayFlex('space-between', 'center'),
position: 'relative',
padding: '0 22px',
borderBottom: '1px solid #e5e5e5',
});
const Affine = () => {
const [show, setShow] = useState(false);
return (
<>
<StyledHeader>
<button
onClick={() => {
setShow(true);
}}
>
click me!
</button>
</StyledHeader>
<Modal
open={show}
onClose={() => {
setShow(false);
}}
>
<div>hi</div>
</Modal>
<Loading />
<Button
icon={<FavouritedIcon />}
onClick={() => {
toast('hello, world!!');
}}
>
click me!
</Button>
<Button icon={<FavouritedIcon />} type={'primary'}>
click me!
</Button>
<Button icon={<FavouritedIcon />} type={'light'}>
click me!
</Button>
<Button icon={<FavouritedIcon />} type={'warning'}>
click me!
</Button>
<Button icon={<FavouritedIcon />} type={'danger'}>
click me!
</Button>
<Button icon={<FavouritedIcon />}></Button>
<Button icon={<FavouritedIcon />} shape="round"></Button>
<Button loading={true}></Button>
<Button loading={true} type="primary"></Button>
</>
);
};
export default Affine;

View File

@@ -1,20 +0,0 @@
// for dynamic route get workspace id maybe path will change
import { useRouter } from 'next/router';
const Post = () => {
const router = useRouter();
const { workspace_id } = router.query;
return (
<p
style={{
height: 'calc(100vh)',
color: 'gray',
}}
>
workspace_id: {workspace_id},
</p>
);
};
export default Post;

View File

@@ -1,6 +1,6 @@
import { useWorkspaceHelper } from '@/hooks/use-workspace-helper'; import { useWorkspaceHelper } from '@/hooks/use-workspace-helper';
import { styled } from '@/styles'; import { styled } from '@affine/component';
import { Empty } from '@/ui/empty'; import { Empty } from '@affine/component';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { PageLoading } from '@/components/loading'; import { PageLoading } from '@/components/loading';

View File

@@ -1,123 +0,0 @@
import { ReactElement } from 'react';
import WorkspaceLayout from '@/components/workspace-layout';
import exampleMarkdown1 from '@/templates/Welcome-to-the-AFFiNE-Alpha.md';
import exampleMarkdown2 from '@/templates/AFFiNE-Docs.md';
import { usePageHelper } from '@/hooks/use-page-helper';
import { useAppState } from '@/providers/app-state-provider';
import { Button } from '@/ui/button';
interface Template {
name: string;
source: string;
}
const TemplateItemContainer = styled('div')(() => {
return {
color: 'blue',
padding: '10px 15px',
borderBottom: '1px solid #eee',
cursor: 'pointer',
'&:hover': {
background: '#eee',
},
};
});
import { styled } from '@/styles';
const TEMPLATES: Template[] = [
{
name: 'Welcome-to-the-AFFiNE-Alpha.md',
source: exampleMarkdown1,
},
{
name: 'AFFiNE-Docs.md',
source: exampleMarkdown2,
},
];
const All = () => {
const { openPage, createPage } = usePageHelper();
const { currentWorkspace } = useAppState();
const _applyTemplate = function (pageId: string, template: Template) {
const page = currentWorkspace?.blocksuiteWorkspace?.getPage(pageId);
const title = template.name;
if (page) {
currentWorkspace?.blocksuiteWorkspace?.setPageMeta(page.id, { title });
if (page && page.root === null) {
setTimeout(async () => {
const editor = document.querySelector('editor-container');
if (editor) {
page.addBlock({ flavour: 'affine:surface' }, null);
const frameId = page.addBlock({ flavour: 'affine:frame' }, pageId);
// TODO blocksuite should offer a method to import markdown from store
await editor.clipboard.importMarkdown(
template.source,
`${frameId}`
);
page.resetHistory();
editor.requestUpdate();
}
}, 300);
}
}
};
const _handleAppleTemplate = async function (template: Template) {
const pageId = await createPage();
if (pageId) {
openPage(pageId);
_applyTemplate(pageId, template);
}
};
const _handleAppleTemplateFromFilePicker = async () => {
if (!window.showOpenFilePicker) {
return;
}
const arrFileHandle = await window.showOpenFilePicker({
types: [
{
accept: {
'image/*': ['.md'],
},
},
],
multiple: false,
});
for (const fileHandle of arrFileHandle) {
const file = await fileHandle.getFile();
const text = await file.text();
_handleAppleTemplate({
name: file.name,
source: text,
});
}
};
return (
<div style={{ padding: '50px' }}>
<div>
<h2>Templates</h2>
{TEMPLATES.map(template => {
return (
<TemplateItemContainer
key={template.name}
onClick={() => _handleAppleTemplate(template)}
>
{template.name}
<Button style={{ marginLeft: '20px' }}> Apply Template</Button>
</TemplateItemContainer>
);
})}
<br />
<h2>Import Markdown</h2>
<Button onClick={() => _handleAppleTemplateFromFilePicker()}>
<a style={{ marginLeft: '20px' }}>Select File To Import Markdown</a>
</Button>
</div>
</div>
);
};
All.getLayout = function getLayout(page: ReactElement) {
return <WorkspaceLayout>{page}</WorkspaceLayout>;
};
export default All;

View File

@@ -1,13 +1,13 @@
import { ReactElement, useEffect, useState } from 'react'; import { ReactElement, useEffect, useState } from 'react';
import { useAppState } from '@/providers/app-state-provider'; import { useAppState } from '@/providers/app-state-provider';
import type { NextPageWithLayout } from '../..//_app'; import type { NextPageWithLayout } from '../..//_app';
import { displayFlex, styled } from '@/styles'; import { displayFlex, styled } from '@affine/component';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { Page as PageStore, Workspace } from '@blocksuite/store'; import { Page as PageStore, Workspace } from '@blocksuite/store';
import { PageLoading } from '@/components/loading'; import { PageLoading } from '@/components/loading';
import { Breadcrumbs } from '@/ui/breadcrumbs'; import { Breadcrumbs } from '@affine/component';
import { IconButton } from '@/ui/button'; import { IconButton } from '@affine/component';
import NextLink from 'next/link'; import NextLink from 'next/link';
import { PaperIcon, SearchIcon } from '@blocksuite/icons'; import { PaperIcon, SearchIcon } from '@blocksuite/icons';
import { WorkspaceUnitAvatar } from '@/components/workspace-avatar'; import { WorkspaceUnitAvatar } from '@/components/workspace-avatar';

View File

@@ -8,7 +8,7 @@ import {
StyledBreadcrumbs, StyledBreadcrumbs,
SearchButton, SearchButton,
} from './[pageId]'; } from './[pageId]';
import { Breadcrumbs } from '@/ui/breadcrumbs'; import { Breadcrumbs } from '@affine/component';
import { WorkspaceUnitAvatar } from '@/components/workspace-avatar'; import { WorkspaceUnitAvatar } from '@/components/workspace-avatar';
import { SearchIcon } from '@blocksuite/icons'; import { SearchIcon } from '@blocksuite/icons';
import { useModal } from '@/providers/GlobalModalProvider'; import { useModal } from '@/providers/GlobalModalProvider';

View File

@@ -1,18 +0,0 @@
import { useEffect } from 'react';
import { getDataCenter } from '@affine/datacenter';
/**
* testing only when development
*/
const Page = () => {
useEffect(() => {
getDataCenter().then(dc => {
// @ts-expect-error global variable
window.dc = dc;
});
}, []);
return <div>Testing only</div>;
};
export default Page;

View File

@@ -15,6 +15,8 @@ import { useRouter } from 'next/router';
import { usePageHelper } from '@/hooks/use-page-helper'; import { usePageHelper } from '@/hooks/use-page-helper';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { EditorContainer } from '@blocksuite/editor'; import { EditorContainer } from '@blocksuite/editor';
import Head from 'next/head';
import { useTranslation } from '@affine/i18n';
const DynamicBlocksuite = dynamic(() => import('@/components/editor'), { const DynamicBlocksuite = dynamic(() => import('@/components/editor'), {
ssr: false, ssr: false,
}); });
@@ -25,8 +27,12 @@ const Page: NextPageWithLayout = () => {
(editor: EditorContainer) => setEditor.current(editor), (editor: EditorContainer) => setEditor.current(editor),
[setEditor] [setEditor]
); );
const { t } = useTranslation();
return ( return (
<> <>
<Head>
<title>{currentPage?.meta?.title || t('Untitled')} - AFFiNE</title>
</Head>
<EditorHeader /> <EditorHeader />
<MobileModal /> <MobileModal />

View File

@@ -5,6 +5,8 @@ import { ReactElement } from 'react';
import WorkspaceLayout from '@/components/workspace-layout'; import WorkspaceLayout from '@/components/workspace-layout';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
import { PageMeta, useAppState } from '@/providers/app-state-provider'; import { PageMeta, useAppState } from '@/providers/app-state-provider';
import Head from 'next/head';
const All = () => { const All = () => {
const { currentWorkspace } = useAppState(); const { currentWorkspace } = useAppState();
const pageList = (currentWorkspace?.blocksuiteWorkspace?.meta.pageMetas || const pageList = (currentWorkspace?.blocksuiteWorkspace?.meta.pageMetas ||
@@ -12,6 +14,9 @@ const All = () => {
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<> <>
<Head>
<title>{t('All pages')} - AFFiNE</title>
</Head>
<PageListHeader icon={<AllPagesIcon />}>{t('All pages')}</PageListHeader> <PageListHeader icon={<AllPagesIcon />}>{t('All pages')}</PageListHeader>
<PageList <PageList
pageList={pageList.filter(p => !p.trash)} pageList={pageList.filter(p => !p.trash)}

View File

@@ -5,13 +5,17 @@ import { ReactElement } from 'react';
import WorkspaceLayout from '@/components/workspace-layout'; import WorkspaceLayout from '@/components/workspace-layout';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
import { useAppState } from '@/providers/app-state-provider'; import { useAppState } from '@/providers/app-state-provider';
import Head from 'next/head';
export const Favorite = () => { export const Favorite = () => {
const { pageList } = useAppState(); const { pageList } = useAppState();
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<> <>
<Head>
<title>{t('Favorites')} - AFFiNE</title>
</Head>
<PageListHeader icon={<FavouritesIcon />}> <PageListHeader icon={<FavouritesIcon />}>
{t('Favourites')} {t('Favorites')}
</PageListHeader> </PageListHeader>
<PageList <PageList
pageList={pageList.filter(p => p.favorite && !p.trash)} pageList={pageList.filter(p => p.favorite && !p.trash)}

View File

@@ -1,8 +1,8 @@
import { styled } from '@/styles'; import { styled } from '@affine/component';
import { ReactElement, ReactNode } from 'react'; import { ReactElement, ReactNode } from 'react';
import WorkspaceLayout from '@/components/workspace-layout'; import WorkspaceLayout from '@/components/workspace-layout';
import { Button } from '@/ui/button'; import { Button } from '@affine/component';
export const FeatureCardDiv = styled('section')({ export const FeatureCardDiv = styled('section')({
width: '800px', width: '800px',

View File

@@ -19,6 +19,7 @@ import WorkspaceLayout from '@/components/workspace-layout';
import { WorkspaceUnit } from '@affine/datacenter'; import { WorkspaceUnit } from '@affine/datacenter';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
import { PageListHeader } from '@/components/header'; import { PageListHeader } from '@/components/header';
import Head from 'next/head';
const useTabMap = () => { const useTabMap = () => {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -79,6 +80,9 @@ const WorkspaceSetting = () => {
useTabMap(); useTabMap();
return ( return (
<> <>
<Head>
<title>{t('Settings')} - AFFiNE</title>
</Head>
<StyledSettingContainer> <StyledSettingContainer>
<PageListHeader icon={<SettingsIcon />}>{t('Settings')}</PageListHeader> <PageListHeader icon={<SettingsIcon />}>{t('Settings')}</PageListHeader>
<StyledSettingSidebar> <StyledSettingSidebar>

View File

@@ -5,11 +5,15 @@ import { ReactElement } from 'react';
import WorkspaceLayout from '@/components/workspace-layout'; import WorkspaceLayout from '@/components/workspace-layout';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
import { useAppState } from '@/providers/app-state-provider'; import { useAppState } from '@/providers/app-state-provider';
import Head from 'next/head';
export const Trash = () => { export const Trash = () => {
const { pageList } = useAppState(); const { pageList } = useAppState();
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<> <>
<Head>
<title>{t('Trash')} - AFFiNE</title>
</Head>
<PageListHeader icon={<TrashIcon />}>{t('Trash')}</PageListHeader> <PageListHeader icon={<TrashIcon />}>{t('Trash')}</PageListHeader>
<PageList <PageList
pageList={pageList.filter(p => p.trash)} pageList={pageList.filter(p => p.trash)}

View File

@@ -1,6 +1,6 @@
import { createContext, useContext, useState, ReactNode } from 'react'; import { createContext, useContext, useState, ReactNode } from 'react';
import type { PropsWithChildren } from 'react'; import type { PropsWithChildren } from 'react';
import { Confirm, ConfirmProps } from '@/ui/confirm'; import { Confirm, ConfirmProps } from '@affine/component';
type ConfirmContextValue = { type ConfirmContextValue = {
confirm: (props: ConfirmProps) => Promise<boolean>; confirm: (props: ConfirmProps) => Promise<boolean>;

View File

@@ -1,9 +1,5 @@
import { createContext, useContext, useEffect, useState } from 'react'; import { createContext, useContext, useEffect, useState } from 'react';
import { import { Global, css } from '@emotion/react';
ThemeProvider as EmotionThemeProvider,
Global,
css,
} from '@emotion/react';
import { import {
ThemeProvider as MuiThemeProvider, ThemeProvider as MuiThemeProvider,
createTheme as MuiCreateTheme, createTheme as MuiCreateTheme,
@@ -14,13 +10,14 @@ import {
ThemeMode, ThemeMode,
ThemeProviderProps, ThemeProviderProps,
ThemeProviderValue, ThemeProviderValue,
} from '@/styles/types'; } from '@affine/component';
import { import {
getLightTheme, getLightTheme,
getDarkTheme, getDarkTheme,
globalThemeVariables, globalThemeVariables,
} from '@/styles/theme'; ThemeProvider as ComponentThemeProvider,
import { SystemThemeHelper, localStorageThemeHelper } from '@/styles/utils'; } from '@affine/component';
import { SystemThemeHelper, localStorageThemeHelper } from '@affine/component';
import useCurrentPageMeta from '@/hooks/use-current-page-meta'; import useCurrentPageMeta from '@/hooks/use-current-page-meta';
export const ThemeContext = createContext<ThemeProviderValue>({ export const ThemeContext = createContext<ThemeProviderValue>({
@@ -106,9 +103,9 @@ export const ThemeProvider = ({
} }
`} `}
/> />
<EmotionThemeProvider theme={themeStyle}> <ComponentThemeProvider theme={themeStyle}>
{children} {children}
</EmotionThemeProvider> </ComponentThemeProvider>
</ThemeContext.Provider> </ThemeContext.Provider>
</MuiThemeProvider> </MuiThemeProvider>
); );

View File

@@ -1,3 +0,0 @@
import emotionStyled from '@emotion/styled';
export { css, keyframes } from '@emotion/react';
export const styled = emotionStyled;

View File

@@ -22,7 +22,7 @@ docker run -it --name affine -d -v [YOUR_PATH]:/app/data -p 3000:3000 ghcr.io/to
### In this release, you can now: ### In this release, you can now:
- Manage your pages from the collapsible **sidebar**, which allows you to add **favourites** and restore deleted files from the **trash** - Manage your pages from the collapsible **sidebar**, which allows you to add **favorites** and restore deleted files from the **trash**
- Search through all your content with the quick search - activate with `Ctrl/⌘ + K` - Search through all your content with the quick search - activate with `Ctrl/⌘ + K`
- A friendly Reminder: - A friendly Reminder:
- In the case of unselected text, `Ctrl/⌘ + K` activates quick search; - In the case of unselected text, `Ctrl/⌘ + K` activates quick search;
@@ -53,7 +53,7 @@ console.log('Hello world');
[] Send a page to trash [] Send a page to trash
[] Favourite a page [] Favorite a page
**Have an enjoyable editing experience !!!** 😃 **Have an enjoyable editing experience !!!** 😃

View File

@@ -1,4 +1,5 @@
{ {
"extends": "../../tsconfig.json",
"compilerOptions": { "compilerOptions": {
"target": "ES2020", "target": "ES2020",
"lib": ["dom", "dom.iterable", "esnext"], "lib": ["dom", "dom.iterable", "esnext"],
@@ -17,7 +18,8 @@
"experimentalDecorators": true, "experimentalDecorators": true,
"baseUrl": ".", "baseUrl": ".",
"paths": { "paths": {
"@/*": ["src/*"] "@/*": ["src/*"],
"@affine/component": ["../component/src/index"]
} }
}, },
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],

View File

@@ -0,0 +1,44 @@
const path = require('node:path');
module.exports = {
stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
staticDirs: ['../../app/public'],
addons: ['@storybook/addon-links', '@storybook/addon-essentials'],
core: {
builder: '@storybook/builder-webpack5',
},
webpackFinal: config => {
const transpile = config.module.rules.find(x =>
x.test.toString().includes('tsx')
).use;
transpile.push({
loader: require.resolve('swc-loader'),
options: {
parseMap: true,
jsc: {
parser: {
syntax: 'typescript',
dynamicImport: true,
tsx: true,
},
target: 'es2022',
transform: {
react: {
runtime: 'automatic',
},
},
},
},
});
config.resolve.alias = {
...config.resolve.alias,
'@': path.resolve(__dirname, '..', 'src'),
'@affine/i18n': path.resolve(__dirname, '..', '..', 'i18n', 'src'),
};
return config;
},
reactOptions: {
fastRefresh: true,
},
};

View File

@@ -0,0 +1,9 @@
export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
};

View File

@@ -0,0 +1,36 @@
{
"name": "@affine/component",
"private": true,
"version": "0.3.1",
"scripts": {
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook"
},
"dependencies": {
"@affine/i18n": "workspace:*",
"@blocksuite/editor": "0.4.0-alpha.2",
"@blocksuite/icons": "^2.0.2",
"@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.5",
"@mui/base": "=5.0.0-alpha.101",
"@mui/icons-material": "=5.10.9",
"@mui/material": "=5.8.6",
"lit": "^2.6.1",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@storybook/addon-actions": "^6.5.16",
"@storybook/addon-essentials": "^6.5.16",
"@storybook/addon-links": "^6.5.16",
"@storybook/builder-webpack5": "^6.5.16",
"@storybook/manager-webpack5": "^6.5.16",
"@storybook/react": "^6.5.16",
"@types/react": "^18.0.27",
"@types/react-dom": "18.0.10",
"swc": "^1.0.11",
"swc-loader": "^0.2.3",
"typescript": "^4.9.5",
"webpack": "^5.75.0"
}
}

View File

@@ -0,0 +1,16 @@
export * from './ui/breadcrumbs';
export * from './ui/button';
export * from './ui/confirm';
export * from './ui/divider';
export * from './ui/empty';
export * from './ui/input';
export * from './ui/layout';
export * from './ui/menu';
export * from './ui/modal';
export * from './ui/popper';
export * from './ui/shared/Container';
export * from './ui/table';
export * from './ui/toast';
export * from './ui/tooltip';
export * from './ui/mui';
export * from './styles';

View File

@@ -0,0 +1,19 @@
import React, { useMemo } from 'react';
import { Meta, Story } from '@storybook/react';
import { Breadcrumbs, getLightTheme, ThemeProvider } from '..';
export default {
title: 'AFFiNE/Breadcrumbs',
component: Breadcrumbs,
} as Meta;
const Template: Story = args => (
<ThemeProvider theme={useMemo(() => getLightTheme('page'), [])}>
<Breadcrumbs {...args} />
</ThemeProvider>
);
export const Primary = Template.bind({});
Primary.args = {
children: [<span>1</span>, <span>2</span>, <span>3</span>],
};

View File

@@ -0,0 +1,20 @@
import React, { useMemo } from 'react';
import { Meta, Story } from '@storybook/react';
import { Button, getLightTheme, ThemeProvider } from '..';
export default {
title: 'AFFiNE/Button',
component: Button,
} as Meta;
const Template: Story = args => (
<ThemeProvider theme={useMemo(() => getLightTheme('page'), [])}>
<Button {...args} />
</ThemeProvider>
);
export const Primary = Template.bind({});
Primary.args = {
type: 'primary',
children: 'This is a button',
};

View File

@@ -60,8 +60,8 @@ export const absoluteCenter = ({
position: 'absolute', position: 'absolute',
left: left ? left : horizontal ? '50%' : 'auto', left: left ? left : horizontal ? '50%' : 'auto',
top: top ? top : vertical ? '50%' : 'auto', top: top ? top : vertical ? '50%' : 'auto',
right: right ? right : horizontal ? 'auto' : 'auto', right: right ? right : 'auto',
bottom: bottom ? bottom : vertical ? 'auto' : 'auto', bottom: bottom ? bottom : 'auto',
transform: `translate(${horizontal ? '-50%' : '0'}, ${ transform: `translate(${horizontal ? '-50%' : '0'}, ${
vertical ? '-50%' : '0' vertical ? '-50%' : '0'
})`, })`,
@@ -92,8 +92,8 @@ export const fixedCenter = ({
position: 'fixed', position: 'fixed',
left: left ? left : horizontal ? '50%' : 'auto', left: left ? left : horizontal ? '50%' : 'auto',
top: top ? top : vertical ? '50%' : 'auto', top: top ? top : vertical ? '50%' : 'auto',
right: right ? right : horizontal ? 'auto' : 'auto', right: right ? right : 'auto',
bottom: bottom ? bottom : vertical ? 'auto' : 'auto', bottom: bottom ? bottom : 'auto',
transform: `translate(${horizontal ? '-50%' : '0'}, ${ transform: `translate(${horizontal ? '-50%' : '0'}, ${
vertical ? '-50%' : '0' vertical ? '-50%' : '0'
})`, })`,

Some files were not shown because too many files have changed in this diff Show More