diff --git a/apps/electron/layers/main/src/handlers/ui/index.ts b/apps/electron/layers/main/src/handlers/ui/index.ts index 7ff5c3bc5a..fc61e991d4 100644 --- a/apps/electron/layers/main/src/handlers/ui/index.ts +++ b/apps/electron/layers/main/src/handlers/ui/index.ts @@ -1,4 +1,4 @@ -import { BrowserWindow, nativeTheme } from 'electron'; +import { app, BrowserWindow, nativeTheme } from 'electron'; import { isMacOS } from '../../../../utils'; import type { NamespaceHandlers } from '../type'; @@ -17,6 +17,25 @@ export const uiHandlers = { }); } }, + handleMinimizeApp: async () => { + const windows = BrowserWindow.getAllWindows(); + windows.forEach(w => { + w.minimize(); + }); + }, + handleMaximizeApp: async () => { + const windows = BrowserWindow.getAllWindows(); + windows.forEach(w => { + if (w.isMaximized()) { + w.unmaximize(); + } else { + w.maximize(); + } + }); + }, + handleCloseApp: async () => { + app.quit(); + }, getGoogleOauthCode: async () => { return getGoogleOauthCode(); }, diff --git a/apps/electron/layers/main/src/main-window.ts b/apps/electron/layers/main/src/main-window.ts index 7654362d16..e58dcf3ac7 100644 --- a/apps/electron/layers/main/src/main-window.ts +++ b/apps/electron/layers/main/src/main-window.ts @@ -2,7 +2,7 @@ import { BrowserWindow, nativeTheme } from 'electron'; import electronWindowState from 'electron-window-state'; import { join } from 'path'; -import { isMacOS } from '../../utils'; +import { isMacOS, isWindows } from '../../utils'; import { logger } from './logger'; const IS_DEV: boolean = @@ -18,7 +18,11 @@ async function createWindow() { }); const browserWindow = new BrowserWindow({ - titleBarStyle: isMacOS() ? 'hiddenInset' : 'default', + titleBarStyle: isMacOS() + ? 'hiddenInset' + : isWindows() + ? 'hidden' + : 'default', trafficLightPosition: { x: 24, y: 18 }, x: mainWindowState.x, y: mainWindowState.y, diff --git a/apps/electron/layers/utils.ts b/apps/electron/layers/utils.ts index 156eaadaa9..af4871d2b5 100644 --- a/apps/electron/layers/utils.ts +++ b/apps/electron/layers/utils.ts @@ -1,3 +1,7 @@ export const isMacOS = () => { return process.platform === 'darwin'; }; + +export const isWindows = () => { + return process.platform === 'win32'; +}; diff --git a/apps/electron/scripts/generate-main-exposed-meta.mjs b/apps/electron/scripts/generate-main-exposed-meta.mjs index eb88a87f8b..031e068528 100644 --- a/apps/electron/scripts/generate-main-exposed-meta.mjs +++ b/apps/electron/scripts/generate-main-exposed-meta.mjs @@ -6,7 +6,7 @@ const mainDistDir = path.resolve(__dirname, '../dist/layers/main'); // be careful and avoid any side effects in const { handlers, events } = await import( - path.resolve(mainDistDir, 'exposed.js') + 'file://' + path.resolve(mainDistDir, 'exposed.js') ); const handlersMeta = Object.entries(handlers).map( diff --git a/apps/electron/tests/basic.spec.ts b/apps/electron/tests/basic.spec.ts index 6e073111db..59467e5ccc 100644 --- a/apps/electron/tests/basic.spec.ts +++ b/apps/electron/tests/basic.spec.ts @@ -12,7 +12,6 @@ test('new page', async ({ page, workspace }) => { }); test('app theme', async ({ page, electronApp }) => { - await page.waitForSelector('v-line'); const root = page.locator('html'); { const themeMode = await root.evaluate(element => @@ -20,30 +19,25 @@ test('app theme', async ({ page, electronApp }) => { ); expect(themeMode).toBe('light'); - // check if electron theme source is set to light - const themeSource = await electronApp.evaluate(({ nativeTheme }) => { - return nativeTheme.themeSource; + const theme = await electronApp.evaluate(({ nativeTheme }) => { + return nativeTheme.shouldUseDarkColors ? 'dark' : 'light'; }); - expect(themeSource).toBe('light'); + expect(theme).toBe('light'); } { await page.getByTestId('editor-option-menu').click(); await page.getByTestId('change-theme-dark').click(); await page.waitForTimeout(50); - { - const themeMode = await root.evaluate(element => - element.getAttribute('data-theme') - ); - expect(themeMode).toBe('dark'); - } - - const themeSource = await electronApp.evaluate(({ nativeTheme }) => { - return nativeTheme.themeSource; + const themeMode = await root.evaluate(element => + element.getAttribute('data-theme') + ); + expect(themeMode).toBe('dark'); + const theme = await electronApp.evaluate(({ nativeTheme }) => { + return nativeTheme.shouldUseDarkColors ? 'dark' : 'light'; }); - - expect(themeSource).toBe('dark'); + expect(theme).toBe('dark'); } }); diff --git a/apps/electron/tests/fixture.ts b/apps/electron/tests/fixture.ts index 9529397a36..03ccad6d30 100644 --- a/apps/electron/tests/fixture.ts +++ b/apps/electron/tests/fixture.ts @@ -42,6 +42,8 @@ export const test = base.extend<{ const logFilePath = await page.evaluate(async () => { return window.apis?.debug.logFilePath(); }); + // wat for blocksuite to be loaded + await page.waitForSelector('v-line'); await use(page); await page.close(); if (logFilePath) { @@ -57,11 +59,12 @@ export const test = base.extend<{ executablePath: resolve(__dirname, '../node_modules/.bin/electron'), colorScheme: 'light', }); - const sessionDataPath = await electronApp.evaluate(async ({ app }) => { - return app.getPath('sessionData'); - }); await use(electronApp); - await fs.rm(sessionDataPath, { recursive: true, force: true }); + // FIXME: the following does not work well on CI + // const sessionDataPath = await electronApp.evaluate(async ({ app }) => { + // return app.getPath('sessionData'); + // }); + // await fs.rm(sessionDataPath, { recursive: true, force: true }); }, appInfo: async ({ electronApp }, use) => { const appInfo = await electronApp.evaluate(async ({ app }) => { diff --git a/apps/web/src/components/affine/workspace-setting-detail/index.css.ts b/apps/web/src/components/affine/workspace-setting-detail/index.css.ts index ca4b15f66e..da1cac3494 100644 --- a/apps/web/src/components/affine/workspace-setting-detail/index.css.ts +++ b/apps/web/src/components/affine/workspace-setting-detail/index.css.ts @@ -110,7 +110,8 @@ export const settingItemLabelHint = style({ export const row = style({ padding: '40px 0', display: 'flex', - gap: '60px', + columnGap: '60px', + rowGap: '12px', selectors: { '&': { borderBottom: '1px solid var(--affine-border-color)', @@ -119,22 +120,22 @@ export const row = style({ paddingTop: 0, }, }, + flexWrap: 'wrap', }); export const col = style({ display: 'flex', flexDirection: 'column', alignItems: 'flex-start', - flexShrink: 0, selectors: { [`${row} &:nth-child(1)`]: { - flex: 3, + flex: '3 0 200px', }, [`${row} &:nth-child(2)`]: { - flex: 5, + flex: '5 0 240px', }, [`${row} &:nth-child(3)`]: { - flex: 2, + flex: '2 0 200px', alignItems: 'flex-end', }, }, diff --git a/apps/web/src/components/affine/workspace-setting-detail/panel/general/index.tsx b/apps/web/src/components/affine/workspace-setting-detail/panel/general/index.tsx index 0ef59a53fb..8e0450c975 100644 --- a/apps/web/src/components/affine/workspace-setting-detail/panel/general/index.tsx +++ b/apps/web/src/components/affine/workspace-setting-detail/panel/general/index.tsx @@ -88,7 +88,6 @@ export const GeneralPanel: React.FC = ({
{ - return { - border: '1px solid var(--affine-border-color)', - borderRadius: '8px', - fontSize: 'var(--affine-font-sm)', - }; -}); +export const StyledInput = Input; export const StyledWorkspaceInfo = styled('div')(() => { return { diff --git a/apps/web/src/components/blocksuite/workspace-header/header-right-items/editor-option-menu.tsx b/apps/web/src/components/blocksuite/workspace-header/header-right-items/editor-option-menu.tsx index 1cd358d739..a9cdcd6484 100644 --- a/apps/web/src/components/blocksuite/workspace-header/header-right-items/editor-option-menu.tsx +++ b/apps/web/src/components/blocksuite/workspace-header/header-right-items/editor-option-menu.tsx @@ -24,10 +24,7 @@ import { useCurrentPageId } from '../../../../hooks/current/use-current-page-id' import { useCurrentWorkspace } from '../../../../hooks/current/use-current-workspace'; import { toast } from '../../../../utils'; import { MenuThemeModeSwitch } from '../header-right-items/theme-mode-switch'; -import { - StyledHorizontalDivider, - StyledHorizontalDividerContainer, -} from '../styles'; +import * as styles from '../styles.css'; import { LanguageMenu } from './language-menu'; const CommonMenu = () => { const content = ( @@ -120,9 +117,9 @@ const PageMenu = () => { }} /> )} - - - +
+
+
@@ -53,6 +50,9 @@ export const enum HeaderRightItemName { ShareMenu = 'shareMenu', EditPage = 'editPage', UserAvatar = 'userAvatar', + + // some windows only items + WindowsAppControls = 'windowsAppControls', } type HeaderItem = { @@ -67,6 +67,7 @@ type HeaderItem = { } ) => boolean; }; + const HeaderRightItems: Record = { [HeaderRightItemName.TrashButtonGroup]: { Component: TrashButtonGroup, @@ -104,6 +105,44 @@ const HeaderRightItems: Record = { return !isPublic && !isPreview; }, }, + [HeaderRightItemName.WindowsAppControls]: { + Component: () => { + return ( +
+ + + +
+ ); + }, + availableWhen: () => { + return environment.isDesktop && environment.isWindows; + }, + }, }; export type HeaderProps = BaseHeaderProps; @@ -127,9 +166,10 @@ export const Header = forwardRef< const mode = useCurrentMode(); return ( - @@ -145,11 +185,12 @@ export const Header = forwardRef< /> )} - {props.children} - +
{useMemo(() => { return Object.entries(HeaderRightItems).map( ([name, { availableWhen, Component }]) => { @@ -184,10 +225,9 @@ export const Header = forwardRef< } ); }, [props])} - {/**/} - - - +
+
+
); }); diff --git a/apps/web/src/components/blocksuite/workspace-header/index.tsx b/apps/web/src/components/blocksuite/workspace-header/index.tsx index 029d10957e..dd0dd3badf 100644 --- a/apps/web/src/components/blocksuite/workspace-header/index.tsx +++ b/apps/web/src/components/blocksuite/workspace-header/index.tsx @@ -15,15 +15,7 @@ import { QuickSearchButton } from '../../pure/quick-search-button'; import { EditorModeSwitch } from './editor-mode-switch'; import type { BaseHeaderProps } from './header'; import { Header } from './header'; -import { - StyledQuickSearchTipButton, - StyledQuickSearchTipContent, - StyledSearchArrowWrapper, - StyledSwitchWrapper, - StyledTitle, - StyledTitleContainer, - StyledTitleWrapper, -} from './styles'; +import * as styles from './styles.css'; export type WorkspaceHeaderProps = BaseHeaderProps; @@ -61,7 +53,7 @@ export const WorkspaceHeader = forwardRef< ); const TipsContent = ( - +
Click button { @@ -78,22 +70,23 @@ export const WorkspaceHeader = forwardRef< {isMac() ? ' ⌘ + K' : ' Ctrl + K'} to activate Quick Search. Then you can search keywords or quickly open recently viewed pages.
- setShowQuickSearchTips(false)} > Got it - - +
+
); return (
{children} {!isPublic && currentPage && ( - - - +
+
+
- - {title || 'Untitled'} +
+
{title || 'Untitled'}
- +
{ setOpenQuickSearch(true); }} /> - +
- - +
+
)}
); diff --git a/apps/web/src/components/blocksuite/workspace-header/styles.css.ts b/apps/web/src/components/blocksuite/workspace-header/styles.css.ts new file mode 100644 index 0000000000..9c062765e4 --- /dev/null +++ b/apps/web/src/components/blocksuite/workspace-header/styles.css.ts @@ -0,0 +1,216 @@ +import { style } from '@vanilla-extract/css'; + +export const headerContainer = style({ + height: '52px', + flexShrink: 0, + position: 'sticky', + top: 0, + background: 'var(--affine-background-primary-color)', + WebkitAppRegion: 'drag', + zIndex: 'var(--affine-z-index-popover)', + '@media': { + '(max-width: 768px)': { + selectors: { + '&[data-open="true"]': { + // @ts-ignore + WebkitAppRegion: 'no-drag', + }, + }, + }, + }, + selectors: { + '&[data-has-warning="true"]': { + height: '96px', + }, + }, +}); + +export const header = style({ + flexShrink: 0, + height: '52px', + width: '100%', + padding: '0 20px', + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + background: 'var(--affine-background-primary-color)', + zIndex: 99, + position: 'relative', + selectors: { + '&[data-is-edgeless="true"]': { + borderBottom: `1px solid var(--affine-border-color)`, + }, + }, +}); + +export const titleContainer = style({ + width: '100%', + height: '100%', + margin: 'auto', + position: 'absolute', + inset: 'auto auto auto 50%', + transform: 'translate(-50%, 0px)', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + alignContent: 'unset', + fontSize: 'var(--affine-font-base)', +}); + +export const title = style({ + maxWidth: '620px', + transition: 'max-width .15s', + userSelect: 'none', + overflow: 'hidden', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + '@media': { + '(max-width: 768px)': { + selectors: { + '&[data-open="true"]': { + // @ts-ignore + WebkitAppRegion: 'no-drag', + }, + }, + }, + }, +}); + +export const titleWrapper = style({ + height: '100%', + position: 'relative', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', +}); + +export const headerRightSide = style({ + height: '100%', + display: 'flex', + alignItems: 'center', + gap: '12px', + zIndex: 1, +}); + +export const browserWarning = style({ + backgroundColor: 'var(--affine-background-warning-color)', + color: 'var(--affine-warning-color)', + height: '36px', + fontSize: 'var(--affine-font-sm)', + display: 'none', + justifyContent: 'center', + alignItems: 'center', + selectors: { + '&[data-show="true"]': { + display: 'flex', + }, + }, +}); + +export const closeButton = style({ + width: '36px', + height: '36px', + color: 'var(--affine-icon-color)', + cursor: 'pointer', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + position: 'absolute', + right: '15px', + top: 0, +}); + +export const switchWrapper = style({ + position: 'absolute', + right: '100%', + top: 0, + bottom: 0, + margin: 'auto', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', +}); + +export const searchArrowWrapper = style({ + position: 'absolute', + left: 'calc(100% + 4px)', + top: 0, + bottom: 0, + margin: 'auto', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', +}); + +export const pageListTitleWrapper = style({ + fontSize: 'var(--affine-font-base)', + color: 'var(--affine-text-primary-color)', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', +}); + +export const pageListTitleIcon = style({ + fontSize: '20px', + height: '1em', + marginRight: '12px', +}); + +export const quickSearchTipButton = style({ + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + marginTop: '12px', + color: '#FFFFFF', + width: '48px', + height: ' 26px', + fontSize: 'var(--affine-font-sm)', + lineHeight: '22px', + background: 'var(--affine-primary-color)', + borderRadius: '8px', + textAlign: 'center', + cursor: 'pointer', +}); + +export const quickSearchTipContent = style({ + display: 'flex', + justifyContent: 'center', + alignItems: 'flex-end', + flexDirection: 'column', +}); + +export const horizontalDivider = style({ + width: '100%', + borderTop: `1px solid var(--affine-border-color)`, +}); + +export const horizontalDividerContainer = style({ + width: '100%', + padding: '14px', +}); + +export const windowAppControlsWrapper = style({ + display: 'flex', + gap: '2px', + transform: 'translateX(8px)', +}); + +export const windowAppControl = style({ + // @ts-ignore + WebkitAppRegion: 'no-drag', + cursor: 'pointer', + display: 'inline-flex', + width: '32px', + alignItems: 'center', + justifyContent: 'center', + borderRadius: '2px', + selectors: { + '&[data-type="close"]:hover': { + background: 'var(--affine-error-color)', + color: '#FFFFFF', + }, + '&:hover': { + background: 'var(--affine-background-tertiary-color)', + }, + }, +}); diff --git a/apps/web/src/components/blocksuite/workspace-header/styles.ts b/apps/web/src/components/blocksuite/workspace-header/styles.ts deleted file mode 100644 index f6233e488d..0000000000 --- a/apps/web/src/components/blocksuite/workspace-header/styles.ts +++ /dev/null @@ -1,186 +0,0 @@ -import { - absoluteCenter, - displayFlex, - styled, - textEllipsis, -} from '@affine/component'; - -export const StyledHeaderContainer = styled('div')<{ - hasWarning: boolean; -}>(({ hasWarning }) => { - return { - height: hasWarning ? '96px' : '52px', - flexShrink: 0, - position: 'sticky', - top: 0, - background: 'var(--affine-background-primary-color)', - WebkitAppRegion: 'drag', - zIndex: 'var(--affine-z-index-popover)', - '@media (max-width: 768px)': { - '&[data-open="true"]': { - WebkitAppRegion: 'no-drag', - }, - }, - }; -}); -export const StyledHeader = styled('div')<{ - hasWarning: boolean; - isEdgeless: boolean; -}>(({ isEdgeless }) => { - return { - flexShrink: 0, - height: '52px', - width: '100%', - padding: '0 20px', - ...displayFlex('space-between', 'center'), - background: 'var(--affine-background-primary-color)', - zIndex: 99, - position: 'relative', - borderBottom: isEdgeless ? '1px solid var(--affine-border-color)' : 'none', - }; -}); - -export const StyledTitleContainer = styled('div')(() => ({ - width: '100%', - height: '100%', - - margin: 'auto', - ...absoluteCenter({ horizontal: true, position: { top: 0 } }), - ...displayFlex('center', 'center'), - fontSize: 'var(--affine-font-base)', -})); - -export const StyledTitle = styled('div')(({ theme }) => { - return { - maxWidth: '620px', - [theme.breakpoints.down('lg')]: { - maxWidth: '480px', - }, - [theme.breakpoints.down('md')]: { - maxWidth: '240px', - }, - [theme.breakpoints.down('sm')]: { - maxWidth: '180px', - }, - transition: 'max-width .15s', - userSelect: 'none', - ...textEllipsis(1), - }; -}); - -export const StyledTitleWrapper = styled('div')({ - height: '100%', - position: 'relative', - ...displayFlex('center', 'center'), -}); - -export const StyledHeaderRightSide = styled('div')({ - height: '100%', - display: 'flex', - alignItems: 'center', - '>*:not(:last-child)': { - marginRight: '12px', - }, -}); - -export const StyledBrowserWarning = styled('div')<{ show: boolean }>( - ({ show }) => { - return { - backgroundColor: 'var(--affine-background-warning-color)', - color: 'var(--affine-background-warning-color)', - height: '36px', - fontSize: 'var(--affine-font-sm)', - display: show ? 'flex' : 'none', - justifyContent: 'center', - alignItems: 'center', - }; - } -); - -export const StyledCloseButton = styled('div')(() => { - return { - width: '36px', - height: '36px', - color: 'var(--affine-icon-color)', - cursor: 'pointer', - ...displayFlex('center', 'center'), - position: 'absolute', - right: '15px', - top: '0', - - svg: { - width: '15px', - height: '15px', - position: 'relative', - zIndex: 1, - }, - }; -}); - -export const StyledSwitchWrapper = styled('div')(() => { - return { - position: 'absolute', - right: '100%', - top: 0, - bottom: 0, - margin: 'auto', - ...displayFlex('center', 'center'), - }; -}); - -export const StyledSearchArrowWrapper = styled('div')(() => { - return { - position: 'absolute', - left: 'calc(100% + 4px)', - top: 0, - bottom: 0, - margin: 'auto', - ...displayFlex('center', 'center'), - }; -}); - -export const StyledPageListTittleWrapper = styled(StyledTitle)(() => { - return { - fontSize: 'var(--affine-font-base)', - color: 'var(--affine-text-primary-color)', - ...displayFlex('center', 'center'), - '>svg': { - fontSize: '20px', - marginRight: '12px', - }, - }; -}); -export const StyledQuickSearchTipButton = styled('div')(() => { - return { - ...displayFlex('center', 'center'), - marginTop: '12px', - color: '#FFFFFF', - width: '48px', - height: ' 26px', - fontSize: 'var(--affine-font-sm)', - lineHeight: '22px', - background: 'var(--affine-primary-color)', - borderRadius: '8px', - textAlign: 'center', - cursor: 'pointer', - }; -}); -export const StyledQuickSearchTipContent = styled('div')(() => { - return { - ...displayFlex('center', 'flex-end'), - flexDirection: 'column', - }; -}); - -export const StyledHorizontalDivider = styled('div')(() => { - return { - width: '100%', - borderTop: `1px solid var(--affine-border-color)`, - }; -}); -export const StyledHorizontalDividerContainer = styled('div')(() => { - return { - width: '100%', - padding: '14px', - }; -}); diff --git a/apps/web/src/components/pure/workspace-title/index.tsx b/apps/web/src/components/pure/workspace-title/index.tsx index 29a613f509..fd031bff43 100644 --- a/apps/web/src/components/pure/workspace-title/index.tsx +++ b/apps/web/src/components/pure/workspace-title/index.tsx @@ -5,7 +5,7 @@ import type React from 'react'; import { openQuickSearchModalAtom } from '../../../atoms'; import type { HeaderProps } from '../../blocksuite/workspace-header/header'; import { Header } from '../../blocksuite/workspace-header/header'; -import { StyledPageListTittleWrapper } from '../../blocksuite/workspace-header/styles'; +import * as styles from '../../blocksuite/workspace-header/styles.css'; import { QuickSearchButton } from '../quick-search-button'; export type WorkspaceTitleProps = React.PropsWithChildren< @@ -22,15 +22,15 @@ export const WorkspaceTitle: React.FC = ({ const setOpenQuickSearch = useSetAtom(openQuickSearchModalAtom); return (
- - {icon} +
+
{icon}
{children} { setOpenQuickSearch(true); }} /> - +
); }; diff --git a/apps/web/src/providers/theme-provider.tsx b/apps/web/src/providers/theme-provider.tsx index 091cd7aff1..4182cf4f9b 100644 --- a/apps/web/src/providers/theme-provider.tsx +++ b/apps/web/src/providers/theme-provider.tsx @@ -1,19 +1,22 @@ import type { ThemeProviderProps } from '@affine/component'; import { ThemeProvider as NextThemeProvider, useTheme } from 'next-themes'; import type { PropsWithChildren } from 'react'; -import type React from 'react'; import { memo, useRef } from 'react'; const themes = ['dark', 'light']; +// a workaround to sync theme to electron +let firstRender = true; + const DesktopThemeSync = memo(function DesktopThemeSync() { const { theme } = useTheme(); const lastThemeRef = useRef(theme); - if (lastThemeRef.current !== theme) { + if (lastThemeRef.current !== theme || firstRender) { if (environment.isDesktop && theme) { window.apis?.ui.handleThemeChange(theme as 'dark' | 'light' | 'system'); } lastThemeRef.current = theme; + firstRender = false; } return null; }); diff --git a/packages/i18n/src/resources/de.json b/packages/i18n/src/resources/de.json index a23a935dae..8277546d33 100644 --- a/packages/i18n/src/resources/de.json +++ b/packages/i18n/src/resources/de.json @@ -22,7 +22,7 @@ "AFFiNE Cloud": "AFFiNE Cloud", "It takes up more space on your device": "Es verbraucht mehr Speicherplatz auf deinem Gerät.", "Sign out description": "Nach dem Abmelden gehen alle nicht synchronisierten Inhalte verloren.", - "Export AFFiNE backup file": "AFFiNE-Backup als Datei exportieren (bald verfügbar)", + "Export AFFiNE backup file": "AFFiNE-Backup als Datei exportieren", "Members": "Mitglieder", "Saved then enable AFFiNE Cloud": "Alle Änderungen werden lokal gespeichert. Klicke hier, um AFFiNE Cloud zu aktivieren.", "Joined Workspace": "Workspace beigetreten", diff --git a/packages/i18n/src/resources/en.json b/packages/i18n/src/resources/en.json index f931039df2..1c960f1ee2 100644 --- a/packages/i18n/src/resources/en.json +++ b/packages/i18n/src/resources/en.json @@ -6,7 +6,7 @@ "Members": "Members", "Add to favorites": "Add to favorites", "It takes up more space on your device": "It takes up more space on your device.", - "Export AFFiNE backup file": "Export AFFiNE backup file (coming soon)", + "Export AFFiNE backup file": "Export AFFiNE backup file", "Saved then enable AFFiNE Cloud": "All changes are saved locally, click to enable AFFiNE Cloud.", "Help and Feedback": "Help and Feedback", "Not now": "Not now", diff --git a/packages/i18n/src/resources/fr.json b/packages/i18n/src/resources/fr.json index d0d16c3455..a704de2a35 100644 --- a/packages/i18n/src/resources/fr.json +++ b/packages/i18n/src/resources/fr.json @@ -188,7 +188,7 @@ "will delete member": "supprimera le membre", "is a Local Workspace": "est un espace de travail local", "Cloud Workspace Description": "Toutes les données vont être synchronisées et sauvegardées sur le compte AFFiNE <1>{{email}}", - "Export AFFiNE backup file": "Exporter un fichier de sauvegarde AFFiNE (à venir...)", + "Export AFFiNE backup file": "Exporter un fichier de sauvegarde AFFiNE", "Export Description": "Vous pouvez exporter l'intégralité des données de l'espace de travail à titre de sauvegarde ; les données ainsi exportées peuvent être réimportées.", "Download data Description1": "Cela prend davantage d’espace sur votre appareil.", "It takes up little space on your device": "Cela prend peu d’espace sur votre appareil.", diff --git a/packages/i18n/src/resources/ru.json b/packages/i18n/src/resources/ru.json index f2c8ff1816..5b368c766a 100644 --- a/packages/i18n/src/resources/ru.json +++ b/packages/i18n/src/resources/ru.json @@ -9,7 +9,7 @@ "Check Our Docs": "Проверьте нашу документацию", "is a Cloud Workspace": "это облачное рабочее пространство.", "Owner": "Владелец", - "Export AFFiNE backup file": "Экспорт файла резервной копии AFFiNE (скоро)", + "Export AFFiNE backup file": "Экспорт файла резервной копии AFFiNE", "is a Local Workspace": "это локальное рабочее пространство", "Wait for Sync": "Дождитесь синхронизации", "Joined Workspace": "Присоединенное рабочее пространство", diff --git a/packages/i18n/src/resources/zh-Hans.json b/packages/i18n/src/resources/zh-Hans.json index b0d0674104..dd33cad0fa 100644 --- a/packages/i18n/src/resources/zh-Hans.json +++ b/packages/i18n/src/resources/zh-Hans.json @@ -178,7 +178,7 @@ "Owner": "所有者", "Published to Web": "公开到互联网", "Data sync mode": "数据同步模式", - "Export AFFiNE backup file": "导出 AFFiNE 备份文件(即将到来)", + "Export AFFiNE backup file": "导出 AFFiNE 备份文件", "AFFiNE Cloud": "AFFiNE 云服务", "Export Description": "您可以导出整个工作区数据进行备份,导出的数据可以重新被导入。", "It takes up little space on your device": "此操作会在你的设备上占用少许空间。",