refactor: new project struct (#8199)

packages/frontend/web -> packages/frontend/apps/web
packages/frontend/mobile -> packages/frontend/apps/mobile
packages/frontend/electron -> packages/frontend/apps/electron
This commit is contained in:
EYHN
2024-09-12 07:42:57 +00:00
parent 7c4eab6cd3
commit cc5a6e6d40
291 changed files with 139 additions and 134 deletions
@@ -0,0 +1,7 @@
import { mintChallengeResponse } from '@affine/native';
export const getChallengeResponse = async (resource: string) => {
// 20 bits challenge is a balance between security and user experience
// 20 bits challenge cost time is about 1-3s on m2 macbook air
return mintChallengeResponse(resource, 20);
};
@@ -0,0 +1,45 @@
import type { MainEventRegister } from '../type';
import {
type AuthenticationRequest,
onActiveTabChanged,
onTabAction,
onTabShellViewActiveChange,
onTabsStatusChange,
onTabViewsMetaChanged,
} from '../windows-manager';
import { uiSubjects } from './subject';
/**
* Events triggered by application menu
*/
export const uiEvents = {
onMaximized: (fn: (maximized: boolean) => void) => {
const sub = uiSubjects.onMaximized$.subscribe(fn);
return () => {
sub.unsubscribe();
};
},
onFullScreen: (fn: (fullScreen: boolean) => void) => {
const sub = uiSubjects.onFullScreen$.subscribe(fn);
return () => {
sub.unsubscribe();
};
},
onTabViewsMetaChanged,
onTabAction,
onToggleRightSidebar: (fn: (tabId: string) => void) => {
const sub = uiSubjects.onToggleRightSidebar$.subscribe(fn);
return () => {
sub.unsubscribe();
};
},
onTabsStatusChange,
onActiveTabChanged,
onTabShellViewActiveChange,
onAuthenticationRequest: (fn: (state: AuthenticationRequest) => void) => {
const sub = uiSubjects.authenticationRequest$.subscribe(fn);
return () => {
sub.unsubscribe();
};
},
} satisfies Record<string, MainEventRegister>;
@@ -0,0 +1,214 @@
import { app, nativeTheme, shell } from 'electron';
import { getLinkPreview } from 'link-preview-js';
import { persistentConfig } from '../config-storage/persist';
import { logger } from '../logger';
import type { NamespaceHandlers } from '../type';
import {
activateView,
addTab,
closeTab,
getMainWindow,
getOnboardingWindow,
getTabsStatus,
getTabViewsMeta,
getWorkbenchMeta,
handleWebContentsResize,
initAndShowMainWindow,
isActiveTab,
launchStage,
moveTab,
pingAppLayoutReady,
showDevTools,
showTab,
updateWorkbenchMeta,
updateWorkbenchViewMeta,
} from '../windows-manager';
import { showTabContextMenu } from '../windows-manager/context-menu';
import { getOrCreateCustomThemeWindow } from '../windows-manager/custom-theme-window';
import { getChallengeResponse } from './challenge';
import { uiSubjects } from './subject';
export let isOnline = true;
export const uiHandlers = {
isMaximized: async () => {
const window = await getMainWindow();
return window?.isMaximized();
},
isFullScreen: async () => {
const window = await getMainWindow();
return window?.isFullScreen();
},
handleThemeChange: async (_, theme: (typeof nativeTheme)['themeSource']) => {
nativeTheme.themeSource = theme;
},
handleMinimizeApp: async () => {
const window = await getMainWindow();
window?.minimize();
},
handleMaximizeApp: async () => {
const window = await getMainWindow();
if (!window) {
return;
}
// allow unmaximize when in full screen mode
if (window.isFullScreen()) {
window.setFullScreen(false);
window.unmaximize();
} else if (window.isMaximized()) {
window.unmaximize();
} else {
window.maximize();
}
},
handleWindowResize: async e => {
await handleWebContentsResize(e.sender);
},
handleCloseApp: async () => {
app.quit();
},
handleNetworkChange: async (_, _isOnline: boolean) => {
isOnline = _isOnline;
},
getChallengeResponse: async (_, challenge: string) => {
return getChallengeResponse(challenge);
},
handleOpenMainApp: async () => {
if (launchStage.value === 'onboarding') {
launchStage.value = 'main';
persistentConfig.patch('onBoarding', false);
}
try {
const onboarding = await getOnboardingWindow();
onboarding?.hide();
await initAndShowMainWindow();
// need to destroy onboarding window after main window is ready
// otherwise the main window will be closed as well
onboarding?.destroy();
} catch (err) {
logger.error('handleOpenMainApp', err);
}
},
getBookmarkDataByLink: async (_, link: string) => {
if (
(link.startsWith('https://x.com/') ||
link.startsWith('https://www.x.com/') ||
link.startsWith('https://www.twitter.com/') ||
link.startsWith('https://twitter.com/')) &&
link.includes('/status/')
) {
// use api.fxtwitter.com
link =
'https://api.fxtwitter.com/status/' + /\/status\/(.*)/.exec(link)?.[1];
try {
const { tweet } = await fetch(link).then(res => res.json());
return {
title: tweet.author.name,
icon: tweet.author.avatar_url,
description: tweet.text,
image: tweet.media?.photos[0].url || tweet.author.banner_url,
};
} catch (err) {
logger.error('getBookmarkDataByLink', err);
return {
title: undefined,
description: undefined,
icon: undefined,
image: undefined,
};
}
} else {
const previewData = (await getLinkPreview(link, {
timeout: 6000,
headers: {
'User-Agent':
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36',
},
followRedirects: 'follow',
}).catch(() => {
return {
title: '',
siteName: '',
description: '',
images: [],
videos: [],
contentType: `text/html`,
favicons: [],
};
})) as any;
return {
title: previewData.title,
description: previewData.description,
icon: previewData.favicons[0],
image: previewData.images[0],
};
}
},
openExternal(_, url: string) {
return shell.openExternal(url);
},
// tab handlers
isActiveTab: async e => {
return isActiveTab(e.sender);
},
getWorkbenchMeta: async (_, ...args: Parameters<typeof getWorkbenchMeta>) => {
return getWorkbenchMeta(...args);
},
updateWorkbenchMeta: async (
_,
...args: Parameters<typeof updateWorkbenchMeta>
) => {
return updateWorkbenchMeta(...args);
},
updateWorkbenchViewMeta: async (
_,
...args: Parameters<typeof updateWorkbenchViewMeta>
) => {
return updateWorkbenchViewMeta(...args);
},
getTabViewsMeta: async () => {
return getTabViewsMeta();
},
getTabsStatus: async () => {
return getTabsStatus();
},
addTab: async (_, ...args: Parameters<typeof addTab>) => {
await addTab(...args);
},
showTab: async (_, ...args: Parameters<typeof showTab>) => {
await showTab(...args);
},
closeTab: async (_, ...args: Parameters<typeof closeTab>) => {
await closeTab(...args);
},
activateView: async (_, ...args: Parameters<typeof activateView>) => {
await activateView(...args);
},
moveTab: async (_, ...args: Parameters<typeof moveTab>) => {
moveTab(...args);
},
toggleRightSidebar: async (_, tabId?: string) => {
tabId ??= getTabViewsMeta().activeWorkbenchId;
if (tabId) {
uiSubjects.onToggleRightSidebar$.next(tabId);
}
},
pingAppLayoutReady: async e => {
pingAppLayoutReady(e.sender);
},
showDevTools: async (_, ...args: Parameters<typeof showDevTools>) => {
return showDevTools(...args);
},
showTabContextMenu: async (_, tabKey: string, viewIndex: number) => {
return showTabContextMenu(tabKey, viewIndex);
},
openThemeEditor: async () => {
const win = await getOrCreateCustomThemeWindow();
win.show();
win.focus();
},
} satisfies NamespaceHandlers;
@@ -0,0 +1,3 @@
export * from './events';
export * from './handlers';
export * from './subject';
@@ -0,0 +1,10 @@
import { Subject } from 'rxjs';
import type { AuthenticationRequest } from '../windows-manager';
export const uiSubjects = {
onMaximized$: new Subject<boolean>(),
onFullScreen$: new Subject<boolean>(),
onToggleRightSidebar$: new Subject<string>(),
authenticationRequest$: new Subject<AuthenticationRequest>(),
};