diff --git a/.github/workflows/nightly-build.yml b/.github/workflows/nightly-build.yml index 0e7745ae06..a2070cf4c2 100644 --- a/.github/workflows/nightly-build.yml +++ b/.github/workflows/nightly-build.yml @@ -1,6 +1,7 @@ name: Build Canary Desktop App on Staging Branch on: + workflow_dispatch: push: branches: # 0.6.x-staging diff --git a/apps/core/package.json b/apps/core/package.json index ac8689eaef..f256c2d969 100644 --- a/apps/core/package.json +++ b/apps/core/package.json @@ -60,7 +60,7 @@ "react-resizable-panels": "^0.0.55", "react-router-dom": "^6.15.0", "rxjs": "^7.8.1", - "ses": "^0.18.7", + "ses": "^0.18.8", "swr": "2.2.1", "y-protocols": "^1.0.5", "yjs": "^13.6.7", diff --git a/apps/core/src/atoms/settings.ts b/apps/core/src/atoms/settings.ts index 84b4ffacef..6ea4af9177 100644 --- a/apps/core/src/atoms/settings.ts +++ b/apps/core/src/atoms/settings.ts @@ -1,4 +1,3 @@ -import { isDesktop } from '@affine/env/constant'; import { atom, useAtom } from 'jotai'; import { atomWithStorage } from 'jotai/utils'; @@ -50,7 +49,7 @@ export const fontStyleOptions = [ }[]; const appSettingBaseAtom = atomWithStorage('affine-settings', { - clientBorder: isDesktop, + clientBorder: environment.isDesktop && globalThis.platform !== 'win32', fullWidthLayout: false, windowFrameStyle: 'frameless', fontStyle: 'Sans', diff --git a/apps/core/src/components/affine/create-workspace-modal/index.tsx b/apps/core/src/components/affine/create-workspace-modal/index.tsx index d40da0922f..e7cb0422b0 100644 --- a/apps/core/src/components/affine/create-workspace-modal/index.tsx +++ b/apps/core/src/components/affine/create-workspace-modal/index.tsx @@ -281,11 +281,7 @@ export const CreateWorkspaceModal = ({ console.error(err); }); } else if (mode === 'new') { - setStep( - environment.isDesktop && runtimeConfig.enableSQLiteProvider - ? 'set-db-location' - : 'name-workspace' - ); + setStep('name-workspace'); } else { setStep(undefined); } diff --git a/apps/core/src/components/affine/setting-modal/general-setting/shortcuts/style.css.ts b/apps/core/src/components/affine/setting-modal/general-setting/shortcuts/style.css.ts index a6a1058738..85a32944f9 100644 --- a/apps/core/src/components/affine/setting-modal/general-setting/shortcuts/style.css.ts +++ b/apps/core/src/components/affine/setting-modal/general-setting/shortcuts/style.css.ts @@ -24,11 +24,8 @@ export const shortcutKey = style({ 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)': { diff --git a/apps/core/src/components/blocksuite/block-suite-header-title/styles.css.ts b/apps/core/src/components/blocksuite/block-suite-header-title/styles.css.ts index abbcfb5a7d..f59ac8413b 100644 --- a/apps/core/src/components/blocksuite/block-suite-header-title/styles.css.ts +++ b/apps/core/src/components/blocksuite/block-suite-header-title/styles.css.ts @@ -25,6 +25,15 @@ export const titleInput = style({ margin: 'auto', width: '100%', height: '100%', + + selectors: { + '&:focus': { + border: '1px solid var(--affine-black-10)', + borderRadius: '8px', + height: '32px', + padding: '6px 8px', + }, + }, }); export const shadowTitle = style({ visibility: 'hidden', diff --git a/apps/core/src/components/pure/workspace-slider-bar/collections/add-collection-button.tsx b/apps/core/src/components/pure/workspace-slider-bar/collections/add-collection-button.tsx index a4db2a288b..c2e0aef789 100644 --- a/apps/core/src/components/pure/workspace-slider-bar/collections/add-collection-button.tsx +++ b/apps/core/src/components/pure/workspace-slider-bar/collections/add-collection-button.tsx @@ -51,7 +51,7 @@ export const AddCollectionButton = ({ onConfirm={setting.saveCollection} open={show} onClose={() => showUpdateCollection(false)} - title={t['Save As New Collection']()} + title={t['Save as New Collection']()} init={defaultCollection} /> diff --git a/apps/core/src/providers/modal-provider.tsx b/apps/core/src/providers/modal-provider.tsx index 6c9dda5663..94e650cea8 100644 --- a/apps/core/src/providers/modal-provider.tsx +++ b/apps/core/src/providers/modal-provider.tsx @@ -8,7 +8,13 @@ import { } from '@toeverything/infra/atom'; import { useAtom, useAtomValue, useSetAtom } from 'jotai'; import type { ReactElement } from 'react'; -import { lazy, Suspense, useCallback, useTransition } from 'react'; +import { + lazy, + startTransition, + Suspense, + useCallback, + useTransition, +} from 'react'; import type { SettingAtom } from '../atoms'; import { @@ -119,13 +125,14 @@ export const AllWorkspaceModals = (): ReactElement => { ); const { jumpToSubPath } = useNavigateHelper(); - const workspaces = useAtomValue(rootWorkspacesMetadataAtom); + const workspaces = useAtomValue(rootWorkspacesMetadataAtom, { + delay: 0, + }); const setWorkspaces = useSetAtom(rootWorkspacesMetadataAtom); const [currentWorkspaceId, setCurrentWorkspaceId] = useAtom( currentWorkspaceIdAtom ); const setCurrentPageId = useSetAtom(currentPageIdAtom); - const [isPending, startTransition] = useTransition(); const [, startCloseTransition] = useTransition(); const [, setOpenSettingModalAtom] = useAtom(openSettingModalAtom); @@ -146,7 +153,6 @@ export const AllWorkspaceModals = (): ReactElement => { <> { test('delete workspace', async ({ page }) => { await page.getByTestId('current-workspace').click(); await page.getByTestId('new-workspace').click(); - await page.getByTestId('create-workspace-default-location-button').click({ - delay: 100, - }); await page.getByTestId('create-workspace-input').type('Delete Me', { delay: 100, }); diff --git a/apps/electron/e2e/fixture.ts b/apps/electron/e2e/fixture.ts index 1f8e9721a9..5ee79c49e3 100644 --- a/apps/electron/e2e/fixture.ts +++ b/apps/electron/e2e/fixture.ts @@ -12,6 +12,8 @@ import fs from 'fs-extra'; import type { ElectronApplication, Page } from 'playwright'; import { _electron as electron } from 'playwright'; +import { removeWithRetry } from '../tests/utils'; + function generateUUID() { return crypto.randomUUID(); } @@ -102,7 +104,7 @@ export const test = base.extend<{ }); await use(electronApp); try { - await fs.rm(clonedDist, { recursive: true, force: true }); + await removeWithRetry(clonedDist); } catch (error) { console.log(error); } diff --git a/apps/electron/e2e/tsconfig.json b/apps/electron/e2e/tsconfig.json deleted file mode 100644 index ce09ef9b86..0000000000 --- a/apps/electron/e2e/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "extends": "../../../tsconfig.json", - "compilerOptions": { - "outDir": "./lib", - "baseUrl": ".", - "target": "ESNext" - }, - "references": [{ "path": "../../../tests/kit" }], - "include": ["**.spec.ts", "**.test.ts", "fixture.ts"], - "exclude": ["lib"] -} diff --git a/apps/electron/forge.config.js b/apps/electron/forge.config.js index ed2c9b38c7..2e86870d8c 100644 --- a/apps/electron/forge.config.js +++ b/apps/electron/forge.config.js @@ -113,7 +113,6 @@ module.exports = { : undefined, // We need the following line for updater extraResource: ['./resources/app-update.yml'], - ignore: ['e2e', 'tests'], }, makers, hooks: { diff --git a/apps/electron/src/main/updater/electron-updater.ts b/apps/electron/src/main/updater/electron-updater.ts index 6615860fd5..91c95ba3d9 100644 --- a/apps/electron/src/main/updater/electron-updater.ts +++ b/apps/electron/src/main/updater/electron-updater.ts @@ -70,10 +70,13 @@ export const registerUpdater = async () => { autoUpdater.on('checking-for-update', () => { logger.info('Checking for update'); }); + let downloading = false; autoUpdater.on('update-available', info => { logger.info('Update available', info); - if (allowAutoUpdate) { + if (allowAutoUpdate && !downloading) { + downloading = true; autoUpdater?.downloadUpdate().catch(e => { + downloading = false; logger.error('Failed to download update', e); }); logger.info('Update available, downloading...', info); @@ -91,6 +94,7 @@ export const registerUpdater = async () => { updaterSubjects.downloadProgress.next(e.percent); }); autoUpdater.on('update-downloaded', e => { + downloading = false; updaterSubjects.updateReady.next({ version: e.version, allowAutoUpdate, diff --git a/apps/electron/tsconfig.json b/apps/electron/tsconfig.json index e87bb8b12a..bb2f2d3d95 100644 --- a/apps/electron/tsconfig.json +++ b/apps/electron/tsconfig.json @@ -33,9 +33,6 @@ { "path": "./tsconfig.node.json" }, - { - "path": "./e2e/tsconfig.json" - }, { "path": "../../tests/kit" } ], "ts-node": { diff --git a/apps/electron/tsconfig.tests.json b/apps/electron/tsconfig.tests.json index 4af2e315d8..4123c61bc1 100644 --- a/apps/electron/tsconfig.tests.json +++ b/apps/electron/tsconfig.tests.json @@ -3,7 +3,7 @@ "compilerOptions": { "composite": true }, - "include": ["**/__tests__/**/*", "./tests"], + "include": ["**/__tests__/**/*", "./tests", "./e2e"], "references": [ { "path": "./tsconfig.json" diff --git a/apps/storybook/package.json b/apps/storybook/package.json index 0187408926..0bd70177c4 100644 --- a/apps/storybook/package.json +++ b/apps/storybook/package.json @@ -25,7 +25,7 @@ "concurrently": "^8.2.0", "jest-mock": "^29.6.2", "serve": "^14.2.0", - "ses": "^0.18.7", + "ses": "^0.18.8", "storybook": "^7.3.1", "storybook-dark-mode": "^3.0.1", "wait-on": "^7.0.1" diff --git a/nx.json b/nx.json index fb81890245..22a1ae8c24 100644 --- a/nx.json +++ b/nx.json @@ -32,8 +32,7 @@ "{projectRoot}/dist", "{projectRoot}/build", "{projectRoot}/out", - "{projectRoot}/storybook-static", - "{workspaceRoot}/packages/i18n/src/i18n-generated.ts" + "{projectRoot}/storybook-static" ], "inputs": [ "{workspaceRoot}/infra/**/*", diff --git a/packages/component/package.json b/packages/component/package.json index cdbf116bff..b927214c52 100644 --- a/packages/component/package.json +++ b/packages/component/package.json @@ -21,6 +21,7 @@ "@affine/jotai": "workspace:*", "@affine/workspace": "workspace:*", "@dnd-kit/core": "^6.0.8", + "@dnd-kit/modifiers": "^6.0.1", "@dnd-kit/sortable": "^7.0.2", "@emotion/cache": "^11.11.0", "@emotion/react": "^11.11.1", diff --git a/packages/component/src/components/app-sidebar/index.css.ts b/packages/component/src/components/app-sidebar/index.css.ts index 2443f1a599..5d7c512bcf 100644 --- a/packages/component/src/components/app-sidebar/index.css.ts +++ b/packages/component/src/components/app-sidebar/index.css.ts @@ -35,7 +35,7 @@ export const navWrapperStyle = style({ '&[data-enable-animation="true"]': { transition: 'margin-left .3s, width .3s', }, - '&.has-background': { + '&[data-is-floating="false"].has-background': { backgroundColor: 'var(--affine-white-60)', borderRight: '1px solid var(--affine-border-color)', }, diff --git a/packages/component/src/components/app-sidebar/index.tsx b/packages/component/src/components/app-sidebar/index.tsx index aab102c6f5..09630ec9d0 100644 --- a/packages/component/src/components/app-sidebar/index.tsx +++ b/packages/component/src/components/app-sidebar/index.tsx @@ -2,6 +2,7 @@ import { Skeleton } from '@mui/material'; import { assignInlineVars } from '@vanilla-extract/dynamic'; import clsx from 'clsx'; import { useAtom, useAtomValue } from 'jotai'; +import debounce from 'lodash/debounce'; import type { PropsWithChildren, ReactElement } from 'react'; import { useEffect, useRef, useState } from 'react'; @@ -77,10 +78,10 @@ export function AppSidebar(props: AppSidebarProps): ReactElement { setAppSidebarFloating(isFloating && !!open); } - onResize(); - window.addEventListener('resize', onResize); + const dOnResize = debounce(onResize, 50); + window.addEventListener('resize', dOnResize); return () => { - window.removeEventListener('resize', onResize); + window.removeEventListener('resize', dOnResize); }; }, [appSidebarWidth, open, setAppSidebarFloating, setOpen]); diff --git a/packages/component/src/components/card/workspace-card/styles.ts b/packages/component/src/components/card/workspace-card/styles.ts index 1aea2c2c55..09005900e8 100644 --- a/packages/component/src/components/card/workspace-card/styles.ts +++ b/packages/component/src/components/card/workspace-card/styles.ts @@ -47,7 +47,6 @@ export const StyledCard = styled('div')<{ borderRadius: '12px', border: `1px solid ${borderColor}`, ...displayFlex('flex-start', 'flex-start'), - marginBottom: '12px', transition: 'background .2s', alignItems: 'center', position: 'relative', @@ -62,6 +61,12 @@ export const StyledCard = styled('div')<{ '.setting-entry': { opacity: 1, pointerEvents: 'auto', + backgroundColor: 'var(--affine-white-30)', + boxShadow: 'var(--affine-shadow-1)', + ':hover': { + background: + 'linear-gradient(0deg, var(--affine-hover-color) 0%, var(--affine-hover-color) 100%), var(--affine-white-30)', + }, }, }, '@media (max-width: 720px)': { diff --git a/packages/component/src/components/page-list/filter/condition.tsx b/packages/component/src/components/page-list/filter/condition.tsx index b6f74d30aa..3b025676bd 100644 --- a/packages/component/src/components/page-list/filter/condition.tsx +++ b/packages/component/src/components/page-list/filter/condition.tsx @@ -63,9 +63,7 @@ export const Condition = ({
{variableDefineMap[ast.left.name].icon}
-
- -
+ ({ type: 'literal', value })), + args: data.defaultArgs().map(value => ({ + type: 'literal', + value, + })), }; }; @@ -137,7 +143,10 @@ filterMatcher.register( ); filterMatcher.register( - tFunction({ args: [tDate.create(), tDate.create()], rt: tBoolean.create() }), + tFunction({ + args: [tDate.create(), tDate.create()], + rt: tBoolean.create(), + }), { name: 'after', defaultArgs: () => { @@ -153,7 +162,10 @@ filterMatcher.register( ); filterMatcher.register( - tFunction({ args: [tDate.create(), tDate.create()], rt: tBoolean.create() }), + tFunction({ + args: [tDate.create(), tDate.create()], + rt: tBoolean.create(), + }), { name: 'before', defaultArgs: () => [dayjs().endOf('day').valueOf()], @@ -165,31 +177,35 @@ filterMatcher.register( }, } ); - +const safeArray = (arr: unknown): LiteralValue[] => { + return Array.isArray(arr) ? arr : []; +}; filterMatcher.register( - tFunction({ args: [tArray(tTag.create())], rt: tBoolean.create() }), + tFunction({ + args: [tArray(tTag.create())], + rt: tBoolean.create(), + }), { name: 'is not empty', defaultArgs: () => [], impl: tags => { - if (Array.isArray(tags)) { - return tags.length > 0; - } - return true; + const safeTags = safeArray(tags); + return safeTags.length > 0; }, } ); filterMatcher.register( - tFunction({ args: [tArray(tTag.create())], rt: tBoolean.create() }), + tFunction({ + args: [tArray(tTag.create())], + rt: tBoolean.create(), + }), { name: 'is empty', defaultArgs: () => [], impl: tags => { - if (Array.isArray(tags)) { - return tags.length == 0; - } - return true; + const safeTags = safeArray(tags); + return safeTags.length == 0; }, } ); @@ -204,10 +220,11 @@ filterMatcher.register( name: 'contains all', defaultArgs: () => [], impl: (tags, target) => { - if (Array.isArray(tags) && Array.isArray(target)) { - return target.every(id => tags.includes(id)); + if (!Array.isArray(target)) { + return true; } - return true; + const safeTags = safeArray(tags); + return target.every(id => safeTags.includes(id)); }, } ); @@ -222,10 +239,11 @@ filterMatcher.register( name: 'contains one of', defaultArgs: () => [], impl: (tags, target) => { - if (Array.isArray(tags) && Array.isArray(target)) { - return target.some(id => tags.includes(id)); + if (!Array.isArray(target)) { + return true; } - return true; + const safeTags = safeArray(tags); + return target.some(id => safeTags.includes(id)); }, } ); @@ -240,10 +258,11 @@ filterMatcher.register( name: 'does not contains all', defaultArgs: () => [], impl: (tags, target) => { - if (Array.isArray(tags) && Array.isArray(target)) { - return !target.every(id => tags.includes(id)); + if (!Array.isArray(target)) { + return true; } - return true; + const safeTags = safeArray(tags); + return !target.every(id => safeTags.includes(id)); }, } ); @@ -258,10 +277,11 @@ filterMatcher.register( name: 'does not contains one of', defaultArgs: () => [], impl: (tags, target) => { - if (Array.isArray(tags) && Array.isArray(target)) { - return !target.some(id => tags.includes(id)); + if (!Array.isArray(target)) { + return true; } - return true; + const safeTags = safeArray(tags); + return !target.some(id => safeTags.includes(id)); }, } ); diff --git a/packages/component/src/components/page-list/use-sorter.ts b/packages/component/src/components/page-list/use-sorter.ts index 1ddc19ea40..3e5e64c991 100644 --- a/packages/component/src/components/page-list/use-sorter.ts +++ b/packages/component/src/components/page-list/use-sorter.ts @@ -1,19 +1,25 @@ import { useState } from 'react'; -type SorterConfig = { +type SorterConfig< + T extends Record = Record< + string | number | symbol, + unknown + >, +> = { data: T[]; key: keyof T; order: 'asc' | 'desc' | 'none'; + sortingFn?: ( + ctx: { + key: keyof T; + order: 'asc' | 'desc'; + }, + a: T, + b: T + ) => number; }; -const defaultSortingFn = >( - ctx: { - key: keyof T; - order: 'asc' | 'desc'; - }, - a: T, - b: T -) => { +const defaultSortingFn: SorterConfig['sortingFn'] = (ctx, a, b) => { const valA = a[ctx.key]; const valB = b[ctx.key]; const revert = ctx.order === 'desc'; @@ -33,6 +39,10 @@ const defaultSortingFn = >( if (!valB) { return 1 * revertSymbol; } + + if (Array.isArray(valA) && Array.isArray(valB)) { + return (valA.length - valB.length) * revertSymbol; + } console.warn( 'Unsupported sorting type! Please use custom sorting function.', valA, @@ -43,6 +53,7 @@ const defaultSortingFn = >( export const useSorter = >({ data, + sortingFn = defaultSortingFn, ...defaultSorter }: SorterConfig & { order: 'asc' | 'desc' }) => { const [sorter, setSorter] = useState, 'data'>>({ @@ -60,9 +71,8 @@ export const useSorter = >({ key: sorter.key, order: sorter.order, }; - // TODO supports custom sorting function - const sortingFn = (a: T, b: T) => defaultSortingFn(sortCtx, a, b); - const sortedData = data.sort(sortingFn); + const compareFn = (a: T, b: T) => sortingFn(sortCtx, a, b); + const sortedData = data.sort(compareFn); const shiftOrder = (key?: keyof T) => { const orders = ['asc', 'desc', 'none'] as const; diff --git a/packages/component/src/components/page-list/view/create-collection.tsx b/packages/component/src/components/page-list/view/create-collection.tsx index 86e8a596f4..32bd9833ae 100644 --- a/packages/component/src/components/page-list/view/create-collection.tsx +++ b/packages/component/src/components/page-list/view/create-collection.tsx @@ -22,22 +22,15 @@ import { import { FilterList } from '../filter'; import * as styles from './collection-list.css'; -type CreateCollectionProps = { +interface EditCollectionModelProps { + init?: Collection; title?: string; - init: Collection; - onConfirm: (collection: Collection) => void; - onConfirmText?: string; + open: boolean; getPageInfo: GetPageInfoById; propertiesMeta: PropertiesMeta; -}; - -type SaveCollectionButtonProps = { - onConfirm: (collection: Collection) => Promise; - getPageInfo: GetPageInfoById; - propertiesMeta: PropertiesMeta; - filterList: Filter[]; - workspaceId: string; -}; + onClose: () => void; + onConfirm: (view: Collection) => Promise; +} export const EditCollectionModel = ({ init, @@ -47,15 +40,7 @@ export const EditCollectionModel = ({ getPageInfo, propertiesMeta, title, -}: { - init?: Collection; - onConfirm: (view: Collection) => Promise; - open: boolean; - onClose: () => void; - title?: string; - getPageInfo: GetPageInfoById; - propertiesMeta: PropertiesMeta; -}) => { +}: EditCollectionModelProps) => { const t = useAFFiNEI18N(); const onConfirmOnCollection = useCallback( (view: Collection) => { @@ -95,47 +80,46 @@ export const EditCollectionModel = ({ ); }; -const Page = ({ - id, - onClick, - getPageInfo, -}: { +interface PageProps { id: string; - onClick: (id: string) => void; getPageInfo: GetPageInfoById; -}) => { + onClick: (id: string) => void; +} + +const Page = ({ id, onClick, getPageInfo }: PageProps) => { const page = getPageInfo(id); - if (!page) { - return null; - } - const icon = page.isEdgeless ? ( - - ) : ( - - ); - const click = () => { - onClick(id); - }; + const handleClick = useCallback(() => onClick(id), [id, onClick]); return ( -
-
{icon}
-
{page.title}
-
- -
-
+ <> + {page ? ( +
+
+ {page.isEdgeless ? ( + + ) : ( + + )} +
+
{page.title}
+
+ +
+
+ ) : null} + ); }; + +interface EditCollectionProps { + title?: string; + onConfirmText?: string; + init: Collection; + getPageInfo: GetPageInfoById; + propertiesMeta: PropertiesMeta; + onCancel: () => void; + onConfirm: (collection: Collection) => void; +} + export const EditCollection = ({ title, init, @@ -144,9 +128,7 @@ export const EditCollection = ({ onConfirmText, getPageInfo, propertiesMeta, -}: CreateCollectionProps & { - onCancel: () => void; -}) => { +}: EditCollectionProps) => { const t = useAFFiNEI18N(); const [value, onChange] = useState(init); const removeFromExcludeList = useCallback( @@ -223,13 +205,8 @@ export const EditCollection = ({ - onChange({ - ...value, - filterList: list, - }) - } - > + onChange={filterList => onChange({ ...value, filterList })} + /> {value.allowList ? (
With follow pages:
@@ -253,12 +230,7 @@ export const EditCollection = ({ data-testid="input-collection-title" placeholder={t['Untitled Collection']()} defaultValue={value.name} - onChange={text => - onChange({ - ...value, - name: text, - }) - } + onChange={name => onChange({ ...value, name })} />
@@ -288,6 +260,15 @@ export const EditCollection = ({ ); }; + +interface SaveCollectionButtonProps { + getPageInfo: GetPageInfoById; + propertiesMeta: PropertiesMeta; + filterList: Filter[]; + workspaceId: string; + onConfirm: (collection: Collection) => Promise; +} + export const SaveCollectionButton = ({ onConfirm, getPageInfo, @@ -316,10 +297,10 @@ export const SaveCollectionButton = ({ size="large" style={{ padding: '7px 8px' }} > - {t['Save As New Collection']()} + {t['Save as New Collection']()} { } const SortableWorkspaceItem = (props: SortableWorkspaceItemProps) => { - const { setNodeRef, attributes, listeners, transform } = useSortable({ - id: props.item.id, - }); + const { setNodeRef, attributes, listeners, transform, transition } = + useSortable({ + id: props.item.id, + }); const style: CSSProperties = useMemo( () => ({ transform: transform ? `translate3d(${transform.x}px, ${transform.y}px, 0)` : undefined, + transition, pointerEvents: props.disabled ? 'none' : undefined, opacity: props.disabled ? 0.6 : undefined, }), - [props.disabled, transform] + [props.disabled, transform, transition] ); return (
{ ); }; +const modifiers = [restrictToParentElement, restrictToVerticalAxis]; + export const WorkspaceList = (props: WorkspaceListProps) => { const sensors = useSensors( useSensor(PointerSensor, { @@ -71,10 +79,33 @@ export const WorkspaceList = (props: WorkspaceListProps) => { }, }) ); + const workspaceList = props.items; + const [optimisticList, setOptimisticList] = useState(workspaceList); + + useEffect(() => { + setOptimisticList(workspaceList); + }, [workspaceList]); + + const onDragEnd = useCallback( + (event: DragEndEvent) => { + const { active, over } = event; + if (active.id !== over?.id) { + setOptimisticList(workspaceList => { + const oldIndex = workspaceList.findIndex(w => w.id === active.id); + const newIndex = workspaceList.findIndex(w => w.id === over?.id); + const newList = arrayMove(workspaceList, oldIndex, newIndex); + return newList; + }); + props.onDragEnd(event); + } + }, + [props] + ); + return ( - - - {props.items.map(item => ( + + + {optimisticList.map(item => ( ))} diff --git a/packages/component/src/ui/confirm/confirm.tsx b/packages/component/src/ui/confirm/confirm.tsx index 5b6342d828..01e4cc0242 100644 --- a/packages/component/src/ui/confirm/confirm.tsx +++ b/packages/component/src/ui/confirm/confirm.tsx @@ -1,5 +1,6 @@ import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { Button } from '@toeverything/components/button'; +import { useCallback, useMemo } from 'react'; import type { ModalProps } from '../modal'; import { Modal, ModalCloseButton } from '../modal'; @@ -39,33 +40,36 @@ export const Confirm = ({ confirmButtonTestId = '', }: ConfirmProps) => { const t = useAFFiNEI18N(); + const cancelText_ = useMemo(() => { + return cancelText === 'Cancel' ? t['Cancel']() : cancelText; + }, [cancelText, t]); + + const handleCancel = useCallback(() => { + onCancel?.(); + }, [onCancel]); + const handleConfirm = useCallback(() => { + onConfirm?.(); + }, [onConfirm]); + return ( - { - onCancel?.(); - }} - /> + {title} {content} {buttonDirection === 'row' ? ( )} diff --git a/packages/i18n/project.json b/packages/i18n/project.json index 42e3e95c77..064d6c9334 100644 --- a/packages/i18n/project.json +++ b/packages/i18n/project.json @@ -5,6 +5,7 @@ "sourceRoot": "packages/i18n/src", "targets": { "build": { + "outputs": ["{workspaceRoot}/src/i18n-generated.ts"], "executor": "nx:run-commands", "options": { "cwd": "packages/i18n", diff --git a/packages/i18n/src/resources/en.json b/packages/i18n/src/resources/en.json index 4fa723916c..511ab0c82a 100644 --- a/packages/i18n/src/resources/en.json +++ b/packages/i18n/src/resources/en.json @@ -237,7 +237,7 @@ "Retain cached cloud data": "Retain cached cloud data", "Retain local cached data": "Retain local cached data", "Save": "Save", - "Save As New Collection": "Save As New Collection", + "Save as New Collection": "Save as New Collection", "Saved then enable AFFiNE Cloud": "All changes are saved locally, click to enable AFFiNE Cloud.", "Select": "Select", "Select All": "Select All", diff --git a/packages/i18n/src/resources/fr.json b/packages/i18n/src/resources/fr.json index 87ea901306..127b926a10 100644 --- a/packages/i18n/src/resources/fr.json +++ b/packages/i18n/src/resources/fr.json @@ -237,7 +237,7 @@ "Retain cached cloud data": "Conserver les données mises en cache dans le cloud", "Retain local cached data": "Conserver les données du cache local", "Save": "Enregistrer", - "Save As New Collection": "Enregistrer en tant que nouvelle collection", + "Save as New Collection": "Enregistrer en tant que nouvelle collection", "Saved then enable AFFiNE Cloud": "Toutes les modifications sont sauvegardées localement, cliquez ici pour activer la sauvegarde AFFiNE Cloud", "Select": "Sélectionner ", "Select All": "Sélectionner l'ensemble", diff --git a/packages/i18n/src/resources/zh-Hant.json b/packages/i18n/src/resources/zh-Hant.json index b962491681..c5c334cdf6 100644 --- a/packages/i18n/src/resources/zh-Hant.json +++ b/packages/i18n/src/resources/zh-Hant.json @@ -237,7 +237,7 @@ "Retain cached cloud data": "保留緩衝的雲數據", "Retain local cached data": "保留本機緩衝數據", "Save": "保存", - "Save As New Collection": "另存為新收藏集", + "Save as New Collection": "另存為新收藏集", "Saved then enable AFFiNE Cloud": "所有修訂已儲存在本機,點按以啟用 AFFiNE Cloud。", "Select": "選擇", "Select All": "全選", diff --git a/packages/plugin-cli/package.json b/packages/plugin-cli/package.json index 3299307f93..330acce0b5 100644 --- a/packages/plugin-cli/package.json +++ b/packages/plugin-cli/package.json @@ -10,7 +10,7 @@ "tsconfig.json" ], "dependencies": { - "@endo/static-module-record": "^0.8.1", + "@endo/static-module-record": "^0.8.2", "@swc/core": "^1.3.77", "@toeverything/infra": "workspace:^", "@vanilla-extract/rollup-plugin": "^1.2.2", diff --git a/packages/templates/v1/getting-started.json b/packages/templates/v1/getting-started.json index e259e501fe..03cc92d5b8 100644 --- a/packages/templates/v1/getting-started.json +++ b/packages/templates/v1/getting-started.json @@ -215,7 +215,7 @@ } }, { - "insert": " feely." + "insert": " freely." } ], "prop:checked": false diff --git a/plugins/outline/src/app.tsx b/plugins/outline/src/app.tsx index 2e3deca44e..73648a5d83 100644 --- a/plugins/outline/src/app.tsx +++ b/plugins/outline/src/app.tsx @@ -50,10 +50,17 @@ export const HeaderItem = ({ const [open, setOpen] = useState(false); const pushLayout = useSetAtom(pushLayoutAtom); const deleteLayout = useSetAtom(deleteLayoutAtom); + const [container, setContainer] = useState(null); return ( - + { if (!open) { setOpen(true); diff --git a/yarn.lock b/yarn.lock index 7596058650..57659e5978 100644 --- a/yarn.lock +++ b/yarn.lock @@ -143,6 +143,7 @@ __metadata: "@blocksuite/lit": 0.0.0-20230830111255-92eab248-nightly "@blocksuite/store": 0.0.0-20230830111255-92eab248-nightly "@dnd-kit/core": ^6.0.8 + "@dnd-kit/modifiers": ^6.0.1 "@dnd-kit/sortable": ^7.0.2 "@emotion/cache": ^11.11.0 "@emotion/react": ^11.11.1 @@ -274,7 +275,7 @@ __metadata: react-resizable-panels: ^0.0.55 react-router-dom: ^6.15.0 rxjs: ^7.8.1 - ses: ^0.18.7 + ses: ^0.18.8 source-map-loader: ^4.0.1 style-loader: ^3.3.3 swc-loader: ^0.2.3 @@ -573,7 +574,7 @@ __metadata: version: 0.0.0-use.local resolution: "@affine/plugin-cli@workspace:packages/plugin-cli" dependencies: - "@endo/static-module-record": ^0.8.1 + "@endo/static-module-record": ^0.8.2 "@swc/core": ^1.3.77 "@toeverything/infra": "workspace:^" "@vanilla-extract/rollup-plugin": ^1.2.2 @@ -723,7 +724,7 @@ __metadata: react: 18.2.0 react-dom: 18.2.0 serve: ^14.2.0 - ses: ^0.18.7 + ses: ^0.18.8 storybook: ^7.3.1 storybook-addon-react-router-v6: ^2.0.4 storybook-dark-mode: ^3.0.1 @@ -3861,6 +3862,19 @@ __metadata: languageName: node linkType: hard +"@dnd-kit/modifiers@npm:^6.0.1": + version: 6.0.1 + resolution: "@dnd-kit/modifiers@npm:6.0.1" + dependencies: + "@dnd-kit/utilities": ^3.2.1 + tslib: ^2.0.0 + peerDependencies: + "@dnd-kit/core": ^6.0.6 + react: ">=16.8.0" + checksum: cd31715aac81baa2398558dc7c877a483d1c4c41cdb2f466557fdc41bb742db5cd1b34b3b84332b94ac4a2835e7e5a0e28c64e621936e976399788f1dd029ea4 + languageName: node + linkType: hard + "@dnd-kit/sortable@npm:^7.0.2": version: 7.0.2 resolution: "@dnd-kit/sortable@npm:7.0.2" @@ -4411,23 +4425,23 @@ __metadata: languageName: node linkType: hard -"@endo/env-options@npm:^0.1.3": - version: 0.1.3 - resolution: "@endo/env-options@npm:0.1.3" - checksum: da8c66865d4d30b0053a00960657dc36f022975a888f0dd6a2f6bb37b9fe731f45a02a2cf263d93b1a40fcb37b25f8ba7076cb8af9e93fd95f496365d9382930 +"@endo/env-options@npm:^0.1.4": + version: 0.1.4 + resolution: "@endo/env-options@npm:0.1.4" + checksum: 6099f0a6b700a60bee7b226aa2a39bb5748e22f25e9606d70e5a66a8e62cbd8c972b0fe578735a658f80bf2ebece62e28c20aa3f16417cbfe6c19a8689966dd3 languageName: node linkType: hard -"@endo/static-module-record@npm:^0.8.1": - version: 0.8.1 - resolution: "@endo/static-module-record@npm:0.8.1" +"@endo/static-module-record@npm:^0.8.2": + version: 0.8.2 + resolution: "@endo/static-module-record@npm:0.8.2" dependencies: "@agoric/babel-generator": ^7.17.6 "@babel/parser": ^7.17.3 "@babel/traverse": ^7.17.3 "@babel/types": ^7.17.0 - ses: ^0.18.7 - checksum: c9dc18a5b8ec13008784e30aa15214a67771c325759b42d54362f891d0328b0abf4cafc7be8fa17d539f5f7ca28b9555127e22e9596f5e52d9bf7f3fa90c7963 + ses: ^0.18.8 + checksum: 0e65f28e95d4ddd495de4cc7e5f0a47a70b89ba5449660158c8813121ab76aa3a8db7e6b2bb9efd3cb24833f8613a952e3a85a8af9fc9b7e4ad49d1d47a9f06c languageName: node linkType: hard @@ -29770,12 +29784,12 @@ __metadata: languageName: node linkType: hard -"ses@npm:^0.18.7": - version: 0.18.7 - resolution: "ses@npm:0.18.7" +"ses@npm:^0.18.8": + version: 0.18.8 + resolution: "ses@npm:0.18.8" dependencies: - "@endo/env-options": ^0.1.3 - checksum: 75ac014771d9bc1f747193c6d0f9e7d2d7700a10311ba8d805d9bc78d4c20d4ef40537f0535b1ea6abf06babf67e70f8bd37b2ad68ad54992a0c5ce842181c87 + "@endo/env-options": ^0.1.4 + checksum: d7976d2ee218baec021c5cfdfb193d63b52bf2b6cbdbbb90c19d835915a1872b6924910f7fd42bc849eb2de78fc7bdd6e7b4667e1df3c79244cc92d4ede48aa6 languageName: node linkType: hard