mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-10 19:38:39 +00:00
Compare commits
21 Commits
v0.7.0-can
...
v0.7.0-can
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4109490789 | ||
|
|
e813436af7 | ||
|
|
5b87d90ffe | ||
|
|
ccbae6f496 | ||
|
|
1ac1c33bb1 | ||
|
|
bd42380f8a | ||
|
|
30dee18835 | ||
|
|
b509302711 | ||
|
|
e51c98c1dd | ||
|
|
bbb1387469 | ||
|
|
4f88774999 | ||
|
|
3968deb6d4 | ||
|
|
37c8465af8 | ||
|
|
d88a21d24a | ||
|
|
6ad2d106bc | ||
|
|
8c1fcee135 | ||
|
|
0514da9759 | ||
|
|
b2fed03f30 | ||
|
|
f5e45573af | ||
|
|
ddb2931f38 | ||
|
|
acf17ebace |
22
.github/workflows/workers.yml
vendored
Normal file
22
.github/workflows/workers.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
name: Deploy Cloudflare Worker
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- packages/workers/**
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
name: Deploy
|
||||
environment: production
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Publish
|
||||
uses: cloudflare/wrangler-action@2.0.0
|
||||
with:
|
||||
apiToken: ${{ secrets.CF_API_TOKEN }}
|
||||
accountId: ${{ secrets.CF_ACCOUNT_ID }}
|
||||
workingDirectory: 'packages/workers'
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@affine/docs",
|
||||
"version": "0.7.0-canary.39",
|
||||
"version": "0.7.0-canary.42",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
@@ -10,12 +10,12 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@affine/component": "workspace:*",
|
||||
"@blocksuite/block-std": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/blocks": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/lit": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/block-std": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/blocks": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/lit": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"express": "^4.18.2",
|
||||
"jotai": "^2.2.2",
|
||||
"react": "18.3.0-canary-1fdacbefd-20230630",
|
||||
|
||||
@@ -149,3 +149,35 @@ test('windows only check', async ({ page }) => {
|
||||
await expect(windowOnlyUI).not.toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test('delete workspace', async ({ page }) => {
|
||||
await page.getByTestId('current-workspace').click();
|
||||
await page.getByTestId('add-or-new-workspace').click();
|
||||
await page.getByTestId('new-workspace').click();
|
||||
await page.getByTestId('create-workspace-default-location-button').click();
|
||||
await page.getByTestId('create-workspace-input').type('Delete Me');
|
||||
await page.getByTestId('create-workspace-create-button').click();
|
||||
await page.getByTestId('create-workspace-continue-button').click();
|
||||
await page.getByTestId('slider-bar-workspace-setting-button').click();
|
||||
await page.getByTestId('current-workspace-label').click();
|
||||
expect(await page.getByTestId('workspace-name-input').inputValue()).toBe(
|
||||
'Delete Me'
|
||||
);
|
||||
const contentElement = await page.getByTestId('setting-modal-content');
|
||||
const boundingBox = await contentElement.boundingBox();
|
||||
if (!boundingBox) {
|
||||
throw new Error('boundingBox is null');
|
||||
}
|
||||
await page.mouse.move(
|
||||
boundingBox.x + boundingBox.width / 2,
|
||||
boundingBox.y + boundingBox.height / 2
|
||||
);
|
||||
await page.mouse.wheel(0, 500);
|
||||
await page.getByTestId('delete-workspace-button').click();
|
||||
await page.getByTestId('delete-workspace-input').type('Delete Me');
|
||||
await page.getByTestId('delete-workspace-confirm-button').click();
|
||||
await page.waitForTimeout(1000);
|
||||
expect(await page.getByTestId('workspace-name').textContent()).toBe(
|
||||
'Demo Workspace'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -26,6 +26,8 @@ const arch =
|
||||
? process.argv[process.argv.indexOf('--arch') + 1]
|
||||
: process.arch;
|
||||
|
||||
const windowsIconUrl = `https://cdn.affine.pro/app-icons/icon_${buildType}.ico`;
|
||||
|
||||
/**
|
||||
* @type {import('@electron-forge/shared-types').ForgeConfig}
|
||||
*/
|
||||
@@ -95,6 +97,7 @@ module.exports = {
|
||||
config: {
|
||||
name: 'AFFiNE',
|
||||
setupIcon: icoPath,
|
||||
iconUrl: windowsIconUrl,
|
||||
loadingGif: './resources/icons/affine_installing.gif',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@affine/electron",
|
||||
"private": true,
|
||||
"version": "0.7.0-canary.39",
|
||||
"version": "0.7.0-canary.42",
|
||||
"author": "affine",
|
||||
"repository": {
|
||||
"url": "https://github.com/toeverything/AFFiNE",
|
||||
@@ -12,7 +12,7 @@
|
||||
"scripts": {
|
||||
"dev": "yarn cross-env DEV_SERVER_URL=http://localhost:8080 node scripts/dev.mjs",
|
||||
"dev:prod": "yarn node scripts/dev.mjs",
|
||||
"build": "zx scripts/build-layers.mjs",
|
||||
"build": "NODE_ENV=production zx scripts/build-layers.mjs",
|
||||
"generate-assets": "zx scripts/generate-assets.mjs",
|
||||
"package": "electron-forge package",
|
||||
"make": "electron-forge make",
|
||||
@@ -26,10 +26,10 @@
|
||||
"@affine-test/kit": "workspace:*",
|
||||
"@affine/env": "workspace:*",
|
||||
"@affine/native": "workspace:*",
|
||||
"@blocksuite/blocks": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/lit": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/blocks": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/lit": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@electron-forge/cli": "^6.2.1",
|
||||
"@electron-forge/core": "^6.2.1",
|
||||
"@electron-forge/core-utils": "^6.2.1",
|
||||
@@ -59,7 +59,7 @@
|
||||
"dependencies": {
|
||||
"@toeverything/plugin-infra": "workspace:*",
|
||||
"async-call-rpc": "^6.3.1",
|
||||
"electron-updater": "^5.0.0",
|
||||
"electron-updater": "^6.0.0",
|
||||
"link-preview-js": "^3.0.4",
|
||||
"lodash-es": "^4.17.21",
|
||||
"nanoid": "^4.0.2",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { app, Menu } from 'electron';
|
||||
|
||||
import { revealLogFile } from '../logger';
|
||||
import { checkForUpdatesAndNotify } from '../updater';
|
||||
import { checkForUpdates } from '../updater';
|
||||
import { isMacOS } from '../utils';
|
||||
import { applicationMenuSubjects } from './subject';
|
||||
|
||||
@@ -125,7 +125,7 @@ export function createApplicationMenu() {
|
||||
{
|
||||
label: 'Check for Updates',
|
||||
click: async () => {
|
||||
await checkForUpdatesAndNotify(true);
|
||||
await checkForUpdates(true);
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -25,11 +25,11 @@ export const quitAndInstall = async () => {
|
||||
};
|
||||
|
||||
let lastCheckTime = 0;
|
||||
export const checkForUpdatesAndNotify = async (force = true) => {
|
||||
export const checkForUpdates = async (force = true) => {
|
||||
// check every 30 minutes (1800 seconds) at most
|
||||
if (force || lastCheckTime + 1000 * 1800 < Date.now()) {
|
||||
lastCheckTime = Date.now();
|
||||
return await autoUpdater.checkForUpdatesAndNotify();
|
||||
return await autoUpdater.checkForUpdates();
|
||||
}
|
||||
return void 0;
|
||||
};
|
||||
@@ -100,6 +100,6 @@ export const registerUpdater = async () => {
|
||||
autoUpdater.forceDevUpdateConfig = isDev;
|
||||
|
||||
app.on('activate', async () => {
|
||||
await checkForUpdatesAndNotify(false);
|
||||
await checkForUpdates(false);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { app } from 'electron';
|
||||
|
||||
import type { NamespaceHandlers } from '../type';
|
||||
import { checkForUpdatesAndNotify, quitAndInstall } from './electron-updater';
|
||||
import { checkForUpdates, quitAndInstall } from './electron-updater';
|
||||
|
||||
export const updaterHandlers = {
|
||||
currentVersion: async () => {
|
||||
@@ -11,7 +11,7 @@ export const updaterHandlers = {
|
||||
return quitAndInstall();
|
||||
},
|
||||
checkForUpdatesAndNotify: async () => {
|
||||
const res = await checkForUpdatesAndNotify(true);
|
||||
const res = await checkForUpdates(true);
|
||||
if (res) {
|
||||
const { updateInfo } = res;
|
||||
return {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@affine/server",
|
||||
"private": true,
|
||||
"version": "0.7.0-canary.39",
|
||||
"version": "0.7.0-canary.42",
|
||||
"description": "Affine Node.js server",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
|
||||
@@ -30,13 +30,13 @@
|
||||
"wait-on": "^7.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@blocksuite/block-std": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/blocks": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/block-std": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/blocks": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/icons": "^2.1.24",
|
||||
"@blocksuite/lit": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/lit": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"react": "18.3.0-canary-1fdacbefd-20230630",
|
||||
"react-dom": "18.3.0-canary-1fdacbefd-20230630"
|
||||
},
|
||||
@@ -48,5 +48,5 @@
|
||||
"@blocksuite/lit": "*",
|
||||
"@blocksuite/store": "*"
|
||||
},
|
||||
"version": "0.7.0-canary.39"
|
||||
"version": "0.7.0-canary.42"
|
||||
}
|
||||
|
||||
@@ -13,6 +13,9 @@ import { blockSuiteFeatureFlags, buildFlags } from './preset.config.mjs';
|
||||
import { getCommitHash, getGitVersion } from './scripts/git-info.mjs';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const packageJson = require('./package.json');
|
||||
const appVersion = packageJson.version;
|
||||
const editorVersion = packageJson.dependencies['@blocksuite/editor'];
|
||||
const { createVanillaExtractPlugin } = require('@vanilla-extract/next-plugin');
|
||||
const withVanillaExtract = createVanillaExtractPlugin();
|
||||
|
||||
@@ -102,6 +105,8 @@ const nextConfig = {
|
||||
publicRuntimeConfig: {
|
||||
PROJECT_NAME: process.env.npm_package_name ?? 'AFFiNE',
|
||||
BUILD_DATE: new Date().toISOString(),
|
||||
appVersion,
|
||||
editorVersion,
|
||||
gitVersion: getGitVersion(),
|
||||
hash: getCommitHash(),
|
||||
serverAPI: profileTarget.local,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@affine/web",
|
||||
"private": true,
|
||||
"version": "0.7.0-canary.39",
|
||||
"version": "0.7.0-canary.42",
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build && next export",
|
||||
@@ -19,13 +19,13 @@
|
||||
"@affine/jotai": "workspace:*",
|
||||
"@affine/templates": "workspace:*",
|
||||
"@affine/workspace": "workspace:*",
|
||||
"@blocksuite/block-std": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/blocks": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/block-std": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/blocks": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/icons": "^2.1.24",
|
||||
"@blocksuite/lit": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/lit": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@dnd-kit/core": "^6.0.8",
|
||||
"@dnd-kit/sortable": "^7.0.2",
|
||||
"@emotion/cache": "^11.11.0",
|
||||
|
||||
@@ -24,6 +24,7 @@ const buildPreset = {
|
||||
enableBroadcastChannelProvider: true,
|
||||
enableDebugPage: true,
|
||||
changelogUrl: 'https://affine.pro/blog/whats-new-affine-0630',
|
||||
imageProxyUrl: 'https://workers.toeverything.workers.dev/proxy/image',
|
||||
enablePreloading: true,
|
||||
enableNewSettingModal: true,
|
||||
enableNewSettingUnstableApi: false,
|
||||
@@ -41,6 +42,7 @@ const buildPreset = {
|
||||
enableBroadcastChannelProvider: true,
|
||||
enableDebugPage: true,
|
||||
changelogUrl: 'https://affine.pro/blog/whats-new-affine-0630',
|
||||
imageProxyUrl: 'https://workers.toeverything.workers.dev/proxy/image',
|
||||
enablePreloading: true,
|
||||
enableNewSettingModal: true,
|
||||
enableNewSettingUnstableApi: false,
|
||||
|
||||
BIN
apps/web/public/fonts/inter/Inter-VariableFont_slnt,wght.ttf
Normal file
BIN
apps/web/public/fonts/inter/Inter-VariableFont_slnt,wght.ttf
Normal file
Binary file not shown.
93
apps/web/public/fonts/inter/OFL.txt
Normal file
93
apps/web/public/fonts/inter/OFL.txt
Normal file
@@ -0,0 +1,93 @@
|
||||
Copyright 2020 The Inter Project Authors (https://github.com/rsms/inter)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
93
apps/web/public/fonts/source-code-pro/OFL.txt
Normal file
93
apps/web/public/fonts/source-code-pro/OFL.txt
Normal file
@@ -0,0 +1,93 @@
|
||||
Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
Binary file not shown.
Binary file not shown.
91
apps/web/public/fonts/source-serif-4/OFL.txt
Normal file
91
apps/web/public/fonts/source-serif-4/OFL.txt
Normal file
@@ -0,0 +1,91 @@
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
BIN
apps/web/public/fonts/source-serif-4/SourceSerif4-Bold.ttf
Normal file
BIN
apps/web/public/fonts/source-serif-4/SourceSerif4-Bold.ttf
Normal file
Binary file not shown.
BIN
apps/web/public/fonts/source-serif-4/SourceSerif4-BoldItalic.ttf
Normal file
BIN
apps/web/public/fonts/source-serif-4/SourceSerif4-BoldItalic.ttf
Normal file
Binary file not shown.
Binary file not shown.
BIN
apps/web/public/fonts/source-serif-4/SourceSerif4-Italic.ttf
Normal file
BIN
apps/web/public/fonts/source-serif-4/SourceSerif4-Italic.ttf
Normal file
Binary file not shown.
BIN
apps/web/public/fonts/source-serif-4/SourceSerif4-Light.ttf
Normal file
BIN
apps/web/public/fonts/source-serif-4/SourceSerif4-Light.ttf
Normal file
Binary file not shown.
Binary file not shown.
BIN
apps/web/public/fonts/source-serif-4/SourceSerif4-Medium.ttf
Normal file
BIN
apps/web/public/fonts/source-serif-4/SourceSerif4-Medium.ttf
Normal file
Binary file not shown.
Binary file not shown.
BIN
apps/web/public/fonts/source-serif-4/SourceSerif4-Regular.ttf
Normal file
BIN
apps/web/public/fonts/source-serif-4/SourceSerif4-Regular.ttf
Normal file
Binary file not shown.
BIN
apps/web/public/fonts/source-serif-4/SourceSerif4-SemiBold.ttf
Normal file
BIN
apps/web/public/fonts/source-serif-4/SourceSerif4-SemiBold.ttf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
93
apps/web/public/fonts/space-mono/OFL.txt
Normal file
93
apps/web/public/fonts/space-mono/OFL.txt
Normal file
@@ -0,0 +1,93 @@
|
||||
Copyright 2016 Google Inc. All Rights Reserved.
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
BIN
apps/web/public/fonts/space-mono/SpaceMono-Bold.ttf
Normal file
BIN
apps/web/public/fonts/space-mono/SpaceMono-Bold.ttf
Normal file
Binary file not shown.
BIN
apps/web/public/fonts/space-mono/SpaceMono-BoldItalic.ttf
Normal file
BIN
apps/web/public/fonts/space-mono/SpaceMono-BoldItalic.ttf
Normal file
Binary file not shown.
BIN
apps/web/public/fonts/space-mono/SpaceMono-Italic.ttf
Normal file
BIN
apps/web/public/fonts/space-mono/SpaceMono-Italic.ttf
Normal file
Binary file not shown.
BIN
apps/web/public/fonts/space-mono/SpaceMono-Regular.ttf
Normal file
BIN
apps/web/public/fonts/space-mono/SpaceMono-Regular.ttf
Normal file
Binary file not shown.
@@ -1,7 +1,7 @@
|
||||
import { DebugLogger } from '@affine/debug';
|
||||
import { initEmptyPage, initPageWithPreloading } from '@affine/env/blocksuite';
|
||||
import {
|
||||
DEFAULT_HELLO_WORLD_PAGE_ID,
|
||||
DEFAULT_HELLO_WORLD_PAGE_ID_SUFFIX,
|
||||
DEFAULT_WORKSPACE_NAME,
|
||||
PageNotFoundError,
|
||||
} from '@affine/env/constant';
|
||||
@@ -42,7 +42,7 @@ export const LocalAdapter: WorkspaceAdapter<WorkspaceFlavour.LOCAL> = {
|
||||
);
|
||||
blockSuiteWorkspace.meta.setName(DEFAULT_WORKSPACE_NAME);
|
||||
const page = blockSuiteWorkspace.createPage({
|
||||
id: DEFAULT_HELLO_WORLD_PAGE_ID,
|
||||
id: `${blockSuiteWorkspace.id}-${DEFAULT_HELLO_WORLD_PAGE_ID_SUFFIX}`,
|
||||
});
|
||||
if (runtimeConfig.enablePreloading) {
|
||||
initPageWithPreloading(page).catch(err => {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { isDesktop } from '@affine/env/constant';
|
||||
import { atom, useAtom } from 'jotai';
|
||||
import { atomWithStorage } from 'jotai/utils';
|
||||
|
||||
@@ -49,7 +50,7 @@ export const fontStyleOptions = [
|
||||
}[];
|
||||
|
||||
const appSettingBaseAtom = atomWithStorage<AppSetting>('affine-settings', {
|
||||
clientBorder: false,
|
||||
clientBorder: isDesktop,
|
||||
fullWidthLayout: false,
|
||||
windowFrameStyle: 'frameless',
|
||||
fontStyle: 'Sans',
|
||||
|
||||
@@ -3,7 +3,6 @@ import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
|
||||
import type { EditorContainer } from '@blocksuite/editor';
|
||||
import type { Page } from '@blocksuite/store';
|
||||
import { Generator } from '@blocksuite/store';
|
||||
import type React from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
@@ -11,10 +10,7 @@ import { BlockSuiteEditor } from '../../blocksuite/block-suite-editor';
|
||||
|
||||
const blockSuiteWorkspace = createEmptyBlockSuiteWorkspace(
|
||||
'test',
|
||||
WorkspaceFlavour.LOCAL,
|
||||
{
|
||||
idGenerator: Generator.AutoIncrement,
|
||||
}
|
||||
WorkspaceFlavour.LOCAL
|
||||
);
|
||||
|
||||
const page = blockSuiteWorkspace.createPage({ id: 'page0' });
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Button, FlexWrapper, Switch } from '@affine/component';
|
||||
import { Button, FlexWrapper, Switch, Tooltip } from '@affine/component';
|
||||
import { SettingRow } from '@affine/component/setting-components';
|
||||
import { Unreachable } from '@affine/env/constant';
|
||||
import type {
|
||||
@@ -92,30 +92,19 @@ const PublishPanelAffine: FC<PublishPanelAffineProps> = props => {
|
||||
|
||||
const FakePublishPanelAffine: FC<{
|
||||
workspace: AffineOfficialWorkspace;
|
||||
}> = ({ workspace }) => {
|
||||
}> = () => {
|
||||
const t = useAFFiNEI18N();
|
||||
const [origin, setOrigin] = useState('');
|
||||
const shareUrl = origin + '/public-workspace/' + workspace.id;
|
||||
|
||||
useEffect(() => {
|
||||
setOrigin(
|
||||
typeof window !== 'undefined' && window.location.origin
|
||||
? window.location.origin
|
||||
: ''
|
||||
);
|
||||
}, []);
|
||||
return (
|
||||
<div className={style.fakeWrapper}>
|
||||
<SettingRow name={t['Publish']()} desc={t['Unpublished hint']()}>
|
||||
<Switch checked={false} />
|
||||
</SettingRow>
|
||||
<FlexWrapper justifyContent="space-between">
|
||||
<Button className={style.urlButton} size="middle" title={shareUrl}>
|
||||
{shareUrl}
|
||||
</Button>
|
||||
<Button size="middle">{t['Copy']()}</Button>
|
||||
</FlexWrapper>
|
||||
</div>
|
||||
<Tooltip
|
||||
content={t['com.affine.settings.workspace.publish.local-tooltip']()}
|
||||
placement="top"
|
||||
>
|
||||
<div className={style.fakeWrapper}>
|
||||
<SettingRow name={t['Publish']()} desc={t['Unpublished hint']()}>
|
||||
<Switch checked={false} />
|
||||
</SettingRow>
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
const PublishPanelLocal: FC<PublishPanelLocalProps> = ({
|
||||
|
||||
@@ -57,7 +57,17 @@ globalStyle(`${urlButton} span`, {
|
||||
|
||||
export const fakeWrapper = style({
|
||||
position: 'relative',
|
||||
borderRadius: '8px',
|
||||
background: 'var(--affine-white-60)',
|
||||
padding: '10px',
|
||||
opacity: 0.4,
|
||||
marginTop: '24px',
|
||||
selectors: {
|
||||
'&::after': {
|
||||
content: '""',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
top: 0,
|
||||
cursor: 'not-allowed',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -26,45 +26,49 @@ export const AboutAffine = () => {
|
||||
subtitle={t['com.affine.settings.about.message']()}
|
||||
data-testid="about-title"
|
||||
/>
|
||||
{runtimeConfig.enableNewSettingUnstableApi && environment.isDesktop ? (
|
||||
<SettingWrapper title={t['Version']()}>
|
||||
<SettingRow
|
||||
name={t['Check for updates']()}
|
||||
desc={t['New version is ready']()}
|
||||
></SettingRow>
|
||||
<SettingRow
|
||||
name={t['Check for updates automatically']()}
|
||||
desc={t['com.affine.settings.about.update.check.message']()}
|
||||
>
|
||||
<Switch
|
||||
checked={appSettings.autoCheckUpdate}
|
||||
onChange={checked => changeSwitch('autoCheckUpdate', checked)}
|
||||
/>
|
||||
</SettingRow>
|
||||
<SettingRow
|
||||
name={t['Download updates automatically']()}
|
||||
desc={t['com.affine.settings.about.update.download.message']()}
|
||||
>
|
||||
<Switch
|
||||
checked={appSettings.autoCheckUpdate}
|
||||
onChange={checked => changeSwitch('autoCheckUpdate', checked)}
|
||||
/>
|
||||
</SettingRow>
|
||||
<SettingRow
|
||||
name={t[`Discover what's new`]()}
|
||||
desc={t['View the AFFiNE Changelog.']()}
|
||||
style={{ cursor: 'pointer' }}
|
||||
onClick={() => {
|
||||
window.open(
|
||||
'https://affine.pro/blog/whats-new-affine-0630',
|
||||
'_blank'
|
||||
);
|
||||
}}
|
||||
>
|
||||
<ArrowRightSmallIcon />
|
||||
</SettingRow>
|
||||
</SettingWrapper>
|
||||
) : null}
|
||||
<SettingWrapper title={t['Version']()}>
|
||||
<SettingRow name="App Version" desc={runtimeConfig.appVersion} />
|
||||
<SettingRow name="Editor Version" desc={runtimeConfig.editorVersion} />
|
||||
{runtimeConfig.enableNewSettingUnstableApi && environment.isDesktop ? (
|
||||
<>
|
||||
<SettingRow
|
||||
name={t['Check for updates']()}
|
||||
desc={t['New version is ready']()}
|
||||
></SettingRow>
|
||||
<SettingRow
|
||||
name={t['Check for updates automatically']()}
|
||||
desc={t['com.affine.settings.about.update.check.message']()}
|
||||
>
|
||||
<Switch
|
||||
checked={appSettings.autoCheckUpdate}
|
||||
onChange={checked => changeSwitch('autoCheckUpdate', checked)}
|
||||
/>
|
||||
</SettingRow>
|
||||
<SettingRow
|
||||
name={t['Download updates automatically']()}
|
||||
desc={t['com.affine.settings.about.update.download.message']()}
|
||||
>
|
||||
<Switch
|
||||
checked={appSettings.autoCheckUpdate}
|
||||
onChange={checked => changeSwitch('autoCheckUpdate', checked)}
|
||||
/>
|
||||
</SettingRow>
|
||||
<SettingRow
|
||||
name={t[`Discover what's new`]()}
|
||||
desc={t['View the AFFiNE Changelog.']()}
|
||||
style={{ cursor: 'pointer' }}
|
||||
onClick={() => {
|
||||
window.open(
|
||||
'https://affine.pro/blog/whats-new-affine-0630',
|
||||
'_blank'
|
||||
);
|
||||
}}
|
||||
>
|
||||
<ArrowRightSmallIcon />
|
||||
</SettingRow>
|
||||
</>
|
||||
) : null}
|
||||
</SettingWrapper>
|
||||
<SettingWrapper title={t['Contact with us']()}>
|
||||
<a className={link} href="https://affine.pro" target="_blank">
|
||||
{t['Official Website']()}
|
||||
|
||||
@@ -23,9 +23,8 @@ globalStyle(`${link} .icon`, {
|
||||
|
||||
export const communityWrapper = style({
|
||||
display: 'grid',
|
||||
justifyContent: 'space-between',
|
||||
gridTemplateColumns: 'repeat(auto-fill, 70px)',
|
||||
gridGap: '6px',
|
||||
gridTemplateColumns: '15% 15% 15% 15% 15% 15%',
|
||||
gap: '2%',
|
||||
});
|
||||
export const communityItem = style({
|
||||
borderRadius: '8px',
|
||||
|
||||
@@ -120,7 +120,7 @@ export const AppearanceSettings = () => {
|
||||
<LanguageMenu triggerProps={{ size: 'small' }} />
|
||||
</div>
|
||||
</SettingRow>
|
||||
{runtimeConfig.enableNewSettingUnstableApi && environment.isDesktop ? (
|
||||
{environment.isDesktop ? (
|
||||
<SettingRow
|
||||
name={t['Client Border Style']()}
|
||||
desc={t['Customize the appearance of the client.']()}
|
||||
|
||||
@@ -2,16 +2,11 @@ import {
|
||||
SettingModal as SettingModalBase,
|
||||
type SettingModalProps,
|
||||
} from '@affine/component/setting-components';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { rootWorkspacesMetadataAtom } from '@affine/workspace/atom';
|
||||
import { ContactWithUsIcon } from '@blocksuite/icons';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import type React from 'react';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { useCurrentWorkspace } from '../../../hooks/current/use-current-workspace';
|
||||
import type { AllWorkspace } from '../../../shared';
|
||||
import { AccountSetting } from './account-setting';
|
||||
import {
|
||||
GeneralSetting,
|
||||
@@ -40,14 +35,7 @@ export const SettingModal: React.FC<SettingModalProps & SettingProps> = ({
|
||||
}) => {
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
const workspaces = useAtomValue(rootWorkspacesMetadataAtom);
|
||||
const [currentWorkspace] = useCurrentWorkspace();
|
||||
const generalSettingList = useGeneralSettingList();
|
||||
const workspaceList = useMemo(() => {
|
||||
return workspaces.filter(
|
||||
({ flavour }) => flavour !== WorkspaceFlavour.PUBLIC
|
||||
);
|
||||
}, [workspaces]);
|
||||
|
||||
const onGeneralSettingClick = useCallback(
|
||||
(key: GeneralSettingKeys) => {
|
||||
@@ -76,15 +64,13 @@ export const SettingModal: React.FC<SettingModalProps & SettingProps> = ({
|
||||
<SettingSidebar
|
||||
generalSettingList={generalSettingList}
|
||||
onGeneralSettingClick={onGeneralSettingClick}
|
||||
currentWorkspace={currentWorkspace as AllWorkspace}
|
||||
workspaceList={workspaceList}
|
||||
onWorkspaceSettingClick={onWorkspaceSettingClick}
|
||||
selectedGeneralKey={activeTab}
|
||||
selectedWorkspaceId={workspaceId}
|
||||
onAccountSettingClick={onAccountSettingClick}
|
||||
/>
|
||||
|
||||
<div className={settingContent}>
|
||||
<div data-testid="setting-modal-content" className={settingContent}>
|
||||
<div className="wrapper">
|
||||
<div className="content">
|
||||
{activeTab === 'workspace' && workspaceId ? (
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
import { UserAvatar } from '@affine/component/user-avatar';
|
||||
import {
|
||||
WorkspaceListItemSkeleton,
|
||||
WorkspaceListSkeleton,
|
||||
} from '@affine/component/setting-components';
|
||||
import { WorkspaceAvatar } from '@affine/component/workspace-avatar';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { RootWorkspaceMetadata } from '@affine/workspace/atom';
|
||||
import { rootWorkspacesMetadataAtom } from '@affine/workspace/atom';
|
||||
import { useStaticBlockSuiteWorkspace } from '@toeverything/hooks/use-block-suite-workspace';
|
||||
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name';
|
||||
import clsx from 'clsx';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import type { FC } from 'react';
|
||||
import { Suspense } from 'react';
|
||||
|
||||
import type { AllWorkspace } from '../../../../shared';
|
||||
import { useCurrentWorkspace } from '../../../../hooks/current/use-current-workspace';
|
||||
import type {
|
||||
GeneralSettingKeys,
|
||||
GeneralSettingList,
|
||||
} from '../general-setting';
|
||||
import {
|
||||
accountButton,
|
||||
settingSlideBar,
|
||||
sidebarItemsWrapper,
|
||||
sidebarSelectItem,
|
||||
@@ -20,25 +26,19 @@ import {
|
||||
sidebarTitle,
|
||||
} from './style.css';
|
||||
|
||||
export const SettingSidebar = ({
|
||||
generalSettingList,
|
||||
onGeneralSettingClick,
|
||||
currentWorkspace,
|
||||
workspaceList,
|
||||
onWorkspaceSettingClick,
|
||||
selectedWorkspaceId,
|
||||
selectedGeneralKey,
|
||||
onAccountSettingClick,
|
||||
}: {
|
||||
export const SettingSidebar: FC<{
|
||||
generalSettingList: GeneralSettingList;
|
||||
onGeneralSettingClick: (key: GeneralSettingKeys) => void;
|
||||
currentWorkspace: AllWorkspace;
|
||||
workspaceList: RootWorkspaceMetadata[];
|
||||
onWorkspaceSettingClick: (workspaceId: string) => void;
|
||||
|
||||
selectedWorkspaceId: string | null;
|
||||
selectedGeneralKey: string | null;
|
||||
onAccountSettingClick: () => void;
|
||||
}> = ({
|
||||
generalSettingList,
|
||||
onGeneralSettingClick,
|
||||
onWorkspaceSettingClick,
|
||||
selectedWorkspaceId,
|
||||
selectedGeneralKey,
|
||||
}) => {
|
||||
const t = useAFFiNEI18N();
|
||||
return (
|
||||
@@ -70,10 +70,29 @@ export const SettingSidebar = ({
|
||||
{t['com.affine.settings.workspace']()}
|
||||
</div>
|
||||
<div className={clsx(sidebarItemsWrapper, 'scroll')}>
|
||||
{workspaceList.map(workspace => {
|
||||
return (
|
||||
<Suspense fallback={<WorkspaceListSkeleton />}>
|
||||
<WorkspaceList
|
||||
onWorkspaceSettingClick={onWorkspaceSettingClick}
|
||||
selectedWorkspaceId={selectedWorkspaceId}
|
||||
/>
|
||||
</Suspense>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const WorkspaceList: FC<{
|
||||
onWorkspaceSettingClick: (workspaceId: string) => void;
|
||||
selectedWorkspaceId: string | null;
|
||||
}> = ({ onWorkspaceSettingClick, selectedWorkspaceId }) => {
|
||||
const workspaces = useAtomValue(rootWorkspacesMetadataAtom);
|
||||
const [currentWorkspace] = useCurrentWorkspace();
|
||||
return (
|
||||
<>
|
||||
{workspaces.map(workspace => {
|
||||
return (
|
||||
<Suspense key={workspace.id} fallback={<WorkspaceListItemSkeleton />}>
|
||||
<WorkspaceListItem
|
||||
key={workspace.id}
|
||||
meta={workspace}
|
||||
onClick={() => {
|
||||
onWorkspaceSettingClick(workspace.id);
|
||||
@@ -81,30 +100,10 @@ export const SettingSidebar = ({
|
||||
isCurrent={workspace.id === currentWorkspace.id}
|
||||
isActive={workspace.id === selectedWorkspaceId}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{runtimeConfig.enableCloud && (
|
||||
<div className={accountButton} onClick={onAccountSettingClick}>
|
||||
<UserAvatar
|
||||
size={28}
|
||||
name="Account NameAccount Name"
|
||||
url={''}
|
||||
className="avatar"
|
||||
/>
|
||||
|
||||
<div className="content">
|
||||
<div className="name" title="xxx">
|
||||
Account NameAccount Name
|
||||
</div>
|
||||
<div className="email" title="xxx">
|
||||
xxxxxxxx@gmail.comxxxxxxxx@gmail.com
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Suspense>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ export const settingContent = style({
|
||||
flexGrow: '1',
|
||||
height: '100%',
|
||||
padding: '40px 15px 20px',
|
||||
overflowX: 'auto',
|
||||
overflow: 'auto',
|
||||
});
|
||||
|
||||
globalStyle(`${settingContent} .wrapper`, {
|
||||
@@ -13,7 +13,10 @@ globalStyle(`${settingContent} .wrapper`, {
|
||||
height: '100%',
|
||||
maxWidth: '560px',
|
||||
margin: '0 auto',
|
||||
overflowY: 'auto',
|
||||
});
|
||||
|
||||
globalStyle(`${settingContent} .wrapper::-webkit-scrollbar`, {
|
||||
display: 'none',
|
||||
});
|
||||
globalStyle(`${settingContent} .content`, {
|
||||
minHeight: '100%',
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { WorkspaceDetailSkeleton } from '@affine/component/setting-components';
|
||||
import { usePassiveWorkspaceEffect } from '@toeverything/hooks/use-block-suite-workspace';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { useRouter } from 'next/router';
|
||||
import { Suspense, useCallback } from 'react';
|
||||
|
||||
import { getUIAdapter } from '../../../../adapters/workspace';
|
||||
import { openSettingModalAtom } from '../../../../atoms';
|
||||
import { useOnTransformWorkspace } from '../../../../hooks/root/use-on-transform-workspace';
|
||||
import { useWorkspace } from '../../../../hooks/use-workspace';
|
||||
import { useAppHelper } from '../../../../hooks/use-workspaces';
|
||||
@@ -9,20 +13,24 @@ import { useAppHelper } from '../../../../hooks/use-workspaces';
|
||||
export const WorkspaceSetting = ({ workspaceId }: { workspaceId: string }) => {
|
||||
const workspace = useWorkspace(workspaceId);
|
||||
usePassiveWorkspaceEffect(workspace.blockSuiteWorkspace);
|
||||
const setSettingModal = useSetAtom(openSettingModalAtom);
|
||||
const helper = useAppHelper();
|
||||
const router = useRouter();
|
||||
|
||||
const { NewSettingsDetail } = getUIAdapter(workspace.flavour);
|
||||
|
||||
const onDeleteWorkspace = useCallback(
|
||||
async (id: string) => {
|
||||
return helper.deleteWorkspace(id);
|
||||
await helper.deleteWorkspace(id);
|
||||
setSettingModal(prev => ({ ...prev, open: false, workspaceId: null }));
|
||||
router.push('/').catch(console.error);
|
||||
},
|
||||
[helper]
|
||||
[helper, setSettingModal, router]
|
||||
);
|
||||
const onTransformWorkspace = useOnTransformWorkspace();
|
||||
|
||||
return (
|
||||
<Suspense fallback={<div>loading</div>}>
|
||||
<Suspense fallback={<WorkspaceDetailSkeleton />}>
|
||||
<NewSettingsDetail
|
||||
onTransformWorkspace={onTransformWorkspace}
|
||||
onDeleteWorkspace={onDeleteWorkspace}
|
||||
|
||||
@@ -210,6 +210,7 @@ export const windowAppControlsWrapper = style({
|
||||
display: 'flex',
|
||||
gap: '2px',
|
||||
transform: 'translateX(8px)',
|
||||
height: '100%',
|
||||
});
|
||||
|
||||
export const windowAppControl = style({
|
||||
@@ -217,11 +218,17 @@ export const windowAppControl = style({
|
||||
cursor: 'pointer',
|
||||
display: 'inline-flex',
|
||||
width: '42px',
|
||||
height: '32px',
|
||||
height: 'calc(100% - 10px)',
|
||||
paddingTop: '10px',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: '4px',
|
||||
borderRadius: '0',
|
||||
selectors: {
|
||||
'&[data-type="close"]': {
|
||||
width: '56px',
|
||||
paddingRight: '14px',
|
||||
marginRight: '-14px',
|
||||
},
|
||||
'&[data-type="close"]:hover': {
|
||||
background: 'var(--affine-error-color)',
|
||||
color: '#FFFFFF',
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import './page-detail-editor.css';
|
||||
|
||||
import {
|
||||
DEFAULT_HELLO_WORLD_PAGE_ID,
|
||||
PageNotFoundError,
|
||||
} from '@affine/env/constant';
|
||||
import { PageNotFoundError } from '@affine/env/constant';
|
||||
import { rootBlockHubAtom } from '@affine/workspace/atom';
|
||||
import type { EditorContainer } from '@blocksuite/editor';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
@@ -61,9 +58,7 @@ const EditorWrapper = memo(function EditorWrapper({
|
||||
);
|
||||
const pageSettingAtom = pageSettingFamily(pageId);
|
||||
const pageSetting = useAtomValue(pageSettingAtom);
|
||||
const currentMode =
|
||||
pageSetting?.mode ??
|
||||
(DEFAULT_HELLO_WORLD_PAGE_ID === pageId ? 'edgeless' : 'page');
|
||||
const currentMode = pageSetting?.mode ?? 'page';
|
||||
|
||||
const setBlockHub = useSetAtom(rootBlockHubAtom);
|
||||
const [appSettings] = useAppSetting();
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
} from '@affine/component/page-list';
|
||||
import type { Collection } from '@affine/env/filter';
|
||||
import type { GetPageInfoById } from '@affine/env/page-info';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import {
|
||||
DeleteIcon,
|
||||
FilterIcon,
|
||||
@@ -51,6 +52,7 @@ const CollectionOperations = ({
|
||||
showUpdateCollection: () => void;
|
||||
setting: ReturnType<typeof useCollectionManager>;
|
||||
}) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const actions = useMemo<
|
||||
Array<
|
||||
| {
|
||||
@@ -68,12 +70,12 @@ const CollectionOperations = ({
|
||||
() => [
|
||||
{
|
||||
icon: <FilterIcon />,
|
||||
name: 'Edit Filter',
|
||||
name: t['Edit Filter'](),
|
||||
click: showUpdateCollection,
|
||||
},
|
||||
{
|
||||
icon: <UnpinIcon />,
|
||||
name: 'Unpin',
|
||||
name: t['Unpin'](),
|
||||
click: () => {
|
||||
return setting.updateCollection({
|
||||
...view,
|
||||
@@ -85,15 +87,15 @@ const CollectionOperations = ({
|
||||
element: <div key="divider" className={styles.menuDividerStyle}></div>,
|
||||
},
|
||||
{
|
||||
icon: <DeleteIcon style={{ color: 'var(--affine-warning-color)' }} />,
|
||||
name: 'Delete',
|
||||
icon: <DeleteIcon />,
|
||||
name: t['Delete'](),
|
||||
click: () => {
|
||||
return setting.deleteCollection(view.id);
|
||||
},
|
||||
className: styles.deleteFolder,
|
||||
},
|
||||
],
|
||||
[setting, showUpdateCollection, view]
|
||||
[setting, showUpdateCollection, t, view]
|
||||
);
|
||||
return (
|
||||
<div style={{ minWidth: 150 }}>
|
||||
|
||||
@@ -39,6 +39,7 @@ export const PageOperations = ({
|
||||
addToExcludeList: (id: string) => void;
|
||||
}) => {
|
||||
const { removeToTrash } = useBlockSuiteMetaHelper(workspace);
|
||||
const t = useAFFiNEI18N();
|
||||
const actions = useMemo<
|
||||
Array<
|
||||
| {
|
||||
@@ -58,7 +59,7 @@ export const PageOperations = ({
|
||||
? [
|
||||
{
|
||||
icon: <FilterMinusIcon />,
|
||||
name: 'Remove special filter',
|
||||
name: t['Remove special filter'](),
|
||||
click: () => removeFromAllowList(page.id),
|
||||
},
|
||||
]
|
||||
@@ -67,7 +68,7 @@ export const PageOperations = ({
|
||||
? [
|
||||
{
|
||||
icon: <FilterUndoIcon />,
|
||||
name: 'Exclude from filter',
|
||||
name: t['Exclude from filter'](),
|
||||
click: () => addToExcludeList(page.id),
|
||||
},
|
||||
]
|
||||
@@ -76,8 +77,8 @@ export const PageOperations = ({
|
||||
element: <div key="divider" className={styles.menuDividerStyle}></div>,
|
||||
},
|
||||
{
|
||||
icon: <DeleteIcon style={{ color: 'var(--affine-warning-color)' }} />,
|
||||
name: 'Delete',
|
||||
icon: <DeleteIcon />,
|
||||
name: t['Delete'](),
|
||||
click: () => {
|
||||
removeToTrash(page.id);
|
||||
},
|
||||
@@ -86,9 +87,10 @@ export const PageOperations = ({
|
||||
],
|
||||
[
|
||||
inAllowList,
|
||||
t,
|
||||
inExcludeList,
|
||||
page.id,
|
||||
removeFromAllowList,
|
||||
page.id,
|
||||
addToExcludeList,
|
||||
removeToTrash,
|
||||
]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { style } from '@vanilla-extract/css';
|
||||
import { globalStyle, style } from '@vanilla-extract/css';
|
||||
|
||||
export const wrapper = style({
|
||||
userSelect: 'none',
|
||||
@@ -36,11 +36,14 @@ export const more = style({
|
||||
},
|
||||
});
|
||||
export const deleteFolder = style({
|
||||
color: 'var(--affine-warning-color)',
|
||||
':hover': {
|
||||
backgroundColor: 'var(--affine-background-warning-color)',
|
||||
color: 'var(--affine-error-color)',
|
||||
backgroundColor: 'var(--affine-background-error-color)',
|
||||
},
|
||||
});
|
||||
globalStyle(`${deleteFolder}:hover svg`, {
|
||||
color: 'var(--affine-error-color)',
|
||||
});
|
||||
export const menuDividerStyle = style({
|
||||
marginTop: '2px',
|
||||
marginBottom: '2px',
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { MenuLinkItem } from '@affine/component/app-sidebar';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { EdgelessIcon, PageIcon } from '@blocksuite/icons';
|
||||
import type { PageMeta, Workspace } from '@blocksuite/store';
|
||||
import * as Collapsible from '@radix-ui/react-collapsible';
|
||||
@@ -40,6 +41,7 @@ export const ReferencePage = ({
|
||||
const collapsible = referencesToShow.length > 0;
|
||||
const nestedItem = parentIds.size > 0;
|
||||
const untitled = !metaMapping[pageId]?.title;
|
||||
const t = useAFFiNEI18N();
|
||||
return (
|
||||
<Collapsible.Root
|
||||
className={styles.favItemWrapper}
|
||||
@@ -56,7 +58,7 @@ export const ReferencePage = ({
|
||||
onCollapsedChange={setCollapsed}
|
||||
>
|
||||
<span className={styles.label} data-untitled={untitled}>
|
||||
{metaMapping[pageId]?.title || 'Untitled'}
|
||||
{metaMapping[pageId]?.title || t['Untitled']()}
|
||||
</span>
|
||||
</MenuLinkItem>
|
||||
{collapsible && (
|
||||
|
||||
@@ -11,7 +11,10 @@ import {
|
||||
WorkspaceFallback,
|
||||
} from '@affine/component/workspace';
|
||||
import { initEmptyPage, initPageWithPreloading } from '@affine/env/blocksuite';
|
||||
import { DEFAULT_HELLO_WORLD_PAGE_ID, isDesktop } from '@affine/env/constant';
|
||||
import {
|
||||
DEFAULT_HELLO_WORLD_PAGE_ID_SUFFIX,
|
||||
isDesktop,
|
||||
} from '@affine/env/constant';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import {
|
||||
rootBlockHubAtom,
|
||||
@@ -46,6 +49,7 @@ import {
|
||||
openWorkspacesModalAtom,
|
||||
} from '../atoms';
|
||||
import { useTrackRouterHistoryEffect } from '../atoms/history';
|
||||
import { useAppSetting } from '../atoms/settings';
|
||||
import { AppContainer } from '../components/affine/app-container';
|
||||
import type { IslandItemNames } from '../components/pure/help-island';
|
||||
import { HelpIsland } from '../components/pure/help-island';
|
||||
@@ -187,7 +191,7 @@ export const WorkspaceLayoutInner: FC<PropsWithChildren> = ({ children }) => {
|
||||
// @ts-expect-error
|
||||
if (currentWorkspace.blockSuiteWorkspace.meta._proxy.isEmpty !== true) {
|
||||
// this is a new workspace, so we should redirect to the new page
|
||||
const pageId = DEFAULT_HELLO_WORLD_PAGE_ID;
|
||||
const pageId = `${currentWorkspace.blockSuiteWorkspace.id}-${DEFAULT_HELLO_WORLD_PAGE_ID_SUFFIX}`;
|
||||
if (currentWorkspace.blockSuiteWorkspace.getPage(pageId) === null) {
|
||||
const page = currentWorkspace.blockSuiteWorkspace.createPage({
|
||||
id: pageId,
|
||||
@@ -213,40 +217,15 @@ export const WorkspaceLayoutInner: FC<PropsWithChildren> = ({ children }) => {
|
||||
}
|
||||
//#endregion
|
||||
|
||||
//#region check if page is valid
|
||||
useEffect(() => {
|
||||
if (
|
||||
typeof router.query.pageId === 'string' &&
|
||||
router.pathname === '/workspace/[workspaceId]/[pageId]' &&
|
||||
currentPageId
|
||||
) {
|
||||
if (currentPageId !== router.query.pageId) {
|
||||
setCurrentPageId(router.query.pageId);
|
||||
} else {
|
||||
const page =
|
||||
currentWorkspace.blockSuiteWorkspace.getPage(currentPageId);
|
||||
if (!page) {
|
||||
router.push('/404').catch(console.error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [
|
||||
currentPageId,
|
||||
currentWorkspace.blockSuiteWorkspace,
|
||||
router,
|
||||
setCurrentPageId,
|
||||
]);
|
||||
//#endregion
|
||||
|
||||
usePassiveWorkspaceEffect(currentWorkspace.blockSuiteWorkspace);
|
||||
|
||||
useEffect(() => {
|
||||
const page = currentWorkspace.blockSuiteWorkspace.getPage(
|
||||
DEFAULT_HELLO_WORLD_PAGE_ID
|
||||
`${currentWorkspace.blockSuiteWorkspace.id}-${DEFAULT_HELLO_WORLD_PAGE_ID_SUFFIX}`
|
||||
);
|
||||
if (page && page.meta.jumpOnce) {
|
||||
currentWorkspace.blockSuiteWorkspace.meta.setPageMeta(
|
||||
DEFAULT_HELLO_WORLD_PAGE_ID,
|
||||
`${currentWorkspace.blockSuiteWorkspace.id}-${DEFAULT_HELLO_WORLD_PAGE_ID_SUFFIX}`,
|
||||
{
|
||||
jumpOnce: false,
|
||||
}
|
||||
@@ -284,7 +263,7 @@ export const WorkspaceLayoutInner: FC<PropsWithChildren> = ({ children }) => {
|
||||
setOpenQuickSearchModalAtom(true);
|
||||
}, [setOpenQuickSearchModalAtom]);
|
||||
|
||||
const [, setOpenSettingModalAtom] = useAtom(openSettingModalAtom);
|
||||
const setOpenSettingModalAtom = useSetAtom(openSettingModalAtom);
|
||||
|
||||
const handleOpenSettingModal = useCallback(() => {
|
||||
setOpenSettingModalAtom({
|
||||
@@ -335,6 +314,8 @@ export const WorkspaceLayoutInner: FC<PropsWithChildren> = ({ children }) => {
|
||||
[moveToTrash, t]
|
||||
);
|
||||
|
||||
const [appSetting] = useAppSetting();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
@@ -364,7 +345,7 @@ export const WorkspaceLayoutInner: FC<PropsWithChildren> = ({ children }) => {
|
||||
currentPath={router.asPath.split('?')[0]}
|
||||
paths={isPublicWorkspace ? publicPathGenerator : pathGenerator}
|
||||
/>
|
||||
<MainContainer>
|
||||
<MainContainer padding={appSetting.clientBorder}>
|
||||
{children}
|
||||
<ToolContainer>
|
||||
<BlockHubWrapper blockHubAtom={rootBlockHubAtom} />
|
||||
|
||||
@@ -8,10 +8,10 @@ import { rootCurrentPageIdAtom } from '@affine/workspace/atom';
|
||||
import type { EditorContainer } from '@blocksuite/editor';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import type { Page } from '@blocksuite/store';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useAtom, useAtomValue } from 'jotai';
|
||||
import { useRouter } from 'next/router';
|
||||
import type React from 'react';
|
||||
import { useCallback } from 'react';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
|
||||
import { getUIAdapter } from '../../../adapters/workspace';
|
||||
import { useCurrentWorkspace } from '../../../hooks/current/use-current-workspace';
|
||||
@@ -73,10 +73,41 @@ const WorkspaceDetail: React.FC = () => {
|
||||
const WorkspaceDetailPage: NextPageWithLayout = () => {
|
||||
const router = useRouter();
|
||||
const [currentWorkspace] = useCurrentWorkspace();
|
||||
const currentPageId = useAtomValue(rootCurrentPageIdAtom);
|
||||
const [currentPageId, setCurrentPageId] = useAtom(rootCurrentPageIdAtom);
|
||||
const page = currentPageId
|
||||
? currentWorkspace.blockSuiteWorkspace.getPage(currentPageId)
|
||||
: null;
|
||||
|
||||
//#region check if page is valid
|
||||
useEffect(() => {
|
||||
// if the workspace changed, ignore the page check
|
||||
if (currentWorkspace.id !== router.query.workspaceId) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
typeof router.query.pageId === 'string' &&
|
||||
router.pathname === '/workspace/[workspaceId]/[pageId]' &&
|
||||
currentPageId
|
||||
) {
|
||||
if (currentPageId !== router.query.pageId) {
|
||||
setCurrentPageId(router.query.pageId);
|
||||
} else {
|
||||
const page =
|
||||
currentWorkspace.blockSuiteWorkspace.getPage(currentPageId);
|
||||
if (!page) {
|
||||
router.push('/404').catch(console.error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [
|
||||
currentPageId,
|
||||
currentWorkspace.blockSuiteWorkspace,
|
||||
currentWorkspace.id,
|
||||
router,
|
||||
setCurrentPageId,
|
||||
]);
|
||||
//#endregion
|
||||
|
||||
if (!router.isReady) {
|
||||
return <PageDetailSkeleton key="router-not-ready" />;
|
||||
} else if (!currentPageId || !page) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { WorkspaceSubPath } from '@affine/env/workspace';
|
||||
import {
|
||||
rootCurrentPageIdAtom,
|
||||
rootCurrentWorkspaceIdAtom,
|
||||
rootWorkspacesMetadataAtom,
|
||||
} from '@affine/workspace/atom';
|
||||
@@ -124,6 +125,7 @@ export const AllWorkspaceModals = (): ReactElement => {
|
||||
const [currentWorkspaceId, setCurrentWorkspaceId] = useAtom(
|
||||
rootCurrentWorkspaceIdAtom
|
||||
);
|
||||
const setCurrentPageId = useSetAtom(rootCurrentPageIdAtom);
|
||||
const [transitioning, transition] = useTransition();
|
||||
const [, setOpenSettingModalAtom] = useAtom(openSettingModalAtom);
|
||||
|
||||
@@ -169,11 +171,17 @@ export const AllWorkspaceModals = (): ReactElement => {
|
||||
workspaceId => {
|
||||
setOpenWorkspacesModal(false);
|
||||
setCurrentWorkspaceId(workspaceId);
|
||||
setCurrentPageId(null);
|
||||
jumpToSubPath(workspaceId, WorkspaceSubPath.ALL).catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
},
|
||||
[jumpToSubPath, setCurrentWorkspaceId, setOpenWorkspacesModal]
|
||||
[
|
||||
jumpToSubPath,
|
||||
setCurrentPageId,
|
||||
setCurrentWorkspaceId,
|
||||
setOpenWorkspacesModal,
|
||||
]
|
||||
)}
|
||||
onClickWorkspaceSetting={handleOpenSettingModal}
|
||||
onNewWorkspace={useCallback(() => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@affine/monorepo",
|
||||
"version": "0.7.0-canary.39",
|
||||
"version": "0.7.0-canary.42",
|
||||
"private": true,
|
||||
"author": "toeverything",
|
||||
"license": "MPL-2.0",
|
||||
|
||||
@@ -19,5 +19,5 @@
|
||||
"peerDependencies": {
|
||||
"ts-node": "*"
|
||||
},
|
||||
"version": "0.7.0-canary.39"
|
||||
"version": "0.7.0-canary.42"
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
"@radix-ui/react-toast": "^1.1.4",
|
||||
"@toeverything/hooks": "workspace:*",
|
||||
"@toeverything/plugin-infra": "workspace:*",
|
||||
"@toeverything/theme": "^0.7.4",
|
||||
"@toeverything/theme": "^0.7.6",
|
||||
"@vanilla-extract/dynamic": "^2.0.3",
|
||||
"clsx": "^1.2.1",
|
||||
"dayjs": "^1.11.9",
|
||||
@@ -51,12 +51,12 @@
|
||||
"rxjs": "^7.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@blocksuite/blocks": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/blocks": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/icons": "^2.1.24",
|
||||
"@blocksuite/lit": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/lit": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@types/react": "^18.2.14",
|
||||
"@types/react-datepicker": "^4.11.2",
|
||||
"@types/react-dnd": "^3.0.2",
|
||||
@@ -66,5 +66,5 @@
|
||||
"vite": "^4.3.9",
|
||||
"yjs": "^13.6.6"
|
||||
},
|
||||
"version": "0.7.0-canary.39"
|
||||
"version": "0.7.0-canary.42"
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ export const buttonStyle = style({
|
||||
margin: '10px 6px',
|
||||
padding: '0 0',
|
||||
':hover': {
|
||||
backgroundColor: 'var(--affine-hover-color)',
|
||||
backgroundColor: 'var(--affine-background-error-color)',
|
||||
backgroundSize: '24px 24px',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -478,7 +478,7 @@ const ImagePreviewModalImpl = (
|
||||
noBorder={true}
|
||||
className={buttonStyle}
|
||||
onClick={() => blockId && deleteHandler(blockId)}
|
||||
hoverColor={'-moz-initial'}
|
||||
hoverColor="var(--affine-error-color)"
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
@@ -11,6 +11,8 @@ export const FilterTag = ({ name }: FilterTagProps) => {
|
||||
return t['Created']();
|
||||
case 'Updated':
|
||||
return t['Updated']();
|
||||
case 'Tags':
|
||||
return t['Tags']();
|
||||
case 'Is Favourited':
|
||||
return t['com.affine.filter.is-favourited']();
|
||||
case 'after':
|
||||
@@ -19,6 +21,18 @@ export const FilterTag = ({ name }: FilterTagProps) => {
|
||||
return t['com.affine.filter.before']();
|
||||
case 'is':
|
||||
return t['com.affine.filter.is']();
|
||||
case 'is not empty':
|
||||
return t['com.affine.filter.is not empty']();
|
||||
case 'is empty':
|
||||
return t['com.affine.filter.is empty']();
|
||||
case 'contains all':
|
||||
return t['com.affine.filter.contains all']();
|
||||
case 'contains one of':
|
||||
return t['com.affine.filter.contains one of']();
|
||||
case 'does not contains all':
|
||||
return t['com.affine.filter.does not contains all']();
|
||||
case 'does not contains one of':
|
||||
return t['com.affine.filter.does not contains one of']();
|
||||
case 'true':
|
||||
return t['com.affine.filter.true']();
|
||||
case 'false':
|
||||
|
||||
@@ -147,6 +147,8 @@ export const TrashOperationCell: React.FC<TrashOperationCellProps> = ({
|
||||
onClick={() => {
|
||||
setOpen(true);
|
||||
}}
|
||||
hoverBackground="var(--affine-background-error-color)"
|
||||
hoverColor="var(--affine-error-color)"
|
||||
>
|
||||
<DeletePermanentlyIcon />
|
||||
</IconButton>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { pushNotificationAtom } from '@affine/component/notification-center';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { PageBlockModel } from '@blocksuite/blocks';
|
||||
import { ContentParser } from '@blocksuite/blocks/content-parser';
|
||||
import {
|
||||
ArrowRightSmallIcon,
|
||||
ExportIcon,
|
||||
@@ -11,16 +10,16 @@ import {
|
||||
ExportToPngIcon,
|
||||
} from '@blocksuite/icons';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { useCallback, useRef } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { Menu, MenuItem } from '../../..';
|
||||
import { getContentParser } from './get-content-parser';
|
||||
import type { CommonMenuItemProps } from './types';
|
||||
|
||||
export const ExportToPdfMenuItem = ({
|
||||
onSelect,
|
||||
}: CommonMenuItemProps<{ type: 'pdf' }>) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const contentParserRef = useRef<ContentParser>();
|
||||
const { currentEditor } = globalThis;
|
||||
const setPushNotification = useSetAtom(pushNotificationAtom);
|
||||
|
||||
@@ -53,9 +52,7 @@ export const ExportToPdfMenuItem = ({
|
||||
});
|
||||
});
|
||||
} else {
|
||||
const contentParser =
|
||||
contentParserRef.current ??
|
||||
(contentParserRef.current = new ContentParser(currentEditor.page));
|
||||
const contentParser = getContentParser(currentEditor.page);
|
||||
|
||||
contentParser
|
||||
.exportPdf()
|
||||
@@ -95,17 +92,14 @@ export const ExportToHtmlMenuItem = ({
|
||||
onSelect,
|
||||
}: CommonMenuItemProps<{ type: 'html' }>) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const contentParserRef = useRef<ContentParser>();
|
||||
const { currentEditor } = globalThis;
|
||||
const setPushNotification = useSetAtom(pushNotificationAtom);
|
||||
const onClickExportHtml = useCallback(() => {
|
||||
if (!currentEditor) {
|
||||
return;
|
||||
}
|
||||
if (!contentParserRef.current) {
|
||||
contentParserRef.current = new ContentParser(currentEditor.page);
|
||||
}
|
||||
contentParserRef.current
|
||||
const contentParser = getContentParser(currentEditor.page);
|
||||
contentParser
|
||||
.exportHtml()
|
||||
.then(() => {
|
||||
onSelect?.({ type: 'html' });
|
||||
@@ -138,7 +132,6 @@ export const ExportToPngMenuItem = ({
|
||||
onSelect,
|
||||
}: CommonMenuItemProps<{ type: 'png' }>) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const contentParserRef = useRef<ContentParser>();
|
||||
const { currentEditor } = globalThis;
|
||||
const setPushNotification = useSetAtom(pushNotificationAtom);
|
||||
|
||||
@@ -146,9 +139,7 @@ export const ExportToPngMenuItem = ({
|
||||
if (!currentEditor) {
|
||||
return;
|
||||
}
|
||||
const contentParser =
|
||||
contentParserRef.current ??
|
||||
(contentParserRef.current = new ContentParser(currentEditor.page));
|
||||
const contentParser = getContentParser(currentEditor.page);
|
||||
|
||||
contentParser
|
||||
.exportPng()
|
||||
@@ -189,17 +180,14 @@ export const ExportToMarkdownMenuItem = ({
|
||||
onSelect,
|
||||
}: CommonMenuItemProps<{ type: 'markdown' }>) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const contentParserRef = useRef<ContentParser>();
|
||||
const { currentEditor } = globalThis;
|
||||
const setPushNotification = useSetAtom(pushNotificationAtom);
|
||||
const onClickExportMarkdown = useCallback(() => {
|
||||
if (!currentEditor) {
|
||||
return;
|
||||
}
|
||||
if (!contentParserRef.current) {
|
||||
contentParserRef.current = new ContentParser(currentEditor.page);
|
||||
}
|
||||
contentParserRef.current
|
||||
const contentParser = getContentParser(currentEditor.page);
|
||||
contentParser
|
||||
.exportMarkdown()
|
||||
.then(() => {
|
||||
onSelect?.({ type: 'markdown' });
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { ContentParser } from '@blocksuite/blocks/content-parser';
|
||||
import type { Page } from '@blocksuite/store';
|
||||
|
||||
const contentParserWeakMap = new WeakMap<Page, ContentParser>();
|
||||
|
||||
export function getContentParser(page: Page) {
|
||||
if (!contentParserWeakMap.has(page)) {
|
||||
contentParserWeakMap.set(
|
||||
page,
|
||||
new ContentParser(page, {
|
||||
imageProxyEndpoint: !environment.isDesktop
|
||||
? runtimeConfig.imageProxyUrl
|
||||
: undefined,
|
||||
})
|
||||
);
|
||||
}
|
||||
return contentParserWeakMap.get(page) as ContentParser;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { globalStyle, style } from '@vanilla-extract/css';
|
||||
|
||||
export const moveToTrashStyle = style({
|
||||
':hover': {
|
||||
backgroundColor: 'var(--affine-background-error-color)',
|
||||
color: 'var(--affine-error-color)',
|
||||
},
|
||||
});
|
||||
|
||||
globalStyle(`${moveToTrashStyle}:hover svg`, {
|
||||
color: 'var(--affine-error-color)',
|
||||
});
|
||||
@@ -3,8 +3,8 @@ import { DeleteTemporarilyIcon } from '@blocksuite/icons';
|
||||
|
||||
import type { ConfirmProps } from '../../..';
|
||||
import { Confirm, MenuItem } from '../../..';
|
||||
import { moveToTrashStyle } from './index.css';
|
||||
import type { CommonMenuItemProps } from './types';
|
||||
|
||||
export const MoveToTrash = ({
|
||||
onSelect,
|
||||
onItemClick,
|
||||
@@ -21,6 +21,7 @@ export const MoveToTrash = ({
|
||||
onSelect?.();
|
||||
}}
|
||||
icon={<DeleteTemporarilyIcon />}
|
||||
className={moveToTrashStyle}
|
||||
>
|
||||
{t['Move to Trash']()}
|
||||
</MenuItem>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { EditCollectionModel } from '@affine/component/page-list';
|
||||
import type { PropertiesMeta } from '@affine/env/filter';
|
||||
import type { GetPageInfoById } from '@affine/env/page-info';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import {
|
||||
DeleteIcon,
|
||||
FilterIcon,
|
||||
@@ -68,7 +69,7 @@ export const CollectionBar = ({
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: <DeleteIcon style={{ color: 'red' }} />,
|
||||
icon: <DeleteIcon style={{ color: 'var(--affine-error-color)' }} />,
|
||||
name: 'delete',
|
||||
click: () => {
|
||||
setting.deleteCollection(collection.id).catch(err => {
|
||||
@@ -80,6 +81,7 @@ export const CollectionBar = ({
|
||||
[setting, collection]
|
||||
);
|
||||
const onClose = useCallback(() => setOpen(false), []);
|
||||
const t = useAFFiNEI18N();
|
||||
return !setting.isDefault ? (
|
||||
<tr style={{ userSelect: 'none' }}>
|
||||
<td>
|
||||
@@ -124,8 +126,11 @@ export const CollectionBar = ({
|
||||
justifyContent: 'end',
|
||||
}}
|
||||
>
|
||||
<Button style={{ border: 'none' }} onClick={() => setting.backToAll()}>
|
||||
Back to all
|
||||
<Button
|
||||
style={{ border: 'none', position: 'static' }}
|
||||
onClick={() => setting.backToAll()}
|
||||
>
|
||||
{t['Back to all']()}
|
||||
</Button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -202,6 +202,7 @@ export const deleteIcon = style({
|
||||
padding: 4,
|
||||
cursor: 'pointer',
|
||||
':hover': {
|
||||
backgroundColor: 'var(--affine-hover-color)',
|
||||
color: 'var(--affine-error-color)',
|
||||
backgroundColor: 'var(--affine-background-error-color)',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -57,7 +57,7 @@ const CollectionOption = ({
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: <DeleteIcon style={{ color: 'red' }} />,
|
||||
icon: <DeleteIcon style={{ color: 'var(--affine-error-color)' }} />,
|
||||
name: 'delete',
|
||||
click: () => {
|
||||
setting.deleteCollection(collection.id).catch(err => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { Collection } from '@affine/env/filter';
|
||||
import type { PropertiesMeta } from '@affine/env/filter';
|
||||
import type { GetPageInfoById } from '@affine/env/page-info';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import {
|
||||
EdgelessIcon,
|
||||
PageIcon,
|
||||
@@ -35,14 +36,17 @@ export const EditCollectionModel = ({
|
||||
onClose,
|
||||
getPageInfo,
|
||||
propertiesMeta,
|
||||
title,
|
||||
}: {
|
||||
init?: Collection;
|
||||
onConfirm: (view: Collection) => void;
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
title?: string;
|
||||
getPageInfo: GetPageInfoById;
|
||||
propertiesMeta: PropertiesMeta;
|
||||
}) => {
|
||||
const t = useAFFiNEI18N();
|
||||
return (
|
||||
<Modal open={open} onClose={onClose}>
|
||||
<ModalWrapper
|
||||
@@ -61,8 +65,8 @@ export const EditCollectionModel = ({
|
||||
{init ? (
|
||||
<EditCollection
|
||||
propertiesMeta={propertiesMeta}
|
||||
title="Update Collection"
|
||||
onConfirmText="Save"
|
||||
title={title}
|
||||
onConfirmText={t['Save']()}
|
||||
init={init}
|
||||
getPageInfo={getPageInfo}
|
||||
onCancel={onClose}
|
||||
@@ -129,6 +133,7 @@ export const EditCollection = ({
|
||||
}: CreateCollectionProps & {
|
||||
onCancel: () => void;
|
||||
}) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const [value, onChange] = useState<Collection>(init);
|
||||
const removeFromExcludeList = useCallback(
|
||||
(id: string) => {
|
||||
@@ -157,7 +162,7 @@ export const EditCollection = ({
|
||||
}}
|
||||
>
|
||||
<div className={styles.saveTitle}>
|
||||
{title ?? 'Save As New Collection'}
|
||||
{title ?? t['Update Collection']()}
|
||||
</div>
|
||||
<ScrollableContainer
|
||||
className={styles.scrollContainer}
|
||||
@@ -244,7 +249,7 @@ export const EditCollection = ({
|
||||
}}
|
||||
>
|
||||
<Button className={styles.cancelButton} onClick={onCancel}>
|
||||
Cancel
|
||||
{t['Cancel']()}
|
||||
</Button>
|
||||
<Button
|
||||
style={{
|
||||
@@ -259,7 +264,7 @@ export const EditCollection = ({
|
||||
}
|
||||
}}
|
||||
>
|
||||
{onConfirmText ?? 'Create'}
|
||||
{onConfirmText ?? t['Create']()}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -272,6 +277,7 @@ export const SaveCollectionButton = ({
|
||||
propertiesMeta,
|
||||
}: CreateCollectionProps) => {
|
||||
const [show, changeShow] = useState(false);
|
||||
const t = useAFFiNEI18N();
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
@@ -288,6 +294,7 @@ export const SaveCollectionButton = ({
|
||||
</div>
|
||||
</Button>
|
||||
<EditCollectionModel
|
||||
title={t['Save As New Collection']()}
|
||||
propertiesMeta={propertiesMeta}
|
||||
init={init}
|
||||
onConfirm={onConfirm}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
export { SettingModal, type SettingModalProps } from './modal';
|
||||
export { SettingHeader } from './setting-header';
|
||||
export { SettingRow } from './setting-row';
|
||||
export * from './workspace-detail-skeleton';
|
||||
export * from './workspace-list-skeleton';
|
||||
export { SettingWrapper } from './wrapper';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { FC, HTMLAttributes } from 'react';
|
||||
import type { FC, HTMLAttributes, ReactNode } from 'react';
|
||||
|
||||
import { settingHeader } from './share.css';
|
||||
|
||||
export const SettingHeader: FC<
|
||||
{ title: string; subtitle?: string } & Omit<
|
||||
{ title: ReactNode; subtitle?: ReactNode } & Omit<
|
||||
HTMLAttributes<HTMLDivElement>,
|
||||
'title'
|
||||
>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import clsx from 'clsx';
|
||||
import type { CSSProperties, FC, PropsWithChildren, ReactElement } from 'react';
|
||||
import type { CSSProperties, FC, PropsWithChildren, ReactNode } from 'react';
|
||||
|
||||
import { settingRow } from './share.css';
|
||||
|
||||
export const SettingRow: FC<
|
||||
PropsWithChildren<{
|
||||
name: string | ReactElement;
|
||||
desc: string | ReactElement;
|
||||
name: ReactNode;
|
||||
desc: ReactNode;
|
||||
style?: CSSProperties;
|
||||
onClick?: () => void;
|
||||
spreadCol?: boolean;
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { Skeleton } from '@mui/material';
|
||||
|
||||
import { SettingHeader } from './setting-header';
|
||||
import { SettingRow } from './setting-row';
|
||||
import { SettingWrapper } from './wrapper';
|
||||
|
||||
export const WorkspaceDetailSkeleton = () => {
|
||||
return (
|
||||
<>
|
||||
<SettingHeader title={<Skeleton />} subtitle={<Skeleton />} />
|
||||
|
||||
{new Array(3).fill(0).map((_, index) => {
|
||||
return (
|
||||
<SettingWrapper title={<Skeleton />} key={index}>
|
||||
<SettingRow
|
||||
name={<Skeleton />}
|
||||
desc={<Skeleton />}
|
||||
spreadCol={false}
|
||||
></SettingRow>
|
||||
</SettingWrapper>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
import { Skeleton } from '@mui/material';
|
||||
|
||||
import { FlexWrapper } from '../../ui/layout';
|
||||
|
||||
export const WorkspaceListItemSkeleton = () => {
|
||||
return (
|
||||
<FlexWrapper
|
||||
alignItems="center"
|
||||
style={{ padding: '0 8px', height: 30, marginBottom: 4 }}
|
||||
>
|
||||
<Skeleton
|
||||
variant="circular"
|
||||
width={14}
|
||||
height={14}
|
||||
style={{ marginRight: 10 }}
|
||||
/>
|
||||
<Skeleton variant="rectangular" height={16} style={{ flexGrow: 1 }} />
|
||||
</FlexWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export const WorkspaceListSkeleton = () => {
|
||||
return (
|
||||
<>
|
||||
{new Array(5).fill(0).map((_, index) => {
|
||||
return <WorkspaceListItemSkeleton key={index} />;
|
||||
})}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { FC, PropsWithChildren } from 'react';
|
||||
import type { FC, PropsWithChildren, ReactNode } from 'react';
|
||||
|
||||
import { wrapper } from './share.css';
|
||||
export const SettingWrapper: FC<
|
||||
PropsWithChildren<{
|
||||
title?: string;
|
||||
title?: ReactNode;
|
||||
}>
|
||||
> = ({ title, children }) => {
|
||||
return (
|
||||
|
||||
@@ -57,9 +57,9 @@ export const mainContainerStyle = style({
|
||||
zIndex: 2,
|
||||
backgroundColor: 'var(--affine-background-primary-color)',
|
||||
selectors: {
|
||||
'&[data-is-desktop="true"]': {
|
||||
margin: '8px 8px 8px 8px',
|
||||
borderRadius: '8px',
|
||||
'&[data-show-padding="true"]': {
|
||||
margin: '8px',
|
||||
borderRadius: '5px',
|
||||
overflow: 'hidden',
|
||||
boxShadow: 'var(--affine-shadow-1)',
|
||||
'@media': {
|
||||
@@ -70,7 +70,10 @@ export const mainContainerStyle = style({
|
||||
},
|
||||
},
|
||||
},
|
||||
'&[data-is-desktop="true"]:before': {
|
||||
'&[data-show-padding="true"][data-is-macos="true"]': {
|
||||
borderRadius: '6px',
|
||||
},
|
||||
'&[data-show-padding="true"]:before': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
height: '8px',
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { isDesktop } from '@affine/env/constant';
|
||||
import { clsx } from 'clsx';
|
||||
import type { FC, PropsWithChildren, ReactElement } from 'react';
|
||||
|
||||
@@ -22,7 +21,7 @@ export const AppContainer: FC<WorkspaceRootProps> = ({
|
||||
<div
|
||||
className={clsx(appStyle, {
|
||||
'noisy-background': noisyBackground,
|
||||
'blur-background': isDesktop && useBlurBackground,
|
||||
'blur-background': environment.isDesktop && useBlurBackground,
|
||||
})}
|
||||
data-noise-background={noisyBackground}
|
||||
data-is-resizing={resizing}
|
||||
@@ -34,15 +33,24 @@ export const AppContainer: FC<WorkspaceRootProps> = ({
|
||||
|
||||
export type MainContainerProps = PropsWithChildren<{
|
||||
className?: string;
|
||||
}>;
|
||||
padding?: boolean;
|
||||
}> &
|
||||
React.HTMLAttributes<HTMLDivElement>;
|
||||
|
||||
export const MainContainer = (props: MainContainerProps): ReactElement => {
|
||||
export const MainContainer = ({
|
||||
className,
|
||||
padding,
|
||||
children,
|
||||
...props
|
||||
}: MainContainerProps): ReactElement => {
|
||||
return (
|
||||
<div
|
||||
className={clsx(mainContainerStyle, 'main-container', props.className)}
|
||||
data-is-desktop={isDesktop}
|
||||
{...props}
|
||||
className={clsx(mainContainerStyle, 'main-container', className)}
|
||||
data-is-macos={environment.isBrowser && environment.isMacOs}
|
||||
data-show-padding={padding}
|
||||
>
|
||||
{props.children}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,3 +1,32 @@
|
||||
/*
|
||||
* Inter (Variable)
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-display: swap;
|
||||
src: url(/fonts/inter/Inter-VariableFont_slnt,wght.ttf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Source Code Pro (Variable)
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Source Code Pro';
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
src: url(/fonts/source-code-pro/SourceCodePro-VariableFont_wght.ttf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Source Code Pro';
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
src: url(/fonts/source-code-pro/SourceCodePro-Italic-VariableFont_wght.ttf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Kalam
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Kalam';
|
||||
font-style: normal;
|
||||
@@ -21,3 +50,105 @@
|
||||
font-display: swap;
|
||||
src: url(/fonts/kalam/Kalam-Bold.ttf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Source Serif 4
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Source Serif 4';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url(/fonts/source-serif-4/SourceSerif4-Regular.ttf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Source Serif 4';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url(/fonts/source-serif-4/SourceSerif4-Italic.ttf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Source Serif 4';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url(/fonts/source-serif-4/SourceSerif4-Medium.ttf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Source Serif 4';
|
||||
font-style: italic;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url(/fonts/source-serif-4/SourceSerif4-MediumItalic.ttf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Source Serif 4';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url(/fonts/source-serif-4/SourceSerif4-SemiBold.ttf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Source Serif 4';
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url(/fonts/source-serif-4/SourceSerif4-SemiBoldItalic.ttf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Source Serif 4';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url(/fonts/source-serif-4/SourceSerif4-Bold.ttf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Source Serif 4';
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url(/fonts/source-serif-4/SourceSerif4-BoldItalic.ttf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Space Mono
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Space Mono';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url(/fonts/space-mono/SpaceMono-Regular.ttf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Space Mono';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url(/fonts/space-mono/SpaceMono-Italic.ttf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Space Mono';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url(/fonts/space-mono/SpaceMono-Bold.ttf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Space Mono';
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url(/fonts/space-mono/SpaceMono-BoldItalic.ttf);
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@ import MuiBreadcrumbs from '@mui/material/Breadcrumbs';
|
||||
import MuiCollapse from '@mui/material/Collapse';
|
||||
import MuiFade from '@mui/material/Fade';
|
||||
import MuiGrow from '@mui/material/Grow';
|
||||
import MuiSkeleton from '@mui/material/Skeleton';
|
||||
import MuiSlide from '@mui/material/Slide';
|
||||
|
||||
export {
|
||||
MuiAvatar,
|
||||
MuiBreadcrumbs,
|
||||
@@ -13,5 +13,6 @@ export {
|
||||
MuiCollapse,
|
||||
MuiFade,
|
||||
MuiGrow,
|
||||
MuiSkeleton,
|
||||
MuiSlide,
|
||||
};
|
||||
|
||||
@@ -8,5 +8,5 @@
|
||||
"devDependencies": {
|
||||
"@types/debug": "^4.1.8"
|
||||
},
|
||||
"version": "0.7.0-canary.39"
|
||||
"version": "0.7.0-canary.42"
|
||||
}
|
||||
|
||||
4
packages/env/package.json
vendored
4
packages/env/package.json
vendored
@@ -5,7 +5,7 @@
|
||||
"module": "./src/index.ts",
|
||||
"types": "./src/global.ts",
|
||||
"devDependencies": {
|
||||
"@blocksuite/global": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"next": "=13.4.2",
|
||||
"react": "18.3.0-canary-1fdacbefd-20230630",
|
||||
"react-dom": "18.3.0-canary-1fdacbefd-20230630",
|
||||
@@ -27,5 +27,5 @@
|
||||
"dependencies": {
|
||||
"lit": "^2.7.5"
|
||||
},
|
||||
"version": "0.7.0-canary.39"
|
||||
"version": "0.7.0-canary.42"
|
||||
}
|
||||
|
||||
3
packages/env/src/constant.ts
vendored
3
packages/env/src/constant.ts
vendored
@@ -14,10 +14,9 @@ export const isBrowser = typeof window !== 'undefined';
|
||||
export const isServer = !isBrowser && typeof navigator === 'undefined';
|
||||
export const isDesktop = isBrowser && !!window.appInfo?.electron;
|
||||
//#endregion
|
||||
export const AFFINE_STORAGE_KEY = 'affine-local-storage-v2';
|
||||
export const DEFAULT_WORKSPACE_NAME = 'Demo Workspace';
|
||||
export const UNTITLED_WORKSPACE_NAME = 'Untitled';
|
||||
export const DEFAULT_HELLO_WORLD_PAGE_ID = 'hello-world';
|
||||
export const DEFAULT_HELLO_WORLD_PAGE_ID_SUFFIX = 'hello-world';
|
||||
|
||||
export const DEFAULT_SORT_KEY = 'updatedDate';
|
||||
export const MessageCode = {
|
||||
|
||||
4
packages/env/src/global.ts
vendored
4
packages/env/src/global.ts
vendored
@@ -63,6 +63,8 @@ export const buildFlagsSchema = z.object({
|
||||
enableBroadcastChannelProvider: z.boolean(),
|
||||
enableDebugPage: z.boolean(),
|
||||
changelogUrl: z.string(),
|
||||
// see: packages/workers
|
||||
imageProxyUrl: z.string(),
|
||||
enablePreloading: z.boolean(),
|
||||
enableNewSettingModal: z.boolean(),
|
||||
enableNewSettingUnstableApi: z.boolean(),
|
||||
@@ -91,6 +93,8 @@ export const publicRuntimeConfigSchema = buildFlagsSchema.extend({
|
||||
PROJECT_NAME: z.string(),
|
||||
BUILD_DATE: z.string(),
|
||||
gitVersion: z.string(),
|
||||
appVersion: z.string(),
|
||||
editorVersion: z.string(),
|
||||
hash: z.string(),
|
||||
serverAPI: z.string(),
|
||||
editorFlags: blockSuiteFeatureFlags,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@affine/graphql",
|
||||
"version": "0.7.0-canary.39",
|
||||
"version": "0.7.0-canary.42",
|
||||
"description": "Autogenerated GraphQL client for affine.pro",
|
||||
"license": "MPL-2.0",
|
||||
"type": "module",
|
||||
|
||||
@@ -8,5 +8,5 @@
|
||||
"@affine/env": "workspace:*",
|
||||
"@toeverything/y-indexeddb": "workspace:*"
|
||||
},
|
||||
"version": "0.7.0-canary.39"
|
||||
"version": "0.7.0-canary.42"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// guid -> Workspace
|
||||
import type { ActiveDocProvider, Workspace } from '@blocksuite/store';
|
||||
import type { PassiveDocProvider } from '@blocksuite/store';
|
||||
import { useAtomValue } from 'jotai/react';
|
||||
@@ -8,6 +7,7 @@ import { useEffect } from 'react';
|
||||
|
||||
/**
|
||||
* DO NOT ACCESS THIS MAP IN PRODUCTION, OR YOU WILL BE FIRED
|
||||
* Map: guid -> Workspace
|
||||
*/
|
||||
export const INTERNAL_BLOCKSUITE_HASH_MAP = new Map<string, Workspace>([]);
|
||||
|
||||
|
||||
@@ -37,5 +37,5 @@
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.1.6"
|
||||
},
|
||||
"version": "0.7.0-canary.39"
|
||||
"version": "0.7.0-canary.42"
|
||||
}
|
||||
|
||||
@@ -61,6 +61,12 @@
|
||||
"Export AFFiNE backup file": "Export AFFiNE backup file",
|
||||
"com.affine.filter.before": "before",
|
||||
"com.affine.filter.is": "is",
|
||||
"com.affine.filter.is not empty": "is not empty",
|
||||
"com.affine.filter.is empty": "is empty",
|
||||
"com.affine.filter.contains all": "contains all",
|
||||
"com.affine.filter.contains one of": "contains one of",
|
||||
"com.affine.filter.does not contains all": "does not contains all",
|
||||
"com.affine.filter.does not contains one of": "does not contains one of",
|
||||
"com.affine.filter.true": "true",
|
||||
"com.affine.filter.false": "false",
|
||||
"com.affine.filter.save-view": "Save View",
|
||||
@@ -364,6 +370,13 @@
|
||||
"Date Format": "Date Format",
|
||||
"Select All": "Select All",
|
||||
"Collections": "Collections",
|
||||
"Save As New Collection": "Save As New Collection",
|
||||
"Update Collection": "Update Collection",
|
||||
"Back to all": "Back to all",
|
||||
"Edit Filter": "Edit Filter",
|
||||
"Unpin": "Unpin",
|
||||
"Remove special filter": "Remove special filter",
|
||||
"Exclude from filter": "Exclude from filter",
|
||||
"Customize your date style.": "Customise your date style.",
|
||||
"Contact with us": "Contact Us",
|
||||
"Terms of Use": "Terms of Use",
|
||||
@@ -407,5 +420,7 @@
|
||||
"You can customize your workspace here.": "You can customise your workspace here.",
|
||||
"Font Style": "Font Style",
|
||||
"Choose your font style": "Choose your font style",
|
||||
"Switch": "Switch"
|
||||
"Switch": "Switch",
|
||||
"com.affine.settings.workspace.publish.local-tooltip": "Enable AFFiNE Cloud to publish this Workspace",
|
||||
"com.affine.settings.workspace.member.local-tooltip": "Enable AFFiNE Cloud to collaborate with others"
|
||||
}
|
||||
|
||||
@@ -46,5 +46,5 @@
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"version": "0.7.0-canary.39"
|
||||
"version": "0.7.0-canary.42"
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
"jotai": "^2.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@blocksuite/blocks": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/lit": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/blocks": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/lit": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"lottie-web": "^5.12.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -21,5 +21,5 @@
|
||||
"@blocksuite/store": "*",
|
||||
"lottie-web": "*"
|
||||
},
|
||||
"version": "0.7.0-canary.39"
|
||||
"version": "0.7.0-canary.42"
|
||||
}
|
||||
|
||||
@@ -38,5 +38,5 @@
|
||||
"test": "cross-env TS_NODE_TRANSPILE_ONLY=1 TS_NODE_PROJECT=./tsconfig.json node --test --loader ts-node/esm --experimental-specifier-resolution=node ./__tests__/**/*.mts",
|
||||
"version": "napi version"
|
||||
},
|
||||
"version": "0.7.0-canary.39"
|
||||
"version": "0.7.0-canary.42"
|
||||
}
|
||||
|
||||
@@ -21,11 +21,11 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@blocksuite/blocks": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/lit": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230708145134-cac23f63-nightly",
|
||||
"@blocksuite/blocks": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/global": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/lit": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"@blocksuite/store": "0.0.0-20230711103520-ce18dd84-nightly",
|
||||
"jotai": "^2.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -43,5 +43,5 @@
|
||||
"react": "*",
|
||||
"react-dom": "*"
|
||||
},
|
||||
"version": "0.7.0-canary.39"
|
||||
"version": "0.7.0-canary.42"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@affine/storage",
|
||||
"version": "0.7.0-canary.39",
|
||||
"version": "0.7.0-canary.42",
|
||||
"engines": {
|
||||
"node": ">= 10.16.0 < 11 || >= 11.8.0"
|
||||
},
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
"./*.md": "./*.md",
|
||||
"./preloading.json": "./preloading.json"
|
||||
},
|
||||
"version": "0.7.0-canary.39"
|
||||
"version": "0.7.0-canary.42"
|
||||
}
|
||||
|
||||
68
packages/workers/src/index.ts
Normal file
68
packages/workers/src/index.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
const ALLOW_ORIGIN = ['https://affine.pro', 'https://affine.fail'];
|
||||
|
||||
function isString(s: any): boolean {
|
||||
return typeof s === 'string' || s instanceof String;
|
||||
}
|
||||
|
||||
function isOriginAllowed(
|
||||
origin: string,
|
||||
allowedOrigin: string | RegExp | Array<string | RegExp>
|
||||
): boolean {
|
||||
if (Array.isArray(allowedOrigin)) {
|
||||
for (let i = 0; i < allowedOrigin.length; ++i) {
|
||||
if (isOriginAllowed(origin, allowedOrigin[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else if (isString(allowedOrigin)) {
|
||||
return origin === allowedOrigin;
|
||||
} else if (allowedOrigin instanceof RegExp) {
|
||||
return allowedOrigin.test(origin);
|
||||
} else {
|
||||
return !!allowedOrigin;
|
||||
}
|
||||
}
|
||||
|
||||
async function proxyImage(request: Request): Promise<Response> {
|
||||
const url = new URL(request.url);
|
||||
const imageURL = url.searchParams.get('url');
|
||||
|
||||
if (!imageURL) {
|
||||
return new Response('Missing "url" parameter', { status: 400 });
|
||||
}
|
||||
|
||||
const imageRequest = new Request(imageURL, {
|
||||
method: 'GET',
|
||||
headers: request.headers,
|
||||
});
|
||||
|
||||
const response = await fetch(imageRequest);
|
||||
const modifiedResponse = new Response(response.body);
|
||||
|
||||
modifiedResponse.headers.set(
|
||||
'Access-Control-Allow-Origin',
|
||||
request.headers.get('Origin') ?? 'null'
|
||||
);
|
||||
modifiedResponse.headers.set('Vary', 'Origin');
|
||||
modifiedResponse.headers.set('Access-Control-Allow-Methods', 'GET');
|
||||
|
||||
return modifiedResponse;
|
||||
}
|
||||
|
||||
const handler = {
|
||||
async fetch(request: Request) {
|
||||
if (!isOriginAllowed(request.headers.get('Origin') ?? '', ALLOW_ORIGIN)) {
|
||||
return new Response('unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
const url = new URL(request.url);
|
||||
if (url.pathname.startsWith('/proxy/image')) {
|
||||
return await proxyImage(request);
|
||||
}
|
||||
|
||||
return new Response('not found', { status: 404 });
|
||||
},
|
||||
};
|
||||
|
||||
export default handler;
|
||||
3
packages/workers/wrangler.toml
Normal file
3
packages/workers/wrangler.toml
Normal file
@@ -0,0 +1,3 @@
|
||||
name = "workers"
|
||||
main = "./src/index.ts"
|
||||
compatibility_date = "2023-07-11"
|
||||
@@ -36,5 +36,5 @@
|
||||
"next": "=13.4.2",
|
||||
"ws": "^8.13.0"
|
||||
},
|
||||
"version": "0.7.0-canary.39"
|
||||
"version": "0.7.0-canary.42"
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user