From 41980188cff9533d9b8a3b0016bbafbba9248beb Mon Sep 17 00:00:00 2001 From: lawvs <18554747+lawvs@users.noreply.github.com> Date: Fri, 12 Aug 2022 13:53:51 +0800 Subject: [PATCH 1/9] chore: update warn message --- libs/components/layout/src/header/LayoutHeader.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/components/layout/src/header/LayoutHeader.tsx b/libs/components/layout/src/header/LayoutHeader.tsx index 604b6caa6d..beade0de0d 100644 --- a/libs/components/layout/src/header/LayoutHeader.tsx +++ b/libs/components/layout/src/header/LayoutHeader.tsx @@ -52,8 +52,8 @@ export const LayoutHeader = () => { - AFFiNE now under active development, the version is - UNSTABLE, please DO NOT store important data in this version + AFFiNE is currently under active development. This build is + UNSTABLE. Please DO NOT store important data. From 7024b7f11a1edd8c410c7528f28973aae6274652 Mon Sep 17 00:00:00 2001 From: lawvs <18554747+lawvs@users.noreply.github.com> Date: Fri, 12 Aug 2022 13:54:11 +0800 Subject: [PATCH 2/9] chore: clean page tree styles --- .../workspace-sidebar/page-tree/DndTree.tsx | 12 +- .../page-tree/tree-item/DndTreeItem.tsx | 6 +- .../page-tree/tree-item/TreeItem.tsx | 73 ++++++------- .../page-tree/tree-item/styles.ts | 103 +++--------------- 4 files changed, 53 insertions(+), 141 deletions(-) diff --git a/libs/components/layout/src/workspace-sidebar/page-tree/DndTree.tsx b/libs/components/layout/src/workspace-sidebar/page-tree/DndTree.tsx index 40991b930c..6db19e3e86 100755 --- a/libs/components/layout/src/workspace-sidebar/page-tree/DndTree.tsx +++ b/libs/components/layout/src/workspace-sidebar/page-tree/DndTree.tsx @@ -36,19 +36,13 @@ export type DndTreeProps = { indentationWidth?: number; collapsible?: boolean; removable?: boolean; - showDragIndicator?: boolean; }; /** * Currently does not support drag and drop using the keyboard. */ export function DndTree(props: DndTreeProps) { - const { - indentationWidth = 20, - collapsible, - removable, - showDragIndicator, - } = props; + const { indentationWidth = 20, collapsible, removable } = props; const sensors = useSensors( useSensor(PointerSensor, { activationConstraint: { distance: 8 } }) @@ -111,7 +105,6 @@ export function DndTree(props: DndTreeProps) { : depth } indentationWidth={indentationWidth} - indicator={showDragIndicator} childCount={children.length} onCollapse={ collapsible && children.length @@ -129,7 +122,8 @@ export function DndTree(props: DndTreeProps) { )} {activeId && activeItem ? ( ble-node; the ref of the inner dom is often used as draggable-node */ - wrapperRef?(node: HTMLLIElement): void; -} & HTMLAttributes; +} & HTMLAttributes; export const TreeItem = forwardRef( ( @@ -52,13 +48,10 @@ export const TreeItem = forwardRef( ghost, handleProps, indentationWidth, - indicator, collapsed, onCollapse, onRemove, - style, value, - wrapperRef, pageId, ...props }, @@ -71,8 +64,8 @@ export const TreeItem = forwardRef( ); return ( - ( active={pageId === page_id} {...props} > - - - {childCount !== 0 ? ( - collapsed ? ( - - ) : ( - - ) - ) : ( - - )} - + {childCount !== 0 ? ( + collapsed ? ( + + + + ) : ( + + + + ) + ) : ( + + )} - - - {value} - - {BooleanPageTreeItemMoreActions && ( - - )} + + + {value} + + {BooleanPageTreeItemMoreActions && ( + + )} - {/*{!clone && onRemove && }*/} - {clone && childCount && childCount > 1 ? ( - {childCount} - ) : null} - - - + {/*{!clone && onRemove && }*/} + {clone && childCount && childCount > 1 ? ( + {childCount} + ) : null} + + ); } ); diff --git a/libs/components/layout/src/workspace-sidebar/page-tree/tree-item/styles.ts b/libs/components/layout/src/workspace-sidebar/page-tree/tree-item/styles.ts index 0040e5bef7..442715229c 100644 --- a/libs/components/layout/src/workspace-sidebar/page-tree/tree-item/styles.ts +++ b/libs/components/layout/src/workspace-sidebar/page-tree/tree-item/styles.ts @@ -1,22 +1,18 @@ import { styled } from '@toeverything/components/ui'; import { Link } from 'react-router-dom'; -export const TreeItemContainer = styled('div')` - box-sizing: border-box; - display: flex; - align-items: center; - color: #4c6275; -`; - -export const Wrapper = styled('li')<{ +export const TreeItemContainer = styled('div')<{ spacing: string; clone?: boolean; ghost?: boolean; - indicator?: boolean; disableSelection?: boolean; disableInteraction?: boolean; active?: boolean; }>` + display: flex; + align-items: center; + color: #4c6275; + box-sizing: border-box; padding-left: ${({ spacing }) => spacing}; list-style: none; @@ -26,21 +22,13 @@ export const Wrapper = styled('li')<{ ${({ clone, disableSelection }) => (clone || disableSelection) && - `width: 100%; - .Text, - .Count { - user-select: none; - -webkit-user-select: none; - }`} - - ${({ indicator }) => - indicator && - `width: 100%; - .Text, - .Count { - user-select: none; - -webkit-user-select: none; - }`} + ` + width: 100%; + user-select: none; + opacity: 0.7; + background: transparent; + cursor: grab; + `} ${({ disableInteraction }) => disableInteraction && `pointer-events: none;`} @@ -48,64 +36,6 @@ export const Wrapper = styled('li')<{ background: #f5f7f8; border-radius: 5px; } - - &.clone { - display: inline-block; - padding: 0; - margin-left: 10px; - margin-top: 5px; - pointer-events: none; - - ${TreeItemContainer} { - padding-right: 20px; - border-radius: 4px; - box-shadow: 0px 15px 15px 0 rgba(34, 33, 81, 0.1); - } - } - - &.ghost { - &.indicator { - opacity: 1; - position: relative; - z-index: 1; - margin-bottom: -1px; - - ${TreeItemContainer} { - position: relative; - padding: 0; - height: 8px; - border-color: #2389ff; - background-color: #56a1f8; - - &:before { - position: absolute; - left: -8px; - top: -4px; - display: block; - content: ''; - width: 12px; - height: 12px; - border-radius: 50%; - border: 1px solid #2389ff; - } - - > * { - /* Items are hidden using height and opacity to retain focus */ - opacity: 0; - height: 0; - } - } - } - - &:not(.indicator) { - opacity: 0.5; - } - - ${TreeItemContainer} > * { - box-shadow: none; - background-color: transparent; - } - } `; export const Counter = styled('span')` @@ -138,7 +68,7 @@ export const ActionButton = styled('button')<{ border: none; outline: none; appearance: none; - background-color: transparent; + background: transparent; -webkit-tap-highlight-color: transparent; svg { @@ -151,8 +81,7 @@ export const ActionButton = styled('button')<{ } &:active { - background-color: ${({ background }) => - background ?? 'rgba(0, 0, 0, 0.05)'}; + background: ${({ background }) => background ?? 'rgba(0, 0, 0, 0.05)'}; svg { fill: ${({ fill }) => fill ?? '#788491'}; @@ -170,9 +99,7 @@ export const TreeItemMoreActions = styled('div')` visibility: hidden; `; -export const TextLink = styled(Link, { - shouldForwardProp: (prop: string) => !['active'].includes(prop), -})<{ active?: boolean }>` +export const TextLink = styled(Link)` display: flex; align-items: center; flex-grow: 1; From e47268bb8b0a6559527436e7b9d8e810c58b46f4 Mon Sep 17 00:00:00 2001 From: xiaodong zuo Date: Fri, 12 Aug 2022 16:41:37 +0800 Subject: [PATCH 3/9] fix: link style issues --- libs/components/common/src/lib/text/plugins/link.tsx | 11 ++++++----- .../editor-blocks/src/blocks/page/PageView.tsx | 3 +++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/libs/components/common/src/lib/text/plugins/link.tsx b/libs/components/common/src/lib/text/plugins/link.tsx index 60193e38a0..5c1425460d 100644 --- a/libs/components/common/src/lib/text/plugins/link.tsx +++ b/libs/components/common/src/lib/text/plugins/link.tsx @@ -25,7 +25,6 @@ import { ReactEditor } from 'slate-react'; import OpenInNewIcon from '@mui/icons-material/OpenInNew'; import EditIcon from '@mui/icons-material/Edit'; import LinkOffIcon from '@mui/icons-material/LinkOff'; -import AttachmentIcon from '@mui/icons-material/Attachment'; import { MuiTooltip as Tooltip, styled, @@ -39,7 +38,7 @@ import { import { getRandomString } from '../utils'; import { colors } from '../../colors'; - +import { LinkIcon } from '@toeverything/components/icons'; export type LinkElement = { type: 'link'; url: string; @@ -124,7 +123,7 @@ const LinkStyledTooltip = styled(({ className, ...props }: MuiTooltipProps) => ( ))(({ theme }) => ({ [`& .${muiTooltipClasses.tooltip}`]: { backgroundColor: '#fff', - color: '#4C6275', + color: '#3E6FDB', boxShadow: theme.affine.shadows.shadow1, fontSize: '14px', }, @@ -419,8 +418,8 @@ export const LinkModal = memo((props: LinkModalProps) => { }} >
-
({ const styles = style9.create({ linkModalContainerIcon: { + display: 'flex', width: '16px', margin: '0 16px 0 4px', }, @@ -517,6 +517,7 @@ const styles = style9.create({ '::-webkit-input-placeholder': { color: '#98acbd', }, + color: '#4C6275', }, linkMask: { position: 'fixed', diff --git a/libs/components/editor-blocks/src/blocks/page/PageView.tsx b/libs/components/editor-blocks/src/blocks/page/PageView.tsx index 64ea3c9536..4d5de824cf 100644 --- a/libs/components/editor-blocks/src/blocks/page/PageView.tsx +++ b/libs/components/editor-blocks/src/blocks/page/PageView.tsx @@ -119,5 +119,8 @@ const PageTitleBlock = styled('div')(({ theme }) => { '.content': { outline: 'none', }, + a: { + color: '#3e6fdb', + }, }; }); From 174779bb28176b6b7ddca33c56a9329fdfd31334 Mon Sep 17 00:00:00 2001 From: xiaodong zuo Date: Fri, 12 Aug 2022 16:49:17 +0800 Subject: [PATCH 4/9] fix: link style issues --- libs/components/common/src/lib/text/plugins/link.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/components/common/src/lib/text/plugins/link.tsx b/libs/components/common/src/lib/text/plugins/link.tsx index 5c1425460d..619239c64d 100644 --- a/libs/components/common/src/lib/text/plugins/link.tsx +++ b/libs/components/common/src/lib/text/plugins/link.tsx @@ -507,6 +507,7 @@ const styles = style9.create({ display: 'flex', width: '16px', margin: '0 16px 0 4px', + color: '#4C6275', }, linkModalContainerInput: { flex: '1', From edfa95057b47af1fca828268df6bc55a8ec578a3 Mon Sep 17 00:00:00 2001 From: DarkSky Date: Fri, 12 Aug 2022 16:54:47 +0800 Subject: [PATCH 5/9] feat: optional provider --- apps/ligo-virgo/src/pages/RoutePrivate.tsx | 2 +- libs/components/account/src/login/fs.tsx | 8 +- libs/components/account/src/login/index.tsx | 3 +- .../layout/src/header/FileSystem.tsx | 112 ++++++++++++++++++ .../layout/src/header/LayoutHeader.tsx | 6 +- .../db-service/src/services/database/index.ts | 13 +- libs/datasource/jwt/src/adapter/yjs/index.ts | 42 ++++--- .../jwt/src/adapter/yjs/provider.ts | 97 ++++++++------- libs/datasource/jwt/src/index.ts | 1 + libs/datasource/state/src/user.ts | 21 +++- pnpm-lock.yaml | 47 +++++++- 11 files changed, 267 insertions(+), 85 deletions(-) create mode 100644 libs/components/layout/src/header/FileSystem.tsx diff --git a/apps/ligo-virgo/src/pages/RoutePrivate.tsx b/apps/ligo-virgo/src/pages/RoutePrivate.tsx index 58dcbe3db5..a7cedac934 100644 --- a/apps/ligo-virgo/src/pages/RoutePrivate.tsx +++ b/apps/ligo-virgo/src/pages/RoutePrivate.tsx @@ -23,7 +23,7 @@ export function RoutePrivate({ return ; } - if (!user) { + if (!user || !pathname.startsWith(`/${user.id}`)) { return ( { }; export const FileSystem = (props: { onError: () => void }) => { - const onSelected = useLocalTrigger(); + const [, onSelected] = useLocalTrigger(); const apiSupported = useMemo(() => { try { @@ -56,12 +56,6 @@ export const FileSystem = (props: { onError: () => void }) => { } }, []); - useEffect(() => { - if (process.env['NX_E2E']) { - onSelected(); - } - }, []); - return ( - {' '} + new Promise((resolve, reject) => { + const req = indexedDB.deleteDatabase(workspace); + req.addEventListener('error', e => reject(e)); + req.addEventListener('blocked', e => reject(e)); + req.addEventListener('upgradeneeded', e => reject(e)); + req.addEventListener('success', e => resolve(e)); + }); + +const requestPermission = async (workspace: string) => { + await cleanupWorkspace(workspace); + const dirHandler = await window.showDirectoryPicker({ + id: 'AFFiNE_' + workspace, + mode: 'readwrite', + startIn: 'documents', + }); + + const fileHandle = await dirHandler.getFileHandle('affine.db', { + create: true, + }); + const file = await fileHandle.getFile(); + const initialData = new Uint8Array(await file.arrayBuffer()); + + const exporter = async (contents: Uint8Array) => { + try { + const writable = await fileHandle.createWritable(); + await writable.write(contents); + await writable.close(); + } catch (e) { + console.log(e); + } + }; + + await services.api.editorBlock.setupDataExporter( + workspace, + new Uint8Array(initialData), + exporter + ); +}; + +const StyledFileSystem = styled('div')<{ disabled?: boolean }>({ + padding: '10px 12px', + fontWeight: 600, + fontSize: '14px', + color: '#3E6FDB', + textTransform: 'uppercase', + cursor: 'pointer', + '&:hover': { + background: '#F5F7F8', + borderRadius: '5px', + }, +}); + +export const FileSystem = () => { + const [selected, onSelected] = useLocalTrigger(); + const [error, setError] = useState(false); + + const onError = useCallback(() => { + setError(true); + setTimeout(() => setError(false), 3000); + }, []); + + const apiSupported = useMemo(() => { + try { + return 'showOpenFilePicker' in window; + } catch (e) { + return false; + } + }, []); + + if (apiSupported && !selected) { + return ( + <> + setError(false)} + > + + + } + /> + { + try { + await requestPermission('AFFiNE'); + onSelected(); + } catch (e) { + onError(); + } + }} + > + Sync to Disk + + + ); + } + return null; +}; diff --git a/libs/components/layout/src/header/LayoutHeader.tsx b/libs/components/layout/src/header/LayoutHeader.tsx index beade0de0d..bc33736157 100644 --- a/libs/components/layout/src/header/LayoutHeader.tsx +++ b/libs/components/layout/src/header/LayoutHeader.tsx @@ -1,4 +1,4 @@ -import { IconButton, styled, MuiButton } from '@toeverything/components/ui'; +import { IconButton, styled } from '@toeverything/components/ui'; import { LogoIcon, SideBarViewIcon, @@ -7,8 +7,9 @@ import { } from '@toeverything/components/icons'; import { useShowSettingsSidebar } from '@toeverything/datasource/state'; -import { CurrentPageTitle } from './Title'; import { EditorBoardSwitcher } from './EditorBoardSwitcher'; +import { FileSystem } from './FileSystem'; +import { CurrentPageTitle } from './Title'; export const LayoutHeader = () => { const { toggleSettingsSidebar: toggleInfoSidebar, showSettingsSidebar } = @@ -25,6 +26,7 @@ export const LayoutHeader = () => { + Share
void; + type YjsProviders = { awareness: Awareness; - idb: IndexedDBProvider; - binariesIdb: IndexedDBProvider; + binaries: Doc; + doc: Doc; gatekeeper: GateKeeper; connListener: { listeners?: ConnectivityListener }; userId: string; remoteToken?: string; // remote storage token }; + const _yjsDatabaseInstance = new Map(); const _asyncInitLoading = new Set(); @@ -90,13 +90,9 @@ async function _initYjsDatabase( const { userId, token } = options; const doc = new Doc({ autoLoad: true, shouldLoad: true }); - const idb = await new IndexedDBProvider(workspace, doc).whenSynced; + // const idb = await new IndexedDBProvider(workspace, doc).whenSynced; const binaries = new Doc({ autoLoad: true, shouldLoad: true }); - const binariesIdb = await new IndexedDBProvider( - `${workspace}_binaries`, - binaries - ).whenSynced; const awareness = new Awareness(doc); @@ -114,16 +110,24 @@ async function _initYjsDatabase( const emitState = (c: Connectivity) => connListener.listeners?.(workspace, c); await Promise.all( - Object.entries(options.provider).map(async ([, p]) => - p({ awareness, doc, token, workspace, emitState }) - ) + Object.entries(options.provider).flatMap(async ([, p]) => [ + p({ awareness, doc, token, workspace, emitState }), + p({ + awareness, + doc: binaries, + token, + workspace: `${workspace}_binaries`, + emitState, + }), + ]) ); } const newInstance = { awareness, - idb, - binariesIdb, + binaries, + doc, gatekeeper, + connListener, userId, remoteToken: token, @@ -183,7 +187,7 @@ export class YjsAdapter implements AsyncDatabaseAdapter { private constructor(providers: YjsProviders) { this._provider = providers; - this._doc = providers.idb.doc; + this._doc = providers.doc; this._awareness = providers.awareness; this._gatekeeper = providers.gatekeeper; this._reload = () => { @@ -201,7 +205,7 @@ export class YjsAdapter implements AsyncDatabaseAdapter { }); // @ts-ignore this._binaries = new YjsRemoteBinaries( - providers.binariesIdb.doc.getMap(), + providers.binaries.getMap(), providers.remoteToken ); // @ts-ignore @@ -336,7 +340,7 @@ export class YjsAdapter implements AsyncDatabaseAdapter { }); const [file] = (await fromEvent(handles)) as File[]; const binary = await file.arrayBuffer(); - await this._provider.idb.clearData(); + // await this._provider.idb.clearData(); const doc = new Doc({ autoLoad: true, shouldLoad: true }); let updated = 0; let isUpdated = false; @@ -357,8 +361,8 @@ export class YjsAdapter implements AsyncDatabaseAdapter { }; check(); }); - await new IndexedDBProvider(this._provider.idb.name, doc) - .whenSynced; + // await new IndexedDBProvider(this._provider.idb.name, doc) + // .whenSynced; applyUpdate(doc, new Uint8Array(binary)); await update_check; console.log('load success'); diff --git a/libs/datasource/jwt/src/adapter/yjs/provider.ts b/libs/datasource/jwt/src/adapter/yjs/provider.ts index f7068288fd..e4cebd1f01 100644 --- a/libs/datasource/jwt/src/adapter/yjs/provider.ts +++ b/libs/datasource/jwt/src/adapter/yjs/provider.ts @@ -2,6 +2,7 @@ import { Doc } from 'yjs'; import { Awareness } from 'y-protocols/awareness.js'; import { + IndexedDBProvider, SQLiteProvider, WebsocketProvider, } from '@toeverything/datasource/jwt-rpc'; @@ -19,7 +20,10 @@ type YjsDefaultInstances = { export type YjsProvider = (instances: YjsDefaultInstances) => Promise; +type ProviderType = 'idb' | 'sqlite' | 'ws'; + export type YjsProviderOptions = { + enabled: ProviderType[]; backend: typeof BucketBackend[keyof typeof BucketBackend]; params?: Record; importData?: () => Promise | Uint8Array | undefined; @@ -30,53 +34,64 @@ export type YjsProviderOptions = { export const getYjsProviders = ( options: YjsProviderOptions ): Record => { + console.log('getYjsProviders', options); return { + indexeddb: async (instances: YjsDefaultInstances) => { + if (options.enabled.includes('idb')) { + await new IndexedDBProvider(instances.workspace, instances.doc) + .whenSynced; + } + }, sqlite: async (instances: YjsDefaultInstances) => { - const fsHandle = setInterval(async () => { - if (options.hasExporter?.()) { - clearInterval(fsHandle); - const fs = new SQLiteProvider( - instances.workspace, - instances.doc, - await options.importData?.() - ); - if (options.exportData) { - fs.registerExporter(options.exportData); + if (options.enabled.includes('sqlite')) { + const fsHandle = setInterval(async () => { + if (options.hasExporter?.()) { + clearInterval(fsHandle); + const fs = new SQLiteProvider( + instances.workspace, + instances.doc, + await options.importData?.() + ); + if (options.exportData) { + fs.registerExporter(options.exportData); + } + await fs.whenSynced; } - await fs.whenSynced; - } - }, 500); + }, 500); + } }, ws: async (instances: YjsDefaultInstances) => { - if (instances.token) { - const ws = new WebsocketProvider( - instances.token, - options.backend, - instances.workspace, - instances.doc, - { - awareness: instances.awareness, - params: options.params, - } - ) as any; // TODO: type is erased after cascading references + if (options.enabled.includes('ws')) { + if (instances.token) { + const ws = new WebsocketProvider( + instances.token, + options.backend, + instances.workspace, + instances.doc, + { + awareness: instances.awareness, + params: options.params, + } + ) as any; // TODO: type is erased after cascading references - // Wait for ws synchronization to complete, otherwise the data will be modified in reverse, which can be optimized later - return new Promise((resolve, reject) => { - // TODO: synced will also be triggered on reconnection after losing sync - // There needs to be an event mechanism to emit the synchronization state to the upper layer - ws.once('synced', () => resolve()); - ws.once('lost-connection', () => resolve()); - ws.once('connection-error', () => reject()); - ws.on('synced', () => instances.emitState('connected')); - ws.on('lost-connection', () => - instances.emitState('retry') - ); - ws.on('connection-error', () => - instances.emitState('retry') - ); - }); - } else { - return; + // Wait for ws synchronization to complete, otherwise the data will be modified in reverse, which can be optimized later + return new Promise((resolve, reject) => { + // TODO: synced will also be triggered on reconnection after losing sync + // There needs to be an event mechanism to emit the synchronization state to the upper layer + ws.once('synced', () => resolve()); + ws.once('lost-connection', () => resolve()); + ws.once('connection-error', () => reject()); + ws.on('synced', () => instances.emitState('connected')); + ws.on('lost-connection', () => + instances.emitState('retry') + ); + ws.on('connection-error', () => + instances.emitState('retry') + ); + }); + } else { + return; + } } }, }; diff --git a/libs/datasource/jwt/src/index.ts b/libs/datasource/jwt/src/index.ts index ecad7aebf9..38bc11396e 100644 --- a/libs/datasource/jwt/src/index.ts +++ b/libs/datasource/jwt/src/index.ts @@ -618,6 +618,7 @@ export class BlockClient< const instance = await YjsAdapter.init(workspace, { provider: getYjsProviders({ + enabled: [], backend: BucketBackend.YjsWebSocketAffine, importData, exportData, diff --git a/libs/datasource/state/src/user.ts b/libs/datasource/state/src/user.ts index fefb689f0a..d32fef2c56 100644 --- a/libs/datasource/state/src/user.ts +++ b/libs/datasource/state/src/user.ts @@ -1,3 +1,4 @@ +import { useNavigate } from 'react-router'; import { getAuth, onAuthStateChanged, @@ -62,11 +63,17 @@ const BRAND_ID = 'AFFiNE'; const _localTrigger = atom(false); const _useUserAndSpacesForFreeLogin = () => { + const navigate = useNavigate(); const [user, setUser] = useAtom(_userAtom); const [loading, setLoading] = useAtom(_loadingAtom); const [localTrigger] = useAtom(_localTrigger); - useEffect(() => setLoading(false), []); + useEffect(() => { + if (loading) { + navigate('/demo'); + setLoading(false); + } + }, []); useEffect(() => { if (localTrigger) { @@ -77,6 +84,14 @@ const _useUserAndSpacesForFreeLogin = () => { nickname: BRAND_ID, email: '', }); + } else { + setUser({ + photo: '', + id: 'demo', + username: 'demo', + nickname: 'demo', + email: '', + }); } }, [localTrigger, setLoading, setUser]); @@ -86,8 +101,8 @@ const _useUserAndSpacesForFreeLogin = () => { }; export const useLocalTrigger = () => { - const [, setTrigger] = useAtom(_localTrigger); - return () => setTrigger(true); + const [trigger, setTrigger] = useAtom(_localTrigger); + return [trigger, () => setTrigger(true)] as [boolean, () => void]; }; export const useUserAndSpaces = process.env['NX_LOCAL'] diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dacfe065aa..a632fb99bd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -194,7 +194,7 @@ importers: yjs: ^13.5.41 dependencies: authing-js-sdk: 4.23.35 - firebase-admin: 11.0.1_@firebase+app-types@0.7.0 + firebase-admin: 11.0.1 lib0: 0.2.52 lru-cache: 7.13.2 nanoid: 4.0.0 @@ -571,6 +571,9 @@ importers: dependencies: ffc-js-client-side-sdk: 1.1.5 + libs/datasource/jwst/pkg: + specifiers: {} + libs/datasource/jwt: specifiers: '@types/debug': ^4.1.7 @@ -3291,6 +3294,15 @@ packages: - utf-8-validate dev: true + /@firebase/auth-interop-types/0.1.6_@firebase+util@1.6.3: + resolution: {integrity: sha512-etIi92fW3CctsmR9e3sYM3Uqnoq861M0Id9mdOPF6PWIg38BXL5k4upCNBggGUpLIS0H1grMOvy/wn1xymwe2g==} + peerDependencies: + '@firebase/app-types': 0.x + '@firebase/util': 1.x + dependencies: + '@firebase/util': 1.6.3 + dev: false + /@firebase/auth-interop-types/0.1.6_pbfwexsq7uf6mrzcwnikj3g37m: resolution: {integrity: sha512-etIi92fW3CctsmR9e3sYM3Uqnoq861M0Id9mdOPF6PWIg38BXL5k4upCNBggGUpLIS0H1grMOvy/wn1xymwe2g==} peerDependencies: @@ -3299,6 +3311,7 @@ packages: dependencies: '@firebase/app-types': 0.7.0 '@firebase/util': 1.6.3 + dev: true /@firebase/auth-types/0.11.0_pbfwexsq7uf6mrzcwnikj3g37m: resolution: {integrity: sha512-q7Bt6cx+ySj9elQHTsKulwk3+qDezhzRBFC9zlQ1BjgMueUOnGMcvqmU0zuKlQ4RhLSH7MNAdBV2znVaoN3Vxw==} @@ -3334,6 +3347,19 @@ packages: '@firebase/util': 1.6.3 tslib: 2.4.0 + /@firebase/database-compat/0.2.4: + resolution: {integrity: sha512-VtsGixO5mTjNMJn6PwxAJEAR70fj+3blCXIdQKel3q+eYGZAfdqxox1+tzZDnf9NWBJpaOgAHPk3JVDxEo9NFQ==} + dependencies: + '@firebase/component': 0.5.17 + '@firebase/database': 0.13.4 + '@firebase/database-types': 0.9.12 + '@firebase/logger': 0.3.3 + '@firebase/util': 1.6.3 + tslib: 2.4.0 + transitivePeerDependencies: + - '@firebase/app-types' + dev: false + /@firebase/database-compat/0.2.4_@firebase+app-types@0.7.0: resolution: {integrity: sha512-VtsGixO5mTjNMJn6PwxAJEAR70fj+3blCXIdQKel3q+eYGZAfdqxox1+tzZDnf9NWBJpaOgAHPk3JVDxEo9NFQ==} dependencies: @@ -3345,6 +3371,7 @@ packages: tslib: 2.4.0 transitivePeerDependencies: - '@firebase/app-types' + dev: true /@firebase/database-types/0.9.10: resolution: {integrity: sha512-2ji6nXRRsY+7hgU6zRhUtK0RmSjVWM71taI7Flgaw+BnopCo/lDF5HSwxp8z7LtiHlvQqeRA3Ozqx5VhlAbiKg==} @@ -3359,6 +3386,19 @@ packages: '@firebase/app-types': 0.7.0 '@firebase/util': 1.6.3 + /@firebase/database/0.13.4: + resolution: {integrity: sha512-NW7bOoiaC4sJCj6DY/m9xHoFNa0CK32YPMCh6FiMweLCDQbOZM8Ql/Kn6yyuxCb7K7ypz9eSbRlCWQJsJRQjhg==} + dependencies: + '@firebase/auth-interop-types': 0.1.6_@firebase+util@1.6.3 + '@firebase/component': 0.5.17 + '@firebase/logger': 0.3.3 + '@firebase/util': 1.6.3 + faye-websocket: 0.11.4 + tslib: 2.4.0 + transitivePeerDependencies: + - '@firebase/app-types' + dev: false + /@firebase/database/0.13.4_@firebase+app-types@0.7.0: resolution: {integrity: sha512-NW7bOoiaC4sJCj6DY/m9xHoFNa0CK32YPMCh6FiMweLCDQbOZM8Ql/Kn6yyuxCb7K7ypz9eSbRlCWQJsJRQjhg==} dependencies: @@ -3370,6 +3410,7 @@ packages: tslib: 2.4.0 transitivePeerDependencies: - '@firebase/app-types' + dev: true /@firebase/firestore-compat/0.1.23_53yvy43rwpg2c45kgeszsxtrca: resolution: {integrity: sha512-QfcuyMAavp//fQnjSfCEpnbWi7spIdKaXys1kOLu7395fLr+U6ykmto1HUMCSz8Yus9cEr/03Ujdi2SUl2GUAA==} @@ -10863,12 +10904,12 @@ packages: semver-regex: 2.0.0 dev: true - /firebase-admin/11.0.1_@firebase+app-types@0.7.0: + /firebase-admin/11.0.1: resolution: {integrity: sha512-rL3wlZbi2Kb/KJgcmj1YHlD4ZhfmhfgRO2YJialxAllm0tj1IQea878hHuBLGmv4DpbW9t9nLvX9kddNR2Y65Q==} engines: {node: '>=14'} dependencies: '@fastify/busboy': 1.1.0 - '@firebase/database-compat': 0.2.4_@firebase+app-types@0.7.0 + '@firebase/database-compat': 0.2.4 '@firebase/database-types': 0.9.10 '@types/node': 18.0.1 jsonwebtoken: 8.5.1 From ce0590449a89bcb4486ba5471e61ba7216841b9d Mon Sep 17 00:00:00 2001 From: DiamondThree Date: Fri, 12 Aug 2022 17:04:12 +0800 Subject: [PATCH 6/9] fix:setTimeout error (#215) --- .../editor-core/src/editor/selection/selection.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libs/components/editor-core/src/editor/selection/selection.ts b/libs/components/editor-core/src/editor/selection/selection.ts index 38d7f86b0f..406f9adecb 100644 --- a/libs/components/editor-core/src/editor/selection/selection.ts +++ b/libs/components/editor-core/src/editor/selection/selection.ts @@ -48,7 +48,7 @@ export class SelectionManager implements VirgoSelection { private _scrollDelay = 150; private _selectEndDelayTime = 500; private _hasEmitEndPending = false; - + private _scrollTimer: number | null = null; /** * * the selection info before current @@ -681,6 +681,9 @@ export class SelectionManager implements VirgoSelection { */ public async activeNodeByNodeId(nodeId: string, position?: CursorTypes) { try { + if (this._scrollTimer) { + clearTimeout(this._scrollTimer); + } const node = await this._editor.getBlockById(nodeId); if (node) { this._activatedNodeId = nodeId; @@ -689,7 +692,7 @@ export class SelectionManager implements VirgoSelection { } this.emit(nodeId, SelectEventTypes.active, this.lastPoint); // TODO: Optimize the related logic after implementing the scroll bar - setTimeout(() => { + this._scrollTimer = window.setTimeout(() => { this._editor.scrollManager.keepBlockInView(node); }, this._scrollDelay); } else { From 06d4dbc99b5ed75523c136028482e25e367968c6 Mon Sep 17 00:00:00 2001 From: xiaodong zuo Date: Fri, 12 Aug 2022 17:06:21 +0800 Subject: [PATCH 7/9] fix: link style issues --- libs/components/editor-blocks/src/blocks/page/PageView.tsx | 3 --- .../editor-blocks/src/components/text-manage/TextManage.tsx | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/components/editor-blocks/src/blocks/page/PageView.tsx b/libs/components/editor-blocks/src/blocks/page/PageView.tsx index 4d5de824cf..64ea3c9536 100644 --- a/libs/components/editor-blocks/src/blocks/page/PageView.tsx +++ b/libs/components/editor-blocks/src/blocks/page/PageView.tsx @@ -119,8 +119,5 @@ const PageTitleBlock = styled('div')(({ theme }) => { '.content': { outline: 'none', }, - a: { - color: '#3e6fdb', - }, }; }); diff --git a/libs/components/editor-blocks/src/components/text-manage/TextManage.tsx b/libs/components/editor-blocks/src/components/text-manage/TextManage.tsx index 99179220a9..f433c1fba9 100644 --- a/libs/components/editor-blocks/src/components/text-manage/TextManage.tsx +++ b/libs/components/editor-blocks/src/components/text-manage/TextManage.tsx @@ -42,6 +42,9 @@ const TextBlockContainer = styled(Text)(({ theme }) => ({ fontFamily: theme.affine.typography.body1.fontFamily, color: theme.affine.typography.body1.color, letterSpacing: '0.1px', + a: { + color: '#3e6fdb', + }, })); const findSlice = (arr: string[], p: string, q: string) => { From c0c042dac0bcdcef23cc1341d82b2b3035e2d69e Mon Sep 17 00:00:00 2001 From: DarkSky Date: Fri, 12 Aug 2022 17:49:39 +0800 Subject: [PATCH 8/9] feat: warning tips --- apps/venus/src/app/index.tsx | 2 +- .../layout/src/header/FileSystem.tsx | 16 ++++++------ .../layout/src/header/LayoutHeader.tsx | 25 ++++++++++++++----- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/apps/venus/src/app/index.tsx b/apps/venus/src/app/index.tsx index e3b4a76c90..6939299dfd 100644 --- a/apps/venus/src/app/index.tsx +++ b/apps/venus/src/app/index.tsx @@ -27,7 +27,7 @@ const DiscordIcon = (props: any) => { viewBox="0 0 71 55" fill="currentcolor" > - + ({ }, }); +export const fsApiSupported = () => { + try { + return 'showOpenFilePicker' in window; + } catch (e) { + return false; + } +}; + export const FileSystem = () => { const [selected, onSelected] = useLocalTrigger(); const [error, setError] = useState(false); @@ -68,13 +76,7 @@ export const FileSystem = () => { setTimeout(() => setError(false), 3000); }, []); - const apiSupported = useMemo(() => { - try { - return 'showOpenFilePicker' in window; - } catch (e) { - return false; - } - }, []); + const apiSupported = useMemo(() => fsApiSupported(), []); if (apiSupported && !selected) { return ( diff --git a/libs/components/layout/src/header/LayoutHeader.tsx b/libs/components/layout/src/header/LayoutHeader.tsx index bc33736157..f933348407 100644 --- a/libs/components/layout/src/header/LayoutHeader.tsx +++ b/libs/components/layout/src/header/LayoutHeader.tsx @@ -1,3 +1,5 @@ +import { useMemo } from 'react'; + import { IconButton, styled } from '@toeverything/components/ui'; import { LogoIcon, @@ -5,16 +7,30 @@ import { SearchIcon, SideBarViewCloseIcon, } from '@toeverything/components/icons'; -import { useShowSettingsSidebar } from '@toeverything/datasource/state'; +import { + useShowSettingsSidebar, + useLocalTrigger, +} from '@toeverything/datasource/state'; import { EditorBoardSwitcher } from './EditorBoardSwitcher'; -import { FileSystem } from './FileSystem'; +import { fsApiSupported, FileSystem } from './FileSystem'; import { CurrentPageTitle } from './Title'; export const LayoutHeader = () => { + const [isLocalWorkspace] = useLocalTrigger(); const { toggleSettingsSidebar: toggleInfoSidebar, showSettingsSidebar } = useShowSettingsSidebar(); + const warningTips = useMemo(() => { + if (!fsApiSupported()) { + return 'Your browser does not support the local storage feature, please upgrade to the latest version of Chrome or Edge browser'; + } else if (isLocalWorkspace) { + return 'You are in DEMO mode. Changes will NOT be saved unless you SYNC TO DISK'; + } else { + return 'AFFiNE is under active development and the current version is UNSTABLE. Please DO NOT store information or data'; + } + }, [isLocalWorkspace]); + return ( @@ -53,10 +69,7 @@ export const LayoutHeader = () => { - - AFFiNE is currently under active development. This build is - UNSTABLE. Please DO NOT store important data. - + {warningTips} ); From dc98d4042befa122dbde0147c73b849a80103e5a Mon Sep 17 00:00:00 2001 From: DarkSky Date: Fri, 12 Aug 2022 17:57:40 +0800 Subject: [PATCH 9/9] fix: types --- libs/components/account/src/login/fs.tsx | 1 + libs/components/layout/src/header/FileSystem.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/libs/components/account/src/login/fs.tsx b/libs/components/account/src/login/fs.tsx index bdccdd47ee..2482e5187c 100644 --- a/libs/components/account/src/login/fs.tsx +++ b/libs/components/account/src/login/fs.tsx @@ -17,6 +17,7 @@ const cleanupWorkspace = (workspace: string) => const requestPermission = async (workspace: string) => { await cleanupWorkspace(workspace); + // @ts-ignore const dirHandler = await window.showDirectoryPicker({ id: 'AFFiNE_' + workspace, mode: 'readwrite', diff --git a/libs/components/layout/src/header/FileSystem.tsx b/libs/components/layout/src/header/FileSystem.tsx index a29ad9ea94..83c638c5b3 100644 --- a/libs/components/layout/src/header/FileSystem.tsx +++ b/libs/components/layout/src/header/FileSystem.tsx @@ -17,6 +17,7 @@ const cleanupWorkspace = (workspace: string) => const requestPermission = async (workspace: string) => { await cleanupWorkspace(workspace); + // @ts-ignore const dirHandler = await window.showDirectoryPicker({ id: 'AFFiNE_' + workspace, mode: 'readwrite',