mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-11 03:48:39 +00:00
Compare commits
49 Commits
v0.8.0-can
...
v0.8.0-can
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
81afecdb0e | ||
|
|
f1cb2fc6d6 | ||
|
|
96b64e1c78 | ||
|
|
4d58f2b4c7 | ||
|
|
ab9452969b | ||
|
|
aea508573b | ||
|
|
068c697be9 | ||
|
|
7a31089c4b | ||
|
|
d50fcaa94e | ||
|
|
7f8dfc17a0 | ||
|
|
fb47a04f55 | ||
|
|
da3dd1e324 | ||
|
|
c3e465d644 | ||
|
|
d8d6620c5f | ||
|
|
9853d0f6ef | ||
|
|
9d723fd487 | ||
|
|
ef7ad4f111 | ||
|
|
c59d1e67ab | ||
|
|
9ab9c0c70d | ||
|
|
f369ca39f7 | ||
|
|
804b8f38b8 | ||
|
|
dd23917e3e | ||
|
|
b604d9b47e | ||
|
|
1e5a4a6849 | ||
|
|
64656c3c98 | ||
|
|
61ba85e1f3 | ||
|
|
61ffc4220c | ||
|
|
866408015e | ||
|
|
651e815b42 | ||
|
|
645a300112 | ||
|
|
e0a3c7f2bc | ||
|
|
3dbefda6ed | ||
|
|
73eddc2386 | ||
|
|
6f9dfcc3c1 | ||
|
|
93d352f3d8 | ||
|
|
7546b080ea | ||
|
|
6988b6f034 | ||
|
|
de2cb1a3bc | ||
|
|
08f01ea1b3 | ||
|
|
0df30e43c6 | ||
|
|
67b33d9b8f | ||
|
|
42dfd0a4bb | ||
|
|
25052220a4 | ||
|
|
48e96cd399 | ||
|
|
ca016f1dd1 | ||
|
|
a4fe7dd119 | ||
|
|
8d2df468ee | ||
|
|
2830cb19fe | ||
|
|
8487b2c4af |
2
.cargo/config.toml
Normal file
2
.cargo/config.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[target.x86_64-pc-windows-msvc]
|
||||
rustflags = ["-C", "target-feature=+crt-static"]
|
||||
22
.github/workflows/build.yml
vendored
22
.github/workflows/build.yml
vendored
@@ -235,28 +235,6 @@ jobs:
|
||||
name: affine
|
||||
fail_ci_if_error: false
|
||||
|
||||
storybook-test:
|
||||
name: Storybook Test
|
||||
runs-on: ubuntu-latest
|
||||
environment: development
|
||||
needs: [build-storybook]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup Node.js
|
||||
uses: ./.github/actions/setup-node
|
||||
with:
|
||||
playwright-install: true
|
||||
electron-install: false
|
||||
- name: Download storybook artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: storybook
|
||||
path: ./apps/storybook/storybook-static
|
||||
- name: Run storybook tests
|
||||
working-directory: ./apps/storybook
|
||||
run: |
|
||||
yarn exec concurrently -k -s first -n "SB,TEST" -c "magenta,blue" "yarn exec serve ./storybook-static -l 6006" "yarn exec wait-on tcp:6006 && yarn test"
|
||||
|
||||
e2e-plugin-test:
|
||||
name: E2E Plugin Test
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
38
.github/workflows/publish-storybook.yml
vendored
Normal file
38
.github/workflows/publish-storybook.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
name: Publish Storybook
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request_target:
|
||||
branches:
|
||||
- master
|
||||
paths-ignore:
|
||||
- README.md
|
||||
- .github/**
|
||||
- '!.github/workflows/publish-storybook.yml'
|
||||
|
||||
jobs:
|
||||
publish-storybook:
|
||||
name: Publish Storybook
|
||||
runs-on: ubuntu-latest
|
||||
environment: development
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.merge_commit_sha }}
|
||||
# This is required to fetch all commits for chromatic
|
||||
fetch-depth: 0
|
||||
- name: Setup Node.js
|
||||
uses: ./.github/actions/setup-node
|
||||
with:
|
||||
electron-install: false
|
||||
- name: Build Plugins
|
||||
run: yarn run build:plugins
|
||||
- name: Publish to Chromatic
|
||||
uses: chromaui/action@v1
|
||||
with:
|
||||
workingDir: apps/storybook
|
||||
buildScriptName: build
|
||||
onlyChanged: true
|
||||
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
||||
12
README.md
12
README.md
@@ -127,7 +127,7 @@ If you have questions, you are welcome to contact us. One of the best places to
|
||||
| [@affine/copilot-plugin](plugins/copilot) | AI Copilot that help you document writing |
|
||||
| [@affine/image-preview-plugin](plugins/image-preview) | Component for previewing an image |
|
||||
|
||||
## Thanks
|
||||
## Upstreams
|
||||
|
||||
We would also like to give thanks to open-source projects that make AFFiNE possible:
|
||||
|
||||
@@ -178,10 +178,18 @@ See [BUILDING.md] for instructions on how to build AFFiNE from source code.
|
||||
We welcome contributions from everyone.
|
||||
See [docs/contributing/tutorial.md](./docs/contributing/tutorial.md) for details.
|
||||
|
||||
## Thanks
|
||||
|
||||
<a href="https://www.chromatic.com/"><img src="https://user-images.githubusercontent.com/321738/84662277-e3db4f80-af1b-11ea-88f5-91d67a5e59f6.png" width="153" height="30" alt="Chromatic" /></a>
|
||||
|
||||
Thanks to [Chromatic](https://www.chromatic.com/) for providing the visual testing platform that helps us review UI changes and catch visual regressions.
|
||||
|
||||
## License
|
||||
|
||||
See [LICENSE] for details.
|
||||
|
||||
[](https://app.fossa.com/projects/git%2Bgithub.com%2Ftoeverything%2FAFFiNE?ref=badge_large)
|
||||
|
||||
[all-contributors-badge]: https://img.shields.io/github/contributors/toeverything/AFFiNE
|
||||
[license]: ./LICENSE
|
||||
[building.md]: ./docs/BUILDING.md
|
||||
@@ -196,5 +204,3 @@ See [LICENSE] for details.
|
||||
[typescript-version-icon]: https://img.shields.io/github/package-json/dependency-version/toeverything/affine/dev/typescript
|
||||
[react-version-icon]: https://img.shields.io/github/package-json/dependency-version/toeverything/AFFiNE/react?filename=apps%2Fcore%2Fpackage.json&color=rgb(97%2C228%2C251)
|
||||
[blocksuite-icon]: https://img.shields.io/github/package-json/dependency-version/toeverything/AFFiNE/@blocksuite/store?color=6880ff&filename=apps%2Fcore%2Fpackage.json&label=blocksuite
|
||||
|
||||
[](https://app.fossa.com/projects/git%2Bgithub.com%2Ftoeverything%2FAFFiNE?ref=badge_large)
|
||||
|
||||
@@ -6,14 +6,21 @@ const require = createRequire(import.meta.url);
|
||||
const packageJson = require('../package.json');
|
||||
|
||||
const editorFlags: BlockSuiteFeatureFlags = {
|
||||
enable_database: true,
|
||||
enable_slash_menu: true,
|
||||
enable_edgeless_toolbar: true,
|
||||
enable_block_hub: true,
|
||||
enable_drag_handle: true,
|
||||
enable_block_hub: true,
|
||||
enable_surface: true,
|
||||
enable_edgeless_toolbar: true,
|
||||
enable_slash_menu: true,
|
||||
enable_database: true,
|
||||
enable_database_filter: false,
|
||||
enable_data_view: false,
|
||||
enable_page_tags: false,
|
||||
enable_toggle_block: false,
|
||||
enable_linked_page: true,
|
||||
enable_bookmark_operation: false,
|
||||
enable_note_index: false,
|
||||
|
||||
enable_attachment_block: true,
|
||||
};
|
||||
|
||||
export function getRuntimeConfig(buildFlags: BuildFlags): RuntimeConfig {
|
||||
|
||||
@@ -2,12 +2,18 @@
|
||||
"name": "@affine/core",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"version": "0.8.0-canary.22",
|
||||
"version": "0.8.0-canary.26",
|
||||
"scripts": {
|
||||
"build": "yarn -T run build-core",
|
||||
"dev": "yarn -T run dev-core",
|
||||
"static-server": "ts-node-esm ./server.mts"
|
||||
},
|
||||
"exports": {
|
||||
"./app": "./src/app.tsx",
|
||||
"./router": "./src/router.ts",
|
||||
"./bootstrap/setup": "./src/bootstrap/setup.ts",
|
||||
"./bootstrap/register-plugins": "./src/bootstrap/register-plugins.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@affine-test/fixtures": "workspace:*",
|
||||
"@affine/component": "workspace:*",
|
||||
@@ -18,27 +24,27 @@
|
||||
"@affine/jotai": "workspace:*",
|
||||
"@affine/templates": "workspace:*",
|
||||
"@affine/workspace": "workspace:*",
|
||||
"@blocksuite/block-std": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/blocks": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/block-std": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/blocks": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/icons": "^2.1.31",
|
||||
"@blocksuite/lit": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/lit": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@dnd-kit/core": "^6.0.8",
|
||||
"@dnd-kit/sortable": "^7.0.2",
|
||||
"@emotion/cache": "^11.11.0",
|
||||
"@emotion/react": "^11.11.1",
|
||||
"@emotion/server": "^11.11.0",
|
||||
"@emotion/styled": "^11.11.0",
|
||||
"@mui/material": "^5.14.4",
|
||||
"@mui/material": "^5.14.5",
|
||||
"@react-hookz/web": "^23.1.0",
|
||||
"@toeverything/components": "^0.0.11",
|
||||
"async-call-rpc": "^6.3.1",
|
||||
"cmdk": "^0.2.0",
|
||||
"css-spring": "^4.1.0",
|
||||
"cssnano": "^6.0.1",
|
||||
"graphql": "^16.7.1",
|
||||
"graphql": "^16.8.0",
|
||||
"intl-segmenter-polyfill-rs": "^0.1.5",
|
||||
"jotai": "^2.3.1",
|
||||
"jotai-devtools": "^0.6.1",
|
||||
@@ -51,21 +57,21 @@
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-is": "18.2.0",
|
||||
"react-resizable-panels": "^0.0.54",
|
||||
"react-resizable-panels": "^0.0.55",
|
||||
"react-router-dom": "^6.15.0",
|
||||
"rxjs": "^7.8.1",
|
||||
"ses": "^0.18.7",
|
||||
"swr": "2.2.1",
|
||||
"y-protocols": "^1.0.5",
|
||||
"yjs": "^13.6.7",
|
||||
"zod": "^3.21.4"
|
||||
"zod": "^3.22.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@perfsee/webpack": "^1.8.4",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.10",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.11",
|
||||
"@sentry/webpack-plugin": "^2.6.2",
|
||||
"@svgr/webpack": "^8.0.1",
|
||||
"@swc/core": "^1.3.76",
|
||||
"@svgr/webpack": "^8.1.0",
|
||||
"@swc/core": "^1.3.77",
|
||||
"@types/lodash.debounce": "^4.0.7",
|
||||
"@types/webpack-env": "^1.18.1",
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
|
||||
@@ -20,8 +20,10 @@ import { getOrCreateWorkspace } from '@affine/workspace/manager';
|
||||
import { createIndexedDBDownloadProvider } from '@affine/workspace/providers';
|
||||
import { nanoid } from '@blocksuite/store';
|
||||
import { useStaticBlockSuiteWorkspace } from '@toeverything/infra/__internal__/react';
|
||||
import { rootStore } from '@toeverything/infra/atom';
|
||||
import { buildShowcaseWorkspace } from '@toeverything/infra/blocksuite';
|
||||
|
||||
import { setPageModeAtom } from '../../atoms';
|
||||
import {
|
||||
BlockSuitePageList,
|
||||
NewWorkspaceSettingDetail,
|
||||
@@ -43,7 +45,12 @@ export const LocalAdapter: WorkspaceAdapter<WorkspaceFlavour.LOCAL> = {
|
||||
);
|
||||
blockSuiteWorkspace.meta.setName(DEFAULT_WORKSPACE_NAME);
|
||||
if (runtimeConfig.enablePreloading) {
|
||||
buildShowcaseWorkspace(blockSuiteWorkspace).catch(err => {
|
||||
buildShowcaseWorkspace(blockSuiteWorkspace, {
|
||||
store: rootStore,
|
||||
atoms: {
|
||||
pageMode: setPageModeAtom,
|
||||
},
|
||||
}).catch(err => {
|
||||
logger.error('init page with preloading failed', err);
|
||||
});
|
||||
} else {
|
||||
|
||||
@@ -36,9 +36,13 @@ const importLogger = new DebugLogger('plugins:import');
|
||||
const pushLayoutAtom = atom<
|
||||
null,
|
||||
// fixme: check plugin name here
|
||||
[pluginName: string, create: (root: HTMLElement) => () => void],
|
||||
[
|
||||
pluginName: string,
|
||||
create: (root: HTMLElement) => () => void,
|
||||
options: { maxWidth: (number | undefined)[] } | undefined,
|
||||
],
|
||||
void
|
||||
>(null, (_, set, pluginName, callback) => {
|
||||
>(null, (_, set, pluginName, callback, options) => {
|
||||
set(pluginWindowAtom, items => ({
|
||||
...items,
|
||||
[pluginName]: callback,
|
||||
@@ -50,20 +54,20 @@ const pushLayoutAtom = atom<
|
||||
first: 'editor',
|
||||
second: pluginName,
|
||||
splitPercentage: 70,
|
||||
maxWidth: options?.maxWidth,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
...layout,
|
||||
direction: 'horizontal',
|
||||
first: 'editor',
|
||||
splitPercentage: 70,
|
||||
second: {
|
||||
direction: 'horizontal',
|
||||
// fixme: incorrect type here
|
||||
first: layout.second,
|
||||
second: pluginName,
|
||||
splitPercentage: 70,
|
||||
first: pluginName,
|
||||
second: layout.second,
|
||||
splitPercentage: 50,
|
||||
},
|
||||
} as ExpectedLayout;
|
||||
} satisfies ExpectedLayout;
|
||||
}
|
||||
});
|
||||
addCleanup(pluginName, () => {
|
||||
@@ -77,40 +81,36 @@ const deleteLayoutAtom = atom<null, [string], void>(null, (_, set, id) => {
|
||||
delete newItems[id];
|
||||
return newItems;
|
||||
});
|
||||
const removeLayout = (layout: LayoutNode): LayoutNode => {
|
||||
if (layout === 'editor') {
|
||||
return 'editor';
|
||||
const removeLayout = (layout: LayoutNode): LayoutNode | string => {
|
||||
if (typeof layout === 'string') {
|
||||
return layout;
|
||||
}
|
||||
if (layout.first === id) {
|
||||
return layout.second;
|
||||
} else if (layout.second === id) {
|
||||
return layout.first;
|
||||
} else {
|
||||
if (typeof layout === 'string') {
|
||||
return layout as ExpectedLayout;
|
||||
}
|
||||
if (layout.first === id) {
|
||||
return layout.second;
|
||||
} else if (layout.second === id) {
|
||||
return layout.first;
|
||||
} else {
|
||||
return removeLayout(layout.second);
|
||||
}
|
||||
return {
|
||||
...layout,
|
||||
second: removeLayout(layout.second),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
set(contentLayoutAtom, layout => {
|
||||
if (layout === 'editor') {
|
||||
return 'editor';
|
||||
} else {
|
||||
if (typeof layout === 'string') {
|
||||
return layout as ExpectedLayout;
|
||||
}
|
||||
if (layout.first === id) {
|
||||
return layout.second as ExpectedLayout;
|
||||
} else if (layout.second === id) {
|
||||
return layout.first as ExpectedLayout;
|
||||
} else {
|
||||
return removeLayout(layout.second) as ExpectedLayout;
|
||||
}
|
||||
return removeLayout(layout) as ExpectedLayout;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// clean up plugin windows when switching to other pages
|
||||
rootStore.sub(currentPageAtom, () => {
|
||||
rootStore.set(contentLayoutAtom, 'editor');
|
||||
});
|
||||
|
||||
// module -> importName -> updater[]
|
||||
export const _rootImportsMap = new Map<string, Map<string, any>>();
|
||||
const rootImportsMapSetupPromise = setupImportsMap(_rootImportsMap, {
|
||||
@@ -123,6 +123,7 @@ const rootImportsMapSetupPromise = setupImportsMap(_rootImportsMap, {
|
||||
swr: import('swr'),
|
||||
'@affine/component': import('@affine/component'),
|
||||
'@blocksuite/icons': import('@blocksuite/icons'),
|
||||
'@blocksuite/blocks': import('@blocksuite/blocks'),
|
||||
'@affine/sdk/entry': {
|
||||
rootStore: rootStore,
|
||||
currentWorkspaceAtom: currentWorkspaceAtom,
|
||||
|
||||
@@ -169,7 +169,14 @@ function createFirstAppData() {
|
||||
rootStore.set(rootWorkspacesMetadataAtom, result);
|
||||
}
|
||||
|
||||
let isSetup = false;
|
||||
|
||||
export async function setup() {
|
||||
if (isSetup) {
|
||||
console.warn('already setup');
|
||||
return;
|
||||
}
|
||||
isSetup = true;
|
||||
rootStore.set(
|
||||
workspaceAdaptersAtom,
|
||||
WorkspaceAdapters as Record<
|
||||
|
||||
@@ -81,11 +81,7 @@ const NameWorkspaceContent = ({
|
||||
onChange={setWorkspaceName}
|
||||
/>
|
||||
<div className={style.buttonGroup}>
|
||||
<Button
|
||||
data-testid="create-workspace-close-button"
|
||||
type="primary"
|
||||
onClick={onClose}
|
||||
>
|
||||
<Button data-testid="create-workspace-close-button" onClick={onClose}>
|
||||
{t.Cancel()}
|
||||
</Button>
|
||||
<Button
|
||||
|
||||
@@ -12,7 +12,6 @@ import type { ReactElement } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
export const StyledListItem = styled(MenuItem)(() => ({
|
||||
width: '132px',
|
||||
height: '38px',
|
||||
textTransform: 'capitalize',
|
||||
}));
|
||||
|
||||
@@ -38,9 +38,8 @@ export const ExportPanel = ({ workspace }: ExportPanelProps) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const onExport = useCallback(async () => {
|
||||
await syncBlobsToSqliteDb(workspace);
|
||||
const result: SaveDBFileResult = await window.apis?.dialog.saveDBFileAs(
|
||||
workspaceId
|
||||
);
|
||||
const result: SaveDBFileResult =
|
||||
await window.apis?.dialog.saveDBFileAs(workspaceId);
|
||||
if (result?.error) {
|
||||
toast(t[result.error]());
|
||||
} else if (!result?.canceled) {
|
||||
|
||||
@@ -3,20 +3,48 @@ import { SettingWrapper } from '@affine/component/setting-components';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
|
||||
import {
|
||||
type ShortcutsInfo,
|
||||
useEdgelessShortcuts,
|
||||
useGeneralShortcuts,
|
||||
useMarkdownShortcuts,
|
||||
usePageShortcuts,
|
||||
} from '../../../../../hooks/affine/use-shortcuts';
|
||||
import { shortcutRow } from './style.css';
|
||||
import { shortcutKey, shortcutKeyContainer, shortcutRow } from './style.css';
|
||||
|
||||
const ShortcutsPanel = ({
|
||||
shortcutsInfo,
|
||||
}: {
|
||||
shortcutsInfo: ShortcutsInfo;
|
||||
}) => {
|
||||
return (
|
||||
<SettingWrapper title={shortcutsInfo.title}>
|
||||
{Object.entries(shortcutsInfo.shortcuts).map(([title, shortcuts]) => {
|
||||
return (
|
||||
<div key={title} className={shortcutRow}>
|
||||
<span>{title}</span>
|
||||
<div className={shortcutKeyContainer}>
|
||||
{shortcuts.map(key => {
|
||||
return (
|
||||
<span className={shortcutKey} key={key}>
|
||||
{key}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</SettingWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export const Shortcuts = () => {
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
const markdownShortcuts = useMarkdownShortcuts();
|
||||
const pageShortcuts = usePageShortcuts();
|
||||
const edgelessShortcuts = useEdgelessShortcuts();
|
||||
const generalShortcuts = useGeneralShortcuts();
|
||||
const markdownShortcutsInfo = useMarkdownShortcuts();
|
||||
const pageShortcutsInfo = usePageShortcuts();
|
||||
const edgelessShortcutsInfo = useEdgelessShortcuts();
|
||||
const generalShortcutsInfo = useGeneralShortcuts();
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -25,46 +53,10 @@ export const Shortcuts = () => {
|
||||
subtitle={t['Check Keyboard Shortcuts quickly']()}
|
||||
data-testid="keyboard-shortcuts-title"
|
||||
/>
|
||||
<SettingWrapper title={t['General']()}>
|
||||
{Object.entries(generalShortcuts).map(([title, shortcuts]) => {
|
||||
return (
|
||||
<div key={title} className={shortcutRow}>
|
||||
<span>{title}</span>
|
||||
<span className="shortcut">{shortcuts}</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</SettingWrapper>
|
||||
<SettingWrapper title={t['Page']()}>
|
||||
{Object.entries(pageShortcuts).map(([title, shortcuts]) => {
|
||||
return (
|
||||
<div key={title} className={shortcutRow}>
|
||||
<span>{title}</span>
|
||||
<span className="shortcut">{shortcuts}</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</SettingWrapper>
|
||||
<SettingWrapper title={t['Edgeless']()}>
|
||||
{Object.entries(edgelessShortcuts).map(([title, shortcuts]) => {
|
||||
return (
|
||||
<div key={title} className={shortcutRow}>
|
||||
<span>{title}</span>
|
||||
<span className="shortcut">{shortcuts}</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</SettingWrapper>
|
||||
<SettingWrapper title={t['Markdown Syntax']()}>
|
||||
{Object.entries(markdownShortcuts).map(([title, shortcuts]) => {
|
||||
return (
|
||||
<div key={title} className={shortcutRow}>
|
||||
<span>{title}</span>
|
||||
<span className="shortcut">{shortcuts}</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</SettingWrapper>
|
||||
<ShortcutsPanel shortcutsInfo={generalShortcutsInfo} />
|
||||
<ShortcutsPanel shortcutsInfo={pageShortcutsInfo} />
|
||||
<ShortcutsPanel shortcutsInfo={edgelessShortcutsInfo} />
|
||||
<ShortcutsPanel shortcutsInfo={markdownShortcutsInfo} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { globalStyle, style } from '@vanilla-extract/css';
|
||||
import { style } from '@vanilla-extract/css';
|
||||
|
||||
export const shortcutRow = style({
|
||||
height: '32px',
|
||||
@@ -14,8 +14,25 @@ export const shortcutRow = style({
|
||||
},
|
||||
});
|
||||
|
||||
globalStyle(`${shortcutRow} .shortcut`, {
|
||||
border: '1px solid var(--affine-border-color)',
|
||||
borderRadius: '8px',
|
||||
padding: '4px 18px',
|
||||
export const shortcutKeyContainer = style({
|
||||
display: 'flex',
|
||||
});
|
||||
export const shortcutKey = style({
|
||||
minWidth: '24px',
|
||||
height: '20px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
padding: '0 6px',
|
||||
border: '1px solid var(--affine-border-color)',
|
||||
borderRadius: '4px',
|
||||
background: 'var(--affine-background-tertiary-color)',
|
||||
boxShadow:
|
||||
'0px 6px 4px 0px rgba(255, 255, 255, 0.24) inset, 0px 0px 0px 0.5px rgba(0, 0, 0, 0.10) inset',
|
||||
fontSize: 'var(--affine-font-xs)',
|
||||
selectors: {
|
||||
'&:not(:last-of-type)': {
|
||||
marginRight: '2px',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import {
|
||||
SettingModal as SettingModalBase,
|
||||
type SettingModalProps as SettingModalBaseProps,
|
||||
WorkspaceDetailSkeleton,
|
||||
} from '@affine/component/setting-components';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { ContactWithUsIcon } from '@blocksuite/icons';
|
||||
import { useCallback } from 'react';
|
||||
import { Suspense, useCallback } from 'react';
|
||||
|
||||
import { AccountSetting } from './account-setting';
|
||||
import {
|
||||
@@ -77,7 +78,9 @@ export const SettingModal = ({
|
||||
<div className="wrapper">
|
||||
<div className="content">
|
||||
{activeTab === 'workspace' && workspaceId ? (
|
||||
<WorkspaceSetting key={workspaceId} workspaceId={workspaceId} />
|
||||
<Suspense fallback={<WorkspaceDetailSkeleton />}>
|
||||
<WorkspaceSetting key={workspaceId} workspaceId={workspaceId} />
|
||||
</Suspense>
|
||||
) : null}
|
||||
{generalSettingList.find(v => v.key === activeTab) ? (
|
||||
<GeneralSetting generalKey={activeTab as GeneralSettingKeys} />
|
||||
|
||||
@@ -28,6 +28,7 @@ globalStyle(`${settingContent} .footer`, {
|
||||
marginTop: '-80px',
|
||||
fontSize: 'var(--affine-font-sm)',
|
||||
display: 'flex',
|
||||
minHeight: '100px',
|
||||
});
|
||||
|
||||
globalStyle(`${settingContent} .footer a`, {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { WorkspaceDetailSkeleton } from '@affine/component/setting-components';
|
||||
import { usePassiveWorkspaceEffect } from '@toeverything/infra/__internal__/react';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { Suspense, useCallback } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { getUIAdapter } from '../../../../adapters/workspace';
|
||||
import { openSettingModalAtom } from '../../../../atoms';
|
||||
@@ -33,12 +32,10 @@ export const WorkspaceSetting = ({ workspaceId }: { workspaceId: string }) => {
|
||||
const onTransformWorkspace = useOnTransformWorkspace();
|
||||
|
||||
return (
|
||||
<Suspense fallback={<WorkspaceDetailSkeleton />}>
|
||||
<NewSettingsDetail
|
||||
onTransformWorkspace={onTransformWorkspace}
|
||||
onDeleteWorkspace={onDeleteWorkspace}
|
||||
currentWorkspaceId={workspaceId}
|
||||
/>
|
||||
</Suspense>
|
||||
<NewSettingsDetail
|
||||
onTransformWorkspace={onTransformWorkspace}
|
||||
onDeleteWorkspace={onDeleteWorkspace}
|
||||
currentWorkspaceId={workspaceId}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { style } from '@vanilla-extract/css';
|
||||
import { type ComplexStyleRule, style } from '@vanilla-extract/css';
|
||||
|
||||
export const headerTitleContainer = style({
|
||||
display: 'flex',
|
||||
@@ -10,11 +10,11 @@ export const headerTitleContainer = style({
|
||||
});
|
||||
|
||||
export const titleEditButton = style({
|
||||
flexGrow: 1,
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
});
|
||||
WebkitAppRegion: 'no-drag',
|
||||
} as ComplexStyleRule);
|
||||
|
||||
export const titleInput = style({
|
||||
position: 'absolute',
|
||||
|
||||
@@ -3,6 +3,8 @@ import type { HTMLAttributes } from 'react';
|
||||
import type React from 'react';
|
||||
import { cloneElement, useState } from 'react';
|
||||
|
||||
import edgelessHover from './animation-data/edgeless-hover.json';
|
||||
import pageHover from './animation-data/page-hover.json';
|
||||
import { StyledSwitchItem } from './style';
|
||||
|
||||
type HoverAnimateControllerProps = {
|
||||
@@ -52,7 +54,7 @@ export const PageSwitchItem = (
|
||||
options={{
|
||||
loop: false,
|
||||
autoplay: false,
|
||||
animationData: require('./animation-data/page-hover.json'),
|
||||
animationData: pageHover,
|
||||
rendererSettings: {
|
||||
preserveAspectRatio: 'xMidYMid slice',
|
||||
},
|
||||
@@ -71,7 +73,7 @@ export const EdgelessSwitchItem = (
|
||||
options={{
|
||||
loop: false,
|
||||
autoplay: false,
|
||||
animationData: require('./animation-data/edgeless-hover.json'),
|
||||
animationData: edgelessHover,
|
||||
rendererSettings: {
|
||||
preserveAspectRatio: 'xMidYMid slice',
|
||||
},
|
||||
|
||||
@@ -17,7 +17,15 @@ import { contentLayoutAtom, rootStore } from '@toeverything/infra/atom';
|
||||
import clsx from 'clsx';
|
||||
import { useAtomValue, useSetAtom } from 'jotai';
|
||||
import type { CSSProperties, ReactElement } from 'react';
|
||||
import { memo, Suspense, useCallback, useMemo } from 'react';
|
||||
import {
|
||||
memo,
|
||||
startTransition,
|
||||
Suspense,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
} from 'react';
|
||||
import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
|
||||
|
||||
import { pageSettingFamily } from '../atoms';
|
||||
@@ -134,25 +142,42 @@ interface PluginContentAdapterProps {
|
||||
|
||||
const PluginContentAdapter = memo<PluginContentAdapterProps>(
|
||||
function PluginContentAdapter({ windowItem, pluginName }) {
|
||||
return (
|
||||
<div
|
||||
className={pluginContainer}
|
||||
ref={useCallback(
|
||||
(ref: HTMLDivElement | null) => {
|
||||
if (ref) {
|
||||
const div = document.createElement('div');
|
||||
const cleanup = windowItem(div);
|
||||
ref.appendChild(div);
|
||||
addCleanup(pluginName, () => {
|
||||
cleanup();
|
||||
ref.removeChild(div);
|
||||
const rootRef = useRef<HTMLDivElement | null>(null);
|
||||
useEffect(() => {
|
||||
const abortController = new AbortController();
|
||||
const root = rootRef.current;
|
||||
if (root) {
|
||||
startTransition(() => {
|
||||
if (abortController.signal.aborted) {
|
||||
return;
|
||||
}
|
||||
const div = document.createElement('div');
|
||||
const cleanup = windowItem(div);
|
||||
root.appendChild(div);
|
||||
if (abortController.signal.aborted) {
|
||||
cleanup();
|
||||
root.removeChild(div);
|
||||
} else {
|
||||
const cl = () => {
|
||||
cleanup();
|
||||
root.removeChild(div);
|
||||
};
|
||||
const dispose = addCleanup(pluginName, cl);
|
||||
abortController.signal.addEventListener('abort', () => {
|
||||
setTimeout(() => {
|
||||
dispose();
|
||||
cl();
|
||||
});
|
||||
}
|
||||
},
|
||||
[pluginName, windowItem]
|
||||
)}
|
||||
/>
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
return () => {
|
||||
abortController.abort();
|
||||
};
|
||||
}
|
||||
return;
|
||||
}, [pluginName, windowItem]);
|
||||
return <div className={pluginContainer} ref={rootRef} />;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -175,13 +200,13 @@ const LayoutPanel = memo(function LayoutPanel(
|
||||
}
|
||||
} else {
|
||||
return (
|
||||
<PanelGroup
|
||||
style={{
|
||||
height: 'calc(100% - 52px)',
|
||||
}}
|
||||
direction={node.direction}
|
||||
>
|
||||
<Panel defaultSize={node.splitPercentage}>
|
||||
<PanelGroup direction={node.direction}>
|
||||
<Panel
|
||||
defaultSize={node.splitPercentage}
|
||||
style={{
|
||||
maxWidth: node.maxWidth?.[0],
|
||||
}}
|
||||
>
|
||||
<Suspense>
|
||||
<LayoutPanel node={node.first} editorProps={props.editorProps} />
|
||||
</Suspense>
|
||||
@@ -191,6 +216,7 @@ const LayoutPanel = memo(function LayoutPanel(
|
||||
defaultSize={100 - node.splitPercentage}
|
||||
style={{
|
||||
overflow: 'scroll',
|
||||
maxWidth: node.maxWidth?.[1],
|
||||
}}
|
||||
>
|
||||
<Suspense>
|
||||
@@ -211,6 +237,18 @@ export const PageDetailEditor = (props: PageDetailEditorProps) => {
|
||||
|
||||
const layout = useAtomValue(contentLayoutAtom);
|
||||
|
||||
if (layout === 'editor') {
|
||||
return (
|
||||
<Suspense>
|
||||
<PanelGroup direction="horizontal">
|
||||
<Panel>
|
||||
<EditorWrapper {...props} />
|
||||
</Panel>
|
||||
</PanelGroup>
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Suspense>
|
||||
|
||||
@@ -8,6 +8,7 @@ export const header = style({
|
||||
padding: '0 16px',
|
||||
minHeight: '52px',
|
||||
borderBottom: '1px solid var(--affine-border-color)',
|
||||
zIndex: 2,
|
||||
selectors: {
|
||||
'&[data-sidebar-floating="false"]': {
|
||||
WebkitAppRegion: 'drag',
|
||||
|
||||
@@ -44,7 +44,7 @@ const OSWarningMessage = () => {
|
||||
return (
|
||||
<span>
|
||||
<Trans i18nKey="recommendBrowser">
|
||||
We recommend the <strong>Chrome</strong> browser for optimal
|
||||
We recommend the <strong>Chrome</strong> browser for an optimal
|
||||
experience.
|
||||
</Trans>
|
||||
</span>
|
||||
|
||||
@@ -60,7 +60,11 @@ export const HelpIsland = ({
|
||||
style={{ height: spread ? `${showList.length * 40 + 4}px` : 0 }}
|
||||
>
|
||||
{showList.includes('whatNew') && (
|
||||
<Tooltip content={t["Discover what's new!"]()} placement="left-end">
|
||||
<Tooltip
|
||||
content={t["Discover what's new!"]()}
|
||||
placement="left-end"
|
||||
showArrow={true}
|
||||
>
|
||||
<StyledIconWrapper
|
||||
data-testid="right-bottom-change-log-icon"
|
||||
onClick={() => {
|
||||
@@ -72,7 +76,11 @@ export const HelpIsland = ({
|
||||
</Tooltip>
|
||||
)}
|
||||
{showList.includes('contact') && (
|
||||
<Tooltip content={t['Contact Us']()} placement="left-end">
|
||||
<Tooltip
|
||||
content={t['Contact Us']()}
|
||||
placement="left-end"
|
||||
showArrow={true}
|
||||
>
|
||||
<StyledIconWrapper
|
||||
data-testid="right-bottom-contact-us-icon"
|
||||
onClick={openAbout}
|
||||
@@ -82,7 +90,11 @@ export const HelpIsland = ({
|
||||
</Tooltip>
|
||||
)}
|
||||
{showList.includes('shortcuts') && (
|
||||
<Tooltip content={t['Keyboard Shortcuts']()} placement="left-end">
|
||||
<Tooltip
|
||||
content={t['Keyboard Shortcuts']()}
|
||||
placement="left-end"
|
||||
showArrow={true}
|
||||
>
|
||||
<StyledIconWrapper
|
||||
data-testid="shortcuts-icon"
|
||||
onClick={() => {
|
||||
@@ -98,6 +110,7 @@ export const HelpIsland = ({
|
||||
<Tooltip
|
||||
content={t['com.affine.helpIsland.gettingStarted']()}
|
||||
placement="left-end"
|
||||
showArrow={true}
|
||||
>
|
||||
<StyledIconWrapper
|
||||
data-testid="easy-guide"
|
||||
@@ -112,7 +125,11 @@ export const HelpIsland = ({
|
||||
)}
|
||||
</StyledAnimateWrapper>
|
||||
|
||||
<Tooltip content={t['Help and Feedback']()} placement="left-end">
|
||||
<Tooltip
|
||||
content={t['Help and Feedback']()}
|
||||
placement={'left-end'}
|
||||
showArrow={true}
|
||||
>
|
||||
<MuiFade in={!spread} data-testid="faq-icon">
|
||||
<StyledTriggerWrapper>
|
||||
<HelpIcon />
|
||||
|
||||
@@ -6,46 +6,80 @@ import {
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
|
||||
import {
|
||||
type ShortcutsInfo,
|
||||
useEdgelessShortcuts,
|
||||
useGeneralShortcuts,
|
||||
useMarkdownShortcuts,
|
||||
usePageShortcuts,
|
||||
} from '../../../hooks/affine/use-shortcuts';
|
||||
import { KeyboardIcon } from './icons';
|
||||
import {
|
||||
StyledListItem,
|
||||
StyledModalHeader,
|
||||
StyledShortcutsModal,
|
||||
StyledSubTitle,
|
||||
StyledTitle,
|
||||
} from './style';
|
||||
import * as styles from './style.css';
|
||||
// import {
|
||||
// StyledListItem,
|
||||
// StyledModalHeader,
|
||||
// StyledShortcutsModal,
|
||||
// StyledSubTitle,
|
||||
// StyledTitle,
|
||||
// } from './style';
|
||||
type ModalProps = {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
const ShortcutsPanel = ({
|
||||
shortcutsInfo,
|
||||
}: {
|
||||
shortcutsInfo: ShortcutsInfo;
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<div className={styles.subtitle}>{shortcutsInfo.title}</div>
|
||||
|
||||
{Object.entries(shortcutsInfo.shortcuts).map(([title, shortcuts]) => {
|
||||
return (
|
||||
<div className={styles.listItem} key={title}>
|
||||
<span>{title}</span>
|
||||
<div className={styles.keyContainer}>
|
||||
{shortcuts.map(key => {
|
||||
return (
|
||||
<span className={styles.key} key={key}>
|
||||
{key}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const ShortcutsModal = ({ open, onClose }: ModalProps) => {
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
const markdownShortcuts = useMarkdownShortcuts();
|
||||
const pageShortcuts = usePageShortcuts();
|
||||
const edgelessShortcuts = useEdgelessShortcuts();
|
||||
const generalShortcuts = useGeneralShortcuts();
|
||||
const markdownShortcutsInfo = useMarkdownShortcuts();
|
||||
const pageShortcutsInfo = usePageShortcuts();
|
||||
const edgelessShortcutsInfo = useEdgelessShortcuts();
|
||||
const generalShortcutsInfo = useGeneralShortcuts();
|
||||
|
||||
return (
|
||||
<MuiSlide direction="left" in={open} mountOnEnter unmountOnExit>
|
||||
<StyledShortcutsModal data-testid="shortcuts-modal">
|
||||
<div className={styles.shortcutsModal} data-testid="shortcuts-modal">
|
||||
<MuiClickAwayListener
|
||||
onClickAway={() => {
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<StyledModalHeader>
|
||||
<StyledTitle>
|
||||
<div
|
||||
className={styles.modalHeader}
|
||||
style={{ marginBottom: '-28px' }}
|
||||
>
|
||||
<div className={styles.title}>
|
||||
<KeyboardIcon />
|
||||
{t['Shortcuts']()}
|
||||
</StyledTitle>
|
||||
</div>
|
||||
|
||||
<ModalCloseButton
|
||||
top={6}
|
||||
@@ -54,48 +88,14 @@ export const ShortcutsModal = ({ open, onClose }: ModalProps) => {
|
||||
onClose();
|
||||
}}
|
||||
/>
|
||||
</StyledModalHeader>
|
||||
<StyledSubTitle style={{ marginTop: 0 }}>
|
||||
{t['General']()}
|
||||
</StyledSubTitle>
|
||||
{Object.entries(generalShortcuts).map(([title, shortcuts]) => {
|
||||
return (
|
||||
<StyledListItem key={title}>
|
||||
<span>{title}</span>
|
||||
<span>{shortcuts}</span>
|
||||
</StyledListItem>
|
||||
);
|
||||
})}
|
||||
<StyledSubTitle>{t['Page']()}</StyledSubTitle>
|
||||
{Object.entries(pageShortcuts).map(([title, shortcuts]) => {
|
||||
return (
|
||||
<StyledListItem key={title}>
|
||||
<span>{title}</span>
|
||||
<span>{shortcuts}</span>
|
||||
</StyledListItem>
|
||||
);
|
||||
})}
|
||||
<StyledSubTitle>{t['Edgeless']()}</StyledSubTitle>
|
||||
{Object.entries(edgelessShortcuts).map(([title, shortcuts]) => {
|
||||
return (
|
||||
<StyledListItem key={title}>
|
||||
<span>{title}</span>
|
||||
<span>{shortcuts}</span>
|
||||
</StyledListItem>
|
||||
);
|
||||
})}
|
||||
<StyledSubTitle>{t['Markdown Syntax']()}</StyledSubTitle>
|
||||
{Object.entries(markdownShortcuts).map(([title, shortcuts]) => {
|
||||
return (
|
||||
<StyledListItem key={title}>
|
||||
<span>{title}</span>
|
||||
<span>{shortcuts}</span>
|
||||
</StyledListItem>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<ShortcutsPanel shortcutsInfo={generalShortcutsInfo} />
|
||||
<ShortcutsPanel shortcutsInfo={pageShortcutsInfo} />
|
||||
<ShortcutsPanel shortcutsInfo={edgelessShortcutsInfo} />
|
||||
<ShortcutsPanel shortcutsInfo={markdownShortcutsInfo} />
|
||||
</div>
|
||||
</MuiClickAwayListener>
|
||||
</StyledShortcutsModal>
|
||||
</div>
|
||||
</MuiSlide>
|
||||
);
|
||||
};
|
||||
|
||||
89
apps/core/src/components/pure/shortcuts-modal/style.css.ts
Normal file
89
apps/core/src/components/pure/shortcuts-modal/style.css.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { globalStyle, style } from '@vanilla-extract/css';
|
||||
|
||||
export const shortcutsModal = style({
|
||||
width: '288px',
|
||||
height: '74vh',
|
||||
paddingBottom: '28px',
|
||||
backgroundColor: 'var(--affine-white)',
|
||||
boxShadow: 'var(--affine-popover-shadow)',
|
||||
borderRadius: `var(--affine-popover-radius)`,
|
||||
overflow: 'auto',
|
||||
position: 'fixed',
|
||||
right: '12px',
|
||||
top: '0',
|
||||
bottom: '0',
|
||||
margin: 'auto',
|
||||
zIndex: 'var(--affine-z-index-modal)',
|
||||
});
|
||||
// export const shortcutsModal = style({
|
||||
// color: 'var(--affine-text-primary-color)',
|
||||
// fontWeight: '500',
|
||||
// fontSize: 'var(--affine-font-sm)',
|
||||
// height: '44px',
|
||||
// display: 'flex',
|
||||
// justifyContent: 'center',
|
||||
// alignItems: 'center',
|
||||
// svg: {
|
||||
// width: '20px',
|
||||
// marginRight: '14px',
|
||||
// color: 'var(--affine-primary-color)',
|
||||
// },
|
||||
// });
|
||||
export const title = style({
|
||||
color: 'var(--affine-text-primary-color)',
|
||||
fontWeight: '500',
|
||||
fontSize: 'var(--affine-font-sm)',
|
||||
height: '44px',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
});
|
||||
|
||||
globalStyle(`${title} svg`, {
|
||||
width: '20px',
|
||||
marginRight: '14px',
|
||||
color: 'var(--affine-primary-color)',
|
||||
});
|
||||
|
||||
export const subtitle = style({
|
||||
fontWeight: '500',
|
||||
fontSize: 'var(--affine-font-sm)',
|
||||
height: '34px',
|
||||
lineHeight: '36px',
|
||||
marginTop: '28px',
|
||||
padding: '0 16px',
|
||||
});
|
||||
export const modalHeader = style({
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
paddingTop: '8px 4px 0 4px',
|
||||
width: '100%',
|
||||
padding: '8px 16px 0 16px',
|
||||
position: 'sticky',
|
||||
left: '0',
|
||||
top: '0',
|
||||
background: 'var(--affine-white)',
|
||||
transition: 'background-color 0.5s',
|
||||
});
|
||||
|
||||
export const listItem = style({
|
||||
height: '34px',
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
fontSize: 'var(--affine-font-sm)',
|
||||
padding: '0 16px',
|
||||
});
|
||||
export const keyContainer = style({
|
||||
display: 'flex',
|
||||
});
|
||||
|
||||
export const key = style({
|
||||
selectors: {
|
||||
'&:not(:last-child)::after': {
|
||||
content: '+',
|
||||
margin: '0 4px',
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1,56 +0,0 @@
|
||||
import { displayFlex, styled } from '@affine/component';
|
||||
|
||||
export const StyledShortcutsModal = styled('div')(() => ({
|
||||
width: '288px',
|
||||
height: '74vh',
|
||||
paddingBottom: '28px',
|
||||
backgroundColor: 'var(--affine-white)',
|
||||
boxShadow: 'var(--affine-popover-shadow)',
|
||||
borderRadius: `var(--affine-popover-radius)`,
|
||||
overflow: 'auto',
|
||||
boxRadius: '10px',
|
||||
position: 'fixed',
|
||||
right: '12px',
|
||||
top: '0',
|
||||
bottom: '0',
|
||||
margin: 'auto',
|
||||
zIndex: 'var(--affine-z-index-modal)',
|
||||
}));
|
||||
export const StyledTitle = styled('div')(() => ({
|
||||
color: 'var(--affine-text-primary-color)',
|
||||
fontWeight: '500',
|
||||
fontSize: 'var(--affine-font-sm)',
|
||||
height: '44px',
|
||||
...displayFlex('center', 'center'),
|
||||
svg: {
|
||||
width: '20px',
|
||||
marginRight: '14px',
|
||||
color: 'var(--affine-primary-color)',
|
||||
},
|
||||
}));
|
||||
export const StyledSubTitle = styled('div')(() => ({
|
||||
fontWeight: '500',
|
||||
fontSize: 'var(--affine-font-sm)',
|
||||
height: '34px',
|
||||
lineHeight: '36px',
|
||||
marginTop: '28px',
|
||||
padding: '0 16px',
|
||||
}));
|
||||
export const StyledModalHeader = styled('div')(() => ({
|
||||
...displayFlex('space-between', 'center'),
|
||||
paddingTop: '8px 4px 0 4px',
|
||||
width: '100%',
|
||||
padding: '8px 16px 0 16px',
|
||||
position: 'sticky',
|
||||
left: '0',
|
||||
top: '0',
|
||||
background: 'var(--affine-white)',
|
||||
transition: 'background-color 0.5s',
|
||||
}));
|
||||
|
||||
export const StyledListItem = styled('div')(() => ({
|
||||
height: '34px',
|
||||
...displayFlex('space-between', 'center'),
|
||||
fontSize: 'var(--affine-font-sm)',
|
||||
padding: '0 16px',
|
||||
}));
|
||||
@@ -8,6 +8,7 @@ export const group = style({
|
||||
display: 'flex',
|
||||
gap: '24px',
|
||||
justifyContent: 'center',
|
||||
zIndex: 2,
|
||||
});
|
||||
export const buttonContainer = style({
|
||||
boxShadow: 'var(--affine-float-button-shadow-2)',
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
import {
|
||||
Menu,
|
||||
MenuItem,
|
||||
Modal,
|
||||
ModalCloseButton,
|
||||
ModalWrapper,
|
||||
Tooltip,
|
||||
} from '@affine/component';
|
||||
import { ScrollableContainer } from '@affine/component';
|
||||
import { Menu, MenuItem, Tooltip } from '@affine/component';
|
||||
import { WorkspaceList } from '@affine/component/workspace-list';
|
||||
import type {
|
||||
AffineCloudWorkspace,
|
||||
@@ -15,28 +7,40 @@ import type {
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { RootWorkspaceMetadata } from '@affine/workspace/atom';
|
||||
import { HelpIcon, ImportIcon, PlusIcon } from '@blocksuite/icons';
|
||||
import type { DragEndEvent } from '@dnd-kit/core';
|
||||
import { useCallback, useRef } from 'react';
|
||||
|
||||
import type { AllWorkspace } from '../../../shared';
|
||||
import { Footer } from '../footer';
|
||||
import {
|
||||
StyledCreateWorkspaceCard,
|
||||
CloudWorkspaceIcon,
|
||||
HelpIcon,
|
||||
ImportIcon,
|
||||
MoreHorizontalIcon,
|
||||
PlusIcon,
|
||||
} from '@blocksuite/icons';
|
||||
import type { DragEndEvent } from '@dnd-kit/core';
|
||||
import { Popover } from '@mui/material';
|
||||
import { IconButton } from '@toeverything/components/button';
|
||||
import { Divider } from '@toeverything/components/divider';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { openDisableCloudAlertModalAtom } from '../../../atoms';
|
||||
import type { AllWorkspace } from '../../../shared';
|
||||
import {
|
||||
StyledCreateWorkspaceCardPill,
|
||||
StyledCreateWorkspaceCardPillContainer,
|
||||
StyledCreateWorkspaceCardPillContent,
|
||||
StyledCreateWorkspaceCardPillIcon,
|
||||
StyledCreateWorkspaceCardPillTextSecondary,
|
||||
StyledHelperContainer,
|
||||
StyledImportWorkspaceCardPill,
|
||||
StyledModalBody,
|
||||
StyledModalContent,
|
||||
StyledModalFooterContent,
|
||||
StyledModalHeader,
|
||||
StyledModalHeaderContent,
|
||||
StyledModalHeaderLeft,
|
||||
StyledModalTitle,
|
||||
StyledOperationWrapper,
|
||||
StyleWorkspaceAdd,
|
||||
StyleWorkspaceInfo,
|
||||
StyleWorkspaceTitle,
|
||||
StyledSignInCardPill,
|
||||
StyledSignInCardPillTextCotainer,
|
||||
StyledSignInCardPillTextPrimary,
|
||||
StyledSignInCardPillTextSecondary,
|
||||
} from './styles';
|
||||
|
||||
interface WorkspaceModalProps {
|
||||
@@ -52,105 +56,94 @@ interface WorkspaceModalProps {
|
||||
onMoveWorkspace: (activeId: string, overId: string) => void;
|
||||
}
|
||||
|
||||
const CreateWorkspaceCard = ({
|
||||
onNewWorkspace,
|
||||
onAddWorkspace,
|
||||
}: {
|
||||
onNewWorkspace: () => void;
|
||||
onAddWorkspace: () => void;
|
||||
}) => {
|
||||
const AccountMenu = () => {
|
||||
const t = useAFFiNEI18N();
|
||||
const anchorEL = useRef<HTMLDivElement>(null);
|
||||
return (
|
||||
<div>
|
||||
<div>Unlimted</div>
|
||||
<Divider></Divider>
|
||||
<MenuItem icon={<ImportIcon />} data-testid="editor-option-menu-import">
|
||||
{t['com.affine.workspace.cloud.join']()}
|
||||
</MenuItem>
|
||||
<MenuItem icon={<ImportIcon />} data-testid="editor-option-menu-import">
|
||||
{t['com.affine.workspace.cloud.account.settings']()}
|
||||
</MenuItem>
|
||||
<Divider></Divider>
|
||||
<MenuItem icon={<ImportIcon />} data-testid="editor-option-menu-import">
|
||||
{t['com.affine.workspace.cloud.account.logout']()}
|
||||
</MenuItem>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
if (runtimeConfig.enableSQLiteProvider && environment.isDesktop) {
|
||||
return (
|
||||
<Menu
|
||||
placement="auto"
|
||||
trigger={['click']}
|
||||
zIndex={1000}
|
||||
content={
|
||||
<StyledCreateWorkspaceCardPillContainer>
|
||||
<StyledCreateWorkspaceCardPill>
|
||||
<MenuItem
|
||||
style={{
|
||||
height: 'auto',
|
||||
padding: '8px 12px',
|
||||
}}
|
||||
onClick={onNewWorkspace}
|
||||
data-testid="new-workspace"
|
||||
>
|
||||
<StyledCreateWorkspaceCardPillContent>
|
||||
<div>
|
||||
<p>{t['New Workspace']()}</p>
|
||||
<StyledCreateWorkspaceCardPillTextSecondary>
|
||||
<p>{t['Create your own workspace']()}</p>
|
||||
</StyledCreateWorkspaceCardPillTextSecondary>
|
||||
</div>
|
||||
<StyledCreateWorkspaceCardPillIcon>
|
||||
<PlusIcon />
|
||||
</StyledCreateWorkspaceCardPillIcon>
|
||||
</StyledCreateWorkspaceCardPillContent>
|
||||
</MenuItem>
|
||||
</StyledCreateWorkspaceCardPill>
|
||||
<StyledCreateWorkspaceCardPill>
|
||||
<MenuItem
|
||||
onClick={onAddWorkspace}
|
||||
data-testid="add-workspace"
|
||||
style={{
|
||||
height: 'auto',
|
||||
padding: '8px 12px',
|
||||
}}
|
||||
>
|
||||
<StyledCreateWorkspaceCardPillContent>
|
||||
<div>
|
||||
<p>{t['Add Workspace']()}</p>
|
||||
<StyledCreateWorkspaceCardPillTextSecondary>
|
||||
<p>{t['Add Workspace Hint']()}</p>
|
||||
</StyledCreateWorkspaceCardPillTextSecondary>
|
||||
</div>
|
||||
<StyledCreateWorkspaceCardPillIcon>
|
||||
<ImportIcon />
|
||||
</StyledCreateWorkspaceCardPillIcon>
|
||||
</StyledCreateWorkspaceCardPillContent>
|
||||
</MenuItem>
|
||||
</StyledCreateWorkspaceCardPill>
|
||||
</StyledCreateWorkspaceCardPillContainer>
|
||||
}
|
||||
>
|
||||
<StyledCreateWorkspaceCard
|
||||
ref={anchorEL}
|
||||
data-testid="add-or-new-workspace"
|
||||
>
|
||||
<StyleWorkspaceAdd className="add-icon">
|
||||
<PlusIcon />
|
||||
</StyleWorkspaceAdd>
|
||||
const CloudWorkSpaceList = ({
|
||||
disabled,
|
||||
workspaces,
|
||||
onClickWorkspace,
|
||||
onClickWorkspaceSetting,
|
||||
currentWorkspaceId,
|
||||
onMoveWorkspace,
|
||||
}: WorkspaceModalProps) => {
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
<StyleWorkspaceInfo>
|
||||
<StyleWorkspaceTitle>{t['New Workspace']()}</StyleWorkspaceTitle>
|
||||
<p>{t['Create Or Import']()}</p>
|
||||
</StyleWorkspaceInfo>
|
||||
</StyledCreateWorkspaceCard>
|
||||
</Menu>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div>
|
||||
<StyledCreateWorkspaceCard
|
||||
onClick={onNewWorkspace}
|
||||
data-testid="new-workspace"
|
||||
>
|
||||
<StyleWorkspaceAdd className="add-icon">
|
||||
<PlusIcon />
|
||||
</StyleWorkspaceAdd>
|
||||
return (
|
||||
<>
|
||||
<StyledModalHeader>
|
||||
<StyledModalHeaderLeft>
|
||||
<StyledModalTitle>
|
||||
{t['com.affine.workspace.cloud.sync']()}
|
||||
</StyledModalTitle>
|
||||
<Tooltip
|
||||
content={t['Workspace description']()}
|
||||
placement="top-start"
|
||||
disablePortal={true}
|
||||
>
|
||||
<StyledHelperContainer>
|
||||
<HelpIcon />
|
||||
</StyledHelperContainer>
|
||||
</Tooltip>
|
||||
</StyledModalHeaderLeft>
|
||||
|
||||
<StyleWorkspaceInfo>
|
||||
<StyleWorkspaceTitle>{t['New Workspace']()}</StyleWorkspaceTitle>
|
||||
<p>{t['Create Or Import']()}</p>
|
||||
</StyleWorkspaceInfo>
|
||||
</StyledCreateWorkspaceCard>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
<StyledOperationWrapper>
|
||||
<Menu
|
||||
placement="bottom-end"
|
||||
trigger={['click']}
|
||||
content={<AccountMenu />}
|
||||
zIndex={1000}
|
||||
>
|
||||
<IconButton
|
||||
data-testid="previous-image-button"
|
||||
icon={<MoreHorizontalIcon />}
|
||||
type="plain"
|
||||
/>
|
||||
</Menu>
|
||||
</StyledOperationWrapper>
|
||||
</StyledModalHeader>
|
||||
<StyledModalContent>
|
||||
<WorkspaceList
|
||||
disabled={disabled}
|
||||
items={
|
||||
workspaces.filter(
|
||||
({ flavour }) => flavour !== WorkspaceFlavour.PUBLIC
|
||||
) as (AffineCloudWorkspace | LocalWorkspace)[]
|
||||
}
|
||||
currentWorkspaceId={currentWorkspaceId}
|
||||
onClick={onClickWorkspace}
|
||||
onSettingClick={onClickWorkspaceSetting}
|
||||
onDragEnd={useCallback(
|
||||
(event: DragEndEvent) => {
|
||||
const { active, over } = event;
|
||||
if (active.id !== over?.id) {
|
||||
onMoveWorkspace(active.id as string, over?.id as string);
|
||||
}
|
||||
},
|
||||
[onMoveWorkspace]
|
||||
)}
|
||||
/>
|
||||
<Divider />
|
||||
</StyledModalContent>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const WorkspaceListModal = ({
|
||||
@@ -166,70 +159,152 @@ export const WorkspaceListModal = ({
|
||||
onMoveWorkspace,
|
||||
}: WorkspaceModalProps) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const setOpen = useSetAtom(openDisableCloudAlertModalAtom);
|
||||
// TODO: AFFiNE Cloud support
|
||||
const isLoggedIn = false;
|
||||
const anchorEl = document.getElementById('current-workspace');
|
||||
|
||||
return (
|
||||
<Modal open={open} onClose={onClose}>
|
||||
<ModalWrapper
|
||||
width={720}
|
||||
height={690}
|
||||
style={{
|
||||
<Popover
|
||||
sx={{
|
||||
color: 'success.main',
|
||||
zIndex: 999,
|
||||
'& .MuiPopover-paper': {
|
||||
borderRadius: '8px',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
<StyledModalHeader>
|
||||
<StyledModalHeaderLeft>
|
||||
<StyledModalTitle>{t['My Workspaces']()}</StyledModalTitle>
|
||||
<Tooltip
|
||||
content={t['Workspace description']()}
|
||||
placement="top-start"
|
||||
disablePortal={true}
|
||||
>
|
||||
<StyledHelperContainer>
|
||||
<HelpIcon />
|
||||
</StyledHelperContainer>
|
||||
</Tooltip>
|
||||
</StyledModalHeaderLeft>
|
||||
|
||||
<StyledOperationWrapper>
|
||||
<ModalCloseButton
|
||||
data-testid="close-workspace-modal"
|
||||
onClick={() => {
|
||||
onClose();
|
||||
}}
|
||||
absolute={false}
|
||||
/>
|
||||
</StyledOperationWrapper>
|
||||
</StyledModalHeader>
|
||||
<ScrollableContainer>
|
||||
<StyledModalContent>
|
||||
<WorkspaceList
|
||||
disabled={disabled}
|
||||
items={
|
||||
workspaces.filter(
|
||||
({ flavour }) => flavour !== WorkspaceFlavour.PUBLIC
|
||||
) as (AffineCloudWorkspace | LocalWorkspace)[]
|
||||
boxShadow: 'var(--affine-shadow-2)',
|
||||
backgroundColor: 'var(--affine-background-overlay-panel-color)',
|
||||
},
|
||||
maxHeight: '90vh',
|
||||
}}
|
||||
open={open}
|
||||
anchorEl={anchorEl}
|
||||
onClose={onClose}
|
||||
>
|
||||
<StyledModalHeaderContent>
|
||||
<StyledSignInCardPill>
|
||||
<MenuItem
|
||||
style={{
|
||||
height: 'auto',
|
||||
padding: '8px 12px',
|
||||
}}
|
||||
onClick={async () => {
|
||||
if (!runtimeConfig.enableCloud) {
|
||||
setOpen(true);
|
||||
}
|
||||
currentWorkspaceId={currentWorkspaceId}
|
||||
onClick={onClickWorkspace}
|
||||
onSettingClick={onClickWorkspaceSetting}
|
||||
onDragEnd={useCallback(
|
||||
(event: DragEndEvent) => {
|
||||
const { active, over } = event;
|
||||
if (active.id !== over?.id) {
|
||||
onMoveWorkspace(active.id as string, over?.id as string);
|
||||
}
|
||||
},
|
||||
[onMoveWorkspace]
|
||||
)}
|
||||
/>
|
||||
<CreateWorkspaceCard
|
||||
onNewWorkspace={onNewWorkspace}
|
||||
onAddWorkspace={onAddWorkspace}
|
||||
/>
|
||||
</StyledModalContent>
|
||||
</ScrollableContainer>
|
||||
<Footer />
|
||||
</ModalWrapper>
|
||||
</Modal>
|
||||
}}
|
||||
data-testid="cloud-signin-button"
|
||||
>
|
||||
<StyledCreateWorkspaceCardPillContent>
|
||||
<StyledCreateWorkspaceCardPillIcon>
|
||||
<CloudWorkspaceIcon />
|
||||
</StyledCreateWorkspaceCardPillIcon>
|
||||
<StyledSignInCardPillTextCotainer>
|
||||
<StyledSignInCardPillTextPrimary>
|
||||
{t['com.affine.workspace.cloud.auth']()}
|
||||
</StyledSignInCardPillTextPrimary>
|
||||
<StyledSignInCardPillTextSecondary>
|
||||
Sync with AFFiNE Cloud
|
||||
</StyledSignInCardPillTextSecondary>
|
||||
</StyledSignInCardPillTextCotainer>
|
||||
</StyledCreateWorkspaceCardPillContent>
|
||||
</MenuItem>
|
||||
</StyledSignInCardPill>
|
||||
<Divider />
|
||||
</StyledModalHeaderContent>
|
||||
<StyledModalBody>
|
||||
{isLoggedIn ? (
|
||||
<CloudWorkSpaceList
|
||||
disabled={disabled}
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
workspaces={workspaces}
|
||||
onClickWorkspace={onClickWorkspace}
|
||||
onClickWorkspaceSetting={onClickWorkspaceSetting}
|
||||
onNewWorkspace={onNewWorkspace}
|
||||
onAddWorkspace={onAddWorkspace}
|
||||
currentWorkspaceId={currentWorkspaceId}
|
||||
onMoveWorkspace={onMoveWorkspace}
|
||||
/>
|
||||
) : null}
|
||||
<StyledModalHeader>
|
||||
<StyledModalTitle>{t['Local Workspace']()}</StyledModalTitle>
|
||||
<Tooltip
|
||||
content={t['Workspace description']()}
|
||||
placement="top-start"
|
||||
disablePortal={true}
|
||||
>
|
||||
<StyledHelperContainer>
|
||||
<HelpIcon />
|
||||
</StyledHelperContainer>
|
||||
</Tooltip>
|
||||
</StyledModalHeader>
|
||||
<StyledModalContent>
|
||||
<WorkspaceList
|
||||
disabled={disabled}
|
||||
items={
|
||||
workspaces.filter(
|
||||
({ flavour }) => flavour !== WorkspaceFlavour.PUBLIC
|
||||
) as (AffineCloudWorkspace | LocalWorkspace)[]
|
||||
}
|
||||
currentWorkspaceId={currentWorkspaceId}
|
||||
onClick={onClickWorkspace}
|
||||
onSettingClick={onClickWorkspaceSetting}
|
||||
onDragEnd={useCallback(
|
||||
(event: DragEndEvent) => {
|
||||
const { active, over } = event;
|
||||
if (active.id !== over?.id) {
|
||||
onMoveWorkspace(active.id as string, over?.id as string);
|
||||
}
|
||||
},
|
||||
[onMoveWorkspace]
|
||||
)}
|
||||
/>
|
||||
</StyledModalContent>
|
||||
{runtimeConfig.enableSQLiteProvider && environment.isDesktop ? (
|
||||
<StyledImportWorkspaceCardPill>
|
||||
<MenuItem
|
||||
onClick={onAddWorkspace}
|
||||
data-testid="add-workspace"
|
||||
style={{
|
||||
height: 'auto',
|
||||
padding: '8px 12px',
|
||||
}}
|
||||
>
|
||||
<StyledCreateWorkspaceCardPillContent>
|
||||
<StyledCreateWorkspaceCardPillIcon>
|
||||
<ImportIcon />
|
||||
</StyledCreateWorkspaceCardPillIcon>
|
||||
<div>
|
||||
<p>{t['com.affine.workspace.local.import']()}</p>
|
||||
</div>
|
||||
</StyledCreateWorkspaceCardPillContent>
|
||||
</MenuItem>
|
||||
</StyledImportWorkspaceCardPill>
|
||||
) : null}
|
||||
</StyledModalBody>
|
||||
<StyledModalFooterContent>
|
||||
<StyledCreateWorkspaceCardPill>
|
||||
<MenuItem
|
||||
style={{
|
||||
height: 'auto',
|
||||
padding: '8px 12px',
|
||||
}}
|
||||
onClick={onNewWorkspace}
|
||||
data-testid="new-workspace"
|
||||
>
|
||||
<StyledCreateWorkspaceCardPillContent>
|
||||
<StyledCreateWorkspaceCardPillIcon>
|
||||
<PlusIcon />
|
||||
</StyledCreateWorkspaceCardPillIcon>
|
||||
<div>
|
||||
<p>{t['New Workspace']()}</p>
|
||||
</div>
|
||||
</StyledCreateWorkspaceCardPillContent>
|
||||
</MenuItem>
|
||||
</StyledCreateWorkspaceCardPill>
|
||||
</StyledModalFooterContent>
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -81,11 +81,29 @@ export const StyledCreateWorkspaceCardPillContainer = styled('div')(() => {
|
||||
});
|
||||
|
||||
export const StyledCreateWorkspaceCardPill = styled('div')(() => {
|
||||
return {
|
||||
borderRadius: '8px',
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
height: '58px',
|
||||
border: `1px solid var(--affine-border-color)`,
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledSignInCardPill = styled('div')(() => {
|
||||
return {
|
||||
borderRadius: '8px',
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
height: '58px',
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledImportWorkspaceCardPill = styled('div')(() => {
|
||||
return {
|
||||
borderRadius: '5px',
|
||||
display: 'flex',
|
||||
boxShadow: '0px 0px 6px 0px rgba(0, 0, 0, 0.1)',
|
||||
background: 'var(--affine-background-primary-color)',
|
||||
width: '100%',
|
||||
};
|
||||
});
|
||||
|
||||
@@ -94,7 +112,6 @@ export const StyledCreateWorkspaceCardPillContent = styled('div')(() => {
|
||||
display: 'flex',
|
||||
gap: '12px',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
};
|
||||
});
|
||||
|
||||
@@ -106,13 +123,30 @@ export const StyledCreateWorkspaceCardPillIcon = styled('div')(() => {
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledCreateWorkspaceCardPillTextSecondary = styled('div')(() => {
|
||||
export const StyledSignInCardPillTextCotainer = styled('div')(() => {
|
||||
return {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledSignInCardPillTextSecondary = styled('div')(() => {
|
||||
return {
|
||||
fontSize: '12px',
|
||||
color: 'var(--affine-text-secondary-color)',
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledSignInCardPillTextPrimary = styled('div')(() => {
|
||||
return {
|
||||
fontSize: 'var(--affine-font-base)',
|
||||
fontWeight: 600,
|
||||
lineHeight: '24px',
|
||||
maxWidth: '200px',
|
||||
...textEllipsis(1),
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledModalHeaderLeft = styled('div')(() => {
|
||||
return { ...displayFlex('flex-start', 'center') };
|
||||
});
|
||||
@@ -120,6 +154,7 @@ export const StyledModalTitle = styled('div')(() => {
|
||||
return {
|
||||
fontWeight: 600,
|
||||
fontSize: 'var(--affine-font-h6)',
|
||||
color: 'var(--affine-text-primary-color)',
|
||||
};
|
||||
});
|
||||
|
||||
@@ -134,11 +169,30 @@ export const StyledHelperContainer = styled('div')(() => {
|
||||
});
|
||||
|
||||
export const StyledModalContent = styled('div')({
|
||||
height: '540px',
|
||||
padding: '8px 40px',
|
||||
...displayFlex('space-between', 'flex-start', 'flex-start'),
|
||||
flexWrap: 'wrap',
|
||||
flexDirection: 'column',
|
||||
width: '100%',
|
||||
});
|
||||
|
||||
export const StyledModalFooterContent = styled('div')({
|
||||
...displayFlex('space-between', 'flex-start', 'flex-start'),
|
||||
flexWrap: 'wrap',
|
||||
flexDirection: 'column',
|
||||
width: '100%',
|
||||
padding: '12px',
|
||||
backgroundColor: 'var(--affine-background-overlay-panel-color)',
|
||||
});
|
||||
|
||||
export const StyledModalHeaderContent = styled('div')({
|
||||
...displayFlex('space-between', 'flex-start', 'flex-start'),
|
||||
flexWrap: 'wrap',
|
||||
flexDirection: 'column',
|
||||
width: '100%',
|
||||
padding: '12px 12px 0px 12px',
|
||||
backgroundColor: 'var(--affine-background-overlay-panel-color)',
|
||||
});
|
||||
|
||||
export const StyledOperationWrapper = styled('div')(() => {
|
||||
return {
|
||||
...displayFlex('flex-end', 'center'),
|
||||
@@ -150,23 +204,34 @@ export const StyleWorkspaceAdd = styled('div')(() => {
|
||||
width: '58px',
|
||||
height: '58px',
|
||||
borderRadius: '100%',
|
||||
background: 'var(--affine-white-80)',
|
||||
background: 'var(--affine-background-overlay-panel-color)',
|
||||
border: '1.5px dashed #f4f5fa',
|
||||
transition: 'background .2s',
|
||||
fontSize: '24px',
|
||||
...displayFlex('center', 'center'),
|
||||
borderColor: 'var(--affine-white)',
|
||||
color: 'var(--affine-primary-color)',
|
||||
color: 'var(--affine-background-overlay-panel-color)',
|
||||
};
|
||||
});
|
||||
export const StyledModalHeader = styled('div')(() => {
|
||||
return {
|
||||
width: '100%',
|
||||
marginTop: '10px',
|
||||
left: 0,
|
||||
top: 0,
|
||||
borderRadius: '24px 24px 0 0',
|
||||
padding: '10px 40px',
|
||||
padding: '12px 14px',
|
||||
...displayFlex('space-between', 'center'),
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledModalBody = styled('div')(() => {
|
||||
return {
|
||||
padding: '0px 12px',
|
||||
display: 'inline-flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-start',
|
||||
gap: '12px',
|
||||
flex: 1,
|
||||
overflowY: 'auto',
|
||||
};
|
||||
});
|
||||
|
||||
@@ -6,7 +6,6 @@ export const StyledSelectorContainer = styled('div')(() => {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
padding: '0 6px',
|
||||
margin: '0 -6px',
|
||||
borderRadius: '8px',
|
||||
color: 'var(--affine-text-primary-color)',
|
||||
':hover': {
|
||||
|
||||
@@ -32,6 +32,7 @@ export const WorkspaceSelector = ({
|
||||
|
||||
// Open dialog when `Enter` or `Space` pressed
|
||||
// TODO-Doma Refactor with `@radix-ui/react-dialog` or other libraries that handle these out of the box and be accessible by default
|
||||
// TODO: Delete this?
|
||||
const handleKeyDown = useCallback(
|
||||
(e: React.KeyboardEvent) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
@@ -50,6 +51,7 @@ export const WorkspaceSelector = ({
|
||||
onClick={onClick}
|
||||
onKeyDown={handleKeyDown}
|
||||
data-testid="current-workspace"
|
||||
id="current-workspace"
|
||||
>
|
||||
<WorkspaceAvatar
|
||||
data-testid="workspace-avatar"
|
||||
|
||||
@@ -211,7 +211,7 @@ const CollectionRenderer = ({
|
||||
}
|
||||
>
|
||||
<div data-testid="collection-options" className={styles.more}>
|
||||
<MoreHorizontalIcon></MoreHorizontalIcon>
|
||||
<MoreHorizontalIcon />
|
||||
</div>
|
||||
</Menu>
|
||||
}
|
||||
@@ -228,8 +228,8 @@ const CollectionRenderer = ({
|
||||
<div>{collection.name}</div>
|
||||
</div>
|
||||
</MenuItem>
|
||||
<Collapsible.Content>
|
||||
<div style={{ marginLeft: 8 }}>
|
||||
<Collapsible.Content className={styles.collapsibleContent}>
|
||||
<div style={{ marginLeft: 20, marginTop: -4 }}>
|
||||
{pagesToRender.map(page => {
|
||||
return (
|
||||
<Page
|
||||
|
||||
@@ -182,20 +182,18 @@ export const Page = ({
|
||||
>
|
||||
{page.title || t['Untitled']()}
|
||||
</MenuItem>
|
||||
<Collapsible.Content>
|
||||
<div style={{ marginLeft: 8 }}>
|
||||
{referencesToRender.map(id => {
|
||||
return (
|
||||
<ReferencePage
|
||||
key={id}
|
||||
workspace={workspace}
|
||||
pageId={id}
|
||||
metaMapping={allPageMeta}
|
||||
parentIds={new Set([pageId])}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<Collapsible.Content className={styles.collapsibleContent}>
|
||||
{referencesToRender.map(id => {
|
||||
return (
|
||||
<ReferencePage
|
||||
key={id}
|
||||
workspace={workspace}
|
||||
pageId={id}
|
||||
metaMapping={allPageMeta}
|
||||
parentIds={new Set([pageId])}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Collapsible.Content>
|
||||
</Collapsible.Root>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { globalStyle, style } from '@vanilla-extract/css';
|
||||
import { globalStyle, keyframes, style } from '@vanilla-extract/css';
|
||||
|
||||
export const wrapper = style({
|
||||
userSelect: 'none',
|
||||
@@ -29,8 +29,9 @@ export const more = style({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: 4,
|
||||
padding: 4,
|
||||
borderRadius: 2,
|
||||
fontSize: 16,
|
||||
color: 'var(--affine-icon-color)',
|
||||
':hover': {
|
||||
backgroundColor: 'var(--affine-hover-color)',
|
||||
},
|
||||
@@ -52,3 +53,34 @@ export const menuDividerStyle = style({
|
||||
height: '1px',
|
||||
background: 'var(--affine-border-color)',
|
||||
});
|
||||
|
||||
const slideDown = keyframes({
|
||||
'0%': {
|
||||
height: '0px',
|
||||
},
|
||||
'100%': {
|
||||
height: 'var(--radix-collapsible-content-height)',
|
||||
},
|
||||
});
|
||||
|
||||
const slideUp = keyframes({
|
||||
'0%': {
|
||||
height: 'var(--radix-collapsible-content-height)',
|
||||
},
|
||||
'100%': {
|
||||
height: '0px',
|
||||
},
|
||||
});
|
||||
|
||||
export const collapsibleContent = style({
|
||||
overflow: 'hidden',
|
||||
marginTop: '4px',
|
||||
selectors: {
|
||||
'&[data-state="open"]': {
|
||||
animation: `${slideDown} 0.2s ease-out`,
|
||||
},
|
||||
'&[data-state="closed"]': {
|
||||
animation: `${slideUp} 0.2s ease-out`,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -29,14 +29,8 @@ export const ReferencePage = ({
|
||||
const icon = setting?.mode === 'edgeless' ? <EdgelessIcon /> : <PageIcon />;
|
||||
const references = useBlockSuitePageReferences(workspace, pageId);
|
||||
const referencesToShow = useMemo(() => {
|
||||
return [
|
||||
...new Set(
|
||||
references.filter(
|
||||
ref => !parentIds.has(ref) && !metaMapping[ref]?.trash
|
||||
)
|
||||
),
|
||||
];
|
||||
}, [references, parentIds, metaMapping]);
|
||||
return [...new Set(references.filter(ref => !metaMapping[ref]?.trash))];
|
||||
}, [references, metaMapping]);
|
||||
const [collapsed, setCollapsed] = useState(true);
|
||||
const collapsible = referencesToShow.length > 0;
|
||||
const nestedItem = parentIds.size > 0;
|
||||
|
||||
@@ -11,11 +11,13 @@ export const label = style({
|
||||
export const favItemWrapper = style({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '4px',
|
||||
selectors: {
|
||||
'&[data-nested="true"]': {
|
||||
marginLeft: '12px',
|
||||
width: 'calc(100% - 12px)',
|
||||
marginLeft: '20px',
|
||||
width: 'calc(100% - 20px)',
|
||||
},
|
||||
'&:not(:first-of-type)': {
|
||||
marginTop: '4px',
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -40,6 +42,7 @@ const slideUp = keyframes({
|
||||
|
||||
export const collapsibleContent = style({
|
||||
overflow: 'hidden',
|
||||
marginTop: '4px',
|
||||
selectors: {
|
||||
'&[data-state="open"]': {
|
||||
animation: `${slideDown} 0.2s ease-out`,
|
||||
@@ -53,5 +56,4 @@ export const collapsibleContent = style({
|
||||
export const collapsibleContentInner = style({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '4px',
|
||||
});
|
||||
|
||||
@@ -51,14 +51,14 @@ export type RootAppSidebarProps = {
|
||||
};
|
||||
|
||||
const RouteMenuLinkItem = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
HTMLButtonElement,
|
||||
{
|
||||
currentPath: string; // todo: pass through useRouter?
|
||||
path: string;
|
||||
icon: ReactElement;
|
||||
children?: ReactElement;
|
||||
isDraggedOver?: boolean;
|
||||
} & React.HTMLAttributes<HTMLDivElement>
|
||||
} & React.HTMLAttributes<HTMLButtonElement>
|
||||
>(({ currentPath, path, icon, children, isDraggedOver, ...props }, ref) => {
|
||||
// Force active style when a page is dragged over
|
||||
const active = isDraggedOver || currentPath === path;
|
||||
@@ -196,6 +196,8 @@ export const RootAppSidebar = ({
|
||||
</CategoryDivider>
|
||||
<CollectionsList workspace={blockSuiteWorkspace} />
|
||||
<CategoryDivider label={t['others']()} />
|
||||
{/* fixme: remove the following spacer */}
|
||||
<div style={{ height: '4px' }} />
|
||||
<RouteMenuLinkItem
|
||||
ref={trashDroppable.setNodeRef}
|
||||
isDraggedOver={trashDroppable.isOver}
|
||||
@@ -211,7 +213,7 @@ export const RootAppSidebar = ({
|
||||
</SidebarScrollableContainer>
|
||||
<SidebarContainer>
|
||||
{isDesktop && <AppUpdaterButton />}
|
||||
<div />
|
||||
<div style={{ height: '4px' }} />
|
||||
<AddPageButton onClick={onClickNewPage} />
|
||||
</SidebarContainer>
|
||||
</AppSidebar>
|
||||
|
||||
@@ -1,20 +1,24 @@
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
interface ShortcutTip {
|
||||
[x: string]: string;
|
||||
interface ShortcutMap {
|
||||
[x: string]: string[];
|
||||
}
|
||||
export interface ShortcutsInfo {
|
||||
title: string;
|
||||
shortcuts: ShortcutMap;
|
||||
}
|
||||
|
||||
export const useWinGeneralKeyboardShortcuts = (): ShortcutTip => {
|
||||
export const useWinGeneralKeyboardShortcuts = (): ShortcutMap => {
|
||||
const t = useAFFiNEI18N();
|
||||
return useMemo(
|
||||
() => ({
|
||||
[t['Cancel']()]: 'ESC',
|
||||
[t['Quick Search']()]: 'Ctrl + K',
|
||||
[t['New Page']()]: 'Ctrl + N',
|
||||
[t['Cancel']()]: ['ESC'],
|
||||
[t['Quick Search']()]: ['Ctrl', 'K'],
|
||||
[t['New Page']()]: ['Ctrl', 'N'],
|
||||
// not implement yet
|
||||
// [t['Append to Daily Note']()]: 'Ctrl + Alt + A',
|
||||
[t['Expand/Collapse Sidebar']()]: 'Ctrl + /',
|
||||
[t['Expand/Collapse Sidebar']()]: ['Ctrl', '/'],
|
||||
// not implement yet
|
||||
// [t['Go Back']()]: 'Ctrl + [',
|
||||
// [t['Go Forward']()]: 'Ctrl + ]',
|
||||
@@ -22,16 +26,16 @@ export const useWinGeneralKeyboardShortcuts = (): ShortcutTip => {
|
||||
[t]
|
||||
);
|
||||
};
|
||||
export const useMacGeneralKeyboardShortcuts = (): ShortcutTip => {
|
||||
export const useMacGeneralKeyboardShortcuts = (): ShortcutMap => {
|
||||
const t = useAFFiNEI18N();
|
||||
return useMemo(
|
||||
() => ({
|
||||
[t['Cancel']()]: 'ESC',
|
||||
[t['Quick Search']()]: '⌘ + K',
|
||||
[t['New Page']()]: '⌘ + N',
|
||||
[t['Cancel']()]: ['ESC'],
|
||||
[t['Quick Search']()]: ['⌘', 'K'],
|
||||
[t['New Page']()]: ['⌘', 'N'],
|
||||
// not implement yet
|
||||
// [t['Append to Daily Note']()]: '⌘ + ⌥ + A',
|
||||
[t['Expand/Collapse Sidebar']()]: '⌘ + /',
|
||||
[t['Expand/Collapse Sidebar']()]: ['⌘', '/'],
|
||||
// not implement yet
|
||||
// [t['Go Back']()]: '⌘ + [',
|
||||
// [t['Go Forward']()]: '⌘ + ]',
|
||||
@@ -40,28 +44,28 @@ export const useMacGeneralKeyboardShortcuts = (): ShortcutTip => {
|
||||
);
|
||||
};
|
||||
|
||||
export const useMacEdgelessKeyboardShortcuts = (): ShortcutTip => {
|
||||
export const useMacEdgelessKeyboardShortcuts = (): ShortcutMap => {
|
||||
const t = useAFFiNEI18N();
|
||||
return useMemo(
|
||||
() => ({
|
||||
[t['Select All']()]: '⌘ + A',
|
||||
[t['Undo']()]: '⌘ + Z',
|
||||
[t['Redo']()]: '⌘ + ⇧ + Z',
|
||||
[t['Zoom in']()]: '⌘ + +',
|
||||
[t['Zoom out']()]: '⌘ + -',
|
||||
[t['Zoom to 100%']()]: '⌘ + 0',
|
||||
[t['Zoom to fit']()]: '⌘ + 1',
|
||||
[t['Select']()]: 'V',
|
||||
[t['Text']()]: 'T',
|
||||
[t['Shape']()]: 'S',
|
||||
[t['Image']()]: 'I',
|
||||
[t['Straight Connector']()]: 'L',
|
||||
[t['Elbowed Connector']()]: 'X',
|
||||
[t['Select All']()]: ['⌘', 'A'],
|
||||
[t['Undo']()]: ['⌘', 'Z'],
|
||||
[t['Redo']()]: ['⌘', '⇧', 'Z'],
|
||||
[t['Zoom in']()]: ['⌘', '+'],
|
||||
[t['Zoom out']()]: ['⌘', '-'],
|
||||
[t['Zoom to 100%']()]: ['⌘', '0'],
|
||||
[t['Zoom to fit']()]: ['⌘', '1'],
|
||||
[t['Select']()]: ['V'],
|
||||
[t['Text']()]: ['T'],
|
||||
[t['Shape']()]: ['S'],
|
||||
[t['Image']()]: ['I'],
|
||||
[t['Straight Connector']()]: ['L'],
|
||||
[t['Elbowed Connector']()]: ['X'],
|
||||
// not implement yet
|
||||
// [t['Curve Connector']()]: 'C',
|
||||
[t['Pen']()]: 'P',
|
||||
[t['Hand']()]: 'H',
|
||||
[t['Note']()]: 'N',
|
||||
[t['Pen']()]: ['P'],
|
||||
[t['Hand']()]: ['H'],
|
||||
[t['Note']()]: ['N'],
|
||||
// not implement yet
|
||||
// [t['Group']()]: '⌘ + G',
|
||||
// [t['Ungroup']()]: '⌘ + ⇧ + G',
|
||||
@@ -69,29 +73,29 @@ export const useMacEdgelessKeyboardShortcuts = (): ShortcutTip => {
|
||||
[t]
|
||||
);
|
||||
};
|
||||
export const useWinEdgelessKeyboardShortcuts = (): ShortcutTip => {
|
||||
export const useWinEdgelessKeyboardShortcuts = (): ShortcutMap => {
|
||||
const t = useAFFiNEI18N();
|
||||
return useMemo(
|
||||
() => ({
|
||||
[t['Select All']()]: 'Ctrl + A',
|
||||
[t['Undo']()]: 'Ctrl + Z',
|
||||
[t['Redo']()]: 'Ctrl + Y/Ctrl + Shift + Z',
|
||||
[t['Zoom in']()]: 'Ctrl + +',
|
||||
[t['Zoom out']()]: 'Ctrl + -',
|
||||
[t['Zoom to 100%']()]: 'Ctrl + 0',
|
||||
[t['Zoom to fit']()]: 'Ctrl + 1',
|
||||
[t['Select']()]: 'V',
|
||||
[t['Text']()]: 'T',
|
||||
[t['Shape']()]: 'S',
|
||||
[t['Image']()]: 'I',
|
||||
[t['Straight Connector']()]: 'L',
|
||||
[t['Elbowed Connector']()]: 'X',
|
||||
[t['Select All']()]: ['Ctrl', 'A'],
|
||||
[t['Undo']()]: ['Ctrl', 'Z'],
|
||||
[t['Redo']()]: ['Ctrl', 'Y/Ctrl', 'Shift', 'Z'],
|
||||
[t['Zoom in']()]: ['Ctrl', '+'],
|
||||
[t['Zoom out']()]: ['Ctrl', '-'],
|
||||
[t['Zoom to 100%']()]: ['Ctrl', '0'],
|
||||
[t['Zoom to fit']()]: ['Ctrl', '1'],
|
||||
[t['Select']()]: ['V'],
|
||||
[t['Text']()]: ['T'],
|
||||
[t['Shape']()]: ['S'],
|
||||
[t['Image']()]: ['I'],
|
||||
[t['Straight Connector']()]: ['L'],
|
||||
[t['Elbowed Connector']()]: ['X'],
|
||||
// not implement yet
|
||||
// [t['Curve Connector']()]: 'C',
|
||||
[t['Pen']()]: 'P',
|
||||
[t['Hand']()]: 'H',
|
||||
[t['Note']()]: 'N',
|
||||
[t['Switch']()]: 'Alt + S',
|
||||
[t['Pen']()]: ['P'],
|
||||
[t['Hand']()]: ['H'],
|
||||
[t['Note']()]: ['N'],
|
||||
[t['Switch']()]: ['Alt ', ''],
|
||||
// not implement yet
|
||||
// [t['Group']()]: 'Ctrl + G',
|
||||
// [t['Ungroup']()]: 'Ctrl + Shift + G',
|
||||
@@ -99,31 +103,31 @@ export const useWinEdgelessKeyboardShortcuts = (): ShortcutTip => {
|
||||
[t]
|
||||
);
|
||||
};
|
||||
export const useMacPageKeyboardShortcuts = (): ShortcutTip => {
|
||||
export const useMacPageKeyboardShortcuts = (): ShortcutMap => {
|
||||
const t = useAFFiNEI18N();
|
||||
return useMemo(
|
||||
() => ({
|
||||
[t['Undo']()]: '⌘+Z',
|
||||
[t['Redo']()]: '⌘+⇧+Z',
|
||||
[t['Bold']()]: '⌘+B',
|
||||
[t['Italic']()]: '⌘+I',
|
||||
[t['Underline']()]: '⌘+U',
|
||||
[t['Strikethrough']()]: '⌘+⇧+S',
|
||||
[t['Inline code']()]: ' ⌘+E',
|
||||
[t['Code block']()]: '⌘+⌥+C',
|
||||
[t['Link']()]: '⌘+K',
|
||||
[t['Quick search']()]: '⌘+K',
|
||||
[t['Body text']()]: '⌘+⌥+0',
|
||||
[t['Heading']({ number: '1' })]: '⌘+⌥+1',
|
||||
[t['Heading']({ number: '2' })]: '⌘+⌥+2',
|
||||
[t['Heading']({ number: '3' })]: '⌘+⌥+3',
|
||||
[t['Heading']({ number: '4' })]: '⌘+⌥+4',
|
||||
[t['Heading']({ number: '5' })]: '⌘+⌥+5',
|
||||
[t['Heading']({ number: '6' })]: '⌘+⌥+6',
|
||||
[t['Increase indent']()]: 'Tab',
|
||||
[t['Reduce indent']()]: '⇧+Tab',
|
||||
[t['Group as Database']()]: '⌘ + G',
|
||||
[t['Switch']()]: '⌥ + S',
|
||||
[t['Undo']()]: ['⌘', 'Z'],
|
||||
[t['Redo']()]: ['⌘', '⇧', 'Z'],
|
||||
[t['Bold']()]: ['⌘', 'B'],
|
||||
[t['Italic']()]: ['⌘', 'I'],
|
||||
[t['Underline']()]: ['⌘', 'U'],
|
||||
[t['Strikethrough']()]: ['⌘', '⇧', 'S'],
|
||||
[t['Inline code']()]: ['⌘', 'E'],
|
||||
[t['Code block']()]: ['⌘', '⌥', 'C'],
|
||||
[t['Link']()]: ['⌘', 'K'],
|
||||
[t['Quick search']()]: ['⌘', 'K'],
|
||||
[t['Body text']()]: ['⌘', '⌥', '0'],
|
||||
[t['Heading']({ number: '1' })]: ['⌘', '⌥', '1'],
|
||||
[t['Heading']({ number: '2' })]: ['⌘', '⌥', '2'],
|
||||
[t['Heading']({ number: '3' })]: ['⌘', '⌥', '3'],
|
||||
[t['Heading']({ number: '4' })]: ['⌘', '⌥', '4'],
|
||||
[t['Heading']({ number: '5' })]: ['⌘', '⌥', '5'],
|
||||
[t['Heading']({ number: '6' })]: ['⌘', '⌥', '6'],
|
||||
[t['Increase indent']()]: ['Tab'],
|
||||
[t['Reduce indent']()]: ['⇧', 'Tab'],
|
||||
[t['Group as Database']()]: ['⌘', 'G'],
|
||||
[t['Switch']()]: ['⌥', 'S'],
|
||||
// not implement yet
|
||||
// [t['Move Up']()]: '⌘ + ⌥ + ↑',
|
||||
// [t['Move Down']()]: '⌘ + ⌥ + ↓',
|
||||
@@ -132,53 +136,53 @@ export const useMacPageKeyboardShortcuts = (): ShortcutTip => {
|
||||
);
|
||||
};
|
||||
|
||||
export const useMacMarkdownShortcuts = (): ShortcutTip => {
|
||||
export const useMacMarkdownShortcuts = (): ShortcutMap => {
|
||||
const t = useAFFiNEI18N();
|
||||
return useMemo(
|
||||
() => ({
|
||||
[t['Bold']()]: '**Text** ',
|
||||
[t['Italic']()]: '*Text* ',
|
||||
[t['Underline']()]: '~Text~ ',
|
||||
[t['Strikethrough']()]: '~~Text~~ ',
|
||||
[t['Divider']()]: '***',
|
||||
[t['Inline code']()]: '`Text` ',
|
||||
[t['Code block']()]: '``` Space',
|
||||
[t['Heading']({ number: '1' })]: '# Text',
|
||||
[t['Heading']({ number: '2' })]: '## Text',
|
||||
[t['Heading']({ number: '3' })]: '### Text',
|
||||
[t['Heading']({ number: '4' })]: '#### Text',
|
||||
[t['Heading']({ number: '5' })]: '##### Text',
|
||||
[t['Heading']({ number: '6' })]: '###### Text',
|
||||
[t['Bold']()]: ['**Text**'],
|
||||
[t['Italic']()]: ['*Text*'],
|
||||
[t['Underline']()]: ['~Text~'],
|
||||
[t['Strikethrough']()]: ['~~Text~~'],
|
||||
[t['Divider']()]: ['***'],
|
||||
[t['Inline code']()]: ['`Text` '],
|
||||
[t['Code block']()]: ['``` Space'],
|
||||
[t['Heading']({ number: '1' })]: ['# Text'],
|
||||
[t['Heading']({ number: '2' })]: ['## Text'],
|
||||
[t['Heading']({ number: '3' })]: ['### Text'],
|
||||
[t['Heading']({ number: '4' })]: ['#### Text'],
|
||||
[t['Heading']({ number: '5' })]: ['##### Text'],
|
||||
[t['Heading']({ number: '6' })]: ['###### Text'],
|
||||
}),
|
||||
[t]
|
||||
);
|
||||
};
|
||||
|
||||
export const useWinPageKeyboardShortcuts = (): ShortcutTip => {
|
||||
export const useWinPageKeyboardShortcuts = (): ShortcutMap => {
|
||||
const t = useAFFiNEI18N();
|
||||
return useMemo(
|
||||
() => ({
|
||||
[t['Undo']()]: 'Ctrl+Z',
|
||||
[t['Redo']()]: 'Ctrl+Y',
|
||||
[t['Bold']()]: 'Ctrl+B',
|
||||
[t['Italic']()]: 'Ctrl+I',
|
||||
[t['Underline']()]: 'Ctrl+U',
|
||||
[t['Strikethrough']()]: 'Ctrl+Shift+S',
|
||||
[t['Inline code']()]: ' Ctrl+E',
|
||||
[t['Code block']()]: 'Ctrl+Alt+C',
|
||||
[t['Link']()]: 'Ctrl+K',
|
||||
[t['Quick search']()]: 'Ctrl+K',
|
||||
[t['Body text']()]: 'Ctrl+Shift+0',
|
||||
[t['Heading']({ number: '1' })]: 'Ctrl+Shift+1',
|
||||
[t['Heading']({ number: '2' })]: 'Ctrl+Shift+2',
|
||||
[t['Heading']({ number: '3' })]: 'Ctrl+Shift+3',
|
||||
[t['Heading']({ number: '4' })]: 'Ctrl+Shift+4',
|
||||
[t['Heading']({ number: '5' })]: 'Ctrl+Shift+5',
|
||||
[t['Heading']({ number: '6' })]: 'Ctrl+Shift+6',
|
||||
[t['Increase indent']()]: 'Tab',
|
||||
[t['Reduce indent']()]: 'Shift+Tab',
|
||||
[t['Group as Database']()]: 'Ctrl + G',
|
||||
['Switch']: 'Alt + S',
|
||||
[t['Undo']()]: ['Ctrl', 'Z'],
|
||||
[t['Redo']()]: ['Ctrl', 'Y'],
|
||||
[t['Bold']()]: ['Ctrl', 'B'],
|
||||
[t['Italic']()]: ['Ctrl', 'I'],
|
||||
[t['Underline']()]: ['Ctrl', 'U'],
|
||||
[t['Strikethrough']()]: ['Ctrl', 'Shift', 'S'],
|
||||
[t['Inline code']()]: [' Ctrl', 'E'],
|
||||
[t['Code block']()]: ['Ctrl', 'Alt', 'C'],
|
||||
[t['Link']()]: ['Ctr', 'K'],
|
||||
[t['Quick search']()]: ['Ctrl', 'K'],
|
||||
[t['Body text']()]: ['Ctrl', 'Shift', '0'],
|
||||
[t['Heading']({ number: '1' })]: ['Ctrl', 'Shift', '1'],
|
||||
[t['Heading']({ number: '2' })]: ['Ctrl', 'Shift', '2'],
|
||||
[t['Heading']({ number: '3' })]: ['Ctrl', 'Shift', '3'],
|
||||
[t['Heading']({ number: '4' })]: ['Ctrl', 'Shift', '4'],
|
||||
[t['Heading']({ number: '5' })]: ['Ctrl', 'Shift', '5'],
|
||||
[t['Heading']({ number: '6' })]: ['Ctrl', 'Shift', '6'],
|
||||
[t['Increase indent']()]: ['Tab'],
|
||||
[t['Reduce indent']()]: ['Shift+Tab'],
|
||||
[t['Group as Database']()]: ['Ctrl + G'],
|
||||
['Switch']: ['Alt + S'],
|
||||
// not implement yet
|
||||
// [t['Move Up']()]: 'Ctrl + Alt + ↑',
|
||||
// [t['Move Down']()]: 'Ctrl + Alt + ↓',
|
||||
@@ -186,54 +190,73 @@ export const useWinPageKeyboardShortcuts = (): ShortcutTip => {
|
||||
[t]
|
||||
);
|
||||
};
|
||||
export const useWinMarkdownShortcuts = (): ShortcutTip => {
|
||||
export const useWinMarkdownShortcuts = (): ShortcutMap => {
|
||||
const t = useAFFiNEI18N();
|
||||
return useMemo(
|
||||
() => ({
|
||||
[t['Bold']()]: '**Text** ',
|
||||
[t['Italic']()]: '*Text* ',
|
||||
[t['Underline']()]: '~Text~ ',
|
||||
[t['Strikethrough']()]: '~~Text~~ ',
|
||||
[t['Divider']()]: '***',
|
||||
[t['Inline code']()]: '`Text` ',
|
||||
[t['Code block']()]: '``` Text',
|
||||
[t['Heading']({ number: '1' })]: '# Text',
|
||||
[t['Heading']({ number: '2' })]: '## Text',
|
||||
[t['Heading']({ number: '3' })]: '### Text',
|
||||
[t['Heading']({ number: '4' })]: '#### Text',
|
||||
[t['Heading']({ number: '5' })]: '##### Text',
|
||||
[t['Heading']({ number: '6' })]: '###### Text',
|
||||
[t['Bold']()]: ['**Text** '],
|
||||
[t['Italic']()]: ['*Text* '],
|
||||
[t['Underline']()]: ['~Text~ '],
|
||||
[t['Strikethrough']()]: ['~~Text~~ '],
|
||||
[t['Divider']()]: ['***'],
|
||||
[t['Inline code']()]: ['`Text` '],
|
||||
[t['Code block']()]: ['``` Text'],
|
||||
[t['Heading']({ number: '1' })]: ['# Text'],
|
||||
[t['Heading']({ number: '2' })]: ['## Text'],
|
||||
[t['Heading']({ number: '3' })]: ['### Text'],
|
||||
[t['Heading']({ number: '4' })]: ['#### Text'],
|
||||
[t['Heading']({ number: '5' })]: ['##### Text'],
|
||||
[t['Heading']({ number: '6' })]: ['###### Text'],
|
||||
}),
|
||||
[t]
|
||||
);
|
||||
};
|
||||
|
||||
export const useMarkdownShortcuts = (): ShortcutTip => {
|
||||
export const useMarkdownShortcuts = (): ShortcutsInfo => {
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
const macMarkdownShortcuts = useMacMarkdownShortcuts();
|
||||
const winMarkdownShortcuts = useWinMarkdownShortcuts();
|
||||
const isMac = environment.isBrowser && environment.isMacOs;
|
||||
return isMac ? macMarkdownShortcuts : winMarkdownShortcuts;
|
||||
return {
|
||||
title: t['Markdown Syntax'](),
|
||||
shortcuts: isMac ? macMarkdownShortcuts : winMarkdownShortcuts,
|
||||
};
|
||||
};
|
||||
|
||||
export const usePageShortcuts = (): ShortcutTip => {
|
||||
export const usePageShortcuts = (): ShortcutsInfo => {
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
const macPageShortcuts = useMacPageKeyboardShortcuts();
|
||||
const winPageShortcuts = useWinPageKeyboardShortcuts();
|
||||
const isMac = environment.isBrowser && environment.isMacOs;
|
||||
return isMac ? macPageShortcuts : winPageShortcuts;
|
||||
return {
|
||||
title: t['Page'](),
|
||||
shortcuts: isMac ? macPageShortcuts : winPageShortcuts,
|
||||
};
|
||||
};
|
||||
|
||||
export const useEdgelessShortcuts = (): ShortcutTip => {
|
||||
export const useEdgelessShortcuts = (): ShortcutsInfo => {
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
const macEdgelessShortcuts = useMacEdgelessKeyboardShortcuts();
|
||||
const winEdgelessShortcuts = useWinEdgelessKeyboardShortcuts();
|
||||
const isMac = environment.isBrowser && environment.isMacOs;
|
||||
|
||||
return isMac ? macEdgelessShortcuts : winEdgelessShortcuts;
|
||||
return {
|
||||
title: t['Edgeless'](),
|
||||
shortcuts: isMac ? macEdgelessShortcuts : winEdgelessShortcuts,
|
||||
};
|
||||
};
|
||||
|
||||
export const useGeneralShortcuts = (): ShortcutTip => {
|
||||
export const useGeneralShortcuts = (): ShortcutsInfo => {
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
const macGeneralShortcuts = useMacGeneralKeyboardShortcuts();
|
||||
const winGeneralShortcuts = useWinGeneralKeyboardShortcuts();
|
||||
const isMac = environment.isBrowser && environment.isMacOs;
|
||||
|
||||
return isMac ? macGeneralShortcuts : winGeneralShortcuts;
|
||||
return {
|
||||
title: t['General'](),
|
||||
shortcuts: isMac ? macGeneralShortcuts : winGeneralShortcuts,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -5,12 +5,14 @@ import { saveWorkspaceToLocalStorage } from '@affine/workspace/local/crud';
|
||||
import { getOrCreateWorkspace } from '@affine/workspace/manager';
|
||||
import { nanoid } from '@blocksuite/store';
|
||||
import { getWorkspace } from '@toeverything/infra/__internal__/workspace';
|
||||
import { rootStore } from '@toeverything/infra/atom';
|
||||
import { buildShowcaseWorkspace } from '@toeverything/infra/blocksuite';
|
||||
import { useAtomValue, useSetAtom } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { LocalAdapter } from '../adapters/local';
|
||||
import { WorkspaceAdapters } from '../adapters/workspace';
|
||||
import { setPageModeAtom } from '../atoms';
|
||||
|
||||
const logger = new DebugLogger('use-workspaces');
|
||||
|
||||
@@ -52,7 +54,12 @@ export function useAppHelper() {
|
||||
id,
|
||||
WorkspaceFlavour.LOCAL
|
||||
);
|
||||
await buildShowcaseWorkspace(blockSuiteWorkspace);
|
||||
await buildShowcaseWorkspace(blockSuiteWorkspace, {
|
||||
store: rootStore,
|
||||
atoms: {
|
||||
pageMode: setPageModeAtom,
|
||||
},
|
||||
});
|
||||
}
|
||||
set(workspaces => [
|
||||
...workspaces,
|
||||
|
||||
@@ -126,6 +126,7 @@ export const AllWorkspaceModals = (): ReactElement => {
|
||||
);
|
||||
const setCurrentPageId = useSetAtom(currentPageIdAtom);
|
||||
const [isPending, startTransition] = useTransition();
|
||||
const [, startCloseTransition] = useTransition();
|
||||
const [, setOpenSettingModalAtom] = useAtom(openSettingModalAtom);
|
||||
|
||||
const handleOpenSettingModal = useCallback(
|
||||
@@ -153,7 +154,9 @@ export const AllWorkspaceModals = (): ReactElement => {
|
||||
isOpenCreateWorkspaceModal === false
|
||||
}
|
||||
onClose={useCallback(() => {
|
||||
setOpenWorkspacesModal(false);
|
||||
startCloseTransition(() => {
|
||||
setOpenWorkspacesModal(false);
|
||||
});
|
||||
}, [setOpenWorkspacesModal])}
|
||||
onMoveWorkspace={useCallback(
|
||||
(activeId, overId) => {
|
||||
@@ -169,10 +172,12 @@ export const AllWorkspaceModals = (): ReactElement => {
|
||||
)}
|
||||
onClickWorkspace={useCallback(
|
||||
workspaceId => {
|
||||
setOpenWorkspacesModal(false);
|
||||
setCurrentWorkspaceId(workspaceId);
|
||||
setCurrentPageId(null);
|
||||
jumpToSubPath(workspaceId, WorkspaceSubPath.ALL);
|
||||
startCloseTransition(() => {
|
||||
setOpenWorkspacesModal(false);
|
||||
setCurrentWorkspaceId(workspaceId);
|
||||
setCurrentPageId(null);
|
||||
jumpToSubPath(workspaceId, WorkspaceSubPath.ALL);
|
||||
});
|
||||
},
|
||||
[
|
||||
jumpToSubPath,
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
import type { RouteObject } from 'react-router-dom';
|
||||
import { createBrowserRouter } from 'react-router-dom';
|
||||
|
||||
export const router = createBrowserRouter(
|
||||
[
|
||||
{
|
||||
path: '/',
|
||||
lazy: () => import('./pages/index'),
|
||||
},
|
||||
{
|
||||
path: '/workspace/:workspaceId',
|
||||
lazy: () => import('./pages/workspace/index'),
|
||||
children: [
|
||||
{
|
||||
path: 'all',
|
||||
lazy: () => import('./pages/workspace/all-page'),
|
||||
},
|
||||
{
|
||||
path: 'trash',
|
||||
lazy: () => import('./pages/workspace/trash-page'),
|
||||
},
|
||||
{
|
||||
path: ':pageId',
|
||||
lazy: () => import('./pages/workspace/detail-page'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/404',
|
||||
lazy: () => import('./pages/404'),
|
||||
},
|
||||
{
|
||||
path: '*',
|
||||
lazy: () => import('./pages/404'),
|
||||
},
|
||||
],
|
||||
export const routes = [
|
||||
{
|
||||
future: {
|
||||
v7_normalizeFormMethod: true,
|
||||
},
|
||||
}
|
||||
);
|
||||
path: '/',
|
||||
lazy: () => import('./pages/index'),
|
||||
},
|
||||
{
|
||||
path: '/workspace/:workspaceId',
|
||||
lazy: () => import('./pages/workspace/index'),
|
||||
children: [
|
||||
{
|
||||
path: 'all',
|
||||
lazy: () => import('./pages/workspace/all-page'),
|
||||
},
|
||||
{
|
||||
path: 'trash',
|
||||
lazy: () => import('./pages/workspace/trash-page'),
|
||||
},
|
||||
{
|
||||
path: ':pageId',
|
||||
lazy: () => import('./pages/workspace/detail-page'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/404',
|
||||
lazy: () => import('./pages/404'),
|
||||
},
|
||||
{
|
||||
path: '*',
|
||||
lazy: () => import('./pages/404'),
|
||||
},
|
||||
] satisfies [RouteObject, ...RouteObject[]];
|
||||
|
||||
export const router = createBrowserRouter(routes, {
|
||||
future: {
|
||||
v7_normalizeFormMethod: true,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"typeRoots": ["../../node_modules", "../../node_modules/@types"],
|
||||
"types": ["webpack-env", "ses", "affine__env"]
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx"],
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.json"],
|
||||
"exclude": ["node_modules"],
|
||||
"references": [
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@affine/docs",
|
||||
"version": "0.8.0-canary.22",
|
||||
"version": "0.8.0-canary.26",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
@@ -10,12 +10,12 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@affine/component": "workspace:*",
|
||||
"@blocksuite/block-std": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/blocks": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/lit": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/block-std": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/blocks": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/lit": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"express": "^4.18.2",
|
||||
"jotai": "^2.3.1",
|
||||
"react": "18.3.0-canary-7118f5dd7-20230705",
|
||||
@@ -28,7 +28,7 @@
|
||||
"@types/react-dom": "^18.2.7",
|
||||
"@vanilla-extract/css": "^1.12.0",
|
||||
"@vanilla-extract/vite-plugin": "^3.8.2",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"autoprefixer": "^10.4.15",
|
||||
"tailwindcss": "^3.3.3",
|
||||
"typescript": "^5.1.6"
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ test('affine cloud disabled', async ({ page }) => {
|
||||
});
|
||||
await page.waitForSelector('v-line');
|
||||
await page.getByTestId('current-workspace').click();
|
||||
await page.getByTestId('sign-in-button').click();
|
||||
await page.getByTestId('cloud-signin-button').click();
|
||||
await page.getByTestId('disable-affine-cloud-modal').waitFor({
|
||||
state: 'visible',
|
||||
});
|
||||
@@ -153,13 +153,23 @@ test('windows only check', async ({ page }) => {
|
||||
|
||||
test('delete workspace', async ({ page }) => {
|
||||
await page.getByTestId('current-workspace').click();
|
||||
await page.getByTestId('add-or-new-workspace').click();
|
||||
await page.getByTestId('new-workspace').click();
|
||||
await page.getByTestId('create-workspace-default-location-button').click();
|
||||
await page.getByTestId('create-workspace-input').type('Delete Me');
|
||||
await page.getByTestId('create-workspace-create-button').click();
|
||||
await page.getByTestId('create-workspace-continue-button').click();
|
||||
await page.getByTestId('slider-bar-workspace-setting-button').click();
|
||||
await page.getByTestId('create-workspace-default-location-button').click({
|
||||
delay: 100,
|
||||
});
|
||||
await page.getByTestId('create-workspace-input').type('Delete Me', {
|
||||
delay: 100,
|
||||
});
|
||||
await page.getByTestId('create-workspace-create-button').click({
|
||||
delay: 100,
|
||||
});
|
||||
await page.getByTestId('create-workspace-continue-button').click({
|
||||
delay: 100,
|
||||
});
|
||||
await page.waitForTimeout(1000);
|
||||
await page.getByTestId('current-workspace').click();
|
||||
await page.getByTestId('workspace-card').nth(1).hover();
|
||||
await page.getByTestId('workspace-card-setting-button').nth(1).click();
|
||||
await page.getByTestId('current-workspace-label').click();
|
||||
expect(await page.getByTestId('workspace-name-input').inputValue()).toBe(
|
||||
'Delete Me'
|
||||
|
||||
@@ -130,6 +130,7 @@ module.exports = {
|
||||
: undefined,
|
||||
// We need the following line for updater
|
||||
extraResource: ['./resources/app-update.yml'],
|
||||
ignore: ['e2e', 'tests'],
|
||||
},
|
||||
makers,
|
||||
hooks: {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@affine/electron",
|
||||
"private": true,
|
||||
"version": "0.8.0-canary.22",
|
||||
"version": "0.8.0-canary.26",
|
||||
"author": "affine",
|
||||
"repository": {
|
||||
"url": "https://github.com/toeverything/AFFiNE",
|
||||
@@ -28,10 +28,10 @@
|
||||
"@affine/env": "workspace:*",
|
||||
"@affine/native": "workspace:*",
|
||||
"@affine/sdk": "workspace:*",
|
||||
"@blocksuite/blocks": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/lit": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/blocks": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/lit": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@electron-forge/cli": "^6.3.0",
|
||||
"@electron-forge/core": "^6.3.0",
|
||||
"@electron-forge/core-utils": "^6.3.0",
|
||||
@@ -44,11 +44,11 @@
|
||||
"@types/fs-extra": "^11.0.1",
|
||||
"@types/uuid": "^9.0.2",
|
||||
"cross-env": "7.0.3",
|
||||
"electron": "^25.5.0",
|
||||
"electron": "^26.0.0",
|
||||
"electron-log": "^5.0.0-beta.25",
|
||||
"electron-squirrel-startup": "1.0.0",
|
||||
"electron-window-state": "^5.0.3",
|
||||
"esbuild": "^0.18.20",
|
||||
"esbuild": "^0.19.2",
|
||||
"fs-extra": "^11.1.1",
|
||||
"jotai": "^2.3.1",
|
||||
"ts-node": "^10.9.1",
|
||||
@@ -62,7 +62,7 @@
|
||||
"@toeverything/infra": "workspace:*",
|
||||
"async-call-rpc": "^6.3.1",
|
||||
"electron-updater": "^6.1.4",
|
||||
"link-preview-js": "^3.0.4",
|
||||
"link-preview-js": "^3.0.5",
|
||||
"lodash-es": "^4.17.21",
|
||||
"nanoid": "^4.0.2",
|
||||
"rxjs": "^7.8.1",
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
/* eslint-disable no-async-promise-executor */
|
||||
import { spawn } from 'node:child_process';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
import electronPath from 'electron';
|
||||
import * as esbuild from 'esbuild';
|
||||
|
||||
import { config, electronDir } from './common.mjs';
|
||||
import { config } from './common.mjs';
|
||||
|
||||
// this means we don't spawn electron windows, mainly for testing
|
||||
const watchMode = process.argv.includes('--watch');
|
||||
@@ -19,20 +17,6 @@ const stderrFilterPatterns = [
|
||||
/ExtensionLoadWarning/,
|
||||
];
|
||||
|
||||
// these are set before calling `config`, so we have a chance to override them
|
||||
try {
|
||||
const devJson = readFileSync(
|
||||
path.resolve(electronDir, './dev.json'),
|
||||
'utf-8'
|
||||
);
|
||||
const devEnv = JSON.parse(devJson);
|
||||
Object.assign(process.env, devEnv);
|
||||
} catch (err) {
|
||||
console.warn(
|
||||
`Could not read dev.json. Some functions may not work as expected.`
|
||||
);
|
||||
}
|
||||
|
||||
/** @type {ChildProcessWithoutNullStreams | null} */
|
||||
let spawnProcess = null;
|
||||
|
||||
|
||||
@@ -91,7 +91,8 @@ test('db should be removed in db$Map after destroyed', async () => {
|
||||
expect(db$Map.has(workspaceId)).toBe(false);
|
||||
});
|
||||
|
||||
test('if db has a secondary db path, we should also poll that', async () => {
|
||||
// we have removed secondary db feature
|
||||
test.skip('if db has a secondary db path, we should also poll that', async () => {
|
||||
const { ensureSQLiteDB } = await import('../ensure-db');
|
||||
const { storeWorkspaceMeta } = await import('../../workspace');
|
||||
const workspaceId = v4();
|
||||
|
||||
@@ -44,10 +44,10 @@ export abstract class BaseSQLiteAdapter {
|
||||
try {
|
||||
if (!this.db) {
|
||||
logger.warn(`${this.path} is not connected`);
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
const blob = await this.db.getBlob(key);
|
||||
return blob?.data;
|
||||
return blob?.data ?? null;
|
||||
} catch (error) {
|
||||
logger.error('getBlob', error);
|
||||
return null;
|
||||
|
||||
@@ -128,7 +128,7 @@ export class WorkspaceSQLiteDB extends BaseSQLiteAdapter {
|
||||
if (doc) {
|
||||
return encodeStateAsUpdate(doc);
|
||||
}
|
||||
return null;
|
||||
return false;
|
||||
};
|
||||
|
||||
// non-blocking and use yDoc to validate the update
|
||||
|
||||
@@ -1,12 +1,24 @@
|
||||
import type {
|
||||
DBHandlers,
|
||||
DialogHandlers,
|
||||
WorkspaceHandlers,
|
||||
} from '@toeverything/infra/type';
|
||||
|
||||
import { dbEvents, dbHandlers } from './db';
|
||||
import { dialogHandlers } from './dialog';
|
||||
import { workspaceEvents, workspaceHandlers } from './workspace';
|
||||
|
||||
type AllHandlers = {
|
||||
db: DBHandlers;
|
||||
workspace: WorkspaceHandlers;
|
||||
dialog: DialogHandlers;
|
||||
};
|
||||
|
||||
export const handlers = {
|
||||
db: dbHandlers,
|
||||
workspace: workspaceHandlers,
|
||||
dialog: dialogHandlers,
|
||||
};
|
||||
} satisfies AllHandlers;
|
||||
|
||||
export const events = {
|
||||
db: dbEvents,
|
||||
|
||||
@@ -34,7 +34,7 @@ async function createWindow() {
|
||||
: isWindows()
|
||||
? 'hidden'
|
||||
: 'default',
|
||||
trafficLightPosition: { x: 24, y: 18 },
|
||||
trafficLightPosition: { x: 20, y: 18 },
|
||||
x: mainWindowState.x,
|
||||
y: mainWindowState.y,
|
||||
width: mainWindowState.width,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@affine/prototype",
|
||||
"private": true,
|
||||
"version": "0.8.0-canary.22",
|
||||
"version": "0.8.0-canary.26",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --host --port 3003",
|
||||
@@ -18,13 +18,13 @@
|
||||
"@affine/jotai": "workspace:*",
|
||||
"@affine/templates": "workspace:*",
|
||||
"@affine/workspace": "workspace:*",
|
||||
"@blocksuite/block-std": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/blocks": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/block-std": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/blocks": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/icons": "^2.1.31",
|
||||
"@blocksuite/lit": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/lit": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@toeverything/hooks": "workspace:*",
|
||||
"@toeverything/y-indexeddb": "workspace:*",
|
||||
"react": "^18.2.0",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@affine/server",
|
||||
"private": true,
|
||||
"version": "0.8.0-canary.22",
|
||||
"version": "0.8.0-canary.26",
|
||||
"description": "Affine Node.js server",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
@@ -18,7 +18,7 @@
|
||||
"dependencies": {
|
||||
"@apollo/server": "^4.9.1",
|
||||
"@auth/prisma-adapter": "^1.0.1",
|
||||
"@aws-sdk/client-s3": "^3.388.0",
|
||||
"@aws-sdk/client-s3": "^3.391.0",
|
||||
"@nestjs/apollo": "^12.0.7",
|
||||
"@nestjs/common": "^10.1.3",
|
||||
"@nestjs/core": "^10.1.3",
|
||||
@@ -31,11 +31,11 @@
|
||||
"cookie-parser": "^1.4.6",
|
||||
"dotenv": "^16.3.1",
|
||||
"express": "^4.18.2",
|
||||
"graphql": "^16.7.1",
|
||||
"graphql": "^16.8.0",
|
||||
"graphql-type-json": "^0.3.2",
|
||||
"graphql-upload": "^16.0.2",
|
||||
"lodash-es": "^4.17.21",
|
||||
"next-auth": "4.22.1",
|
||||
"next-auth": "4.22.5",
|
||||
"nodemailer": "^6.9.4",
|
||||
"parse-duration": "^1.1.0",
|
||||
"prisma": "^5.1.1",
|
||||
@@ -50,7 +50,7 @@
|
||||
"@types/cookie-parser": "^1.4.3",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/lodash-es": "^4.17.8",
|
||||
"@types/node": "^18.17.4",
|
||||
"@types/node": "^18.17.5",
|
||||
"@types/nodemailer": "^6.4.9",
|
||||
"@types/supertest": "^2.0.12",
|
||||
"c8": "^8.0.1",
|
||||
|
||||
@@ -5,6 +5,7 @@ import { mergeConfig } from 'vite';
|
||||
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||
import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin';
|
||||
import { getRuntimeConfig } from '../../core/.webpack/runtime-config';
|
||||
import turbosnap from 'vite-plugin-turbosnap';
|
||||
|
||||
runCli(
|
||||
{
|
||||
@@ -28,11 +29,12 @@ export default {
|
||||
'@storybook/addon-interactions',
|
||||
'@storybook/addon-storysource',
|
||||
'storybook-dark-mode',
|
||||
'storybook-addon-react-router-v6',
|
||||
],
|
||||
framework: {
|
||||
name: '@storybook/react-vite',
|
||||
},
|
||||
async viteFinal(config, _) {
|
||||
async viteFinal(config, { configType }) {
|
||||
return mergeConfig(config, {
|
||||
assetsInclude: ['**/*.md'],
|
||||
plugins: [
|
||||
@@ -40,6 +42,11 @@ export default {
|
||||
tsconfigPaths({
|
||||
root: fileURLToPath(new URL('../../../', import.meta.url)),
|
||||
}),
|
||||
configType === 'PRODUCTION'
|
||||
? turbosnap({
|
||||
rootDir: fileURLToPath(new URL('../../../', import.meta.url)),
|
||||
})
|
||||
: null,
|
||||
],
|
||||
define: {
|
||||
'process.env': {},
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
import 'ses';
|
||||
import '@affine/component/theme/global.css';
|
||||
import '@affine/component/theme/theme.css';
|
||||
import { LOCALES, createI18n } from '@affine/i18n';
|
||||
import '@toeverything/components/style.css';
|
||||
import { createI18n } from '@affine/i18n';
|
||||
import { ThemeProvider, useTheme } from 'next-themes';
|
||||
import { setupGlobal } from '@affine/env/global';
|
||||
import type { ComponentType } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import { useDarkMode } from 'storybook-dark-mode';
|
||||
import { setup } from '@affine/core/bootstrap/setup';
|
||||
import { AffineContext } from '@affine/component/context';
|
||||
import { use } from 'foxact/use';
|
||||
import useSWR from 'swr';
|
||||
import type { Decorator } from '@storybook/react';
|
||||
|
||||
setupGlobal();
|
||||
const setupPromise = setup();
|
||||
|
||||
export const parameters = {
|
||||
backgrounds: { disable: true },
|
||||
@@ -20,51 +24,42 @@ export const parameters = {
|
||||
},
|
||||
};
|
||||
|
||||
export const globalTypes = {
|
||||
locale: {
|
||||
name: 'Locale',
|
||||
description: 'Internationalization locale',
|
||||
defaultValue: 'en',
|
||||
toolbar: {
|
||||
icon: 'globe',
|
||||
items: LOCALES.map(locale => ({
|
||||
title: locale.originalName,
|
||||
value: locale.tag,
|
||||
right: locale.flagEmoji,
|
||||
})),
|
||||
const i18n = createI18n();
|
||||
const withI18n: Decorator = (Story, context) => {
|
||||
const locale = context.globals.locale;
|
||||
useSWR(
|
||||
locale,
|
||||
async () => {
|
||||
await i18n.changeLanguage(locale);
|
||||
},
|
||||
},
|
||||
{
|
||||
suspense: true,
|
||||
}
|
||||
);
|
||||
return <Story {...context} />;
|
||||
};
|
||||
|
||||
const createI18nDecorator = () => {
|
||||
const i18n = createI18n();
|
||||
const withI18n = (Story: any, context: any) => {
|
||||
const locale = context.globals.locale;
|
||||
useEffect(() => {
|
||||
i18n.changeLanguage(locale);
|
||||
}, [locale]);
|
||||
return <Story {...context} />;
|
||||
};
|
||||
return withI18n;
|
||||
};
|
||||
|
||||
const Component = () => {
|
||||
const ThemeChange = () => {
|
||||
const isDark = useDarkMode();
|
||||
const theme = useTheme();
|
||||
useEffect(() => {
|
||||
theme.setTheme(isDark ? 'dark' : 'light');
|
||||
}, [isDark]);
|
||||
if (theme.resolvedTheme === 'dark' && !isDark) {
|
||||
theme.setTheme('light');
|
||||
} else if (theme.resolvedTheme === 'light' && isDark) {
|
||||
theme.setTheme('dark');
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const decorators = [
|
||||
(Story: ComponentType) => {
|
||||
return (
|
||||
<ThemeProvider>
|
||||
<Component />
|
||||
<Story />
|
||||
</ThemeProvider>
|
||||
);
|
||||
},
|
||||
createI18nDecorator(),
|
||||
];
|
||||
const withContextDecorator: Decorator = (Story, context) => {
|
||||
use(setupPromise);
|
||||
return (
|
||||
<ThemeProvider>
|
||||
<AffineContext>
|
||||
<ThemeChange />
|
||||
<Story {...context} />
|
||||
</AffineContext>
|
||||
</ThemeProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export const decorators = [withContextDecorator, withI18n];
|
||||
|
||||
1
apps/storybook/README.md
Normal file
1
apps/storybook/README.md
Normal file
@@ -0,0 +1 @@
|
||||
# Storybook
|
||||
@@ -3,42 +3,46 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "storybook dev -p 6006",
|
||||
"build": "NODE_OPTIONS=--max_old_space_size=4096 storybook build",
|
||||
"build": "storybook build",
|
||||
"test": "test-storybook"
|
||||
},
|
||||
"dependencies": {
|
||||
"@affine/component": "workspace:*",
|
||||
"@affine/i18n": "workspace:*",
|
||||
"@storybook/addon-actions": "^7.2.3",
|
||||
"@storybook/addon-essentials": "^7.2.3",
|
||||
"@storybook/addon-interactions": "^7.2.3",
|
||||
"@storybook/addon-links": "^7.2.3",
|
||||
"@storybook/addon-storysource": "^7.2.3",
|
||||
"@storybook/blocks": "^7.2.3",
|
||||
"@storybook/builder-vite": "^7.2.3",
|
||||
"@storybook/addon-actions": "^7.3.1",
|
||||
"@storybook/addon-essentials": "^7.3.1",
|
||||
"@storybook/addon-interactions": "^7.3.1",
|
||||
"@storybook/addon-links": "^7.3.1",
|
||||
"@storybook/addon-storysource": "^7.3.1",
|
||||
"@storybook/blocks": "^7.3.1",
|
||||
"@storybook/builder-vite": "^7.3.1",
|
||||
"@storybook/jest": "^0.1.0",
|
||||
"@storybook/react": "^7.2.3",
|
||||
"@storybook/react-vite": "^7.2.3",
|
||||
"@storybook/react": "^7.3.1",
|
||||
"@storybook/react-vite": "^7.3.1",
|
||||
"@storybook/test-runner": "^0.13.0",
|
||||
"@storybook/testing-library": "^0.2.0",
|
||||
"@vitejs/plugin-react": "^4.0.4",
|
||||
"concurrently": "^8.2.0",
|
||||
"jest-mock": "^29.6.2",
|
||||
"serve": "^14.2.0",
|
||||
"storybook": "^7.2.3",
|
||||
"ses": "^0.18.7",
|
||||
"storybook": "^7.3.1",
|
||||
"storybook-dark-mode": "^3.0.1",
|
||||
"wait-on": "^7.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@blocksuite/block-std": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/blocks": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/block-std": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/blocks": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/icons": "^2.1.31",
|
||||
"@blocksuite/lit": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/lit": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"chromatic": "^6.22.0",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0"
|
||||
"react-dom": "18.2.0",
|
||||
"storybook-addon-react-router-v6": "^2.0.4",
|
||||
"vite-plugin-turbosnap": "^1.0.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@blocksuite/blocks": "*",
|
||||
@@ -48,5 +52,5 @@
|
||||
"@blocksuite/lit": "*",
|
||||
"@blocksuite/store": "*"
|
||||
},
|
||||
"version": "0.8.0-canary.22"
|
||||
"version": "0.8.0-canary.26"
|
||||
}
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
/* deepscan-disable USELESS_ARROW_FUNC_BIND */
|
||||
import { BlockHubWrapper } from '@affine/component/block-hub';
|
||||
import type { EditorProps } from '@affine/component/block-suite-editor';
|
||||
import { BlockSuiteEditor } from '@affine/component/block-suite-editor';
|
||||
import { rootBlockHubAtom } from '@affine/workspace/atom';
|
||||
import { __unstableSchemas, AffineSchemas } from '@blocksuite/blocks/models';
|
||||
import type { EditorContainer } from '@blocksuite/editor';
|
||||
import type { Page } from '@blocksuite/store';
|
||||
import { createMemoryStorage, Schema, Workspace } from '@blocksuite/store';
|
||||
import { expect } from '@storybook/jest';
|
||||
import type { Meta, StoryFn } from '@storybook/react';
|
||||
import { use } from 'foxact/use';
|
||||
|
||||
const schema = new Schema();
|
||||
|
||||
schema.register(AffineSchemas).register(__unstableSchemas);
|
||||
|
||||
const blockSuiteWorkspace = new Workspace({
|
||||
id: 'test',
|
||||
blobStorages: [createMemoryStorage],
|
||||
schema,
|
||||
});
|
||||
|
||||
async function initPage(page: Page) {
|
||||
await page.waitForLoaded();
|
||||
// Add page block and surface block at root level
|
||||
const pageBlockId = page.addBlock('affine:page', {
|
||||
title: new page.Text('Hello, world!'),
|
||||
});
|
||||
page.addBlock('affine:surface', {}, pageBlockId);
|
||||
const frameId = page.addBlock('affine:note', {}, pageBlockId);
|
||||
page.addBlock(
|
||||
'affine:paragraph',
|
||||
{
|
||||
text: new page.Text('This is a paragraph.'),
|
||||
},
|
||||
frameId
|
||||
);
|
||||
page.resetHistory();
|
||||
}
|
||||
|
||||
const page = blockSuiteWorkspace.createPage('page0');
|
||||
|
||||
type BlockSuiteMeta = Meta<typeof BlockSuiteEditor>;
|
||||
export default {
|
||||
title: 'BlockSuite/Editor',
|
||||
component: BlockSuiteEditor,
|
||||
} satisfies BlockSuiteMeta;
|
||||
|
||||
const Template: StoryFn<EditorProps> = (props: Partial<EditorProps>) => {
|
||||
if (!page.loaded) {
|
||||
use(initPage(page));
|
||||
}
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
height: '100vh',
|
||||
width: '100vw',
|
||||
overflow: 'auto',
|
||||
}}
|
||||
>
|
||||
<BlockSuiteEditor onInit={initPage} page={page} mode="page" {...props} />
|
||||
<BlockHubWrapper
|
||||
style={{
|
||||
position: 'absolute',
|
||||
right: 12,
|
||||
bottom: 12,
|
||||
}}
|
||||
blockHubAtom={rootBlockHubAtom}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Empty = Template.bind({});
|
||||
Empty.play = async ({ canvasElement }) => {
|
||||
await new Promise<void>(resolve => {
|
||||
setTimeout(() => resolve(), 500);
|
||||
});
|
||||
const editorContainer = canvasElement.querySelector(
|
||||
'[data-testid="editor-page0"]'
|
||||
) as HTMLDivElement;
|
||||
expect(editorContainer).not.toBeNull();
|
||||
const editor = editorContainer.querySelector(
|
||||
'editor-container'
|
||||
) as EditorContainer;
|
||||
expect(editor).not.toBeNull();
|
||||
};
|
||||
|
||||
Empty.args = {
|
||||
mode: 'page',
|
||||
};
|
||||
@@ -7,6 +7,9 @@ import { within } from '@storybook/testing-library';
|
||||
export default {
|
||||
title: 'AFFiNE/Breadcrumbs',
|
||||
component: Breadcrumbs,
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} as Meta<typeof Breadcrumbs>;
|
||||
|
||||
const Template: StoryFn = args => <Breadcrumbs {...args} />;
|
||||
|
||||
@@ -9,11 +9,15 @@ import {
|
||||
HelpIcon,
|
||||
PageIcon,
|
||||
} from '@blocksuite/icons';
|
||||
import type { Meta } from '@storybook/react';
|
||||
|
||||
export default {
|
||||
title: 'AFFiNE/Card',
|
||||
component: WorkspaceCard,
|
||||
};
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} satisfies Meta;
|
||||
|
||||
const blockSuiteWorkspace = getOrCreateWorkspace(
|
||||
'blocksuite-local',
|
||||
|
||||
110
apps/storybook/src/stories/core.stories.tsx
Normal file
110
apps/storybook/src/stories/core.stories.tsx
Normal file
@@ -0,0 +1,110 @@
|
||||
import { pluginRegisterPromise } from '@affine/core/bootstrap/register-plugins';
|
||||
import { routes } from '@affine/core/router';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import type { Decorator, StoryFn } from '@storybook/react';
|
||||
import { userEvent, waitFor } from '@storybook/testing-library';
|
||||
import { use } from 'foxact/use';
|
||||
import { Outlet, useLocation } from 'react-router-dom';
|
||||
import {
|
||||
reactRouterOutlets,
|
||||
reactRouterParameters,
|
||||
withRouter,
|
||||
} from 'storybook-addon-react-router-v6';
|
||||
|
||||
const withCleanLocalStorage: Decorator = (Story, context) => {
|
||||
localStorage.clear();
|
||||
return <Story {...context} />;
|
||||
};
|
||||
|
||||
const FakeApp = () => {
|
||||
const location = useLocation();
|
||||
// fixme: `key` is a hack to force the storybook to re-render the outlet
|
||||
return <Outlet key={location.pathname} />;
|
||||
};
|
||||
|
||||
export default {
|
||||
title: 'Preview/Core',
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: false },
|
||||
},
|
||||
};
|
||||
|
||||
export const Index: StoryFn = () => {
|
||||
use(pluginRegisterPromise);
|
||||
return <FakeApp />;
|
||||
};
|
||||
Index.decorators = [withRouter, withCleanLocalStorage];
|
||||
Index.parameters = {
|
||||
reactRouter: reactRouterParameters({
|
||||
routing: reactRouterOutlets(routes),
|
||||
}),
|
||||
};
|
||||
|
||||
export const SettingPage: StoryFn = () => {
|
||||
return <FakeApp />;
|
||||
};
|
||||
SettingPage.play = async ({ canvasElement }) => {
|
||||
await waitFor(
|
||||
() => {
|
||||
assertExists(
|
||||
canvasElement.querySelector('[data-testid="settings-modal-trigger"]')
|
||||
);
|
||||
},
|
||||
{
|
||||
timeout: 5000,
|
||||
}
|
||||
);
|
||||
const settingModalBtn = canvasElement.querySelector(
|
||||
'[data-testid="settings-modal-trigger"]'
|
||||
) as Element;
|
||||
await userEvent.click(settingModalBtn);
|
||||
};
|
||||
SettingPage.decorators = [withRouter, withCleanLocalStorage];
|
||||
SettingPage.parameters = {
|
||||
reactRouter: reactRouterParameters({
|
||||
routing: reactRouterOutlets(routes),
|
||||
}),
|
||||
};
|
||||
|
||||
export const NotFoundPage: StoryFn = () => {
|
||||
return <FakeApp />;
|
||||
};
|
||||
NotFoundPage.decorators = [withRouter, withCleanLocalStorage];
|
||||
NotFoundPage.parameters = {
|
||||
reactRouter: reactRouterParameters({
|
||||
routing: reactRouterOutlets(routes),
|
||||
location: {
|
||||
path: '/404',
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
export const WorkspaceList: StoryFn = () => {
|
||||
return <FakeApp />;
|
||||
};
|
||||
WorkspaceList.play = async ({ canvasElement }) => {
|
||||
// click current-workspace
|
||||
await waitFor(
|
||||
() => {
|
||||
assertExists(
|
||||
canvasElement.querySelector('[data-testid="current-workspace"]')
|
||||
);
|
||||
},
|
||||
{
|
||||
timeout: 5000,
|
||||
}
|
||||
);
|
||||
const currentWorkspace = canvasElement.querySelector(
|
||||
'[data-testid="current-workspace"]'
|
||||
) as Element;
|
||||
await userEvent.click(currentWorkspace);
|
||||
};
|
||||
WorkspaceList.decorators = [withRouter, withCleanLocalStorage];
|
||||
WorkspaceList.parameters = {
|
||||
reactRouter: reactRouterParameters({
|
||||
routing: reactRouterOutlets(routes),
|
||||
location: {
|
||||
path: '/',
|
||||
},
|
||||
}),
|
||||
};
|
||||
@@ -1,11 +1,14 @@
|
||||
import { AFFiNEDatePicker } from '@affine/component/date-picker';
|
||||
import type { StoryFn } from '@storybook/react';
|
||||
import type { Meta, StoryFn } from '@storybook/react';
|
||||
import { useState } from 'react';
|
||||
|
||||
export default {
|
||||
title: 'AFFiNE/AFFiNEDatePicker',
|
||||
component: AFFiNEDatePicker,
|
||||
};
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} satisfies Meta;
|
||||
|
||||
export const Default: StoryFn = () => {
|
||||
const [value, setValue] = useState<string>(new Date().toString());
|
||||
|
||||
@@ -2,11 +2,15 @@
|
||||
import { toast } from '@affine/component';
|
||||
import { ImportPage } from '@affine/component/import-page';
|
||||
import type { StoryFn } from '@storybook/react';
|
||||
import type { Meta } from '@storybook/react';
|
||||
|
||||
export default {
|
||||
title: 'AFFiNE/ImportPage',
|
||||
component: ImportPage,
|
||||
};
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} satisfies Meta;
|
||||
|
||||
const Template: StoryFn<typeof ImportPage> = args => <ImportPage {...args} />;
|
||||
|
||||
|
||||
@@ -9,6 +9,9 @@ import { useAtomValue, useSetAtom } from 'jotai';
|
||||
export default {
|
||||
title: 'AFFiNE/NotificationCenter',
|
||||
component: NotificationCenter,
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} satisfies Meta<typeof NotificationCenter>;
|
||||
|
||||
let id = 0;
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
/* deepscan-disable USELESS_ARROW_FUNC_BIND */
|
||||
import { TourModal } from '@affine/component/tour-modal';
|
||||
import type { StoryFn } from '@storybook/react';
|
||||
import type { Meta, StoryFn } from '@storybook/react';
|
||||
|
||||
export default {
|
||||
title: 'AFFiNE/TourModal',
|
||||
component: TourModal,
|
||||
};
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} satisfies Meta;
|
||||
|
||||
export const Basic: StoryFn = () => {
|
||||
return <TourModal open={true} onClose={() => {}} />;
|
||||
|
||||
@@ -4,6 +4,9 @@ import type { Meta } from '@storybook/react';
|
||||
export default {
|
||||
title: 'AFFiNE/PageDetailSkeleton',
|
||||
component: PageDetailSkeleton,
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} satisfies Meta<typeof PageDetailSkeleton>;
|
||||
|
||||
export const Basic = () => {
|
||||
|
||||
@@ -7,13 +7,16 @@ import { NewPageButton } from '@affine/component/page-list';
|
||||
import { OperationCell } from '@affine/component/page-list';
|
||||
import { PageIcon } from '@blocksuite/icons';
|
||||
import { expect } from '@storybook/jest';
|
||||
import type { StoryFn } from '@storybook/react';
|
||||
import type { Meta, StoryFn } from '@storybook/react';
|
||||
import { userEvent } from '@storybook/testing-library';
|
||||
|
||||
export default {
|
||||
title: 'AFFiNE/PageList',
|
||||
component: PageList,
|
||||
};
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} satisfies Meta;
|
||||
|
||||
export const AffineOperationCell: StoryFn<OperationCellProps> = ({
|
||||
...props
|
||||
@@ -34,7 +37,7 @@ AffineOperationCell.play = async ({ canvasElement }) => {
|
||||
'[data-testid="page-list-operation-button"]'
|
||||
) as HTMLButtonElement;
|
||||
expect(button).not.toBeNull();
|
||||
userEvent.click(button);
|
||||
await userEvent.click(button);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -51,7 +54,7 @@ AffineNewPageButton.play = async ({ canvasElement }) => {
|
||||
expect(button).not.toBeNull();
|
||||
const dropdown = button.querySelector('svg') as SVGSVGElement;
|
||||
expect(dropdown).not.toBeNull();
|
||||
userEvent.click(dropdown);
|
||||
await userEvent.click(dropdown);
|
||||
};
|
||||
|
||||
export const AffineAllPageList: StoryFn<typeof PageList> = ({ ...props }) => (
|
||||
@@ -69,11 +72,11 @@ AffineAllPageList.args = {
|
||||
favorite: false,
|
||||
icon: <PageIcon />,
|
||||
isPublicPage: true,
|
||||
title: 'Today Page',
|
||||
title: 'Last Page',
|
||||
tags: [],
|
||||
preview: 'this is page preview',
|
||||
createDate: new Date(),
|
||||
updatedDate: new Date(),
|
||||
createDate: new Date('2021-01-01'),
|
||||
updatedDate: new Date('2023-08-15'),
|
||||
bookmarkPage: () => toast('Bookmark page'),
|
||||
onClickPage: () => toast('Click page'),
|
||||
onDisablePublicSharing: () => toast('Disable public sharing'),
|
||||
|
||||
@@ -12,14 +12,17 @@ import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { getOrCreateWorkspace } from '@affine/workspace/manager';
|
||||
import type { Page } from '@blocksuite/store';
|
||||
import { expect } from '@storybook/jest';
|
||||
import type { StoryFn } from '@storybook/react';
|
||||
import type { Meta, StoryFn } from '@storybook/react';
|
||||
import { use } from 'foxact/use';
|
||||
import { useState } from 'react';
|
||||
|
||||
export default {
|
||||
title: 'AFFiNE/ShareMenu',
|
||||
component: ShareMenu,
|
||||
};
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} satisfies Meta;
|
||||
|
||||
async function initPage(page: Page) {
|
||||
await page.waitForLoaded();
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
/* deepscan-disable USELESS_ARROW_FUNC_BIND */
|
||||
import { Switch } from '@affine/component';
|
||||
import type { StoryFn } from '@storybook/react';
|
||||
import type { Meta, StoryFn } from '@storybook/react';
|
||||
|
||||
export default {
|
||||
title: 'AFFiNE/Switch',
|
||||
component: Switch,
|
||||
};
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} satisfies Meta;
|
||||
|
||||
export const Basic: StoryFn = () => {
|
||||
return <Switch>Switch</Switch>;
|
||||
|
||||
@@ -16,6 +16,9 @@ export default {
|
||||
},
|
||||
},
|
||||
},
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} satisfies Meta<WorkspaceAvatarProps>;
|
||||
|
||||
const schema = new Schema();
|
||||
|
||||
@@ -9,6 +9,9 @@ import { useState } from 'react';
|
||||
export default {
|
||||
title: 'AFFiNE/WorkspaceList',
|
||||
component: WorkspaceList,
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} satisfies Meta<WorkspaceListProps>;
|
||||
|
||||
export const Default = () => {
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
"outDir": "lib"
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"path": "../../apps/core"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/component"
|
||||
},
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"composite": true,
|
||||
"module": "ESNext",
|
||||
"jsx": "react-jsx",
|
||||
"moduleResolution": "Node",
|
||||
"moduleResolution": "bundler",
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"noEmit": false,
|
||||
@@ -13,6 +13,7 @@
|
||||
"include": [".storybook/**/*"],
|
||||
"exclude": ["lib"],
|
||||
"references": [
|
||||
{ "path": "../../apps/core" },
|
||||
{ "path": "../../packages/i18n" },
|
||||
{
|
||||
"path": "../../packages/env"
|
||||
|
||||
20
package.json
20
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@affine/monorepo",
|
||||
"version": "0.8.0-canary.22",
|
||||
"version": "0.8.0-canary.26",
|
||||
"private": true,
|
||||
"author": "toeverything",
|
||||
"license": "MPL-2.0",
|
||||
@@ -66,7 +66,7 @@
|
||||
"@faker-js/faker": "^8.0.2",
|
||||
"@istanbuljs/schema": "^0.1.3",
|
||||
"@magic-works/i18n-codegen": "^0.5.0",
|
||||
"@nx/vite": "16.6.0",
|
||||
"@nx/vite": "16.7.0",
|
||||
"@perfsee/sdk": "^1.9.0",
|
||||
"@playwright/test": "^1.37.0",
|
||||
"@taplo/cli": "^0.5.2",
|
||||
@@ -74,9 +74,9 @@
|
||||
"@toeverything/infra": "workspace:*",
|
||||
"@types/affine__env": "workspace:*",
|
||||
"@types/eslint": "^8.44.2",
|
||||
"@types/node": "^18.17.4",
|
||||
"@typescript-eslint/eslint-plugin": "^6.3.0",
|
||||
"@typescript-eslint/parser": "^6.3.0",
|
||||
"@types/node": "^18.17.5",
|
||||
"@typescript-eslint/eslint-plugin": "^6.4.0",
|
||||
"@typescript-eslint/parser": "^6.4.0",
|
||||
"@vanilla-extract/vite-plugin": "^3.8.2",
|
||||
"@vanilla-extract/webpack-plugin": "^2.2.0",
|
||||
"@vitejs/plugin-react-swc": "^3.3.2",
|
||||
@@ -86,7 +86,7 @@
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-i": "^2.28.0",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"eslint-plugin-react": "^7.33.1",
|
||||
"eslint-plugin-react": "^7.33.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-simple-import-sort": "^10.0.0",
|
||||
"eslint-plugin-sonarjs": "^0.20.0",
|
||||
@@ -94,16 +94,16 @@
|
||||
"eslint-plugin-unused-imports": "^3.0.0",
|
||||
"eslint-plugin-vue": "^9.17.0",
|
||||
"fake-indexeddb": "4.0.2",
|
||||
"happy-dom": "^10.9.0",
|
||||
"happy-dom": "^10.10.0",
|
||||
"husky": "^8.0.3",
|
||||
"lint-staged": "^13.2.3",
|
||||
"lint-staged": "^14.0.0",
|
||||
"madge": "^6.1.0",
|
||||
"msw": "^1.2.3",
|
||||
"nanoid": "^4.0.2",
|
||||
"nx": "16.6.0",
|
||||
"nx": "16.7.0",
|
||||
"nx-cloud": "latest",
|
||||
"nyc": "^15.1.0",
|
||||
"prettier": "^3.0.1",
|
||||
"prettier": "^3.0.2",
|
||||
"semver": "^7.5.4",
|
||||
"serve": "^14.2.0",
|
||||
"ts-node": "^10.9.1",
|
||||
|
||||
2
packages/@types/env/package.json
vendored
2
packages/@types/env/package.json
vendored
@@ -7,5 +7,5 @@
|
||||
"@affine/env": "workspace:*",
|
||||
"@toeverything/infra": "workspace:*"
|
||||
},
|
||||
"version": "0.8.0-canary.22"
|
||||
"version": "0.8.0-canary.26"
|
||||
}
|
||||
|
||||
@@ -20,5 +20,5 @@
|
||||
"peerDependencies": {
|
||||
"ts-node": "*"
|
||||
},
|
||||
"version": "0.8.0-canary.22"
|
||||
"version": "0.8.0-canary.26"
|
||||
}
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
"@emotion/react": "^11.11.1",
|
||||
"@emotion/server": "^11.11.0",
|
||||
"@emotion/styled": "^11.11.0",
|
||||
"@mui/base": "5.0.0-beta.10",
|
||||
"@mui/base": "5.0.0-beta.11",
|
||||
"@mui/icons-material": "^5.14.3",
|
||||
"@mui/material": "^5.14.4",
|
||||
"@mui/material": "^5.14.5",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@radix-ui/react-avatar": "^1.0.3",
|
||||
"@radix-ui/react-collapsible": "^1.0.3",
|
||||
@@ -51,12 +51,12 @@
|
||||
"rxjs": "^7.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@blocksuite/blocks": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/blocks": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/icons": "^2.1.31",
|
||||
"@blocksuite/lit": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/lit": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@types/react": "^18.2.20",
|
||||
"@types/react-datepicker": "^4.15.0",
|
||||
"@types/react-dnd": "^3.0.2",
|
||||
@@ -66,5 +66,5 @@
|
||||
"vite": "^4.4.9",
|
||||
"yjs": "^13.6.7"
|
||||
},
|
||||
"version": "0.8.0-canary.22"
|
||||
"version": "0.8.0-canary.26"
|
||||
}
|
||||
|
||||
@@ -3,13 +3,16 @@ import { style } from '@vanilla-extract/css';
|
||||
export const root = style({
|
||||
fontSize: 'var(--affine-font-xs)',
|
||||
minHeight: '16px',
|
||||
width: 'calc(100% + 6px)',
|
||||
userSelect: 'none',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
marginBottom: '4px',
|
||||
padding: '0 8px',
|
||||
selectors: {
|
||||
'&:not(:first-of-type)': {
|
||||
marginTop: '10px',
|
||||
marginTop: '16px',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -52,7 +52,6 @@ export const navStyle = style({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
zIndex: parseInt(baseTheme.zIndexModal),
|
||||
borderRight: '1px solid transparent',
|
||||
});
|
||||
|
||||
export const navHeaderStyle = style({
|
||||
@@ -76,6 +75,7 @@ export const navBodyStyle = style({
|
||||
height: 'calc(100% - 52px)',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
rowGap: '4px',
|
||||
});
|
||||
|
||||
export const sidebarFloatMaskStyle = style({
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
import { style } from '@vanilla-extract/css';
|
||||
|
||||
export const linkItemRoot = style({
|
||||
color: 'inherit',
|
||||
display: 'contents',
|
||||
});
|
||||
|
||||
export const root = style({
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
borderRadius: '4px',
|
||||
textAlign: 'left',
|
||||
color: 'inherit',
|
||||
width: '100%',
|
||||
minHeight: '30px',
|
||||
userSelect: 'none',
|
||||
cursor: 'pointer',
|
||||
padding: '0 12px',
|
||||
fontSize: 'var(--affine-font-sm)',
|
||||
margin: '2px 0',
|
||||
marginTop: '4px',
|
||||
selectors: {
|
||||
'&:hover': {
|
||||
background: 'var(--affine-hover-color)',
|
||||
@@ -29,10 +37,8 @@ export const root = style({
|
||||
// 'linear-gradient(0deg, rgba(0, 0, 0, 0.04), rgba(0, 0, 0, 0.04)), rgba(0, 0, 0, 0.04)',
|
||||
// },
|
||||
'&[data-collapsible="true"]': {
|
||||
width: 'calc(100% + 8px)',
|
||||
transform: 'translateX(-8px)',
|
||||
paddingLeft: '4px',
|
||||
paddingRight: '12px',
|
||||
paddingRight: '4px',
|
||||
},
|
||||
'&[data-type="collection-list-item"][data-collapsible="false"][data-active="true"],&[data-type="favorite-list-item"][data-collapsible="false"][data-active="true"], &[data-type="favorite-list-item"][data-collapsible="false"]:hover, &[data-type="collection-list-item"][data-collapsible="false"]:hover':
|
||||
{
|
||||
@@ -41,6 +47,9 @@ export const root = style({
|
||||
paddingLeft: '20px',
|
||||
paddingRight: '12px',
|
||||
},
|
||||
[`${linkItemRoot}:first-of-type &`]: {
|
||||
marginTop: '0px',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -53,6 +62,12 @@ export const content = style({
|
||||
|
||||
export const postfix = style({
|
||||
justifySelf: 'flex-end',
|
||||
display: 'none',
|
||||
selectors: {
|
||||
[`${root}:hover &`]: {
|
||||
display: 'flex',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const icon = style({
|
||||
@@ -68,10 +83,15 @@ export const collapsedIconContainer = style({
|
||||
justifyContent: 'center',
|
||||
borderRadius: '2px',
|
||||
transition: 'transform 0.2s',
|
||||
color: 'inherit',
|
||||
selectors: {
|
||||
'&[data-collapsed="true"]': {
|
||||
transform: 'rotate(-90deg)',
|
||||
},
|
||||
'&[data-disabled="true"]': {
|
||||
opacity: 0.3,
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
'&:hover': {
|
||||
background: 'var(--affine-hover-color)',
|
||||
},
|
||||
@@ -103,8 +123,3 @@ export const collapsedIcon = style({
|
||||
export const spacer = style({
|
||||
flex: 1,
|
||||
});
|
||||
|
||||
export const linkItemRoot = style({
|
||||
color: 'inherit',
|
||||
display: 'contents',
|
||||
});
|
||||
|
||||
@@ -6,11 +6,13 @@ import { Link } from 'react-router-dom';
|
||||
|
||||
import * as styles from './index.css';
|
||||
|
||||
export interface MenuItemProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
export interface MenuItemProps extends React.HTMLAttributes<HTMLButtonElement> {
|
||||
icon?: React.ReactElement;
|
||||
active?: boolean;
|
||||
disabled?: boolean;
|
||||
collapsed?: boolean; // true, false, undefined. undefined means no collapse
|
||||
// true, false, undefined. undefined means no collapse
|
||||
collapsed?: boolean;
|
||||
// if onCollapsedChange is given, but collapsed is undefined, then we will render the collapse button as disabled
|
||||
onCollapsedChange?: (collapsed: boolean) => void;
|
||||
postfix?: React.ReactElement;
|
||||
}
|
||||
@@ -23,7 +25,7 @@ const stopPropagation: React.MouseEventHandler = e => {
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
export const MenuItem = React.forwardRef<HTMLDivElement, MenuItemProps>(
|
||||
export const MenuItem = React.forwardRef<HTMLButtonElement, MenuItemProps>(
|
||||
(
|
||||
{
|
||||
onClick,
|
||||
@@ -38,14 +40,9 @@ export const MenuItem = React.forwardRef<HTMLDivElement, MenuItemProps>(
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const collapsible = collapsed !== undefined;
|
||||
if (collapsible && !onCollapsedChange) {
|
||||
throw new Error(
|
||||
'onCollapsedChange is required when collapsed is defined'
|
||||
);
|
||||
}
|
||||
const collapsible = onCollapsedChange !== undefined;
|
||||
return (
|
||||
<div
|
||||
<button
|
||||
ref={ref}
|
||||
{...props}
|
||||
onClick={onClick}
|
||||
@@ -58,6 +55,7 @@ export const MenuItem = React.forwardRef<HTMLDivElement, MenuItemProps>(
|
||||
<div className={styles.iconsContainer} data-collapsible={collapsible}>
|
||||
{collapsible && (
|
||||
<div
|
||||
data-disabled={collapsed === undefined ? true : undefined}
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault(); // for links
|
||||
@@ -68,7 +66,7 @@ export const MenuItem = React.forwardRef<HTMLDivElement, MenuItemProps>(
|
||||
>
|
||||
<ArrowDownSmallIcon
|
||||
className={styles.collapsedIcon}
|
||||
data-collapsed={collapsed}
|
||||
data-collapsed={collapsed !== false}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@@ -84,21 +82,22 @@ export const MenuItem = React.forwardRef<HTMLDivElement, MenuItemProps>(
|
||||
{postfix}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
);
|
||||
MenuItem.displayName = 'MenuItem';
|
||||
|
||||
export const MenuLinkItem = React.forwardRef<HTMLDivElement, MenuLinkItemProps>(
|
||||
({ to, ...props }, ref) => {
|
||||
return (
|
||||
<Link to={to} className={styles.linkItemRoot}>
|
||||
{/* The <a> element rendered by Link does not generate display box due to `display: contents` style */}
|
||||
{/* Thus ref is passed to MenuItem instead of Link */}
|
||||
<MenuItem ref={ref} {...props}></MenuItem>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
);
|
||||
export const MenuLinkItem = React.forwardRef<
|
||||
HTMLButtonElement,
|
||||
MenuLinkItemProps
|
||||
>(({ to, ...props }, ref) => {
|
||||
return (
|
||||
<Link to={to} className={styles.linkItemRoot}>
|
||||
{/* The <a> element rendered by Link does not generate display box due to `display: contents` style */}
|
||||
{/* Thus ref is passed to MenuItem instead of Link */}
|
||||
<MenuItem ref={ref} {...props}></MenuItem>
|
||||
</Link>
|
||||
);
|
||||
});
|
||||
MenuLinkItem.displayName = 'MenuLinkItem';
|
||||
|
||||
@@ -12,7 +12,7 @@ export const root = style({
|
||||
userSelect: 'none',
|
||||
cursor: 'pointer',
|
||||
padding: '0 12px',
|
||||
margin: '12px 0',
|
||||
margin: '20px 0',
|
||||
position: 'relative',
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import { useAtom, useSetAtom } from 'jotai';
|
||||
import type { ReactElement } from 'react';
|
||||
import { useCallback, useLayoutEffect, useState } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import {
|
||||
appSidebarOpenAtom,
|
||||
@@ -18,16 +19,10 @@ export const ResizeIndicator = (props: ResizeIndicatorProps): ReactElement => {
|
||||
const [sidebarOpen, setSidebarOpen] = useAtom(appSidebarOpenAtom);
|
||||
const [isResizing, setIsResizing] = useAtom(appSidebarResizingAtom);
|
||||
|
||||
const [anchorLeft, setAnchorLeft] = useState(0);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!props.targetElement) return;
|
||||
const { left } = props.targetElement.getBoundingClientRect();
|
||||
setAnchorLeft(left);
|
||||
}, [props.targetElement]);
|
||||
|
||||
const onResizeStart = useCallback(() => {
|
||||
let resized = false;
|
||||
assertExists(props.targetElement);
|
||||
const { left: anchorLeft } = props.targetElement.getBoundingClientRect();
|
||||
|
||||
function onMouseMove(e: MouseEvent) {
|
||||
e.preventDefault();
|
||||
@@ -51,13 +46,7 @@ export const ResizeIndicator = (props: ResizeIndicatorProps): ReactElement => {
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
}, [
|
||||
anchorLeft,
|
||||
props.targetElement,
|
||||
setIsResizing,
|
||||
setSidebarOpen,
|
||||
setWidth,
|
||||
]);
|
||||
}, [props.targetElement, setIsResizing, setSidebarOpen, setWidth]);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
@@ -4,7 +4,6 @@ export const baseContainer = style({
|
||||
padding: '4px 16px',
|
||||
display: 'flex',
|
||||
flexFlow: 'column nowrap',
|
||||
rowGap: '4px',
|
||||
});
|
||||
|
||||
export const scrollableContainerRoot = style({
|
||||
@@ -45,6 +44,7 @@ export const scrollableContainer = style([
|
||||
baseContainer,
|
||||
{
|
||||
height: '100%',
|
||||
padding: '4px 8px',
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -69,6 +69,7 @@ export const scrollbarThumb = style({
|
||||
position: 'relative',
|
||||
background: 'var(--affine-black-30)',
|
||||
borderRadius: '4px',
|
||||
overflow: 'hidden',
|
||||
selectors: {
|
||||
'&::before': {
|
||||
content: '""',
|
||||
|
||||
@@ -2,12 +2,6 @@ import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { RootWorkspaceMetadata } from '@affine/workspace/atom';
|
||||
import { SettingsIcon } from '@blocksuite/icons';
|
||||
import {
|
||||
CloudWorkspaceIcon as DefaultCloudWorkspaceIcon,
|
||||
CollaborationIcon as DefaultJoinedWorkspaceIcon,
|
||||
LocalDataIcon as DefaultLocalDataIcon,
|
||||
LocalWorkspaceIcon as DefaultLocalWorkspaceIcon,
|
||||
} from '@blocksuite/icons';
|
||||
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name';
|
||||
import { useStaticBlockSuiteWorkspace } from '@toeverything/infra/__internal__/react';
|
||||
import { useCallback } from 'react';
|
||||
@@ -16,25 +10,10 @@ import { WorkspaceAvatar } from '../../workspace-avatar';
|
||||
import {
|
||||
StyledCard,
|
||||
StyledSettingLink,
|
||||
StyleWorkspaceInfo,
|
||||
StyleWorkspaceTitle,
|
||||
StyledWorkspaceInfo,
|
||||
StyledWorkspaceTitle,
|
||||
} from './styles';
|
||||
|
||||
const JoinedWorkspaceIcon = () => {
|
||||
return <DefaultJoinedWorkspaceIcon style={{ color: '#FF646B' }} />;
|
||||
};
|
||||
const LocalWorkspaceIcon = () => {
|
||||
return <DefaultLocalWorkspaceIcon style={{ color: '#FDBD32' }} />;
|
||||
};
|
||||
|
||||
const CloudWorkspaceIcon = () => {
|
||||
return <DefaultCloudWorkspaceIcon style={{ color: '#60A5FA' }} />;
|
||||
};
|
||||
|
||||
const LocalDataIcon = () => {
|
||||
return <DefaultLocalDataIcon style={{ color: '#62CD80' }} />;
|
||||
};
|
||||
|
||||
export interface WorkspaceTypeProps {
|
||||
flavour: WorkspaceFlavour;
|
||||
}
|
||||
@@ -46,21 +25,18 @@ const WorkspaceType = ({ flavour }: WorkspaceTypeProps) => {
|
||||
|
||||
if (flavour === WorkspaceFlavour.LOCAL) {
|
||||
return (
|
||||
<p title={t['Local Workspace']()}>
|
||||
<LocalWorkspaceIcon />
|
||||
<p style={{ fontSize: '10px' }} title={t['Local Workspace']()}>
|
||||
<span>{t['Local Workspace']()}</span>
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
return isOwner ? (
|
||||
<p title={t['Cloud Workspace']()}>
|
||||
<CloudWorkspaceIcon />
|
||||
<p style={{ fontSize: '10px' }} title={t['Cloud Workspace']()}>
|
||||
<span>{t['Cloud Workspace']()}</span>
|
||||
</p>
|
||||
) : (
|
||||
<p title={t['Joined Workspace']()}>
|
||||
<JoinedWorkspaceIcon />
|
||||
<p style={{ fontSize: '10px' }} title={t['Joined Workspace']()}>
|
||||
<span>{t['Joined Workspace']()}</span>
|
||||
</p>
|
||||
);
|
||||
@@ -79,7 +55,7 @@ export const WorkspaceCard = ({
|
||||
currentWorkspaceId,
|
||||
meta,
|
||||
}: WorkspaceCardProps) => {
|
||||
const t = useAFFiNEI18N();
|
||||
// const t = useAFFiNEI18N();
|
||||
const workspace = useStaticBlockSuiteWorkspace(meta.id);
|
||||
const [name] = useBlockSuiteWorkspaceName(workspace);
|
||||
|
||||
@@ -91,20 +67,21 @@ export const WorkspaceCard = ({
|
||||
}, [onClick, meta.id])}
|
||||
active={workspace.id === currentWorkspaceId}
|
||||
>
|
||||
<WorkspaceAvatar size={58} workspace={workspace} />
|
||||
<WorkspaceAvatar size={28} workspace={workspace} />
|
||||
|
||||
<StyleWorkspaceInfo>
|
||||
<StyleWorkspaceTitle>{name}</StyleWorkspaceTitle>
|
||||
<StyledWorkspaceInfo>
|
||||
<StyledWorkspaceTitle>{name}</StyledWorkspaceTitle>
|
||||
<WorkspaceType flavour={meta.flavour} />
|
||||
{meta.flavour === WorkspaceFlavour.LOCAL && (
|
||||
{/* {meta.flavour === WorkspaceFlavour.LOCAL && (
|
||||
<p title={t['Available Offline']()}>
|
||||
<LocalDataIcon />
|
||||
<span>{t['Available Offline']()}</span>
|
||||
</p>
|
||||
)}
|
||||
</StyleWorkspaceInfo>
|
||||
)} */}
|
||||
</StyledWorkspaceInfo>
|
||||
<StyledSettingLink
|
||||
className="setting-entry"
|
||||
data-testid="workspace-card-setting-button"
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
onSettingClick(meta.id);
|
||||
|
||||
@@ -2,7 +2,7 @@ import { IconButton } from '@toeverything/components/button';
|
||||
|
||||
import { displayFlex, styled, textEllipsis } from '../../../styles';
|
||||
|
||||
export const StyleWorkspaceInfo = styled('div')(() => {
|
||||
export const StyledWorkspaceInfo = styled('div')(() => {
|
||||
return {
|
||||
marginLeft: '15px',
|
||||
width: '202px',
|
||||
@@ -23,13 +23,13 @@ export const StyleWorkspaceInfo = styled('div')(() => {
|
||||
};
|
||||
});
|
||||
|
||||
export const StyleWorkspaceTitle = styled('div')(() => {
|
||||
export const StyledWorkspaceTitle = styled('div')(() => {
|
||||
return {
|
||||
fontSize: 'var(--affine-font-base)',
|
||||
fontWeight: 600,
|
||||
lineHeight: '24px',
|
||||
marginBottom: '10px',
|
||||
maxWidth: '200px',
|
||||
color: 'var(--affine-text-primary-color)',
|
||||
...textEllipsis(1),
|
||||
};
|
||||
});
|
||||
@@ -38,19 +38,21 @@ export const StyledCard = styled('div')<{
|
||||
active?: boolean;
|
||||
}>(({ active }) => {
|
||||
const borderColor = active ? 'var(--affine-primary-color)' : 'transparent';
|
||||
const backgroundColor = active ? 'var(--affine-white)' : 'transparent';
|
||||
return {
|
||||
width: '310px',
|
||||
height: '124px',
|
||||
width: '280px',
|
||||
height: '58px',
|
||||
cursor: 'pointer',
|
||||
padding: '16px',
|
||||
boxShadow: 'var(--affine-shadow-1)',
|
||||
borderRadius: '12px',
|
||||
border: `1px solid ${borderColor}`,
|
||||
...displayFlex('flex-start', 'flex-start'),
|
||||
marginBottom: '24px',
|
||||
marginBottom: '12px',
|
||||
transition: 'background .2s',
|
||||
background: 'var(--affine-white-80)',
|
||||
alignItems: 'center',
|
||||
position: 'relative',
|
||||
color: 'var(--affine-text-secondary-color)',
|
||||
background: backgroundColor,
|
||||
':hover': {
|
||||
background: 'var(--affine-hover-color)',
|
||||
'.add-icon': {
|
||||
@@ -96,3 +98,9 @@ export const StyledSettingLink = styled(IconButton)(() => {
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledWorkspaceType = styled('p')(() => {
|
||||
return {
|
||||
fontSize: 10,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -14,6 +14,7 @@ export const avatarImageStyle = style({
|
||||
height: '100%',
|
||||
objectFit: 'cover',
|
||||
objectPosition: 'center',
|
||||
display: 'block',
|
||||
});
|
||||
|
||||
const bottomAnimation = keyframes({
|
||||
|
||||
@@ -67,7 +67,6 @@ export const mainContainerStyle = style({
|
||||
width: 0,
|
||||
flex: 1,
|
||||
maxWidth: '100%',
|
||||
zIndex: 2,
|
||||
backgroundColor: 'var(--affine-background-primary-color)',
|
||||
selectors: {
|
||||
'&[data-show-padding="true"]': {
|
||||
@@ -103,6 +102,9 @@ export const toolStyle = style({
|
||||
right: '30px',
|
||||
bottom: '30px',
|
||||
zIndex: 'var(--affine-z-index-popover)',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '12px',
|
||||
'@media': {
|
||||
[breakpoints.down('md', true)]: {
|
||||
right: 'calc((100vw - 640px) * 3 / 19 + 14px)',
|
||||
|
||||
@@ -252,3 +252,11 @@ affine-block-hub {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
button,
|
||||
input,
|
||||
select,
|
||||
textarea,
|
||||
[role='button'] {
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import {
|
||||
|
||||
import { styled } from '../../styles';
|
||||
import type { PopperProps, VirtualElement } from './interface';
|
||||
import { PopperArrow } from './popover-arrow';
|
||||
export const Popper = ({
|
||||
children,
|
||||
content,
|
||||
@@ -41,7 +40,8 @@ export const Popper = ({
|
||||
}: PopperProps) => {
|
||||
const [anchorEl, setAnchorEl] = useState<VirtualElement>();
|
||||
const [visible, setVisible] = useState(defaultVisible);
|
||||
const [arrowRef, setArrowRef] = useState<HTMLElement>();
|
||||
//const [arrowRef, setArrowRef] = useState<HTMLElement>();
|
||||
const arrowRef = null;
|
||||
const pointerLeaveTimer = useRef<number>();
|
||||
const pointerEnterTimer = useRef<number>();
|
||||
|
||||
@@ -170,12 +170,111 @@ export const Popper = ({
|
||||
}
|
||||
}}
|
||||
>
|
||||
{showArrow && (
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
<PopperArrow placement={placement} ref={setArrowRef} />
|
||||
{showArrow ? (
|
||||
<>
|
||||
{placement.indexOf('bottom') === 0 ? (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="11"
|
||||
height="6"
|
||||
viewBox="0 0 11 6"
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
d="M6.38889 0.45C5.94444 -0.15 5.05555 -0.150001 4.61111 0.449999L0.499999 6L10.5 6L6.38889 0.45Z"
|
||||
style={{ fill: 'var(--affine-tooltip)' }}
|
||||
/>
|
||||
</svg>
|
||||
{content}
|
||||
</div>
|
||||
) : placement.indexOf('top') === 0 ? (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
{content}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="11"
|
||||
height="6"
|
||||
viewBox="0 0 11 6"
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
d="M4.61111 5.55C5.05556 6.15 5.94445 6.15 6.38889 5.55L10.5 -4.76837e-07H0.5L4.61111 5.55Z"
|
||||
style={{ fill: 'var(--affine-tooltip)' }}
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
) : placement.indexOf('left') === 0 ? (
|
||||
<>
|
||||
{content}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="6"
|
||||
height="10"
|
||||
viewBox="0 0 6 10"
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
d="M5.55 5.88889C6.15 5.44444 6.15 4.55555 5.55 4.11111L-4.76837e-07 0L-4.76837e-07 10L5.55 5.88889Z"
|
||||
style={{ fill: 'var(--affine-tooltip)' }}
|
||||
/>
|
||||
</svg>
|
||||
</>
|
||||
) : placement.indexOf('right') === 0 ? (
|
||||
<>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="6"
|
||||
height="10"
|
||||
viewBox="0 0 6 10"
|
||||
style={{ fill: 'var(--affine-tooltip)' }}
|
||||
>
|
||||
<path
|
||||
d="M0.45 4.11111C-0.15 4.55556 -0.15 5.44445 0.45 5.88889L6 10V0L0.45 4.11111Z"
|
||||
style={{ fill: 'var(--affine-tooltip)' }}
|
||||
/>
|
||||
</svg>
|
||||
{content}
|
||||
</>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
{content}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="11"
|
||||
height="6"
|
||||
viewBox="0 0 11 6"
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
d="M4.61111 5.55C5.05556 6.15 5.94445 6.15 6.38889 5.55L10.5 -4.76837e-07H0.5L4.61111 5.55Z"
|
||||
style={{ fill: 'var(--affine-tooltip)' }}
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>{content}</>
|
||||
)}
|
||||
{content}
|
||||
</div>
|
||||
</Grow>
|
||||
)}
|
||||
|
||||
@@ -70,6 +70,7 @@ export const scrollbarThumb = style({
|
||||
position: 'relative',
|
||||
background: 'var(--affine-divider-color)',
|
||||
width: '50%',
|
||||
overflow: 'hidden',
|
||||
borderRadius: '4px',
|
||||
':hover': {
|
||||
background: 'var(--affine-icon-color)',
|
||||
|
||||
@@ -7,15 +7,16 @@ import StyledPopperContainer from '../shared/container';
|
||||
|
||||
const StyledTooltip = styled(StyledPopperContainer)(() => {
|
||||
return {
|
||||
maxWidth: '320px',
|
||||
boxShadow: 'var(--affine-float-button-shadow)',
|
||||
padding: '4px 12px',
|
||||
display: 'inline-flex',
|
||||
minHeight: '38px',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
flexShrink: 0,
|
||||
backgroundColor: 'var(--affine-tooltip)',
|
||||
borderRadius: '4px',
|
||||
color: 'var(--affine-white)',
|
||||
fontSize: 'var(--affine-font-sm)',
|
||||
borderRadius: '8px',
|
||||
marginBottom: '12px',
|
||||
overflowWrap: 'break-word',
|
||||
padding: '5px 12px',
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -8,5 +8,5 @@
|
||||
"devDependencies": {
|
||||
"@types/debug": "^4.1.8"
|
||||
},
|
||||
"version": "0.8.0-canary.22"
|
||||
"version": "0.8.0-canary.26"
|
||||
}
|
||||
|
||||
6
packages/env/package.json
vendored
6
packages/env/package.json
vendored
@@ -5,10 +5,10 @@
|
||||
"main": "./src/index.ts",
|
||||
"module": "./src/index.ts",
|
||||
"devDependencies": {
|
||||
"@blocksuite/global": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"zod": "^3.21.4"
|
||||
"zod": "^3.22.1"
|
||||
},
|
||||
"exports": {
|
||||
"./automation": "./src/automation.ts",
|
||||
@@ -27,5 +27,5 @@
|
||||
"dependencies": {
|
||||
"lit": "^2.8.0"
|
||||
},
|
||||
"version": "0.8.0-canary.22"
|
||||
"version": "0.8.0-canary.26"
|
||||
}
|
||||
|
||||
7
packages/env/src/global.ts
vendored
7
packages/env/src/global.ts
vendored
@@ -5,15 +5,22 @@ import { z } from 'zod';
|
||||
import { isBrowser, isDesktop, isServer } from './constant.js';
|
||||
import { isValidIPAddress } from './is-valid-ip-address.js';
|
||||
import { UaHelper } from './ua-helper.js';
|
||||
|
||||
export const blockSuiteFeatureFlags = z.object({
|
||||
enable_database: z.boolean(),
|
||||
enable_database_filter: z.boolean(),
|
||||
enable_data_view: z.boolean(),
|
||||
enable_page_tags: z.boolean(),
|
||||
enable_drag_handle: z.boolean(),
|
||||
enable_surface: z.boolean(),
|
||||
enable_block_hub: z.boolean(),
|
||||
enable_slash_menu: z.boolean(),
|
||||
enable_toggle_block: z.boolean(),
|
||||
enable_edgeless_toolbar: z.boolean(),
|
||||
enable_linked_page: z.boolean(),
|
||||
enable_bookmark_operation: z.boolean(),
|
||||
enable_note_index: z.boolean(),
|
||||
enable_attachment_block: z.boolean(),
|
||||
});
|
||||
|
||||
export const runtimeFlagsSchema = z.object({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@affine/graphql",
|
||||
"version": "0.8.0-canary.22",
|
||||
"version": "0.8.0-canary.26",
|
||||
"description": "Autogenerated GraphQL client for affine.pro",
|
||||
"license": "MPL-2.0",
|
||||
"type": "module",
|
||||
@@ -16,12 +16,12 @@
|
||||
"@graphql-codegen/typescript-operations": "^4.0.1",
|
||||
"@types/lodash-es": "^4.17.8",
|
||||
"lodash-es": "^4.17.21",
|
||||
"prettier": "^3.0.1"
|
||||
"prettier": "^3.0.2"
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "gql-gen"
|
||||
},
|
||||
"dependencies": {
|
||||
"graphql": "^16.7.1"
|
||||
"graphql": "^16.8.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,17 +6,17 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"foxact": "^0.2.17"
|
||||
"foxact": "^0.2.20"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@affine/env": "workspace:*",
|
||||
"@affine/y-provider": "workspace:*",
|
||||
"@blocksuite/block-std": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/blocks": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/lit": "0.0.0-20230814155455-ceb5d5d8-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230814155455-ceb5d5d8-nightly"
|
||||
"@blocksuite/block-std": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/blocks": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/lit": "0.0.0-20230818021533-7e342436-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230818021533-7e342436-nightly"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@affine/y-provider": "workspace:*",
|
||||
@@ -53,5 +53,5 @@
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"version": "0.8.0-canary.22"
|
||||
"version": "0.8.0-canary.26"
|
||||
}
|
||||
|
||||
@@ -31,11 +31,11 @@
|
||||
"react-i18next": "^13.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.17.4",
|
||||
"@types/node": "^18.17.5",
|
||||
"@types/prettier": "^3.0.0",
|
||||
"prettier": "^3.0.1",
|
||||
"prettier": "^3.0.2",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.1.6"
|
||||
},
|
||||
"version": "0.8.0-canary.22"
|
||||
"version": "0.8.0-canary.26"
|
||||
}
|
||||
|
||||
@@ -399,6 +399,83 @@
|
||||
"com.affine.workspace.cannot-delete": "You cannot delete the last workspace",
|
||||
"com.affine.write_with_a_blank_page": "Write with a blank page",
|
||||
"com.affine.yesterday": "Yesterday",
|
||||
"com.affine.settings.sign": "Sign in / Sign up",
|
||||
"com.affine.setting.sign.message": "Sync with AFFiNE Cloud",
|
||||
"com.affine.setting.sign.out.message": "Securely sign out of your account.",
|
||||
"com.affine.setting.account": "Account Settings",
|
||||
"com.affine.setting.account.message": "Your personal information",
|
||||
"com.affine.setting.account.delete": "Delete Account",
|
||||
"com.affine.setting.account.delete.message": "Permanently delete this account and the Workspace data backup in AFFiNE Cloud. This action can not be undone.",
|
||||
"com.affine.settings.email": "Email",
|
||||
"com.affine.settings.email.action": "Change Email",
|
||||
"com.affine.settings.password": "Password",
|
||||
"com.affine.settings.password.message": "Set a password to sign in to your account",
|
||||
"com.affine.settings.password.action.change": "Change password",
|
||||
"com.affine.settings.password.action.set": "Set password",
|
||||
"com.affine.settings.profile": "My Profile",
|
||||
"com.affine.settings.profile.message": "Your account profile will be displayed to everyone.",
|
||||
"com.affine.settings.profile.name": "Display Name",
|
||||
"com.affine.settings.profile.placeholder": "Input account name",
|
||||
"com.affine.auth.sign.in": "Sign in",
|
||||
"com.affine.auth.sign.up": "Sign up",
|
||||
"com.affine.auth.sign.up.sent.email.subtitle": "Create your account",
|
||||
"com.affine.auth.sign.sent.email.message.start": "An email with a magic link has been sent to ",
|
||||
"com.affine.auth.sign.sent.email.message.end": " You can click the link to create an account automatically.",
|
||||
"com.affine.auth.sign.up.success.title": "Your account has been created and you’re now signed in!",
|
||||
"com.affine.auth.sign.up.success.subtitle": "The app will automatically open or redirect to the web version. if you encounter any issues, you can also click the button below to manually open the AFFiNE app.",
|
||||
"com.affine.auth.page.sent.email.title": "Welcome to AFFiNE Cloud, you are almost there!",
|
||||
"com.affine.auth.page.sent.email.subtitle": "Please set a password of 8-20 characters with both letters and numbers to continue signing up with ",
|
||||
"com.affine.auth.later": "Later",
|
||||
"com.affine.auth.open.affine": "Open AFFiNE",
|
||||
"com.affine.auth.sign.in.sent.email.subtitle": "Confirm your email",
|
||||
"com.affine.auth.sign.auth.code.message": "If you haven't received the email, please check your spam folder.",
|
||||
"com.affine.auth.sign.auth.code.message.password": "If you haven't received the email, please check your spam folder. Or <1>sign in with password</1> instead.",
|
||||
"com.affine.auth.password.error": "Invalid password",
|
||||
"com.affine.auth.forget": "Forgot password",
|
||||
"com.affine.auth.has.signed": " has signed in!",
|
||||
"com.affine.auth.signed.success.title": "You’re almost there!",
|
||||
"com.affine.auth.signed.success.subtitle": "You have successfully signed in. The app will automatically open or redirect to the web version. if you encounter any issues, you can also click the button below to manually open the AFFiNE app.",
|
||||
"com.affine.auth.reset.password": "Reset Password",
|
||||
"com.affine.auth.reset.password.message": "You will receive an email with a link to reset your password. Please check your inbox.",
|
||||
"com.affine.auth.send.reset.password.link": "Send reset link",
|
||||
"com.affine.auth.send.set.password.link": "Send set link",
|
||||
"com.affine.auth.send.change.email.link": "Send verification link",
|
||||
"com.affine.auth.sent": "Sent",
|
||||
"com.affine.auth.sent.change.password.hint": "Reset password link has been sent.",
|
||||
"com.affine.auth.sent.set.password.hint": "Set password link has been sent.",
|
||||
"com.affine.auth.sent.change.email.hint": "Verification link has been sent.",
|
||||
"com.affine.auth.set.password.page.title": "Set your AFFiNE Cloud password",
|
||||
"com.affine.auth.reset.password.page.title": "Reset your AFFiNE Cloud password",
|
||||
"com.affine.auth.set.password.page.success": "Password set successful",
|
||||
"com.affine.auth.set.password.save": "Save Password",
|
||||
"com.affine.auth.set.email.save": "Save Email",
|
||||
"com.affine.auth.change.email.page.title": "Change email address",
|
||||
"com.affine.auth.change.email.page.success.title": "Email address updated!",
|
||||
"com.affine.auth.change.email.page.subtitle": "Please enter your new email address below. We will send a verification link to this email address to complete the process.",
|
||||
"com.affine.auth.change.email.page.success.subtitle": "Congratulations! You have successfully updated the email address associated with your AFFiNE Cloud account.",
|
||||
"com.affine.auth.sign.email.placeholder": "Enter your email address",
|
||||
"com.affine.auth.sign.email.continue": "Continue with Email",
|
||||
"com.affine.auth.sign.email.error": "Invalid email",
|
||||
"com.affine.auth.sign.condition": "Terms of Conditions",
|
||||
"com.affine.auth.sign.policy": "Privacy Policy",
|
||||
"com.affine.auth.sign.message": "By clicking “Continue with Google/Email” above, you acknowledge that you agree to AFFiNE's <1>Terms of Conditions</1> and <3>Privacy Policy</3>.",
|
||||
"com.affine.auth.sign.auth.code.error.hint": "Wrong code, please try again",
|
||||
"com.affine.auth.sign.auth.code.on.resend.hint": "Send code again",
|
||||
"com.affine.auth.sign.auth.code.resend.hint": "Resend code",
|
||||
"com.affine.auth.password": "Password",
|
||||
"com.affine.auth.set.password": "Set password",
|
||||
"com.affine.auth.set.password.message": "Please set a password of 8-20 characters with both letters and numbers to continue signing up with ",
|
||||
"com.affine.auth.set.password.placeholder": "Set a password at least 8 letters long",
|
||||
"com.affine.auth.set.password.placeholder.confirm": "Confirm password",
|
||||
"com.affine.auth.create.count": "Create Account",
|
||||
"com.affine.expired.page.title": "This link has expired...",
|
||||
"com.affine.expired.page.subtitle": "Please request a new reset password link.",
|
||||
"com.affine.workspace.cloud.join": "Join Workspace",
|
||||
"com.affine.workspace.cloud.account.settings": "Account Settings",
|
||||
"com.affine.workspace.cloud.account.logout": "Log Out",
|
||||
"com.affine.workspace.cloud.sync": "Cloud sync",
|
||||
"com.affine.workspace.cloud.auth": "Sign up/ Sign in",
|
||||
"com.affine.workspace.local.import": "Import Workspace",
|
||||
"core": "core",
|
||||
"dark": "Dark",
|
||||
"emptyAllPages": "Click on the <1>$t(New Page)</1> button to create your first page.",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user