Compare commits

..

21 Commits

Author SHA1 Message Date
Alex Yang
4109490789 v0.7.0-canary.42 2023-07-12 23:01:11 +08:00
Peng Xiao
e813436af7 fix: iconUrl for windows build (#3194) 2023-07-12 14:35:45 +00:00
Alex Yang
5b87d90ffe fix: first page id conflict (#3192) 2023-07-12 10:43:52 +00:00
Alex Yang
ccbae6f496 fix: unexpected jump 404 page (#3190) 2023-07-12 10:18:02 +00:00
JimmFly
1ac1c33bb1 style: update delete button style (#3180) 2023-07-12 09:23:39 +00:00
Peng Xiao
bd42380f8a fix: add default fonts (#3185) 2023-07-12 08:43:25 +00:00
xiaodong zuo
30dee18835 fix: enhancing the security of image proxy (#3176) 2023-07-12 08:35:46 +00:00
Alex Yang
b509302711 v0.7.0-canary.41 2023-07-12 14:49:08 +08:00
Alex Yang
e51c98c1dd chore: bump version (#3179) 2023-07-12 06:21:11 +00:00
Alex Yang
bbb1387469 feat: display app version in setting panel (#3170) 2023-07-12 02:39:00 +00:00
xiaodong zuo
4f88774999 fix: the image lost after exporting (#3150)
Co-authored-by: Alex Yang <himself65@outlook.com>
2023-07-12 02:21:23 +00:00
Alex Yang
3968deb6d4 feat: add suspense to workspace settings (#3167)
Co-authored-by: Qi <474021214@qq.com>
2023-07-11 15:50:30 +00:00
Alex Yang
37c8465af8 fix: jump to index page after deletion (#3169) 2023-07-11 15:44:00 +00:00
Peng Xiao
d88a21d24a fix: settings style update (#3161) 2023-07-11 12:55:28 +00:00
3720
6ad2d106bc fix: some typo and i18n (#3155) 2023-07-11 11:04:45 +00:00
Alex Yang
8c1fcee135 refactor: remove unused code (#3149) 2023-07-11 08:53:01 +00:00
Peng Xiao
0514da9759 fix: updater not working (#3144) 2023-07-11 07:06:04 +00:00
JimmFly
b2fed03f30 style: modify the style of community item (#3143) 2023-07-11 06:44:06 +00:00
Alex Yang
f5e45573af v0.7.0-canary.40 2023-07-11 12:59:12 +08:00
Alex Yang
ddb2931f38 fix: remove workspace not working (#3140) 2023-07-11 04:37:47 +00:00
Alex Yang
acf17ebace chore: bump version (#3138) 2023-07-11 04:28:01 +00:00
110 changed files with 1280 additions and 502 deletions

22
.github/workflows/workers.yml vendored Normal file
View 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'

View File

@@ -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",

View File

@@ -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'
);
});

View File

@@ -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',
},
},

View File

@@ -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",

View File

@@ -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);
},
},
],

View File

@@ -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);
});
};

View File

@@ -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 {

View File

@@ -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": {

View File

@@ -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"
}

View File

@@ -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,

View File

@@ -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",

View File

@@ -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,

View 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.

View 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.

View 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.

View 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.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -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 => {

View File

@@ -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',

View File

@@ -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' });

View File

@@ -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> = ({

View File

@@ -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',
},
},
});

View File

@@ -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']()}

View File

@@ -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',

View File

@@ -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.']()}

View File

@@ -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 ? (

View File

@@ -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>
);
})}
</>
);
};

View File

@@ -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%',

View File

@@ -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}

View File

@@ -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',

View File

@@ -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();

View File

@@ -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 }}>

View File

@@ -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,
]

View File

@@ -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',

View File

@@ -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 && (

View File

@@ -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} />

View File

@@ -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) {

View File

@@ -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(() => {

View File

@@ -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",

View File

@@ -19,5 +19,5 @@
"peerDependencies": {
"ts-node": "*"
},
"version": "0.7.0-canary.39"
"version": "0.7.0-canary.42"
}

View File

@@ -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"
}

View File

@@ -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',
},
});

View File

@@ -478,7 +478,7 @@ const ImagePreviewModalImpl = (
noBorder={true}
className={buttonStyle}
onClick={() => blockId && deleteHandler(blockId)}
hoverColor={'-moz-initial'}
hoverColor="var(--affine-error-color)"
/>
</Tooltip>
</div>

View File

@@ -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':

View File

@@ -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>

View File

@@ -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' });

View File

@@ -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;
}

View File

@@ -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)',
});

View File

@@ -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>

View File

@@ -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>

View File

@@ -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)',
},
});

View File

@@ -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 => {

View File

@@ -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}

View File

@@ -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';

View File

@@ -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'
>

View File

@@ -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;

View File

@@ -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>
);
})}
</>
);
};

View File

@@ -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} />;
})}
</>
);
};

View File

@@ -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 (

View File

@@ -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',

View File

@@ -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>
);
};

View File

@@ -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);
}

View File

@@ -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,
};

View File

@@ -8,5 +8,5 @@
"devDependencies": {
"@types/debug": "^4.1.8"
},
"version": "0.7.0-canary.39"
"version": "0.7.0-canary.42"
}

View File

@@ -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"
}

View File

@@ -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 = {

View File

@@ -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,

View File

@@ -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",

View File

@@ -8,5 +8,5 @@
"@affine/env": "workspace:*",
"@toeverything/y-indexeddb": "workspace:*"
},
"version": "0.7.0-canary.39"
"version": "0.7.0-canary.42"
}

View File

@@ -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>([]);

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -46,5 +46,5 @@
"optional": true
}
},
"version": "0.7.0-canary.39"
"version": "0.7.0-canary.42"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
},

View File

@@ -6,5 +6,5 @@
"./*.md": "./*.md",
"./preloading.json": "./preloading.json"
},
"version": "0.7.0-canary.39"
"version": "0.7.0-canary.42"
}

View 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;

View File

@@ -0,0 +1,3 @@
name = "workers"
main = "./src/index.ts"
compatibility_date = "2023-07-11"

View File

@@ -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