refactor: migrate environment to BUILD_CONFIG (#8206)

This commit is contained in:
forehalo
2024-09-13 07:58:20 +00:00
parent 561f96bb71
commit a387e4ac07
90 changed files with 297 additions and 260 deletions
+1 -1
View File
@@ -34,7 +34,7 @@ const createPattern = packageName => [
{ {
group: ['@affine/env/constant'], group: ['@affine/env/constant'],
message: message:
'Do not import from @affine/env/constant. Use `environment.isElectron` instead', 'Do not import from @affine/env/constant. Use `BUILD_CONFIG.isElectron` instead',
importNames: ['isElectron'], importNames: ['isElectron'],
}, },
]; ];
-3
View File
@@ -10,9 +10,6 @@ declare global {
}; };
} }
//#region runtime variables
export const isElectron = !!globalThis.__appInfo?.electron;
//#endregion
export const DEFAULT_WORKSPACE_NAME = 'Demo Workspace'; export const DEFAULT_WORKSPACE_NAME = 'Demo Workspace';
export const UNTITLED_WORKSPACE_NAME = 'Untitled'; export const UNTITLED_WORKSPACE_NAME = 'Untitled';
+39 -55
View File
@@ -1,51 +1,47 @@
/// <reference types="@blocksuite/global" /> /// <reference types="@blocksuite/global" />
import { assertEquals } from '@blocksuite/global/utils';
import { z } from 'zod';
import { isElectron } from './constant.js';
import { UaHelper } from './ua-helper.js'; import { UaHelper } from './ua-helper.js';
export const BUILD_CONFIG_SCHEMA = z.object({ export type BUILD_CONFIG_TYPE = {
// this is for the electron app debug: boolean;
serverUrlPrefix: z.string(), distribution: 'web' | 'desktop' | 'admin' | 'mobile';
appVersion: z.string(), /**
editorVersion: z.string(), * 'web' | 'desktop' | 'admin'
distribution: z.enum(['web', 'desktop', 'admin', 'mobile']), */
appBuildType: z.union([
z.literal('stable'),
z.literal('beta'),
z.literal('internal'),
z.literal('canary'),
]),
isSelfHosted: z.boolean().optional(),
githubUrl: z.string(),
changelogUrl: z.string(),
downloadUrl: z.string(),
// see: tools/workers
imageProxyUrl: z.string(),
linkPreviewUrl: z.string(),
allowLocalWorkspace: z.boolean(),
enablePreloading: z.boolean(),
enableNewSettingUnstableApi: z.boolean(),
enableExperimentalFeature: z.boolean(),
enableThemeEditor: z.boolean(),
});
export type BUILD_CONFIG_TYPE = z.infer<typeof BUILD_CONFIG_SCHEMA>;
export type Environment = {
isDebug: boolean;
// Edition
isDesktopEdition: boolean; isDesktopEdition: boolean;
/**
* 'mobile'
*/
isMobileEdition: boolean; isMobileEdition: boolean;
// Platform/Entry
isElectron: boolean; isElectron: boolean;
isDesktopWeb: boolean; isWeb: boolean;
isMobileWeb: boolean; isMobileWeb: boolean;
isStandalone?: boolean;
// this is for the electron app
serverUrlPrefix: string;
appVersion: string;
editorVersion: string;
appBuildType: 'stable' | 'beta' | 'internal' | 'canary';
githubUrl: string;
changelogUrl: string;
downloadUrl: string;
// see: tools/workers
imageProxyUrl: string;
linkPreviewUrl: string;
allowLocalWorkspace: boolean;
enablePreloading: boolean;
enableNewSettingUnstableApi: boolean;
enableExperimentalFeature: boolean;
enableThemeEditor: boolean;
// TODO(@forehalo): remove
isSelfHosted: boolean;
};
export type Environment = {
// Device // Device
isLinux: boolean; isLinux: boolean;
isMacOs: boolean; isMacOs: boolean;
@@ -55,6 +51,8 @@ export type Environment = {
isFireFox: boolean; isFireFox: boolean;
isMobile: boolean; isMobile: boolean;
isChrome: boolean; isChrome: boolean;
isPwa: boolean;
chromeVersion?: number; chromeVersion?: number;
}; };
@@ -64,17 +62,9 @@ export function setupGlobal() {
} }
let environment: Environment; let environment: Environment;
const isDebug = process.env.NODE_ENV === 'development';
if (!globalThis.navigator) { if (!globalThis.navigator) {
environment = { environment = {
isDesktopEdition: false,
isMobileEdition: false,
isElectron: false,
isDesktopWeb: false,
isMobileWeb: false,
isMobile: false,
isDebug,
isLinux: false, isLinux: false,
isMacOs: false, isMacOs: false,
isSafari: false, isSafari: false,
@@ -82,17 +72,13 @@ export function setupGlobal() {
isFireFox: false, isFireFox: false,
isChrome: false, isChrome: false,
isIOS: false, isIOS: false,
isPwa: false,
isMobile: false,
}; };
} else { } else {
const uaHelper = new UaHelper(globalThis.navigator); const uaHelper = new UaHelper(globalThis.navigator);
environment = { environment = {
isDesktopEdition: BUILD_CONFIG.distribution !== 'mobile',
isMobileEdition: BUILD_CONFIG.distribution === 'mobile',
isDesktopWeb: BUILD_CONFIG.distribution === 'web',
isMobileWeb: BUILD_CONFIG.distribution === 'mobile',
isElectron,
isDebug,
isMobile: uaHelper.isMobile, isMobile: uaHelper.isMobile,
isLinux: uaHelper.isLinux, isLinux: uaHelper.isLinux,
isMacOs: uaHelper.isMacOs, isMacOs: uaHelper.isMacOs,
@@ -101,12 +87,10 @@ export function setupGlobal() {
isFireFox: uaHelper.isFireFox, isFireFox: uaHelper.isFireFox,
isChrome: uaHelper.isChrome, isChrome: uaHelper.isChrome,
isIOS: uaHelper.isIOS, isIOS: uaHelper.isIOS,
isStandalone: uaHelper.isStandalone, isPwa: uaHelper.isStandalone,
}; };
// Chrome on iOS is still Safari // Chrome on iOS is still Safari
if (environment.isChrome && !environment.isIOS) { if (environment.isChrome && !environment.isIOS) {
assertEquals(environment.isSafari, false);
assertEquals(environment.isFireFox, false);
environment = { environment = {
...environment, ...environment,
isSafari: false, isSafari: false,
+2 -2
View File
@@ -44,7 +44,7 @@ export const dateFormatOptions: DateFormats[] = [
]; ];
const appSettingBaseAtom = atomWithStorage<AppSetting>('affine-settings', { const appSettingBaseAtom = atomWithStorage<AppSetting>('affine-settings', {
clientBorder: environment.isElectron && !environment.isWindows, clientBorder: BUILD_CONFIG.isElectron && !environment.isWindows,
windowFrameStyle: 'frameless', windowFrameStyle: 'frameless',
dateFormat: dateFormatOptions[0], dateFormat: dateFormatOptions[0],
startWeekOnMonday: false, startWeekOnMonday: false,
@@ -61,7 +61,7 @@ type SetStateAction<Value> = Value | ((prev: Value) => Value);
const appSettingEffect = atomEffect(get => { const appSettingEffect = atomEffect(get => {
const settings = get(appSettingBaseAtom); const settings = get(appSettingBaseAtom);
// some values in settings should be synced into electron side // some values in settings should be synced into electron side
if (environment.isElectron) { if (BUILD_CONFIG.isElectron) {
logger.debug('sync settings to electron', settings); logger.debug('sync settings to electron', settings);
// this api type in @affine/electron-api, but it is circular dependency this package, use any here // this api type in @affine/electron-api, but it is circular dependency this package, use any here
(window as any).apis?.updater (window as any).apis?.updater
@@ -75,7 +75,7 @@ export function effect<T, A, B, C, D, E, F>(
export function effect(...args: any[]) { export function effect(...args: any[]) {
const subject$ = new Subject<any>(); const subject$ = new Subject<any>();
const effectLocation = environment.isDebug const effectLocation = BUILD_CONFIG.debug
? `(${new Error().stack?.split('\n')[2].trim()})` ? `(${new Error().stack?.split('\n')[2].trim()})`
: ''; : '';
@@ -1,7 +1,7 @@
import type { FlagInfo } from './types'; import type { FlagInfo } from './types';
const isNotStableBuild = BUILD_CONFIG.appBuildType !== 'stable'; const isNotStableBuild = BUILD_CONFIG.appBuildType !== 'stable';
const isDesktopEnvironment = environment.isElectron; const isDesktopEnvironment = BUILD_CONFIG.isElectron;
const isCanaryBuild = BUILD_CONFIG.appBuildType === 'canary'; const isCanaryBuild = BUILD_CONFIG.appBuildType === 'canary';
export const AFFINE_FLAGS = { export const AFFINE_FLAGS = {
@@ -43,8 +43,8 @@ const desktopWhiteList = [
'/magic-link', '/magic-link',
]; ];
if ( if (
!environment.isElectron && !BUILD_CONFIG.isElectron &&
environment.isDebug && BUILD_CONFIG.debug &&
desktopWhiteList.every(path => !location.pathname.startsWith(path)) desktopWhiteList.every(path => !location.pathname.startsWith(path))
) { ) {
document.body.innerHTML = `<h1 style="color:red;font-size:5rem;text-align:center;">Don't run electron entry in browser.</h1>`; document.body.innerHTML = `<h1 style="color:red;font-size:5rem;text-align:center;">Don't run electron entry in browser.</h1>`;
@@ -39,7 +39,7 @@ function main() {
performanceMainLogger.info('skip setup'); performanceMainLogger.info('skip setup');
} else { } else {
performanceMainLogger.info('setup start'); performanceMainLogger.info('setup start');
if (window.SENTRY_RELEASE || environment.isDebug) { if (BUILD_CONFIG.debug || window.SENTRY_RELEASE) {
// https://docs.sentry.io/platforms/javascript/guides/electron/ // https://docs.sentry.io/platforms/javascript/guides/electron/
init({ init({
dsn: process.env.SENTRY_DSN, dsn: process.env.SENTRY_DSN,
@@ -1,4 +1,4 @@
import { AppFallback } from '@affine/core/components/affine/app-container'; import { ShellAppFallback } from '@affine/core/components/affine/app-container';
import { useAppSettingHelper } from '@affine/core/hooks/affine/use-app-setting-helper'; import { useAppSettingHelper } from '@affine/core/hooks/affine/use-app-setting-helper';
import { AppTabsHeader } from '@affine/core/modules/app-tabs-header'; import { AppTabsHeader } from '@affine/core/modules/app-tabs-header';
import { SplitViewFallback } from '@affine/core/modules/workbench/view/split-view/split-view'; import { SplitViewFallback } from '@affine/core/modules/workbench/view/split-view/split-view';
@@ -8,15 +8,15 @@ import * as styles from './shell.css';
export function ShellRoot() { export function ShellRoot() {
const { appSettings } = useAppSettingHelper(); const { appSettings } = useAppSettingHelper();
const translucent = const translucent =
environment.isElectron && BUILD_CONFIG.isElectron &&
environment.isMacOs && environment.isMacOs &&
appSettings.enableBlurBackground; appSettings.enableBlurBackground;
return ( return (
<div className={styles.root} data-translucent={translucent}> <div className={styles.root} data-translucent={translucent}>
<AppTabsHeader mode="shell" className={styles.appTabsHeader} /> <AppTabsHeader mode="shell" className={styles.appTabsHeader} />
<AppFallback className={styles.fallbackRoot}> <ShellAppFallback className={styles.fallbackRoot}>
<SplitViewFallback className={styles.splitViewFallback} /> <SplitViewFallback className={styles.splitViewFallback} />
</AppFallback> </ShellAppFallback>
</div> </div>
); );
} }
@@ -2,7 +2,7 @@ import { resolve } from 'node:path';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'node:url';
// eslint-disable-next-line @typescript-eslint/no-restricted-imports // eslint-disable-next-line @typescript-eslint/no-restricted-imports
import { getRuntimeConfig } from '@affine/cli/src/webpack/runtime-config'; import { getBuildConfig } from '@affine/cli/src/webpack/runtime-config';
import { sentryEsbuildPlugin } from '@sentry/esbuild-plugin'; import { sentryEsbuildPlugin } from '@sentry/esbuild-plugin';
import type { BuildOptions, Plugin } from 'esbuild'; import type { BuildOptions, Plugin } from 'esbuild';
@@ -20,8 +20,8 @@ export const config = (): BuildOptions => {
define['REPLACE_ME_BUILD_ENV'] = `"${process.env.BUILD_TYPE ?? 'stable'}"`; define['REPLACE_ME_BUILD_ENV'] = `"${process.env.BUILD_TYPE ?? 'stable'}"`;
define['runtimeConfig'] = JSON.stringify( define['BUILD_CONFIG'] = JSON.stringify(
getRuntimeConfig({ getBuildConfig({
channel: (process.env.BUILD_TYPE as any) ?? 'canary', channel: (process.env.BUILD_TYPE as any) ?? 'canary',
distribution: 'desktop', distribution: 'desktop',
mode: mode:
@@ -254,10 +254,10 @@ export async function openUrlInHiddenWindow(urlObj: URL) {
preload: join(__dirname, './preload.js'), preload: join(__dirname, './preload.js'),
additionalArguments: await getWindowAdditionalArguments(), additionalArguments: await getWindowAdditionalArguments(),
}, },
show: environment.isDebug, show: BUILD_CONFIG.debug,
}); });
if (environment.isDebug) { if (BUILD_CONFIG.debug) {
win.webContents.openDevTools({ win.webContents.openDevTools({
mode: 'detach', mode: 'detach',
}); });
@@ -29,11 +29,6 @@ import { RouterProvider } from 'react-router-dom';
import { configureMobileModules } from './modules'; import { configureMobileModules } from './modules';
import { router } from './router'; import { router } from './router';
if (environment.isElectron && environment.isDebug) {
document.body.innerHTML = `<h1 style="color:red;font-size:5rem;text-align:center;">Don't run web entry in electron.</h1>`;
throw new Error('Wrong distribution');
}
const future = { const future = {
v7_startTransition: true, v7_startTransition: true,
} as const; } as const;
+1 -1
View File
@@ -20,7 +20,7 @@ import { App } from './app';
const performanceMainLogger = performanceLogger.namespace('main'); const performanceMainLogger = performanceLogger.namespace('main');
function main() { function main() {
performanceMainLogger.info('setup start'); performanceMainLogger.info('setup start');
if (window.SENTRY_RELEASE || environment.isDebug) { if (BUILD_CONFIG.debug || window.SENTRY_RELEASE) {
// https://docs.sentry.io/platforms/javascript/guides/react/#configure // https://docs.sentry.io/platforms/javascript/guides/react/#configure
init({ init({
dsn: process.env.SENTRY_DSN, dsn: process.env.SENTRY_DSN,
@@ -125,8 +125,8 @@ export const Component = () => {
if (workspaceNotFound) { if (workspaceNotFound) {
if ( if (
detailDocRoute /* */ && BUILD_CONFIG.isDesktopEdition /* only browser has share page */ &&
environment.isDesktopEdition /* only browser has share page */ detailDocRoute
) { ) {
return <div>TODO: share page</div>; return <div>TODO: share page</div>;
} }
-5
View File
@@ -31,11 +31,6 @@ import {
import { Suspense } from 'react'; import { Suspense } from 'react';
import { RouterProvider } from 'react-router-dom'; import { RouterProvider } from 'react-router-dom';
if (environment.isElectron && environment.isDebug) {
document.body.innerHTML = `<h1 style="color:red;font-size:5rem;text-align:center;">Don't run web entry in electron.</h1>`;
throw new Error('Wrong distribution');
}
const performanceI18nLogger = performanceLogger.namespace('i18n'); const performanceI18nLogger = performanceLogger.namespace('i18n');
const cache = createEmotionCache(); const cache = createEmotionCache();
+2 -2
View File
@@ -23,11 +23,11 @@ function main() {
performanceMainLogger.info('start'); performanceMainLogger.info('start');
// skip bootstrap setup for desktop onboarding // skip bootstrap setup for desktop onboarding
if (environment.isElectron && appInfo?.windowName === 'onboarding') { if (BUILD_CONFIG.isElectron && appInfo?.windowName === 'onboarding') {
performanceMainLogger.info('skip setup'); performanceMainLogger.info('skip setup');
} else { } else {
performanceMainLogger.info('setup start'); performanceMainLogger.info('setup start');
if (window.SENTRY_RELEASE || environment.isDebug) { if (BUILD_CONFIG.debug || window.SENTRY_RELEASE) {
// https://docs.sentry.io/platforms/javascript/guides/react/#configure // https://docs.sentry.io/platforms/javascript/guides/react/#configure
init({ init({
dsn: process.env.SENTRY_DSN, dsn: process.env.SENTRY_DSN,
@@ -3,7 +3,7 @@ import { StorybookConfig } from '@storybook/react-vite';
import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin'; import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin';
import swc from 'unplugin-swc'; import swc from 'unplugin-swc';
import { mergeConfig } from 'vite'; import { mergeConfig } from 'vite';
import { getRuntimeConfig } from '@affine/cli/src/webpack/runtime-config'; import { getBuildConfig } from '@affine/cli/src/webpack/runtime-config';
export default { export default {
stories: ['../src/ui/**/*.@(mdx|stories.@(js|jsx|ts|tsx))'], stories: ['../src/ui/**/*.@(mdx|stories.@(js|jsx|ts|tsx))'],
@@ -54,13 +54,12 @@ export default {
], ],
define: { define: {
'process.env.CAPTCHA_SITE_KEY': `"${process.env.CAPTCHA_SITE_KEY}"`, 'process.env.CAPTCHA_SITE_KEY': `"${process.env.CAPTCHA_SITE_KEY}"`,
runtimeConfig: getRuntimeConfig({ runtimeConfig: getBuildConfig({
distribution: 'web', distribution: 'web',
mode: 'development', mode: 'development',
channel: 'canary', channel: 'canary',
static: false, static: false,
coverage: false, coverage: false,
static: false,
}), }),
}, },
}); });
@@ -20,7 +20,7 @@ export const AffineOtherPageLayout = ({
return ( return (
<div className={styles.root}> <div className={styles.root}>
{environment.isElectron ? ( {BUILD_CONFIG.isElectron ? (
<div className={styles.draggableHeader} /> <div className={styles.draggableHeader} />
) : ( ) : (
<div className={styles.topNav}> <div className={styles.topNav}>
@@ -119,8 +119,8 @@ export const OnboardingPage = ({
() => questions?.[questionIdx], () => questions?.[questionIdx],
[questionIdx, questions] [questionIdx, questions]
); );
const isMacosDesktop = environment.isElectron && environment.isMacOs; const isMacosDesktop = BUILD_CONFIG.isElectron && environment.isMacOs;
const isWindowsDesktop = environment.isElectron && environment.isWindows; const isWindowsDesktop = BUILD_CONFIG.isElectron && environment.isWindows;
if (!questions) { if (!questions) {
return null; return null;
@@ -10,7 +10,7 @@ const DesktopThemeSync = memo(function DesktopThemeSync() {
const lastThemeRef = useRef(theme); const lastThemeRef = useRef(theme);
const onceRef = useRef(false); const onceRef = useRef(false);
if (lastThemeRef.current !== theme || !onceRef.current) { if (lastThemeRef.current !== theme || !onceRef.current) {
if (environment.isElectron && theme) { if (BUILD_CONFIG.isElectron && theme) {
apis?.ui apis?.ui
.handleThemeChange(theme as 'dark' | 'light' | 'system') .handleThemeChange(theme as 'dark' | 'light' | 'system')
.catch(err => { .catch(err => {
@@ -162,7 +162,7 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
data-size={size} data-size={size}
data-variant={variant} data-variant={variant}
data-no-hover={withoutHover || undefined} data-no-hover={withoutHover || undefined}
data-mobile={environment.isMobileEdition} data-mobile={BUILD_CONFIG.isMobileEdition}
onClick={handleClick} onClick={handleClick}
> >
<IconSlot <IconSlot
@@ -9,12 +9,14 @@ import { MobileMenu } from './mobile/root';
import { MobileMenuSeparator } from './mobile/separator'; import { MobileMenuSeparator } from './mobile/separator';
import { MobileMenuSub } from './mobile/sub'; import { MobileMenuSub } from './mobile/sub';
const MenuItem = environment.isMobileEdition ? MobileMenuItem : DesktopMenuItem; const MenuItem = BUILD_CONFIG.isMobileEdition
const MenuSeparator = environment.isMobileEdition ? MobileMenuItem
: DesktopMenuItem;
const MenuSeparator = BUILD_CONFIG.isMobileEdition
? MobileMenuSeparator ? MobileMenuSeparator
: DesktopMenuSeparator; : DesktopMenuSeparator;
const MenuSub = environment.isMobileEdition ? MobileMenuSub : DesktopMenuSub; const MenuSub = BUILD_CONFIG.isMobileEdition ? MobileMenuSub : DesktopMenuSub;
const Menu = environment.isMobileEdition ? MobileMenu : DesktopMenu; const Menu = BUILD_CONFIG.isMobileEdition ? MobileMenu : DesktopMenu;
export { export {
DesktopMenu, DesktopMenu,
@@ -26,7 +26,7 @@ export const useMenuItem = <T extends MenuItemProps>({
checked, checked,
selected, selected,
block, block,
[mobileMenuItem]: environment.isMobileEdition, [mobileMenuItem]: BUILD_CONFIG.isMobileEdition,
}, },
propsClassName propsClassName
); );
@@ -149,7 +149,7 @@ export const ModalInner = forwardRef<HTMLDivElement, ModalProps>(
children, children,
contentWrapperClassName, contentWrapperClassName,
contentWrapperStyle, contentWrapperStyle,
animation = environment.isMobileEdition ? 'slideBottom' : 'fadeScaleTop', animation = BUILD_CONFIG.isMobileEdition ? 'slideBottom' : 'fadeScaleTop',
fullScreen, fullScreen,
...otherProps ...otherProps
} = props; } = props;
@@ -208,7 +208,7 @@ export const ModalInner = forwardRef<HTMLDivElement, ModalProps>(
`anim-${animation}`, `anim-${animation}`,
styles.modalOverlay, styles.modalOverlay,
overlayClassName, overlayClassName,
{ mobile: environment.isMobileEdition } { mobile: BUILD_CONFIG.isMobileEdition }
)} )}
style={{ style={{
...overlayStyle, ...overlayStyle,
@@ -216,7 +216,7 @@ export const ModalInner = forwardRef<HTMLDivElement, ModalProps>(
{...otherOverlayOptions} {...otherOverlayOptions}
> >
<SafeArea <SafeArea
bottom={environment.isMobileEdition} bottom={BUILD_CONFIG.isMobileEdition}
bottomOffset={12} bottomOffset={12}
data-full-screen={fullScreen} data-full-screen={fullScreen}
data-modal={modal} data-modal={modal}
@@ -30,7 +30,7 @@ export const SafeArea = forwardRef<HTMLDivElement, SafeAreaProps>(
<div <div
ref={ref} ref={ref}
className={clsx(safeArea, className)} className={clsx(safeArea, className)}
data-standalone={environment.isStandalone ? '' : undefined} data-standalone={environment.isPwa ? '' : undefined}
data-bottom={bottom ? '' : undefined} data-bottom={bottom ? '' : undefined}
data-top={top ? '' : undefined} data-top={top ? '' : undefined}
style={{ style={{
@@ -23,7 +23,7 @@ export function registerAffineCreationCommands({
category: 'affine:creation', category: 'affine:creation',
label: t['com.affine.cmdk.affine.new-page'](), label: t['com.affine.cmdk.affine.new-page'](),
icon: <PlusIcon />, icon: <PlusIcon />,
keyBinding: environment.isElectron keyBinding: BUILD_CONFIG.isElectron
? { ? {
binding: '$mod+N', binding: '$mod+N',
skipRegister: true, skipRegister: true,
@@ -73,7 +73,7 @@ export function registerAffineCreationCommands({
icon: <ImportIcon />, icon: <ImportIcon />,
label: t['com.affine.cmdk.affine.import-workspace'](), label: t['com.affine.cmdk.affine.import-workspace'](),
preconditionStrategy: () => { preconditionStrategy: () => {
return environment.isElectron; return BUILD_CONFIG.isElectron;
}, },
run() { run() {
track.$.cmdk.workspace.createWorkspace({ track.$.cmdk.workspace.createWorkspace({
@@ -183,7 +183,7 @@ export function registerAffineSettingsCommands({
`, `,
category: 'affine:settings', category: 'affine:settings',
icon: <SettingsIcon />, icon: <SettingsIcon />,
preconditionStrategy: () => environment.isElectron, preconditionStrategy: () => BUILD_CONFIG.isElectron,
run() { run() {
track.$.cmdk.settings.changeAppSetting({ track.$.cmdk.settings.changeAppSetting({
key: 'clientBorder', key: 'clientBorder',
@@ -231,7 +231,7 @@ export function registerAffineSettingsCommands({
]()}`, ]()}`,
category: 'affine:settings', category: 'affine:settings',
icon: <SettingsIcon />, icon: <SettingsIcon />,
preconditionStrategy: () => environment.isElectron, preconditionStrategy: () => BUILD_CONFIG.isElectron,
run() { run() {
track.$.cmdk.settings.changeAppSetting({ track.$.cmdk.settings.changeAppSetting({
key: 'enableNoisyBackground', key: 'enableNoisyBackground',
@@ -257,7 +257,8 @@ export function registerAffineSettingsCommands({
]()}`, ]()}`,
category: 'affine:settings', category: 'affine:settings',
icon: <SettingsIcon />, icon: <SettingsIcon />,
preconditionStrategy: () => environment.isElectron && environment.isMacOs, preconditionStrategy: () =>
BUILD_CONFIG.isElectron && environment.isMacOs,
run() { run() {
track.$.cmdk.settings.changeAppSetting({ track.$.cmdk.settings.changeAppSetting({
key: 'enableBlurBackground', key: 'enableBlurBackground',
@@ -2,7 +2,7 @@ import clsx from 'clsx';
import type { PropsWithChildren, ReactElement } from 'react'; import type { PropsWithChildren, ReactElement } from 'react';
import { useAppSettingHelper } from '../../hooks/affine/use-app-setting-helper'; import { useAppSettingHelper } from '../../hooks/affine/use-app-setting-helper';
import { AppSidebarFallback } from '../app-sidebar'; import { AppSidebarFallback, ShellAppSidebarFallback } from '../app-sidebar';
import type { WorkspaceRootProps } from '../workspace'; import type { WorkspaceRootProps } from '../workspace';
import { import {
AppContainer as AppContainerWithoutSettings, AppContainer as AppContainerWithoutSettings,
@@ -16,11 +16,7 @@ export const AppContainer = (props: WorkspaceRootProps) => {
return ( return (
<AppContainerWithoutSettings <AppContainerWithoutSettings
useNoisyBackground={appSettings.enableNoisyBackground} useNoisyBackground={appSettings.enableNoisyBackground}
useBlurBackground={ useBlurBackground={appSettings.enableBlurBackground}
appSettings.enableBlurBackground &&
environment.isElectron &&
environment.isMacOs
}
{...props} {...props}
/> />
); );
@@ -36,7 +32,7 @@ export const AppFallback = ({
<AppContainer <AppContainer
className={clsx( className={clsx(
className, className,
environment.isElectron && styles.electronFallback BUILD_CONFIG.isElectron && styles.electronFallback
)} )}
> >
<AppSidebarFallback /> <AppSidebarFallback />
@@ -44,3 +40,17 @@ export const AppFallback = ({
</AppContainer> </AppContainer>
); );
}; };
export const ShellAppFallback = ({
className,
children,
}: PropsWithChildren<{
className?: string;
}>): ReactElement => {
return (
<AppContainer className={className}>
<ShellAppSidebarFallback />
<MainContainerFallback>{children}</MainContainerFallback>
</AppContainer>
);
};
@@ -50,10 +50,10 @@ function OAuthProvider({ provider }: { provider: OAuthProviderType }) {
const onClick = useCallback(() => { const onClick = useCallback(() => {
let oauthUrl = let oauthUrl =
(environment.isElectron ? BUILD_CONFIG.serverUrlPrefix : '') + (BUILD_CONFIG.isElectron ? BUILD_CONFIG.serverUrlPrefix : '') +
`/oauth/login?provider=${provider}`; `/oauth/login?provider=${provider}`;
if (environment.isElectron) { if (BUILD_CONFIG.isElectron) {
oauthUrl += `&client=${appInfo?.schema}`; oauthUrl += `&client=${appInfo?.schema}`;
} }
@@ -122,7 +122,7 @@ const useSendEmail = (emailType: AuthPanelProps<'sendEmail'>['emailType']) => {
return trigger({ return trigger({
email, email,
callbackUrl: `/auth/${callbackUrl}?isClient=${ callbackUrl: `/auth/${callbackUrl}?isClient=${
environment.isElectron ? 'true' : 'false' BUILD_CONFIG.isElectron ? 'true' : 'false'
}`, }`,
}); });
}, },
@@ -14,7 +14,7 @@ type Challenge = {
}; };
const challengeFetcher = async (url: string) => { const challengeFetcher = async (url: string) => {
if (!environment.isElectron) { if (!BUILD_CONFIG.isElectron) {
return undefined; return undefined;
} }
@@ -31,7 +31,7 @@ const challengeFetcher = async (url: string) => {
}; };
const generateChallengeResponse = async (challenge: string) => { const generateChallengeResponse = async (challenge: string) => {
if (!environment.isElectron) { if (!BUILD_CONFIG.isElectron) {
return undefined; return undefined;
} }
@@ -56,7 +56,7 @@ export const Captcha = () => {
return null; return null;
} }
if (environment.isElectron) { if (BUILD_CONFIG.isElectron) {
if (response) { if (response) {
return <div className={style.captchaWrapper}>Making Challenge</div>; return <div className={style.captchaWrapper}>Making Challenge</div>;
} else { } else {
@@ -86,8 +86,8 @@ export const useCaptcha = (): [string | undefined, string?] => {
useEffect(() => { useEffect(() => {
if ( if (
BUILD_CONFIG.isElectron &&
hasCaptchaFeature && hasCaptchaFeature &&
environment.isElectron &&
challenge?.challenge && challenge?.challenge &&
prevChallenge.current !== challenge.challenge prevChallenge.current !== challenge.challenge
) { ) {
@@ -104,7 +104,7 @@ export const useCaptcha = (): [string | undefined, string?] => {
return ['XXXX.DUMMY.TOKEN.XXXX']; return ['XXXX.DUMMY.TOKEN.XXXX'];
} }
if (environment.isElectron) { if (BUILD_CONFIG.isElectron) {
if (response) { if (response) {
return [response, challenge?.challenge]; return [response, challenge?.challenge];
} else { } else {
@@ -17,11 +17,11 @@ export const ActionButton = ({
<Button <Button
size="large" size="large"
className={clsx( className={clsx(
environment.isMobileEdition ? mobileActionButton : actionButton, BUILD_CONFIG.isMobileEdition ? mobileActionButton : actionButton,
className className
)} )}
contentClassName={clsx( contentClassName={clsx(
environment.isMobileEdition ? mobileActionContent : actionContent, BUILD_CONFIG.isMobileEdition ? mobileActionContent : actionContent,
contentClassName contentClassName
)} )}
{...props} {...props}
@@ -30,7 +30,9 @@ export const EmptyCollectionDetail = ({
title={t['com.affine.empty.collection-detail.title']()} title={t['com.affine.empty.collection-detail.title']()}
description={t['com.affine.empty.collection-detail.description']()} description={t['com.affine.empty.collection-detail.description']()}
action={ action={
environment.isMobileEdition ? null : <Actions collection={collection} /> BUILD_CONFIG.isMobileEdition ? null : (
<Actions collection={collection} />
)
} }
{...props} {...props}
/> />
@@ -31,7 +31,7 @@ export const EmptyDocs = ({
const pageHelper = usePageHelper(currentWorkspace.docCollection); const pageHelper = usePageHelper(currentWorkspace.docCollection);
const tag = useLiveData(tagService.tagList.tagByTagId$(tagId)); const tag = useLiveData(tagService.tagList.tagByTagId$(tagId));
const showActionButton = type !== 'trash'; // && !environment.isMobileEdition; const showActionButton = type !== 'trash'; // && !BUILD_CONFIG.isMobileEdition;
const onCreate = useCallback( const onCreate = useCallback(
(e: MouseEvent) => { (e: MouseEvent) => {
@@ -43,7 +43,7 @@ export const Onboarding = ({ onOpenApp }: OnboardingProps) => {
return ( return (
<div <div
className={styles.onboarding} className={styles.onboarding}
data-is-desktop={environment.isElectron} data-is-desktop={BUILD_CONFIG.isElectron}
data-is-window={!!status.activeId || !!status.unfoldingId} data-is-window={!!status.activeId || !!status.unfoldingId}
> >
<div className={styles.offsetOrigin}> <div className={styles.offsetOrigin}>
@@ -72,7 +72,7 @@ export const AboutAffine = () => {
name={t['com.affine.aboutAFFiNE.version.editor.title']()} name={t['com.affine.aboutAFFiNE.version.editor.title']()}
desc={BUILD_CONFIG.editorVersion} desc={BUILD_CONFIG.editorVersion}
/> />
{environment.isElectron ? ( {BUILD_CONFIG.isElectron ? (
<> <>
<UpdateCheckSection /> <UpdateCheckSection />
<SettingRow <SettingRow
@@ -86,7 +86,7 @@ export const AppearanceSettings = () => {
<LanguageMenu /> <LanguageMenu />
</div> </div>
</SettingRow> </SettingRow>
{environment.isElectron ? ( {BUILD_CONFIG.isElectron ? (
<SettingRow <SettingRow
name={t['com.affine.appearanceSettings.clientBorder.title']()} name={t['com.affine.appearanceSettings.clientBorder.title']()}
desc={t['com.affine.appearanceSettings.clientBorder.description']()} desc={t['com.affine.appearanceSettings.clientBorder.description']()}
@@ -98,7 +98,7 @@ export const AppearanceSettings = () => {
/> />
</SettingRow> </SettingRow>
) : null} ) : null}
{BUILD_CONFIG.enableNewSettingUnstableApi && environment.isElectron ? ( {BUILD_CONFIG.enableNewSettingUnstableApi && BUILD_CONFIG.isElectron ? (
<SettingRow <SettingRow
name={t['com.affine.appearanceSettings.windowFrame.title']()} name={t['com.affine.appearanceSettings.windowFrame.title']()}
desc={t['com.affine.appearanceSettings.windowFrame.description']()} desc={t['com.affine.appearanceSettings.windowFrame.description']()}
@@ -144,7 +144,7 @@ export const AppearanceSettings = () => {
</SettingWrapper> </SettingWrapper>
) : null} ) : null}
{environment.isElectron ? ( {BUILD_CONFIG.isElectron ? (
<SettingWrapper <SettingWrapper
title={t['com.affine.appearanceSettings.sidebar.title']()} title={t['com.affine.appearanceSettings.sidebar.title']()}
> >
@@ -13,7 +13,7 @@ export const ThemeEditorSetting = () => {
const modified = useLiveData(themeEditor.modified$); const modified = useLiveData(themeEditor.modified$);
const open = useCallback(() => { const open = useCallback(() => {
if (environment.isElectron) { if (BUILD_CONFIG.isElectron) {
apis?.ui.openThemeEditor().catch(console.error); apis?.ui.openThemeEditor().catch(console.error);
} else { } else {
popupWindow('/theme-editor'); popupWindow('/theme-editor');
@@ -89,7 +89,7 @@ const FontFamilySettings = () => {
const radioItems = useMemo(() => { const radioItems = useMemo(() => {
const items = getBaseFontStyleOptions(t); const items = getBaseFontStyleOptions(t);
if (!environment.isElectron) return items; if (!BUILD_CONFIG.isElectron) return items;
// resolve custom fonts // resolve custom fonts
const customOption = fontStyleOptions.find(opt => opt.key === 'Custom'); const customOption = fontStyleOptions.find(opt => opt.key === 'Custom');
@@ -279,7 +279,7 @@ const CustomFontFamilySettings = () => {
}, },
[editorSettingService.editorSetting] [editorSettingService.editorSetting]
); );
if (settings.fontFamily !== 'Custom' || !environment.isElectron) { if (settings.fontFamily !== 'Custom' || !BUILD_CONFIG.isElectron) {
return null; return null;
} }
return ( return (
@@ -69,7 +69,7 @@ export const WorkspaceSettingDetail = ({
<MembersPanel /> <MembersPanel />
</SettingWrapper> </SettingWrapper>
<SharingPanel /> <SharingPanel />
{environment.isElectron && ( {BUILD_CONFIG.isElectron && (
<SettingWrapper title={t['Storage and Export']()}> <SettingWrapper title={t['Storage and Export']()}>
<ExportPanel <ExportPanel
workspace={workspace} workspace={workspace}
@@ -156,8 +156,6 @@ export const AFFiNESharePage = (props: ShareMenuProps) => {
} }
}, [shareInfoService, t]); }, [shareInfoService, t]);
const isMac = environment.isMacOs;
const { blockIds, elementIds } = useMemo( const { blockIds, elementIds } = useMemo(
() => getSelectedNodes(editorContainer?.host || null, currentMode), () => getSelectedNodes(editorContainer?.host || null, currentMode),
[editorContainer, currentMode] [editorContainer, currentMode]
@@ -270,9 +268,9 @@ export const AFFiNESharePage = (props: ShareMenuProps) => {
<span className={styles.copyLinkLabelStyle}> <span className={styles.copyLinkLabelStyle}>
{t['com.affine.share-menu.copy']()} {t['com.affine.share-menu.copy']()}
</span> </span>
{!environment.isMobile && ( {BUILD_CONFIG.isDesktopEdition && (
<span className={styles.copyLinkShortcutStyle}> <span className={styles.copyLinkShortcutStyle}>
{isMac ? '⌘ + ⌥ + C' : 'Ctrl + Shift + C'} {environment.isMacOs ? '⌘ + ⌥ + C' : 'Ctrl + Shift + C'}
</span> </span>
)} )}
</Button> </Button>
@@ -49,7 +49,6 @@ const SubscriptionChangedNotifyFooter = ({
); );
}; };
const isDesktop = environment.isElectron;
export const useUpgradeNotify = () => { export const useUpgradeNotify = () => {
const t = useI18n(); const t = useI18n();
const prevNotifyIdRef = useRef<string | number | null>(null); const prevNotifyIdRef = useRef<string | number | null>(null);
@@ -71,7 +70,7 @@ export const useUpgradeNotify = () => {
<SubscriptionChangedNotifyFooter <SubscriptionChangedNotifyFooter
to={link} to={link}
okText={ okText={
isDesktop BUILD_CONFIG.isElectron
? t['com.affine.payment.upgrade-success-notify.ok-client']() ? t['com.affine.payment.upgrade-success-notify.ok-client']()
: t['com.affine.payment.upgrade-success-notify.ok-web']() : t['com.affine.payment.upgrade-success-notify.ok-web']()
} }
@@ -112,7 +111,7 @@ export const useDowngradeNotify = () => {
<SubscriptionChangedNotifyFooter <SubscriptionChangedNotifyFooter
to={link} to={link}
okText={ okText={
isDesktop BUILD_CONFIG.isElectron
? t['com.affine.payment.downgraded-notify.ok-client']() ? t['com.affine.payment.downgraded-notify.ok-client']()
: t['com.affine.payment.downgraded-notify.ok-web']() : t['com.affine.payment.downgraded-notify.ok-web']()
} }
@@ -2,7 +2,7 @@ import { atom } from 'jotai';
import { atomWithStorage } from 'jotai/utils'; import { atomWithStorage } from 'jotai/utils';
export const APP_SIDEBAR_OPEN = 'app-sidebar-open'; export const APP_SIDEBAR_OPEN = 'app-sidebar-open';
export const isMobile = window.innerWidth < 768 && !environment.isElectron; export const isMobile = !BUILD_CONFIG.isElectron && window.innerWidth < 768;
export const appSidebarOpenAtom = atomWithStorage(APP_SIDEBAR_OPEN, !isMobile); export const appSidebarOpenAtom = atomWithStorage(APP_SIDEBAR_OPEN, !isMobile);
export const appSidebarFloatingAtom = atom(isMobile); export const appSidebarFloatingAtom = atom(isMobile);
@@ -47,7 +47,7 @@ export function AppSidebar({ children }: PropsWithChildren) {
useEffect(() => { useEffect(() => {
// do not float app sidebar on desktop // do not float app sidebar on desktop
if (environment.isElectron) { if (BUILD_CONFIG.isElectron) {
return; return;
} }
@@ -77,8 +77,9 @@ export function AppSidebar({ children }: PropsWithChildren) {
}; };
}, [open, setFloating, setOpen, width]); }, [open, setFloating, setOpen, width]);
const hasRightBorder = !environment.isElectron && !clientBorder; const hasRightBorder = !BUILD_CONFIG.isElectron && !clientBorder;
const isMacosDesktop = environment.isElectron && environment.isMacOs; const isMacosDesktop = BUILD_CONFIG.isElectron && environment.isMacOs;
return ( return (
<> <>
<ResizePanel <ResizePanel
@@ -103,7 +104,7 @@ export function AppSidebar({ children }: PropsWithChildren) {
data-client-border={clientBorder} data-client-border={clientBorder}
> >
<nav className={navStyle} data-testid="app-sidebar"> <nav className={navStyle} data-testid="app-sidebar">
{!environment.isElectron && <SidebarHeader />} {!BUILD_CONFIG.isElectron && <SidebarHeader />}
<div className={navBodyStyle} data-testid="sliderBar-inner"> <div className={navBodyStyle} data-testid="sliderBar-inner">
{children} {children}
</div> </div>
@@ -120,7 +121,15 @@ export function AppSidebar({ children }: PropsWithChildren) {
); );
} }
const FallbackHeader = () => { export function FallbackHeader() {
return (
<div className={styles.fallbackHeader}>
<FallbackHeaderSkeleton />
</div>
);
}
export function FallbackHeaderWithWorkspaceNavigator() {
// if navigate is not defined, it is rendered outside of router // if navigate is not defined, it is rendered outside of router
// WorkspaceNavigator requires navigate context // WorkspaceNavigator requires navigate context
// todo: refactor // todo: refactor
@@ -136,15 +145,21 @@ const FallbackHeader = () => {
showEnableCloudButton showEnableCloudButton
/> />
) : ( ) : (
<> <FallbackHeaderSkeleton />
<Skeleton variant="rectangular" width={32} height={32} />
<Skeleton variant="rectangular" width={150} height={32} flex={1} />
<Skeleton variant="circular" width={25} height={25} />
</>
)} )}
</div> </div>
); );
}; }
export function FallbackHeaderSkeleton() {
return (
<>
<Skeleton variant="rectangular" width={32} height={32} />
<Skeleton variant="rectangular" width={150} height={32} flex={1} />
<Skeleton variant="circular" width={25} height={25} />
</>
);
}
const randomWidth = () => { const randomWidth = () => {
return Math.floor(Math.random() * 200) + 100; return Math.floor(Math.random() * 200) + 100;
@@ -195,17 +210,44 @@ export const AppSidebarFallback = (): ReactElement | null => {
const width = useAtomValue(appSidebarWidthAtom); const width = useAtomValue(appSidebarWidthAtom);
const { appSettings } = useAppSettingHelper(); const { appSettings } = useAppSettingHelper();
const clientBorder = appSettings.clientBorder; const clientBorder = appSettings.clientBorder;
const hasRightBorder = !environment.isElectron && !clientBorder;
return ( return (
<div <div
style={{ width }} style={{ width }}
className={navWrapperStyle} className={navWrapperStyle}
data-has-border={hasRightBorder} data-has-border={!BUILD_CONFIG.isElectron && !clientBorder}
data-open="true" data-open="true"
> >
<nav className={navStyle}> <nav className={navStyle}>
{!environment.isElectron ? <div className={navHeaderStyle} /> : null} {!BUILD_CONFIG.isElectron ? <div className={navHeaderStyle} /> : null}
<div className={navBodyStyle}>
<div className={styles.fallback}>
<FallbackHeaderWithWorkspaceNavigator />
<FallbackBody />
</div>
</div>
</nav>
</div>
);
};
/**
* NOTE(@forehalo): this is a copy of [AppSidebarFallback] without [WorkspaceNavigator] which will introduce a lot useless dependencies for shell(tab bar)
*/
export const ShellAppSidebarFallback = () => {
const width = useAtomValue(appSidebarWidthAtom);
const { appSettings } = useAppSettingHelper();
const clientBorder = appSettings.clientBorder;
return (
<div
style={{ width }}
className={navWrapperStyle}
data-has-border={!BUILD_CONFIG.isElectron && !clientBorder}
data-open="true"
>
<nav className={navStyle}>
{!BUILD_CONFIG.isElectron ? <div className={navHeaderStyle} /> : null}
<div className={navBodyStyle}> <div className={navBodyStyle}>
<div className={styles.fallback}> <div className={styles.fallback}>
<FallbackHeader /> <FallbackHeader />
@@ -13,7 +13,6 @@ interface QuickSearchInputProps extends HTMLAttributes<HTMLDivElement> {
// Although it is called an input, it is actually a button. // Although it is called an input, it is actually a button.
export function QuickSearchInput({ onClick, ...props }: QuickSearchInputProps) { export function QuickSearchInput({ onClick, ...props }: QuickSearchInputProps) {
const t = useI18n(); const t = useI18n();
const isMac = environment.isMacOs;
return ( return (
<div <div
@@ -27,7 +26,7 @@ export function QuickSearchInput({ onClick, ...props }: QuickSearchInputProps) {
</span> </span>
<div className={styles.spacer} /> <div className={styles.spacer} />
<div className={styles.shortcutHint}> <div className={styles.shortcutHint}>
{isMac ? ' ⌘ + K' : ' Ctrl + K'} {environment.isMacOs ? ' ⌘ + K' : ' Ctrl + K'}
</div> </div>
<Spotlight /> <Spotlight />
</div> </div>
@@ -292,8 +292,7 @@ export const PageHeaderMenuButton = ({
> >
{t['com.affine.workbench.tab.page-menu-open']()} {t['com.affine.workbench.tab.page-menu-open']()}
</MenuItem> </MenuItem>
{BUILD_CONFIG.isElectron && (
{environment.isElectron && (
<MenuItem <MenuItem
prefixIcon={<SplitViewIcon />} prefixIcon={<SplitViewIcon />}
data-testid="editor-option-menu-open-in-split-new" data-testid="editor-option-menu-open-in-split-new"
@@ -176,12 +176,10 @@ export const PageOperationCell = ({
<MenuItem onClick={onOpenInfoModal} prefixIcon={<InformationIcon />}> <MenuItem onClick={onOpenInfoModal} prefixIcon={<InformationIcon />}>
{t['com.affine.page-properties.page-info.view']()} {t['com.affine.page-properties.page-info.view']()}
</MenuItem> </MenuItem>
<MenuItem onClick={onOpenInNewTab} prefixIcon={<OpenInNewIcon />}> <MenuItem onClick={onOpenInNewTab} prefixIcon={<OpenInNewIcon />}>
{t['com.affine.workbench.tab.page-menu-open']()} {t['com.affine.workbench.tab.page-menu-open']()}
</MenuItem> </MenuItem>
{BUILD_CONFIG.isElectron && enableSplitView ? (
{environment.isElectron && enableSplitView ? (
<MenuItem onClick={onOpenInSplitView} prefixIcon={<SplitViewIcon />}> <MenuItem onClick={onOpenInSplitView} prefixIcon={<SplitViewIcon />}>
{t['com.affine.workbench.split-view.page-menu-open']()} {t['com.affine.workbench.split-view.page-menu-open']()}
</MenuItem> </MenuItem>
@@ -154,7 +154,7 @@ export const CollectionOperations = ({
name: t['com.affine.workbench.tab.page-menu-open'](), name: t['com.affine.workbench.tab.page-menu-open'](),
click: openCollectionNewTab, click: openCollectionNewTab,
}, },
...(enableMultiView && environment.isElectron ...(BUILD_CONFIG.isElectron && enableMultiView
? [ ? [
{ {
icon: <SplitViewIcon />, icon: <SplitViewIcon />,
@@ -29,7 +29,9 @@ const DEFAULT_SHOW_LIST: IslandItemNames[] = [
const DESKTOP_SHOW_LIST: IslandItemNames[] = [...DEFAULT_SHOW_LIST]; const DESKTOP_SHOW_LIST: IslandItemNames[] = [...DEFAULT_SHOW_LIST];
type IslandItemNames = 'whatNew' | 'contact' | 'shortcuts'; type IslandItemNames = 'whatNew' | 'contact' | 'shortcuts';
const showList = environment.isElectron ? DESKTOP_SHOW_LIST : DEFAULT_SHOW_LIST; const showList = BUILD_CONFIG.isElectron
? DESKTOP_SHOW_LIST
: DEFAULT_SHOW_LIST;
export const HelpIsland = () => { export const HelpIsland = () => {
const { globalContextService } = useServices({ const { globalContextService } = useServices({
@@ -106,7 +106,7 @@ export const RootAppSidebar = (): ReactElement => {
); );
useEffect(() => { useEffect(() => {
if (environment.isElectron) { if (BUILD_CONFIG.isElectron) {
return events?.applicationMenu.onNewPageAction(() => { return events?.applicationMenu.onNewPageAction(() => {
apis?.ui apis?.ui
.isActiveTab() .isActiveTab()
@@ -197,7 +197,7 @@ export const RootAppSidebar = (): ReactElement => {
</div> </div>
</SidebarScrollableContainer> </SidebarScrollableContainer>
<SidebarContainer> <SidebarContainer>
{environment.isElectron ? <UpdaterButton /> : <AppDownloadButton />} {BUILD_CONFIG.isElectron ? <UpdaterButton /> : <AppDownloadButton />}
</SidebarContainer> </SidebarContainer>
</AppSidebar> </AppSidebar>
); );
@@ -12,12 +12,12 @@ import { AuthService } from '../modules/cloud';
const minimumChromeVersion = 106; const minimumChromeVersion = 106;
const shouldShowWarning = (() => { const shouldShowWarning = (() => {
if (environment.isElectron) { if (BUILD_CONFIG.isElectron) {
// even though desktop has compatibility issues, // even though desktop has compatibility issues,
// we don't want to show the warning // we don't want to show the warning
return false; return false;
} }
if (environment.isMobile) { if (BUILD_CONFIG.isMobileEdition) {
return true; return true;
} }
if (environment.isChrome && environment.chromeVersion) { if (environment.isChrome && environment.chromeVersion) {
@@ -75,8 +75,8 @@ export const TopTip = ({
}, [setAuthModal]); }, [setAuthModal]);
if ( if (
!BUILD_CONFIG.isElectron &&
showLocalDemoTips && showLocalDemoTips &&
!environment.isElectron &&
workspace.flavour === WorkspaceFlavour.LOCAL workspace.flavour === WorkspaceFlavour.LOCAL
) { ) {
return ( return (
@@ -15,7 +15,7 @@ export const AddWorkspace = ({
return ( return (
<div> <div>
{environment.isElectron ? ( {BUILD_CONFIG.isElectron && (
<MenuItem <MenuItem
block={true} block={true}
prefixIcon={<ImportIcon />} prefixIcon={<ImportIcon />}
@@ -27,7 +27,7 @@ export const AddWorkspace = ({
{t['com.affine.workspace.local.import']()} {t['com.affine.workspace.local.import']()}
</div> </div>
</MenuItem> </MenuItem>
) : null} )}
<MenuItem <MenuItem
block={true} block={true}
prefixIcon={<PlusIcon />} prefixIcon={<PlusIcon />}
@@ -60,7 +60,7 @@ const UnSyncWorkspaceStatus = () => {
const LocalWorkspaceStatus = () => { const LocalWorkspaceStatus = () => {
return ( return (
<> <>
{!environment.isElectron ? ( {!BUILD_CONFIG.isElectron ? (
<InformationFillDuotoneIcon style={{ color: cssVar('errorColor') }} /> <InformationFillDuotoneIcon style={{ color: cssVar('errorColor') }} />
) : ( ) : (
<LocalWorkspaceIcon /> <LocalWorkspaceIcon />
@@ -98,7 +98,7 @@ const useSyncEngineSyncProgress = (meta: WorkspaceMetadata) => {
let content; let content;
// TODO(@eyhn): add i18n // TODO(@eyhn): add i18n
if (workspace.flavour === WorkspaceFlavour.LOCAL) { if (workspace.flavour === WorkspaceFlavour.LOCAL) {
if (!environment.isElectron) { if (!BUILD_CONFIG.isElectron) {
content = 'This is a local demo workspace.'; content = 'This is a local demo workspace.';
} else { } else {
content = 'Saved locally'; content = 'Saved locally';
@@ -28,8 +28,9 @@ export const AppContainer = ({
className, className,
...rest ...rest
}: WorkspaceRootProps) => { }: WorkspaceRootProps) => {
const noisyBackground = useNoisyBackground && environment.isElectron; const noisyBackground = BUILD_CONFIG.isElectron && useNoisyBackground;
const blurBackground = environment.isElectron && useBlurBackground; const blurBackground =
BUILD_CONFIG.isElectron && environment.isMacOs && useBlurBackground;
return ( return (
<div <div
{...rest} {...rest}
@@ -59,7 +60,7 @@ export const MainContainer = forwardRef<
<div <div
{...props} {...props}
className={clsx(mainContainerStyle, className)} className={clsx(mainContainerStyle, className)}
data-is-desktop={environment.isElectron} data-is-desktop={BUILD_CONFIG.isElectron}
data-transparent={false} data-transparent={false}
data-client-border={appSettings.clientBorder} data-client-border={appSettings.clientBorder}
data-side-bar-open={appSideBarOpen} data-side-bar-open={appSideBarOpen}
@@ -18,7 +18,7 @@ export function useRegisterFindInPageCommands() {
}, [findInPage]); }, [findInPage]);
useEffect(() => { useEffect(() => {
if (!environment.isElectron) { if (!BUILD_CONFIG.isElectron) {
return; return;
} }
const unsubs: Array<() => void> = []; const unsubs: Array<() => void> = [];
@@ -279,50 +279,56 @@ export const useWinMarkdownShortcuts = (): ShortcutMap => {
); );
}; };
const shortcutsMap = environment.isMacOs
? {
useMarkdownShortcuts: useMacMarkdownShortcuts,
usePageShortcuts: useMacPageKeyboardShortcuts,
useEdgelessShortcuts: useMacEdgelessKeyboardShortcuts,
useGeneralShortcuts: useMacGeneralKeyboardShortcuts,
}
: {
useMarkdownShortcuts: useWinMarkdownShortcuts,
usePageShortcuts: useWinPageKeyboardShortcuts,
useEdgelessShortcuts: useWinEdgelessKeyboardShortcuts,
useGeneralShortcuts: useWinGeneralKeyboardShortcuts,
};
export const useMarkdownShortcuts = (): ShortcutsInfo => { export const useMarkdownShortcuts = (): ShortcutsInfo => {
const t = useI18n(); const t = useI18n();
const shortcuts = shortcutsMap.useMarkdownShortcuts();
const macMarkdownShortcuts = useMacMarkdownShortcuts();
const winMarkdownShortcuts = useWinMarkdownShortcuts();
const isMac = environment.isMacOs;
return { return {
title: t['com.affine.shortcutsTitle.markdownSyntax'](), title: t['com.affine.shortcutsTitle.markdownSyntax'](),
shortcuts: isMac ? macMarkdownShortcuts : winMarkdownShortcuts, shortcuts,
}; };
}; };
export const usePageShortcuts = (): ShortcutsInfo => { export const usePageShortcuts = (): ShortcutsInfo => {
const t = useI18n(); const t = useI18n();
const shortcuts = shortcutsMap.usePageShortcuts();
const macPageShortcuts = useMacPageKeyboardShortcuts();
const winPageShortcuts = useWinPageKeyboardShortcuts();
const isMac = environment.isMacOs;
return { return {
title: t['com.affine.shortcutsTitle.page'](), title: t['com.affine.shortcutsTitle.page'](),
shortcuts: isMac ? macPageShortcuts : winPageShortcuts, shortcuts,
}; };
}; };
export const useEdgelessShortcuts = (): ShortcutsInfo => { export const useEdgelessShortcuts = (): ShortcutsInfo => {
const t = useI18n(); const t = useI18n();
const shortcuts = shortcutsMap.useEdgelessShortcuts();
const macEdgelessShortcuts = useMacEdgelessKeyboardShortcuts();
const winEdgelessShortcuts = useWinEdgelessKeyboardShortcuts();
const isMac = environment.isMacOs;
return { return {
title: t['com.affine.shortcutsTitle.edgeless'](), title: t['com.affine.shortcutsTitle.edgeless'](),
shortcuts: isMac ? macEdgelessShortcuts : winEdgelessShortcuts, shortcuts,
}; };
}; };
export const useGeneralShortcuts = (): ShortcutsInfo => { export const useGeneralShortcuts = (): ShortcutsInfo => {
const t = useI18n(); const t = useI18n();
const shortcuts = shortcutsMap.useGeneralShortcuts();
const macGeneralShortcuts = useMacGeneralKeyboardShortcuts();
const winGeneralShortcuts = useWinGeneralKeyboardShortcuts();
const isMac = environment.isMacOs;
return { return {
title: t['com.affine.shortcutsTitle.general'](), title: t['com.affine.shortcutsTitle.general'](),
shortcuts: isMac ? macGeneralShortcuts : winGeneralShortcuts, shortcuts,
}; };
}; };
@@ -1,5 +1,4 @@
import { apis } from '@affine/electron-api'; import { apis } from '@affine/electron-api';
import { setupGlobal } from '@affine/env/global';
import { assertExists } from '@blocksuite/global/utils'; import { assertExists } from '@blocksuite/global/utils';
import type { AppConfigSchema } from '@toeverything/infra'; import type { AppConfigSchema } from '@toeverything/infra';
import { AppConfigStorage, defaultAppConfig } from '@toeverything/infra'; import { AppConfigStorage, defaultAppConfig } from '@toeverything/infra';
@@ -33,9 +32,7 @@ class AppConfigProxy {
} }
export const appConfigProxy = new AppConfigProxy(); export const appConfigProxy = new AppConfigProxy();
setupGlobal(); const storage = BUILD_CONFIG.isElectron
const storage = environment.isElectron
? new AppConfigStorage({ ? new AppConfigStorage({
config: defaultAppConfig, config: defaultAppConfig,
get: () => appConfigProxy.get(), get: () => appConfigProxy.get(),
@@ -29,7 +29,7 @@ function rpcToObservable<
return new Observable<T | null>(subscriber => { return new Observable<T | null>(subscriber => {
subscriber.next(initialValue); subscriber.next(initialValue);
onSubscribe?.(); onSubscribe?.();
if (!environment.isElectron || !event) { if (!BUILD_CONFIG.isElectron || !event) {
subscriber.complete(); subscriber.complete();
return; return;
} }
@@ -3,7 +3,7 @@ import { useEffect } from 'react';
export function useDocumentTitle(newTitle?: string | null) { export function useDocumentTitle(newTitle?: string | null) {
useEffect(() => { useEffect(() => {
if (environment.isElectron || !newTitle) { if (BUILD_CONFIG.isElectron || !newTitle) {
return noop; return noop;
} }
@@ -211,6 +211,8 @@ const BrowserLayout = ({ children }: PropsWithChildren) => {
); );
}; };
const LayoutComponent = BUILD_CONFIG.isElectron ? DesktopLayout : BrowserLayout;
/** /**
* Wraps the workspace layout main router view * Wraps the workspace layout main router view
*/ */
@@ -223,9 +225,6 @@ const WorkspaceLayoutUIContainer = ({ children }: PropsWithChildren) => {
); );
const resizing = useAtomValue(appSidebarResizingAtom); const resizing = useAtomValue(appSidebarResizingAtom);
const LayoutComponent = environment.isElectron
? DesktopLayout
: BrowserLayout;
return ( return (
<AppContainer data-current-path={currentPath} resizing={resizing}> <AppContainer data-current-path={currentPath} resizing={resizing}>
@@ -35,8 +35,8 @@ function createMixpanel() {
appVersion: BUILD_CONFIG.appVersion, appVersion: BUILD_CONFIG.appVersion,
environment: BUILD_CONFIG.appBuildType, environment: BUILD_CONFIG.appBuildType,
editorVersion: BUILD_CONFIG.editorVersion, editorVersion: BUILD_CONFIG.editorVersion,
isSelfHosted: Boolean(BUILD_CONFIG.isSelfHosted), isSelfHosted: BUILD_CONFIG.isSelfHosted,
isDesktop: environment.isElectron, isDesktop: BUILD_CONFIG.isElectron,
}); });
}, },
reset() { reset() {
@@ -303,7 +303,8 @@ export const AppTabsHeader = ({
const sidebarWidth = useAtomValue(appSidebarWidthAtom); const sidebarWidth = useAtomValue(appSidebarWidthAtom);
const sidebarOpen = useAtomValue(appSidebarOpenAtom); const sidebarOpen = useAtomValue(appSidebarOpenAtom);
const sidebarResizing = useAtomValue(appSidebarResizingAtom); const sidebarResizing = useAtomValue(appSidebarResizingAtom);
const isMacosDesktop = environment.isElectron && environment.isMacOs; const isMacosDesktop = BUILD_CONFIG.isElectron && environment.isMacOs;
const isWindowsDesktop = BUILD_CONFIG.isElectron && environment.isWindows;
const fullScreen = useIsFullScreen(); const fullScreen = useIsFullScreen();
const tabsHeaderService = useService(AppTabsHeaderService); const tabsHeaderService = useService(AppTabsHeaderService);
@@ -412,7 +413,7 @@ export const AppTabsHeader = ({
className={clsx(styles.root, className)} className={clsx(styles.root, className)}
style={style} style={style}
data-mode={mode} data-mode={mode}
data-is-windows={environment.isElectron && environment.isWindows} data-is-windows={isWindowsDesktop}
> >
<div <div
style={{ style={{
@@ -473,9 +474,9 @@ export const AppTabsHeader = ({
<IconButton size="24" onClick={onToggleRightSidebar}> <IconButton size="24" onClick={onToggleRightSidebar}>
<RightSidebarIcon /> <RightSidebarIcon />
</IconButton> </IconButton>
{environment.isElectron && environment.isWindows ? ( {isWindowsDesktop && (
<div className={styles.windowsAppControlsPlaceholder} /> <div className={styles.windowsAppControlsPlaceholder} />
) : null} )}
</div> </div>
); );
}; };
@@ -91,7 +91,7 @@ export class AuthService extends Service {
email, email,
// we call it [callbackUrl] instead of [redirect_uri] // we call it [callbackUrl] instead of [redirect_uri]
// to make it clear the url is used to finish the sign-in process instead of redirect after signed-in // to make it clear the url is used to finish the sign-in process instead of redirect after signed-in
callbackUrl: `/magic-link?client=${environment.isElectron ? appInfo?.schema : 'web'}`, callbackUrl: `/magic-link?client=${BUILD_CONFIG.isElectron ? appInfo?.schema : 'web'}`,
}), }),
headers: { headers: {
'content-type': 'application/json', 'content-type': 'application/json',
@@ -5,7 +5,7 @@ import { fromPromise, Service } from '@toeverything/infra';
import { BackendError, NetworkError } from '../error'; import { BackendError, NetworkError } from '../error';
export function getAffineCloudBaseUrl(): string { export function getAffineCloudBaseUrl(): string {
if (environment.isElectron) { if (BUILD_CONFIG.isElectron) {
return BUILD_CONFIG.serverUrlPrefix; return BUILD_CONFIG.serverUrlPrefix;
} }
const { protocol, hostname, port } = window.location; const { protocol, hostname, port } = window.location;
@@ -28,7 +28,7 @@ const getDefaultSubscriptionSuccessCallbackLink = (
plan === SubscriptionPlan.AI ? '/ai-upgrade-success' : '/upgrade-success'; plan === SubscriptionPlan.AI ? '/ai-upgrade-success' : '/upgrade-success';
const urlString = getAffineCloudBaseUrl() + path; const urlString = getAffineCloudBaseUrl() + path;
const url = new URL(urlString); const url = new URL(urlString);
if (environment.isElectron && appInfo) { if (BUILD_CONFIG.isElectron && appInfo) {
url.searchParams.set('schema', appInfo.schema); url.searchParams.set('schema', appInfo.schema);
} }
return url.toString(); return url.toString();
@@ -183,7 +183,7 @@ export const useExplorerCollectionNodeOperations = (
</MenuItem> </MenuItem>
), ),
}, },
...(environment.isElectron && enableMultiView ...(BUILD_CONFIG.isElectron && enableMultiView
? [ ? [
{ {
index: 99, index: 99,
@@ -192,7 +192,7 @@ export const useExplorerDocNodeOperations = (
</MenuItem> </MenuItem>
), ),
}, },
...(enableMultiView && environment.isElectron ...(BUILD_CONFIG.isElectron && enableMultiView
? [ ? [
{ {
index: 100, index: 100,
@@ -119,7 +119,7 @@ export const useExplorerTagNodeOperations = (
</MenuItem> </MenuItem>
), ),
}, },
...(enableMultiView && environment.isElectron ...(BUILD_CONFIG.isElectron && enableMultiView
? [ ? [
{ {
index: 100, index: 100,
@@ -40,7 +40,7 @@ export class Navigator extends Entity {
); );
back() { back() {
if (!environment.isElectron) { if (!BUILD_CONFIG.isElectron) {
window.history.back(); window.history.back();
} else { } else {
this.history$.value.back(); this.history$.value.back();
@@ -48,7 +48,7 @@ export class Navigator extends Entity {
} }
forward() { forward() {
if (!environment.isElectron) { if (!BUILD_CONFIG.isElectron) {
window.history.forward(); window.history.forward();
} else { } else {
this.history$.value.forward(); this.history$.value.forward();
@@ -10,6 +10,14 @@ import * as styles from './navigation-buttons.css';
const tooltipSideBottom = { side: 'bottom' as const }; const tooltipSideBottom = { side: 'bottom' as const };
export const NavigationButtons = () => { export const NavigationButtons = () => {
if (!BUILD_CONFIG.isElectron) {
return null;
}
return <ElectronNavigationButtons />;
};
const ElectronNavigationButtons = () => {
const t = useI18n(); const t = useI18n();
const navigator = useService(NavigatorService).navigator; const navigator = useService(NavigatorService).navigator;
@@ -44,10 +52,6 @@ export const NavigationButtons = () => {
}; };
}, [navigator]); }, [navigator]);
if (!environment.isElectron) {
return null;
}
return ( return (
<div className={styles.container}> <div className={styles.container}>
<IconButton <IconButton
@@ -129,7 +129,7 @@ export const DocPeekViewControls = ({
peekView.close('none'); peekView.close('none');
}, },
}, },
environment.isElectron && { BUILD_CONFIG.isElectron && {
icon: <SplitViewIcon />, icon: <SplitViewIcon />,
nameKey: 'split-view', nameKey: 'split-view',
name: t['com.affine.peek-view-controls.open-doc-in-split-view'](), name: t['com.affine.peek-view-controls.open-doc-in-split-view'](),
@@ -13,7 +13,7 @@ export class DesktopStateSynchronizer extends Service {
} }
startSync = () => { startSync = () => {
if (!environment.isElectron) { if (!BUILD_CONFIG.isElectron) {
return; return;
} }
@@ -54,7 +54,7 @@ export const RouteContainer = () => {
return ( return (
<div className={styles.root}> <div className={styles.root}>
<div className={styles.header}> <div className={styles.header}>
{viewPosition.isFirst && !environment.isElectron && ( {!BUILD_CONFIG.isElectron && viewPosition.isFirst && (
<SidebarSwitch <SidebarSwitch
show={!leftSidebarOpen} show={!leftSidebarOpen}
className={styles.leftSidebarButton} className={styles.leftSidebarButton}
@@ -64,7 +64,7 @@ export const RouteContainer = () => {
viewId={view.id} viewId={view.id}
className={styles.viewHeaderContainer} className={styles.viewHeaderContainer}
/> />
{viewPosition.isLast && !environment.isElectron && ( {!BUILD_CONFIG.isElectron && viewPosition.isLast && (
<ToggleButton <ToggleButton
show={!sidebarOpen} show={!sidebarOpen}
className={styles.rightSidebarButton} className={styles.rightSidebarButton}
@@ -38,7 +38,7 @@ export const SidebarContainer = ({
viewId={view.id} viewId={view.id}
className={clsx( className={clsx(
styles.sidebarBodyTarget, styles.sidebarBodyTarget,
!environment.isElectron && styles.borderTop !BUILD_CONFIG.isElectron && styles.borderTop
)} )}
/> />
)) ))
@@ -44,7 +44,7 @@ export const Header = ({ floating, children, onToggle }: HeaderProps) => {
return ( return (
<Container className={styles.header} floating={floating}> <Container className={styles.header} floating={floating}>
{children} {children}
{!environment.isElectron && ( {!BUILD_CONFIG.isElectron && (
<> <>
<div className={styles.spacer} /> <div className={styles.spacer} />
<ToggleButton onToggle={onToggle} /> <ToggleButton onToggle={onToggle} />
@@ -40,7 +40,7 @@ export const WorkbenchLink = forwardRef<HTMLAnchorElement, WorkbenchLinkProps>(
} }
const at = (() => { const at = (() => {
if (isNewTabTrigger(event)) { if (isNewTabTrigger(event)) {
return event.altKey && enableMultiView && environment.isElectron return BUILD_CONFIG.isElectron && event.altKey && enableMultiView
? 'tail' ? 'tail'
: 'new-tab'; : 'new-tab';
} }
@@ -22,7 +22,7 @@ import { ViewIslandRegistryProvider } from './view-islands';
import { ViewRoot } from './view-root'; import { ViewRoot } from './view-root';
import * as styles from './workbench-root.css'; import * as styles from './workbench-root.css';
const useAdapter = environment.isElectron const useAdapter = BUILD_CONFIG.isElectron
? useBindWorkbenchToDesktopRouter ? useBindWorkbenchToDesktopRouter
: useBindWorkbenchToBrowserRouter; : useBindWorkbenchToBrowserRouter;
@@ -51,7 +51,7 @@ export class LocalWorkspaceFlavourProvider
JSON.stringify(allWorkspaceIDs.filter(x => x !== id)) JSON.stringify(allWorkspaceIDs.filter(x => x !== id))
); );
if (apis && environment.isElectron) { if (BUILD_CONFIG.isElectron && apis) {
await apis.workspace.delete(id); await apis.workspace.delete(id);
} }
@@ -5,5 +5,5 @@ export const supportedClient = z.enum([
'affine', 'affine',
'affine-canary', 'affine-canary',
'affine-beta', 'affine-beta',
...(environment.isDebug ? ['affine-dev'] : []), ...(BUILD_CONFIG.debug ? ['affine-dev'] : []),
]); ]);
@@ -1,7 +1,6 @@
import { AffineOtherPageLayout } from '@affine/component/affine-other-page-layout'; import { AffineOtherPageLayout } from '@affine/component/affine-other-page-layout';
import { SignInPageContainer } from '@affine/component/auth-components'; import { SignInPageContainer } from '@affine/component/auth-components';
import { AuthService } from '@affine/core/modules/cloud'; import { AuthService } from '@affine/core/modules/cloud';
import { appInfo } from '@affine/electron-api';
import { useLiveData, useService } from '@toeverything/infra'; import { useLiveData, useService } from '@toeverything/infra';
import { useEffect } from 'react'; import { useEffect } from 'react';
// eslint-disable-next-line @typescript-eslint/no-restricted-imports // eslint-disable-next-line @typescript-eslint/no-restricted-imports
@@ -20,10 +19,6 @@ export const SignIn = () => {
const isLoggedIn = status === 'authenticated' && !isRevalidating; const isLoggedIn = status === 'authenticated' && !isRevalidating;
useEffect(() => { useEffect(() => {
if (environment.isElectron && appInfo?.windowName === 'hidden-window') {
return;
}
if (isLoggedIn) { if (isLoggedIn) {
const redirectUri = searchParams.get('redirect_uri'); const redirectUri = searchParams.get('redirect_uri');
if (redirectUri) { if (redirectUri) {
@@ -11,7 +11,7 @@ import {
import { RouteLogic, useNavigateHelper } from '../hooks/use-navigate-helper'; import { RouteLogic, useNavigateHelper } from '../hooks/use-navigate-helper';
export const loader = () => { export const loader = () => {
if (!environment.isElectron && !appConfigStorage.get('onBoarding')) { if (!BUILD_CONFIG.isElectron && !appConfigStorage.get('onBoarding')) {
// onboarding is off, redirect to index // onboarding is off, redirect to index
return redirect('/'); return redirect('/');
} }
@@ -24,7 +24,7 @@ export const Component = () => {
const [, setOnboarding] = useAppConfigStorage('onBoarding'); const [, setOnboarding] = useAppConfigStorage('onBoarding');
const openApp = useCallback(() => { const openApp = useCallback(() => {
if (environment.isElectron) { if (BUILD_CONFIG.isElectron) {
assertExists(apis); assertExists(apis);
apis.ui.handleOpenMainApp().catch(err => { apis.ui.handleOpenMainApp().catch(err => {
console.log('failed to open main app', err); console.log('failed to open main app', err);
@@ -204,7 +204,6 @@ const DetailPageImpl = memo(function DetailPageImpl() {
); );
const [refCallback, hasScrollTop] = useHasScrollTop(); const [refCallback, hasScrollTop] = useHasScrollTop();
const dynamicTopBorder = environment.isElectron;
const openOutlinePanel = useCallback(() => { const openOutlinePanel = useCallback(() => {
workbench.openSidebar(); workbench.openSidebar();
@@ -219,7 +218,7 @@ const DetailPageImpl = memo(function DetailPageImpl() {
<ViewBody> <ViewBody>
<div <div
className={styles.mainContainer} className={styles.mainContainer}
data-dynamic-top-border={dynamicTopBorder} data-dynamic-top-border={BUILD_CONFIG.isElectron}
data-has-scroll-top={hasScrollTop} data-has-scroll-top={hasScrollTop}
> >
{/* Add a key to force rerender when page changed, to avoid error boundary persisting. */} {/* Add a key to force rerender when page changed, to avoid error boundary persisting. */}
@@ -20,10 +20,10 @@ export const useDetailPageHeaderResponsive = (availableWidth: number) => {
const hideToday = availableWidth < 300; const hideToday = availableWidth < 300;
const showDivider = const showDivider =
!BUILD_CONFIG.isElectron &&
viewPosition.isLast && viewPosition.isLast &&
!rightSidebarOpen && !rightSidebarOpen &&
!(hidePresent && hideShare) && !(hidePresent && hideShare);
!environment.isElectron;
return { return {
hideShare, hideShare,
@@ -99,8 +99,8 @@ export const Component = (): ReactElement => {
if (workspaceNotFound) { if (workspaceNotFound) {
if ( if (
detailDocRoute /* */ && !BUILD_CONFIG.isElectron /* only browser has share page */ &&
!environment.isElectron /* only browser has share page */ detailDocRoute
) { ) {
return ( return (
<SharePage <SharePage
@@ -62,7 +62,7 @@ export const Setting = () => {
); );
useEffect(() => { useEffect(() => {
if (environment.isElectron) { if (BUILD_CONFIG.isElectron) {
return events?.applicationMenu.openAboutPageInSettingModal(() => return events?.applicationMenu.openAboutPageInSettingModal(() =>
setOpenSettingModalAtom({ setOpenSettingModalAtom({
activeTab: 'about', activeTab: 'about',
@@ -120,7 +120,7 @@ export function CurrentWorkspaceModals() {
)} )}
<AiLoginRequiredModal /> <AiLoginRequiredModal />
<PeekViewManagerModal /> <PeekViewManagerModal />
{environment.isElectron && <FindInPageModal />} {BUILD_CONFIG.isElectron && <FindInPageModal />}
<MoveToTrash.ConfirmModal <MoveToTrash.ConfirmModal
open={trashConfirmOpen} open={trashConfirmOpen}
onConfirm={handleOnConfirm} onConfirm={handleOnConfirm}
+1 -1
View File
@@ -10,7 +10,7 @@ import { gqlFetcherFactory } from './fetcher';
setupGlobal(); setupGlobal();
export function getBaseUrl(): string { export function getBaseUrl(): string {
if (environment.isElectron) { if (BUILD_CONFIG.isElectron) {
return BUILD_CONFIG.serverUrlPrefix; return BUILD_CONFIG.serverUrlPrefix;
} }
if (typeof window === 'undefined') { if (typeof window === 'undefined') {
+2 -2
View File
@@ -1,7 +1,7 @@
import { getRuntimeConfig } from '@affine/cli/src/webpack/runtime-config'; import { getBuildConfig } from '@affine/cli/src/webpack/runtime-config';
import { setupGlobal } from '@affine/env/global'; import { setupGlobal } from '@affine/env/global';
globalThis.BUILD_CONFIG = getRuntimeConfig({ globalThis.BUILD_CONFIG = getBuildConfig({
distribution: 'web', distribution: 'web',
mode: 'development', mode: 'development',
channel: 'canary', channel: 'canary',
+2
View File
@@ -1,3 +1,5 @@
import '@affine/env/constant';
import type { BUILD_CONFIG_TYPE, Environment } from '@affine/env/global'; import type { BUILD_CONFIG_TYPE, Environment } from '@affine/env/global';
declare global { declare global {
+13 -2
View File
@@ -3,11 +3,23 @@ import type { BUILD_CONFIG_TYPE } from '@affine/env/global';
import packageJson from '../../package.json' assert { type: 'json' }; import packageJson from '../../package.json' assert { type: 'json' };
import type { BuildFlags } from '../config'; import type { BuildFlags } from '../config';
export function getRuntimeConfig(buildFlags: BuildFlags): BUILD_CONFIG_TYPE { export function getBuildConfig(buildFlags: BuildFlags): BUILD_CONFIG_TYPE {
const buildPreset: Record<BuildFlags['channel'], BUILD_CONFIG_TYPE> = { const buildPreset: Record<BuildFlags['channel'], BUILD_CONFIG_TYPE> = {
get stable() { get stable() {
return { return {
debug: buildFlags.mode === 'development',
distribution: buildFlags.distribution, distribution: buildFlags.distribution,
isDesktopEdition: (
['web', 'desktop', 'admin'] as BuildFlags['distribution'][]
).includes(buildFlags.distribution),
isMobileEdition: (['mobile'] as BuildFlags['distribution'][]).includes(
buildFlags.distribution
),
isElectron: buildFlags.distribution === 'desktop',
isWeb: buildFlags.distribution === 'web',
isMobileWeb: buildFlags.distribution === 'mobile',
isSelfHosted: process.env.SELF_HOSTED === 'true',
appBuildType: 'stable' as const, appBuildType: 'stable' as const,
serverUrlPrefix: 'https://app.affine.pro', serverUrlPrefix: 'https://app.affine.pro',
appVersion: packageJson.version, appVersion: packageJson.version,
@@ -87,7 +99,6 @@ export function getRuntimeConfig(buildFlags: BuildFlags): BUILD_CONFIG_TYPE {
} }
return { return {
isSelfHosted: process.env.SELF_HOSTED === 'true',
...currentBuildPreset, ...currentBuildPreset,
// environment preset will overwrite current build preset // environment preset will overwrite current build preset
// this environment variable is for debug proposes only // this environment variable is for debug proposes only
+3 -3
View File
@@ -9,7 +9,7 @@ import webpack from 'webpack';
import { merge } from 'webpack-merge'; import { merge } from 'webpack-merge';
import { createConfiguration, rootPath, workspaceRoot } from './config.js'; import { createConfiguration, rootPath, workspaceRoot } from './config.js';
import { getRuntimeConfig } from './runtime-config.js'; import { getBuildConfig } from './runtime-config.js';
const DESCRIPTION = `There can be more than Notion and Miro. AFFiNE is a next-gen knowledge base that brings planning, sorting and creating all together.`; const DESCRIPTION = `There can be more than Notion and Miro. AFFiNE is a next-gen knowledge base that brings planning, sorting and creating all together.`;
@@ -31,8 +31,8 @@ const gitShortHash = once(() => {
export function createWebpackConfig(cwd: string, flags: BuildFlags) { export function createWebpackConfig(cwd: string, flags: BuildFlags) {
console.log('build flags', flags); console.log('build flags', flags);
const runtimeConfig = getRuntimeConfig(flags); const runtimeConfig = getBuildConfig(flags);
console.log('runtime config', runtimeConfig); console.log('BUILD_CONFIG', runtimeConfig);
const config = createConfiguration(cwd, flags, runtimeConfig); const config = createConfiguration(cwd, flags, runtimeConfig);
const entry = const entry =
typeof flags.entry === 'string' || !flags.entry typeof flags.entry === 'string' || !flags.entry