diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c2803f110b..3fe14d8106 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,7 +30,7 @@ jobs: - name: Install Node.js, NPM and Yarn uses: actions/setup-node@v1 with: - node-version: 16.19.0 + node-version: 18.15.0 - name: Install Webpack run: npm install --save-dev webpack-cli --legacy-peer-deps diff --git a/dist/workers/graph.js b/dist/workers/graph.js index 4a3983bb4e..4b2aca0bee 100644 --- a/dist/workers/graph.js +++ b/dist/workers/graph.js @@ -481,7 +481,7 @@ drawNode = (d) => { x = d.x - radius; y = d.y - radius; - if (isIconCircle(d)) { + if (isLayoutHuman(d)) { util.circle(d.x, d.y, radius); } else { util.roundedRect(d.x - radius, d.y - radius, diameter, diameter, getBorderRadius()); @@ -753,10 +753,6 @@ const isLayoutBookmark = (d) => { return d.layout == ObjectLayout.Bookmark; }; -const isIconCircle = (d) => { - return isLayoutHuman(d); -}; - const getNodeById = (id) => { return nodes.find(d => d.id == id); }; diff --git a/electron/hook/aftersign.js b/electron/hook/aftersign.js index ce42cc6575..70f849d8ca 100644 --- a/electron/hook/aftersign.js +++ b/electron/hook/aftersign.js @@ -1,4 +1,4 @@ -const { notarize } = require('electron-notarize'); +const { notarize } = require('@electron/notarize'); require('dotenv').config(); @@ -13,11 +13,13 @@ exports.default = async function notarizing (context) { const appName = context.packager.appInfo.productFilename; return await notarize({ - appBundleId: 'com.anytype.anytype', + tool: 'notarytool', appPath: `${appOutDir}/${appName}.app`, appleId: process.env.APPLEID, appleIdPassword: process.env.APPLEIDPASS, - ascProvider: process.env.APPLETEAM, + teamId: process.env.APPLETEAM, + //appBundleId: 'com.anytype.anytype', + //ascProvider: process.env.APPLETEAM, }); }; diff --git a/electron/js/api.js b/electron/js/api.js index 97e97ced79..544ce7666c 100644 --- a/electron/js/api.js +++ b/electron/js/api.js @@ -70,6 +70,26 @@ class Api { this.setConfig(win, { zoom }); }; + setHideTray (win, show) { + ConfigManager.set({ hideTray: !show }, () => { + Util.send(win, 'config', ConfigManager.config); + + MenuManager.initMenu(); + MenuManager.initTray(); + }); + }; + + setMenuBarVisibility (win, show) { + const hide = !show; + + ConfigManager.set({ hideMenuBar: hide }, () => { + Util.send(win, 'config', ConfigManager.config); + + win.setMenuBarVisibility(show); + win.setAutoHideMenuBar(hide); + }); + }; + spellcheckAdd (win, s) { win.webContents.session.addWordToSpellCheckerDictionary(s); }; diff --git a/electron/js/menu.js b/electron/js/menu.js index 4fb3748dc9..65629d8960 100644 --- a/electron/js/menu.js +++ b/electron/js/menu.js @@ -322,6 +322,13 @@ class MenuManager { } }, + (is.windows || is.linux) ? { + label: Util.translate('electronMenuShowMenu'), type: 'checkbox', checked: !config.hideMenuBar, click: () => { + Api.setConfig(this.win, { hideMenuBar: !config.hideMenuBar }); + this.initTray(); + } + } : null, + Separator, { @@ -359,7 +366,7 @@ class MenuManager { Util.send(this.win, 'commandGlobal', 'create'); } }, - ]; + ].filter(it => it); }; openSettings (page, param) { diff --git a/electron/js/window.js b/electron/js/window.js index e47704679f..1716c748a3 100644 --- a/electron/js/window.js +++ b/electron/js/window.js @@ -24,7 +24,7 @@ class WindowManager { create (options, param) { const Api = require('./api.js'); const { route, isChild } = options; - const { languages, zoom } = ConfigManager.config; + const { languages, zoom, hideMenuBar } = ConfigManager.config; param = Object.assign({ backgroundColor: Util.getBgColor('dark'), @@ -67,6 +67,11 @@ class WindowManager { Api.setSpellingLang(win, languages); Api.setZoom(win, zoom); + if (hideMenuBar) { + win.setMenuBarVisibility(false); + win.setAutoHideMenuBar(true); + }; + return win; }; diff --git a/middleware.version b/middleware.version index f9fa7c8fce..35711f7367 100644 --- a/middleware.version +++ b/middleware.version @@ -1 +1 @@ -0.29.3 \ No newline at end of file +0.29.8 \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 9f3ff1f005..2b81cd52db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "anytype", - "version": "0.35.9-alpha", + "version": "0.35.17-beta", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "anytype", - "version": "0.35.9-alpha", + "version": "0.35.17-beta", "hasInstallScript": true, "license": "SEE LICENSE IN LICENSE.md", "dependencies": { @@ -62,6 +62,7 @@ "sha1": "^1.1.1" }, "devDependencies": { + "@electron/notarize": "^2.1.0", "@types/history": "^4.7.8", "@types/jquery": "^3.5.14", "@types/katex": "^0.14.0", @@ -78,7 +79,6 @@ "css-loader": "^3.6.0", "electron": "^25.0.0", "electron-builder": "^24.6.3", - "electron-notarize": "^1.2.2", "eslint": "^8.29.0", "eslint-plugin-react": "^7.31.11", "husky": "^8.0.3", @@ -231,13 +231,14 @@ } }, "node_modules/@electron/notarize": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-1.2.4.tgz", - "integrity": "sha512-W5GQhJEosFNafewnS28d3bpQ37/s91CDWqxVchHfmv2dQSTWpOzNlUVQwYzC1ay5bChRV/A9BTL68yj0Pa+TSg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.1.0.tgz", + "integrity": "sha512-Q02xem1D0sg4v437xHgmBLxI2iz/fc0D4K7fiVWHa/AnW8o7D751xyKNXgziA6HrTOme9ul1JfWN5ark8WH1xA==", "dev": true, "dependencies": { "debug": "^4.1.1", - "fs-extra": "^9.0.1" + "fs-extra": "^9.0.1", + "promise-retry": "^2.0.1" }, "engines": { "node": ">= 10.0.0" @@ -1893,6 +1894,34 @@ "node": ">=14.0.0" } }, + "node_modules/app-builder-lib/node_modules/@electron/notarize": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-1.2.4.tgz", + "integrity": "sha512-W5GQhJEosFNafewnS28d3bpQ37/s91CDWqxVchHfmv2dQSTWpOzNlUVQwYzC1ay5bChRV/A9BTL68yj0Pa+TSg==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.1" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/app-builder-lib/node_modules/@electron/notarize/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/app-builder-lib/node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -4199,56 +4228,6 @@ "version": "3.0.9", "license": "MIT" }, - "node_modules/electron-notarize": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/electron-notarize/-/electron-notarize-1.2.2.tgz", - "integrity": "sha512-ZStVWYcWI7g87/PgjPJSIIhwQXOaw4/XeXU+pWqMMktSLHaGMLHdyPPN7Cmao7+Cr7fYufA16npdtMndYciHNw==", - "deprecated": "Please use @electron/notarize moving forward. There is no API change, just a package name change", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "fs-extra": "^9.0.1" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/electron-notarize/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/electron-notarize/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/electron-notarize/node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, "node_modules/electron-publish": { "version": "24.5.0", "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-24.5.0.tgz", diff --git a/package.json b/package.json index 2ea36a67bd..b408509073 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "anytype", - "version": "0.35.9-alpha", + "version": "0.35.17-beta", "description": "Anytype", "main": "electron.js", "scripts": { @@ -44,6 +44,7 @@ }, "homepage": "https://anytype.io", "devDependencies": { + "@electron/notarize": "^2.1.0", "@types/history": "^4.7.8", "@types/jquery": "^3.5.14", "@types/katex": "^0.14.0", @@ -60,7 +61,6 @@ "css-loader": "^3.6.0", "electron": "^25.0.0", "electron-builder": "^24.6.3", - "electron-notarize": "^1.2.2", "eslint": "^8.29.0", "eslint-plugin-react": "^7.31.11", "husky": "^8.0.3", diff --git a/src/img/icon/menu/space/settings.svg b/src/img/icon/menu/space/settings.svg index f4fe3725ec..a0a35259ee 100644 --- a/src/img/icon/menu/space/settings.svg +++ b/src/img/icon/menu/space/settings.svg @@ -1,15 +1,15 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/src/img/icon/plus/space.svg b/src/img/icon/plus/space.svg index 9670fb62a3..946944a976 100644 --- a/src/img/icon/plus/space.svg +++ b/src/img/icon/plus/space.svg @@ -1,10 +1,10 @@ - + - + diff --git a/src/img/theme/dark/icon/plus/space.svg b/src/img/theme/dark/icon/plus/space.svg index 64a2fd0137..b135a633f5 100644 --- a/src/img/theme/dark/icon/plus/space.svg +++ b/src/img/theme/dark/icon/plus/space.svg @@ -1,10 +1,10 @@ - + - + diff --git a/src/json/constant.json b/src/json/constant.json index c42102494a..d4df5a3f26 100644 --- a/src/json/constant.json +++ b/src/json/constant.json @@ -26,7 +26,8 @@ "interfaceLang": "en-US", "cover": "sky", "codeLang": "javascript", - "pinTime": 600 + "pinTime": 600, + "typeKey": "ot-note" }, "delay": { diff --git a/src/json/text.json b/src/json/text.json index 37c3d3fc8f..8619e92a96 100644 --- a/src/json/text.json +++ b/src/json/text.json @@ -110,6 +110,7 @@ "commonSetDefault": "Set as default", "commonTemplates": "Templates", "commonSkip": "Skip", + "commonCreateNew": "Create new", "commonLCCollection": "Collection", "commonLCSet": "Set", @@ -122,7 +123,7 @@ "pluralTemplate": "template|templates", "pluralRelation": "Relation|Relations", "pluralBlock": "Block|Blocks", - "pluralType": "Type|Types", + "pluralType": "Object Type|Object Types", "pluralUCRelation": "Relation|Relations", "electronAboutVersion": "Version:", @@ -139,6 +140,7 @@ "electronMenuSpaceSettings": "Space", "electronMenuAccountSettings": "Account", "electronMenuShowTray": "Show Anytype in Menu Bar", + "electronMenuShowMenu": "Show system menu", "electronMenuQuit": "Quit", "electronMenuFile": "File", "electronMenuDirectory": "Show Work Directory", @@ -374,6 +376,7 @@ "pageMainArchiveEmpty": "Your Bin is empty", "pageMainBlockEmpty": "Block not found", + "pageMainRelationObjectsCreated": "%s created", "editorControlIcon": "Icon", "editorControlCover": "Cover", @@ -579,6 +582,7 @@ "popupSettingsPersonalTitle": "Preferences", "popupSettingsPersonalDefaultObjectType": "Default Object Type", + "popupSettingsPersonalDefaultObjectTypeDescription": "Set the default type for newly created objects", "popupSettingsPersonalDefaultObjectTypeSelect": "Select", "popupSettingsPersonalSpellcheckLanguage": "Spellcheck Languages", "popupSettingsPersonalInterfaceLanguage": "Interface Language", @@ -810,7 +814,7 @@ "popupShortcutMain": "Main", "popupShortcutNavigation": "Navigation", "popupShortcutMarkdown": "Markdown", - "popupShortcutCommands": "Commands", + "popupShortcutCommand": "Commands", "popupShortcutBasics": "Basics", "popupShortcutMainBasics1": "Create new Object", @@ -871,6 +875,7 @@ "popupShortcutNavigationBasics6": "Return to the home screen", "popupShortcutNavigationBasics7": "Show previous object from History", "popupShortcutNavigationBasics8": "Show next Object from History", + "popupShortcutNavigationBasics9": "Switch spaces", "popupShortcutNavigationMenu": "Menu, search and navigation pane", "popupShortcutNavigationMenu1": "Go the next option", "popupShortcutNavigationMenu2": "Go to the previous option", @@ -1505,6 +1510,18 @@ "onboardingInlineCollection2Title": "Views", "onboardingInlineCollection2Description": "Adjust rules and views to suit the current context.", + "onboardingDefaultTypeTitle": "Change Types Easily", + "onboardingDefaultTypeDescription": "You can change type and template of a new object in this menu.", + + "onboardingCalendarTitle": "New Calendar View", + "onboardingCalendarDescription": "Display objects on a calendar based on selected date attributes.", + + "onboardingTemplateSelectTitle": "New Template Selector", + "onboardingTemplateSelectDescription": "Easily switch your templates when creating objects.", + + "onboardingSpaceSelectTitle": "Meet Multiple Spaces", + "onboardingSpaceSelectDescription": "Click your profile icon to access the space selector. Switch between spaces or create new ones here.", + "libDataviewRelations": "Relations", "libDataviewGroups": "Groups", "libDataviewView": "View", diff --git a/src/scss/block/dataview/view/calendar.scss b/src/scss/block/dataview/view/calendar.scss index 734ff4164d..16e39b5da6 100644 --- a/src/scss/block/dataview/view/calendar.scss +++ b/src/scss/block/dataview/view/calendar.scss @@ -22,23 +22,37 @@ } .day { - text-align: left; vertical-align: top; border-color: $colorShapeSecondary; border-style: solid; - border-right-width: 1px; border-top-width: 1px; padding: 6px 8px; position: relative; height: 136px; + text-align: left; vertical-align: top; border-color: $colorShapeSecondary; border-style: solid; display: flex; flex-direction: column; + border-right-width: 1px; border-top-width: 1px; padding: 6px 0px; position: relative; height: 136px; } .day.first { border-top-width: 0px; } - .day.active .number { color: $colorSystemAccent100; } - .day.other .number { color: $colorTextSecondary; } + + .day.active { + .number { + display: inline-block; color: $colorTextInversion; background-color: $colorSystemAccent100; border-radius: 12px; padding: 0px 7px; align-self: flex-end; + padding: 0px 8x; + } + } + + .day.other { + .number { color: $colorTextTertiary; } + } .day { .number { @include text-paragraph; text-align: right; } .item { display: flex; flex-direction: row; align-items: center; gap: 0px 4px; @include text-small; @include text-overflow-nw; - margin: 0px 0px 2px 0px; + margin: 0px 0px 2px 0px; position: relative; padding: 0px 8px; } .item { .iconObject { flex-shrink: 0; } .name { @include text-overflow-nw; } } + .item::before { + content: ""; position: absolute; left: 0px; top: 0px; width: 100%; height: 100%; background: rgba(79,79,79,0); z-index: 1; + pointer-events: none; + } + .item:hover::before { background: $colorShapeHighlightMedium; } .item.more { display: block; color: $colorTextSecondary; } } diff --git a/src/scss/common.scss b/src/scss/common.scss index f80e750344..b26b345e1c 100644 --- a/src/scss/common.scss +++ b/src/scss/common.scss @@ -48,7 +48,7 @@ input, textarea, select { font-family: 'Inter'; } } #globalFade { - position: fixed; z-index: 10000; background: $colorBgPrimary; left: 0px; top: 0px; width: 100%; height: 100%; display: none; opacity: 0; + position: fixed; z-index: 999; background: $colorBgPrimary; left: 0px; top: 0px; width: 100%; height: 100%; display: none; opacity: 0; transition: opacity 0.25s ease-in-out; } #globalFade.show { opacity: 1; } diff --git a/src/scss/component/navigation.scss b/src/scss/component/navigation.scss index 099cb9d611..55f3e379f2 100644 --- a/src/scss/component/navigation.scss +++ b/src/scss/component/navigation.scss @@ -14,7 +14,7 @@ width: 32px; height: 32px; border-radius: 4px; display: flex; align-items: center; justify-content: center; transition: $transitionAllCommon; } - .iconWrap:not(.disabled):hover { background-color: $colorShapeHighlightMedium; } + .iconWrap:not(.disabled):hover { background-color: rgba(37, 37, 37, 0.15); } .icon { width: 20px; height: 20px; } .icon.back, .icon.forward { background-image: url('~img/icon/navigation/back.svg'); } diff --git a/src/scss/component/progressBar.scss b/src/scss/component/progressBar.scss index a8d6e74ecd..c5e42d8a2c 100644 --- a/src/scss/component/progressBar.scss +++ b/src/scss/component/progressBar.scss @@ -1,9 +1,11 @@ @import "~scss/_vars"; .progressBar { - .bar { position: relative; overflow: hidden; height: 6px; border-radius: 8px; background-color: $colorShapeTertiary; } + .bar { position: relative; overflow: hidden; height: 12px; border-radius: 4px; display: flex; flex-direction: row; gap: 0px 2px; } .bar { - .fill { height: 6px; background-color: $colorSystemAccent100; } + .fill { height: 100%; background-color: $colorSystemAccent25; min-width: 6px; } + .fill.isActive { background-color: $colorSystemAccent100; } + .fill.empty { background-color: $colorShapeTertiary; } } .labels { display: flex; justify-content: space-between; } .labels { diff --git a/src/scss/menu/common.scss b/src/scss/menu/common.scss index 9dcc10bcb8..d251cf5dd8 100644 --- a/src/scss/menu/common.scss +++ b/src/scss/menu/common.scss @@ -87,7 +87,7 @@ .item.isReadonly { cursor: default; } .item::before { - content: ""; position: absolute; left: 0px; top: 0px; width: 100%; height: 100%; background: rgba(80,73,28,0); z-index: 1; + content: ""; position: absolute; left: 0px; top: 0px; width: 100%; height: 100%; background: rgba(79,79,79,0); z-index: 1; pointer-events: none; } .item.hover::before { background: $colorShapeHighlightMedium; } diff --git a/src/scss/menu/dataview/template.scss b/src/scss/menu/dataview/template.scss index e4a96a625d..d3cb428d26 100644 --- a/src/scss/menu/dataview/template.scss +++ b/src/scss/menu/dataview/template.scss @@ -16,16 +16,12 @@ .item::before { display: none; } .item { - .icon.more { - position: static; - width: 20px; - height: 20px; - margin: 0px; - } + .icon.more { position: static; width: 20px; height: 20px; margin: 0px; opacity: 1; } .icon.more:hover { background-color: unset; } .previewObject { .add { width: 20px; height: 20px; @include pos-abs-mid; margin: -10px 0px 0px -10px; } + .moreWrapper.hover { opacity: 1; } } .previewObject.isDefault { .border { border-color: $colorSystemAccent100; border-width: 2px; } diff --git a/src/scss/menu/space.scss b/src/scss/menu/space.scss index 41cc79bf60..9302073ec7 100644 --- a/src/scss/menu/space.scss +++ b/src/scss/menu/space.scss @@ -2,16 +2,16 @@ .menus { .menu.menuSpace { - border-radius: 16px; background: rgba(37, 37, 37, 0.15) !important; backdrop-filter: blur(12.5px); padding: 24px 24px 16px 24px; - box-shadow: 0px 0px; min-width: 368px; + border-radius: 16px; background: rgba(37, 37, 37, 0.4) !important; backdrop-filter: blur(12.5px); padding: 20px 16px 16px 16px; + box-shadow: 0px 0px; min-width: 480px; color: $colorTextInversion; } .menu.menuSpace { .wrap { width: 100%; } .head { - display: flex; flex-direction: row; align-items: center; justify-content: space-between; margin: 0px 0px 24px 0px; - @include text-paragraph; font-weight: 600; gap: 0px 16px; + display: flex; flex-direction: row; align-items: center; justify-content: space-between; margin: 0px 0px 12px 0px; + @include text-paragraph; font-weight: 600; gap: 0px 16px; padding: 0px 8px; } .head { .side.left { display: flex; flex-direction: row; align-items: center; gap: 0px 10px; width: calc(100% - 36px); } @@ -23,32 +23,25 @@ .icon.settings { background-image: url('~img/icon/menu/space/settings.svg'); } } - .items { display: flex; flex-direction: row; gap: 16px; flex-wrap: wrap; } + .items { display: flex; flex-direction: row; flex-wrap: wrap; } .items { - .item { width: 96px; } - .item.space { display: flex; flex-direction: column; align-items: center; gap: 8px 0px; } - .item.space { - .iconWrap { - width: 96px; height: 96px; border-radius: 4px; overflow: hidden; transition: all 0.2s $easeInQuint; - transform-origin: 50% 100%; - } - .iconObject { border-radius: 0px; } - .name { @include text-overflow-nw; width: 100%; text-align: center; } + .item { + width: 112px; border-radius: 8px; padding: 8px; transition: all 0.2s $easeInQuint; + display: flex; flex-direction: column; align-items: center; gap: 8px 0px; + } + .item { + .iconWrap { width: 96px; height: 96px; border-radius: 4px; overflow: hidden; } + .name { @include text-overflow-nw; @include text-small; width: 100%; text-align: center; font-weight: 500; } } .item.add { - border-radius: 4px; height: 96px; background-color: rgba(255, 255, 255, 0.3); - background-image: url('~img/icon/plus/space.svg'); background-size: 20px; background-position: center; - background-repeat: no-repeat; margin: 0px 0px 26px 0px; transition: all 0.2s $easeInQuint; transform-origin: 50% 100%; + .iconWrap { + background-image: url('~img/icon/plus/space.svg'); background-size: 20px; + background-position: center; background-repeat: no-repeat; box-shadow: 0px 0px 0px 1px $colorBgPrimary inset; + } } - .item.space.hover { - .iconWrap { transform: scale(1.06, 1.06); } - } - .item.space.isActive { - .iconWrap { box-shadow: 0px 0px 0px 4px #fff, 0px 0px 6px rgba(0,0,0,0.1); } - } - .item.add.hover { transform: scale(1.06, 1.06); } + .item.hover { background: rgba(37, 37, 37, 0.15); } } } } \ No newline at end of file diff --git a/src/scss/page/main/store.scss b/src/scss/page/main/store.scss index aeb2b5b00b..02a66979f8 100644 --- a/src/scss/page/main/store.scss +++ b/src/scss/page/main/store.scss @@ -29,6 +29,10 @@ @media (max-width: 960px) { .title { @include text-header1; } } + + @media (max-width: 660px) { + .title { @include text-header2; } + } } .tabs { white-space: nowrap; text-align: left; display: flex; flex-direction: row; gap: 0px 24px; } diff --git a/src/scss/popup/settings.scss b/src/scss/popup/settings.scss index 3f8ba411e3..d548f69b2e 100644 --- a/src/scss/popup/settings.scss +++ b/src/scss/popup/settings.scss @@ -216,7 +216,9 @@ .input { padding: 0; } .name { margin-bottom: 8px; } - .name .input { @include text-header1; } + .name { + .input { @include text-header1; height: 32px; } + } .spaceType { display: inline-block; width: unset; padding: 3px 7px 3px 26px; border-radius: 6px; @@ -242,6 +244,7 @@ > .item { .sides { display: flex; justify-content: space-between; gap: 0px 16px; } + .sides:not(.alignTop) { align-items: center; } .sides { .side { width: unset; background: unset; padding: unset; } .side.left { flex-grow: 1; } @@ -273,14 +276,6 @@ .label { display: inline; } .label.extend { color: $colorRed; } } - .progressBar { - .fill { background: $colorLime; } - } - } - > .item.red { - .progressBar { - .fill { background: $colorRed; } - } } } } @@ -609,4 +604,4 @@ .popupSettings.isSpaceCreate { .innerWrap { width: 684px; height: 406px; } } -} \ No newline at end of file +} diff --git a/src/scss/theme/dark/block.scss b/src/scss/theme/dark/block.scss index 8c33a5bb18..38f6c46c66 100644 --- a/src/scss/theme/dark/block.scss +++ b/src/scss/theme/dark/block.scss @@ -223,6 +223,10 @@ .item { border-color: $colorShapeSecondary; } } } + + .day.other { + .number { color: $colorTextTertiary; } + } } .content { diff --git a/src/scss/theme/dark/common.scss b/src/scss/theme/dark/common.scss index f79ffa4d95..1e817207d4 100644 --- a/src/scss/theme/dark/common.scss +++ b/src/scss/theme/dark/common.scss @@ -72,11 +72,6 @@ html.themeDark { .controls, .emptySearch { border-color: $colorShapePrimary; } } - .progressBar { - .bar { background: $colorBgSecondary; } - .fill { background: $colorSystemAccent100; } - } - /* Components */ .loaderWrapper { @@ -263,6 +258,12 @@ html.themeDark { } } + .progressBar { + .bar { + .fill.empty { background-color: $colorShapeTertiary; } + } + } + .tooltip { background: $colorShapeSecondary; color: $colorTextPrimary; } .tooltip.big { background: $colorBgSecondary; border: 1px solid rgba(229, 229, 229, 0.1); } @@ -362,7 +363,7 @@ html.themeDark { .navigationPanel { background: rgba(141, 141, 141, 0.2); } .navigationPanel { - .iconWrap:hover { background-color: $colorShapeHighlightMedium; } + .iconWrap:hover { background-color: rgba(255, 255, 255, 0.1); } } @import "./menu.scss"; diff --git a/src/scss/theme/dark/menu.scss b/src/scss/theme/dark/menu.scss index 24c078c3c5..f03c6b677f 100644 --- a/src/scss/theme/dark/menu.scss +++ b/src/scss/theme/dark/menu.scss @@ -52,6 +52,7 @@ .separator .inner { background: $colorShapeSecondary; } .item { background: none; } + .item::before { background: rgba(238, 238, 238, 0); } .item.hover::before { background: $colorShapeHighlightMedium; } .item { .icon.delete:hover, .icon.more:hover { background-color: $colorShapeHighlightMedium; } @@ -324,6 +325,9 @@ .menu.menuOnboarding { width: 288px; background: #373632; color: #fff; box-shadow: 0px 4px 16px rgb(0 0 0 / 20%); } .menu.menuOnboarding { a { color: $colorBgPrimary; } + + video { border-color: $colorShapeSecondary; } + .highlight { background: $colorShapeSecondary; color: $colorOrange; } .bottom { @@ -388,6 +392,8 @@ .emptySearch { border-color: $colorShapePrimary; } .items { .item { + .icon.more:hover { background-color: unset; } + .previewObject { background-color: $colorBgPrimary; } .previewObject::before { background-color: $colorShapeHighlightMedium; } } @@ -403,13 +409,18 @@ /* MenuSpace */ + .menu.menuSpace { color: $colorTextPrimary; } .menu.menuSpace { .head { .icon.settings { background-image: url('#{$themePath}/icon/menu/space/settings.svg'); } } .items { - .item.add { background-color: rgba(255, 255, 255, 0.1); background-image: url('#{$themePath}/icon/plus/space.svg'); } + .item.add { + .iconWrap { box-shadow: 0px 0px 0px 1px $colorControlActive inset; background-image: url('#{$themePath}/icon/plus/space.svg'); } + } + + .item.hover { background-color: rgba(255, 255, 255, 0.1); } } } } diff --git a/src/scss/theme/dark/popup.scss b/src/scss/theme/dark/popup.scss index 8e785b02db..f30f1edd7e 100644 --- a/src/scss/theme/dark/popup.scss +++ b/src/scss/theme/dark/popup.scss @@ -91,9 +91,6 @@ .item { .icon.arrow.down { background-image: url('#{$themePath}/arrow/button/black.svg'); } } - .item.red { - .progressBar .fill { background: $colorRed; } - } } } } diff --git a/src/scss/widget/list.scss b/src/scss/widget/list.scss index dea548174d..344a67c688 100644 --- a/src/scss/widget/list.scss +++ b/src/scss/widget/list.scss @@ -79,7 +79,6 @@ .item.canDrag { .inner { padding-left: 0px; } - .dropTarget { width: calc(100% - 20px); } } .item.isDragging { margin-top: -46px; margin-left: -12px; } diff --git a/src/ts/app.tsx b/src/ts/app.tsx index 653e9d98c6..db30e9dfbc 100644 --- a/src/ts/app.tsx +++ b/src/ts/app.tsx @@ -238,6 +238,7 @@ window.Lib = { UtilFile, UtilObject, UtilMenu, + UtilRouter, analytics, dispatcher, keyboard, diff --git a/src/ts/component/block/dataview.tsx b/src/ts/component/block/dataview.tsx index b11c3280f5..7b5e519f37 100644 --- a/src/ts/component/block/dataview.tsx +++ b/src/ts/component/block/dataview.tsx @@ -4,7 +4,7 @@ import raf from 'raf'; import arrayMove from 'array-move'; import { observer } from 'mobx-react'; import { set } from 'mobx'; -import { I, C, UtilCommon, UtilData, UtilObject, analytics, Dataview, keyboard, Onboarding, Relation, Renderer, focus, translate, Action } from 'Lib'; +import { I, C, UtilCommon, UtilData, UtilObject, analytics, Dataview, keyboard, Onboarding, Relation, Renderer, focus, translate, Action, UtilDate } from 'Lib'; import { blockStore, menuStore, dbStore, detailStore, commonStore } from 'Store'; import Constant from 'json/constant.json'; @@ -237,21 +237,19 @@ const BlockDataview = observer(class BlockDataview extends React.Component { - console.log('ITEM', JSON.stringify(item)); - if (item.id == Constant.templateId.new) { this.onTemplateAdd(item.targetObjectType); } else { @@ -838,8 +840,6 @@ const BlockDataview = observer(class BlockDataview extends React.Component { if (!message.error.code) { diff --git a/src/ts/component/block/dataview/controls.tsx b/src/ts/component/block/dataview/controls.tsx index 7b53e1da3c..2af11aeb68 100644 --- a/src/ts/component/block/dataview/controls.tsx +++ b/src/ts/component/block/dataview/controls.tsx @@ -48,6 +48,7 @@ const Controls = observer(class Controls extends React.Component { const hasSources = (isCollection || getSources().length); const isAllowedObject = this.props.isAllowedObject(); const isAllowedTemplate = UtilObject.isAllowedTemplate(getTypeId()) || (target && UtilObject.isSetLayout(target.layout) && hasSources); + const cmd = keyboard.cmdSymbol(); if (isAllowedTemplate) { buttonWrapCn.push('withSelect'); @@ -148,6 +149,8 @@ const Controls = observer(class Controls extends React.Component { ref={ref => this.refFilter = ref} placeholder={translate('blockDataviewSearch')} icon="search" + tooltip={translate('commonSearch')} + tooltipCaption={`${cmd} + F`} onChange={onFilterChange} onIconClick={this.onFilterShow} /> @@ -414,12 +417,15 @@ const Controls = observer(class Controls extends React.Component { return; }; - const { isPopup } = this.props; + const { isPopup, isInline } = this.props; const container = UtilCommon.getPageContainer(isPopup); const win = $(window); this.refFilter.setActive(true); - this.refFilter.focus(); + + if (!isInline) { + this.refFilter.focus(); + }; container.off('mousedown.filter').on('mousedown.filter', (e: any) => { const value = this.refFilter.getValue(); diff --git a/src/ts/component/block/dataview/view/gallery.tsx b/src/ts/component/block/dataview/view/gallery.tsx index b050e24618..d7f5874622 100644 --- a/src/ts/component/block/dataview/view/gallery.tsx +++ b/src/ts/component/block/dataview/view/gallery.tsx @@ -157,14 +157,6 @@ const ViewGallery = observer(class ViewGallery extends React.Component - ) : ''} - - {isAllowedObject && !isInline ? ( + {isAllowedObject ? (
-
{ onRecordAdd(e, 1); }}> +
onRecordAdd(e, 1)}>
{translate('blockDataviewNew')}
) : null} + + {isInline && (limit + offset < total) ? ( + + ) : ''}
diff --git a/src/ts/component/block/dataview/view/list.tsx b/src/ts/component/block/dataview/view/list.tsx index 84e58de5bd..d2de4330e9 100644 --- a/src/ts/component/block/dataview/view/list.tsx +++ b/src/ts/component/block/dataview/view/list.tsx @@ -103,20 +103,20 @@ const ViewList = observer(class ViewList extends React.Component {content} - {isInline && (limit + offset < total) ? ( - - ) : ''} - - {isAllowedObject && !isInline ? ( + {isAllowedObject ? (
-
{ onRecordAdd(e, 1); }}> +
onRecordAdd(e, 1)}>
{translate('blockDataviewNew')}
) : null} + + {isInline && (limit + offset < total) ? ( + + ) : ''}
diff --git a/src/ts/component/block/relation.tsx b/src/ts/component/block/relation.tsx index 3affe939a7..aaa4cc3132 100644 --- a/src/ts/component/block/relation.tsx +++ b/src/ts/component/block/relation.tsx @@ -137,6 +137,7 @@ const BlockRelation = observer(class BlockRelation extends React.Component void) => { C.ObjectRelationAdd(rootId, [ relation.relationKey ], (message: any) => { if (message.error.code) { diff --git a/src/ts/component/block/text.tsx b/src/ts/component/block/text.tsx index 0c05ad3a51..a05d7f9d44 100644 --- a/src/ts/component/block/text.tsx +++ b/src/ts/component/block/text.tsx @@ -674,10 +674,12 @@ const BlockText = observer(class BlockText extends React.Component { { key: `${cmd}+-`, preventDefault: false }, { key: `${cmd}+z`, preventDefault: true }, { key: `${cmd}+shift+z`, preventDefault: true }, + { key: `${cmd}+/`, preventDefault: false }, { key: `tab`, preventDefault: true }, { key: `shift+tab`, preventDefault: true }, { key: `shift+space`, preventDefault: false }, { key: `ctrl+shift+l`, preventDefault: false }, + { key: `ctrl+shift+/`, preventDefault: false }, ]; if (isInsideTable) { diff --git a/src/ts/component/block/type.tsx b/src/ts/component/block/type.tsx index 6425c309bc..2ecc147014 100644 --- a/src/ts/component/block/type.tsx +++ b/src/ts/component/block/type.tsx @@ -217,7 +217,7 @@ const BlockType = observer(class BlockType extends React.Component { className: '', inputClassName: '', placeholder: translate('commonFilterClick'), + tooltipY: I.MenuDirection.Bottom, }; state = { @@ -53,7 +58,7 @@ class Filter extends React.Component { render () { const { isActive } = this.state; - const { id, value, icon, placeholder, className, inputClassName, onKeyDown, onKeyUp, onClick, onIconClick } = this.props; + const { id, value, icon, tooltip, tooltipCaption, tooltipX, tooltipY, placeholder, className, inputClassName, onKeyDown, onKeyUp, onClick, onIconClick } = this.props; const cn = [ 'filter' ]; if (className) { @@ -64,6 +69,20 @@ class Filter extends React.Component { cn.push('isActive'); }; + let iconObj = null; + if (icon) { + iconObj = ( + + ); + }; + return (
this.node = node} @@ -72,7 +91,7 @@ class Filter extends React.Component { onClick={onClick} >
- {icon ? : ''} + {iconObj}
void) => { C.ObjectRelationAdd(rootId, [ relation.relationKey ], onChange); }, diff --git a/src/ts/component/menu/dataview/calendar/day.tsx b/src/ts/component/menu/dataview/calendar/day.tsx index 775c419f4b..3ca8c6f170 100644 --- a/src/ts/component/menu/dataview/calendar/day.tsx +++ b/src/ts/component/menu/dataview/calendar/day.tsx @@ -108,7 +108,7 @@ const MenuCalendarDay = observer(class MenuCalendarDay extends React.Component dbStore.getTypeById(id)?.uniqueKey).filter(it => it); - filters.push({ operator: I.FilterOperator.And, relationKey: 'type.uniqueKey', condition: I.FilterCondition.In, value: map }); - } else { - filters.push({ operator: I.FilterOperator.And, relationKey: 'layout', condition: I.FilterCondition.NotIn, value: UtilObject.getSystemLayouts() }); + if (map.length) { + filters.push({ operator: I.FilterOperator.And, relationKey: 'type.uniqueKey', condition: I.FilterCondition.In, value: map }); + }; }; if (clear) { @@ -336,8 +338,6 @@ const MenuDataviewObjectList = observer(class MenuDataviewObjectList extends Rea cellRef.clear(); }; - const objectTypes = Relation.getArrayValue(relation.objectTypes); - const cb = (id: string) => { if (!id) { return; @@ -357,31 +357,7 @@ const MenuDataviewObjectList = observer(class MenuDataviewObjectList extends Rea }; if (item.id == 'add') { - const details: any = { name: filter }; - const flags: I.ObjectFlag[] = [ I.ObjectFlag.SelectTemplate ]; - - let type = null; - - if (objectTypes.length) { - const allowedTypes = objectTypes.map(id => dbStore.getTypeById(id)).filter(it => { - return it && !UtilObject.isFileOrSystemLayout(it.recommendedLayout); - }); - const l = allowedTypes.length; - - if (l) { - type = allowedTypes[0]; - - if (l > 1) { - flags.push(I.ObjectFlag.SelectType); - }; - }; - }; - - if (type) { - details.type = type.id; - } else { - flags.push(I.ObjectFlag.SelectType); - }; + const { details, flags } = Relation.getParamForNewObject(filter, relation); UtilObject.create('', '', details, I.BlockPosition.Bottom, '', {}, flags, (message: any) => { cb(message.targetId); diff --git a/src/ts/component/menu/dataview/relation/edit.tsx b/src/ts/component/menu/dataview/relation/edit.tsx index 1413bdfcc4..94588301c4 100644 --- a/src/ts/component/menu/dataview/relation/edit.tsx +++ b/src/ts/component/menu/dataview/relation/edit.tsx @@ -356,7 +356,7 @@ const MenuRelationEdit = observer(class MenuRelationEdit extends React.Component menuIdEdit: 'blockRelationEdit', filter: '', ref: 'dataview', - skipKeys: relations.map(it => it.relationKey), + skipKeys: relations.map(it => it.relationKey).concat(Relation.systemKeysWithoutUser()), addCommand: (rootId: string, blockId: string, relation: any, onChange: (message: any) => void) => { Dataview.relationAdd(rootId, blockId, relation.relationKey, Math.max(0, idx + item.dir), view, (message: any) => { menuStore.closeAll([ this.props.id, 'relationSuggest' ]); diff --git a/src/ts/component/menu/dataview/relation/list.tsx b/src/ts/component/menu/dataview/relation/list.tsx index fd3ab7dca5..b4fd5d93c6 100644 --- a/src/ts/component/menu/dataview/relation/list.tsx +++ b/src/ts/component/menu/dataview/relation/list.tsx @@ -251,7 +251,7 @@ const MenuRelationList = observer(class MenuRelationList extends React.Component menuIdEdit: 'dataviewRelationEdit', filter: '', ref: 'dataview', - skipKeys: relations.map(it => it.relationKey), + skipKeys: relations.map(it => it.relationKey).concat(Relation.systemKeysWithoutUser()), onAdd, addCommand: (rootId: string, blockId: string, relation: any, onChange: (message: any) => void) => { Dataview.relationAdd(rootId, blockId, relation.relationKey, relations.length, getView(), (message: any) => { diff --git a/src/ts/component/menu/dataview/source.tsx b/src/ts/component/menu/dataview/source.tsx index 3d7353ef07..6bd62f97d3 100644 --- a/src/ts/component/menu/dataview/source.tsx +++ b/src/ts/component/menu/dataview/source.tsx @@ -161,16 +161,9 @@ const MenuSource = observer(class MenuSource extends React.Component { save (value: string[], callBack?: () => void) { const { param } = this.props; const { data } = param; - const { objectId, blockId } = data; - - C.ObjectSetSource(objectId, value, () => { - $(window).trigger(`updateDataviewData.${blockId}`); - - if (callBack) { - callBack(); - }; - }); + const { objectId } = data; + C.ObjectSetSource(objectId, value, callBack); this.forceUpdate(); }; diff --git a/src/ts/component/menu/dataview/template/context.tsx b/src/ts/component/menu/dataview/template/context.tsx index 59f56dce82..743eac574d 100644 --- a/src/ts/component/menu/dataview/template/context.tsx +++ b/src/ts/component/menu/dataview/template/context.tsx @@ -52,9 +52,10 @@ class MenuTemplateContext extends React.Component { const { template, isView, onSetDefault, templateId } = data; const isBlank = template.id == Constant.templateId.blank; const isDefault = template.id == templateId; + const defaultName = isView ? translate('menuDataviewTemplateSetDefaultForView') : translate('commonSetDefault'); return [ - !isDefault && onSetDefault ? ({ id: 'default', name: isView ? translate('menuDataviewTemplateSetDefaultForView') : translate('commonSetDefault') }) : null, + !isDefault && onSetDefault ? ({ id: 'default', name: defaultName }) : null, !isBlank ? ({ id: 'edit', name: translate('menuDataviewTemplateEdit') }) : null, { id: 'duplicate', name: translate('commonDuplicate') }, !isBlank ? ({ id: 'remove', name: translate('commonDelete'), color: 'red' }) : null, diff --git a/src/ts/component/menu/dataview/template/list.tsx b/src/ts/component/menu/dataview/template/list.tsx index 72f4f1aecd..3272713f5c 100644 --- a/src/ts/component/menu/dataview/template/list.tsx +++ b/src/ts/component/menu/dataview/template/list.tsx @@ -245,7 +245,7 @@ const MenuTemplateList = observer(class MenuTemplateList extends React.Component onMore (e: any, template: any) { const { param, getId } = this.props; const { data } = param; - const { onSetDefault, route, typeId } = data; + const { onSetDefault, route, typeId, getView } = data; const item = UtilCommon.objectCopy(template); const node = $(`#item-${item.id}`); const templateId = this.getTemplateId(); @@ -278,11 +278,11 @@ const MenuTemplateList = observer(class MenuTemplateList extends React.Component data: { rebind: this.rebind, template: item, - isView: true, + isView: !!getView, typeId, templateId, route, - onDuplicate: (object) => UtilObject.openPopup(object, {}), + onDuplicate: object => UtilObject.openPopup(object, {}), onSetDefault, } }); diff --git a/src/ts/component/menu/dataview/view/layout.tsx b/src/ts/component/menu/dataview/view/layout.tsx index c0f79b0fd5..ee3b2148d1 100644 --- a/src/ts/component/menu/dataview/view/layout.tsx +++ b/src/ts/component/menu/dataview/view/layout.tsx @@ -148,14 +148,20 @@ const MenuViewLayout = observer(class MenuViewLayout extends React.Component { diff --git a/src/ts/component/menu/index.tsx b/src/ts/component/menu/index.tsx index cee1fb3a78..fa0cefd08a 100644 --- a/src/ts/component/menu/index.tsx +++ b/src/ts/component/menu/index.tsx @@ -565,7 +565,7 @@ const Menu = observer(class Menu extends React.Component { x = Math.min(ww - width - BORDER, x); y = Math.max(minY, y); - y = Math.min(wh - height - BORDER, y); + y = Math.min(wh - height - 80, y); if (undefined !== fixedX) x = fixedX; if (undefined !== fixedY) y = fixedY; diff --git a/src/ts/component/menu/relation/suggest.tsx b/src/ts/component/menu/relation/suggest.tsx index ce611cdcbd..f5c82138c0 100644 --- a/src/ts/component/menu/relation/suggest.tsx +++ b/src/ts/component/menu/relation/suggest.tsx @@ -223,11 +223,10 @@ const MenuRelationSuggest = observer(class MenuRelationSuggest extends React.Com const { param } = this.props; const { data } = param; const filter = String(data.filter || ''); - const skipKeys = (data.skipKeys || []).concat(Relation.systemKeysWithoutUser()); const filters: any[] = [ { operator: I.FilterOperator.And, relationKey: 'spaceId', condition: I.FilterCondition.In, value: [ commonStore.space, Constant.storeSpaceId ] }, { operator: I.FilterOperator.And, relationKey: 'layout', condition: I.FilterCondition.In, value: I.ObjectLayout.Relation }, - { operator: I.FilterOperator.And, relationKey: 'relationKey', condition: I.FilterCondition.NotIn, value: skipKeys }, + { operator: I.FilterOperator.And, relationKey: 'relationKey', condition: I.FilterCondition.NotIn, value: data.skipKeys || [] }, ]; const sorts = [ { relationKey: 'spaceId', type: I.SortType.Desc }, diff --git a/src/ts/component/menu/smile.tsx b/src/ts/component/menu/smile.tsx index dc1f223219..548e18b6ee 100644 --- a/src/ts/component/menu/smile.tsx +++ b/src/ts/component/menu/smile.tsx @@ -503,7 +503,7 @@ class MenuSmile extends React.Component { setActive (item?: any, row?: number) { const node = $(this.node); - if (row) { + if (row && this.refList) { this.refList.scrollToRow(Math.max(0, row)); }; @@ -513,14 +513,11 @@ class MenuSmile extends React.Component { this.active = item; if (this.active) { - const item = node.find(`#item-${$.escapeSelector(this.active.id)}`); + const element = node.find(`#item-${$.escapeSelector(this.active.id)}`); - item.addClass('active'); + element.addClass('active'); - Preview.tooltipShow({ - text: this.aliases[this.active.itemId] || this.active.itemId, - element: item, - }); + Preview.tooltipShow({ text: (this.aliases[this.active.itemId] || this.active.itemId), element }); }; }; diff --git a/src/ts/component/menu/space.tsx b/src/ts/component/menu/space.tsx index d36b0e030f..257030a137 100644 --- a/src/ts/component/menu/space.tsx +++ b/src/ts/component/menu/space.tsx @@ -55,7 +55,10 @@ const MenuSpace = observer(class MenuSpace extends React.Component { onClick={this.onAdd} onMouseEnter={e => this.onMouseEnter(e, item)} onMouseLeave={e => setHover()} - /> + > +
+
{translate('commonCreateNew')}
+
); return ( @@ -65,7 +68,7 @@ const MenuSpace = observer(class MenuSpace extends React.Component { >
- +
@@ -100,7 +103,7 @@ const MenuSpace = observer(class MenuSpace extends React.Component { }; componentDidUpdate (): void { - this.beforePosition(); + this.props.position(); }; componentWillUnmount (): void { @@ -189,23 +192,15 @@ const MenuSpace = observer(class MenuSpace extends React.Component { this.n = 0; }; - this.props.setActive(); + if (items[this.n] && (items[this.n].id == 'add')) { + this.onArrow(dir); + } else { + this.props.setActive(); + }; }; getItems () { - const subId = Constant.subId.space; - const { spaceview } = blockStore; - - const items = UtilCommon.objectCopy(dbStore.getRecords(subId, '')). - map(id => detailStore.get(subId, id, UtilData.spaceRelationKeys())). - filter(it => (it.spaceAccountStatus != I.SpaceStatus.Deleted) && (it.spaceLocalStatus == I.SpaceStatus.Ok)). - map(it => ({ ...it, isActive: spaceview == it.id })); - - items.sort((c1, c2) => { - if (c1.isActive && !c2.isActive) return -1; - if (!c1.isActive && c2.isActive) return 1; - return 0; - }); + const items = UtilCommon.objectCopy(dbStore.getSpaces()); if (items.length < Constant.limit.space) { items.push({ id: 'add' }); diff --git a/src/ts/component/menu/type/suggest.tsx b/src/ts/component/menu/type/suggest.tsx index 571094b65a..e73c85d2c7 100644 --- a/src/ts/component/menu/type/suggest.tsx +++ b/src/ts/component/menu/type/suggest.tsx @@ -232,6 +232,7 @@ const MenuTypeSuggest = observer(class MenuTypeSuggest extends React.Component { - C.AccountRecover((message) => this.setError(message.error)); + C.AccountRecover(message => this.setError(message.error)); }); }); }; @@ -145,9 +145,11 @@ const PageAuthLogin = observer(class PageAuthLogin extends React.Component { this.onSubmit(e); }); + keyboard.shortcut('enter', e, () => this.onSubmit(e)); }; onCancel () { diff --git a/src/ts/component/page/auth/onboard.tsx b/src/ts/component/page/auth/onboard.tsx index 91979253b6..912ac822db 100644 --- a/src/ts/component/page/auth/onboard.tsx +++ b/src/ts/component/page/auth/onboard.tsx @@ -297,6 +297,7 @@ const PageAuthOnboard = observer(class PageAuthOnboard extends React.Component { Action.importUsecase(commonStore.space, I.Usecase.Skip, callBack); diff --git a/src/ts/component/page/head/banner.tsx b/src/ts/component/page/head/banner.tsx index 6196b2f766..71c280bac2 100644 --- a/src/ts/component/page/head/banner.tsx +++ b/src/ts/component/page/head/banner.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import $ from 'jquery'; import { IconObject, Label, ObjectName } from 'Component'; -import { I, Action, translate, UtilObject, UtilCommon, C, analytics } from 'Lib'; +import { I, Action, translate, UtilObject, UtilCommon, C, analytics, Onboarding } from 'Lib'; import { dbStore, menuStore } from 'Store'; import Constant from 'json/constant.json'; @@ -85,6 +85,14 @@ class HeaderBanner extends React.Component { ); }; + componentDidMount (): void { + const { type, isPopup } = this.props; + + if (type == I.BannerType.TemplateSelect) { + Onboarding.start('templateSelect', isPopup); + }; + }; + onTemplateMenu () { const { object, isPopup } = this.props; const { sourceObject } = object; @@ -92,7 +100,7 @@ class HeaderBanner extends React.Component { const templateId = sourceObject || Constant.templateId.blank; const node = $(this.node); - if (menuStore.isOpen('dataviewTemplateList')) { + if (!type || menuStore.isOpen('dataviewTemplateList')) { return; }; @@ -120,15 +128,19 @@ class HeaderBanner extends React.Component { typeId: type.id, templateId, previewSize: I.PreviewSize.Medium, + onSetDefault: () => { + UtilObject.setDefaultTemplateId(type.id, templateId); + }, onSelect: (item: any) => { C.ObjectApplyTemplate(object.id, item.id); - analytics.event('SelectTemplate'); + analytics.event('SelectTemplate', { route: 'Banner' }); menuContext.close(); }, }, }); }; + }; -export default HeaderBanner; +export default HeaderBanner; \ No newline at end of file diff --git a/src/ts/component/page/head/controls.tsx b/src/ts/component/page/head/controls.tsx index 83e2d63b3a..b0b13e9812 100644 --- a/src/ts/component/page/head/controls.tsx +++ b/src/ts/component/page/head/controls.tsx @@ -145,21 +145,15 @@ const Controls = observer(class Controls extends React.Component { }; onCoverOpen () { - if (!this._isMounted) { - return; + if (this._isMounted) { + $(this.node).addClass('hover'); }; - - const node = $(this.node); - node.addClass('hover'); }; onCoverClose () { - if (!this._isMounted) { - return; + if (this._isMounted) { + $(this.node).removeClass('hover'); }; - - const node = $(this.node); - node.removeClass('hover'); }; onCoverSelect (item: any) { diff --git a/src/ts/component/page/main/relation.tsx b/src/ts/component/page/main/relation.tsx index 65b7be5e87..72bf0cdd10 100644 --- a/src/ts/component/page/main/relation.tsx +++ b/src/ts/component/page/main/relation.tsx @@ -75,7 +75,7 @@ const PageMainRelation = observer(class PageMainRelation extends React.Component {object.isInstalled ? (
-
{totalObject} {UtilCommon.plural(totalObject, translate('pluralObject'))}
+
{totalObject} {UtilCommon.sprintf(translate('pageMainRelationObjectsCreated'), UtilCommon.plural(totalObject, translate('pluralObject')))}
diff --git a/src/ts/component/page/main/type.tsx b/src/ts/component/page/main/type.tsx index c9aa7b5f4e..bb7fa58b7e 100644 --- a/src/ts/component/page/main/type.tsx +++ b/src/ts/component/page/main/type.tsx @@ -506,7 +506,7 @@ const PageMainType = observer(class PageMainType extends React.Component { menuStore.open('dataviewTemplateContext', { menuKey: item.id, - element: `#item-${item.id} .more`, + element: `#item-more-${item.id}`, vertical: I.MenuDirection.Bottom, horizontal: I.MenuDirection.Right, onOpen: () => $(`#item-${item.id}`).addClass('active'), diff --git a/src/ts/component/popup/export.tsx b/src/ts/component/popup/export.tsx index 0f0a640e50..9e2482d41a 100644 --- a/src/ts/component/popup/export.tsx +++ b/src/ts/component/popup/export.tsx @@ -49,7 +49,7 @@ const PopupExport = observer(class PopupExport extends React.Component control = ( { this.data[item.id] = v; this.save(); diff --git a/src/ts/component/popup/page/settings/appearance.tsx b/src/ts/component/popup/page/settings/appearance.tsx index c4d41215ee..d77e7ba699 100644 --- a/src/ts/component/popup/page/settings/appearance.tsx +++ b/src/ts/component/popup/page/settings/appearance.tsx @@ -40,9 +40,7 @@ const PopupSettingsPageAppearance = observer(class PopupSettingsPageAppearance e
-
diff --git a/src/ts/component/popup/page/settings/delete.tsx b/src/ts/component/popup/page/settings/delete.tsx index 66298868ef..91764573bf 100644 --- a/src/ts/component/popup/page/settings/delete.tsx +++ b/src/ts/component/popup/page/settings/delete.tsx @@ -1,15 +1,22 @@ import * as React from 'react'; -import { Title, Button, Checkbox } from 'Component'; +import { Title, Button, Checkbox, Error } from 'Component'; import { I, C, translate, UtilRouter, analytics } from 'Lib'; import { authStore } from 'Store'; import { observer } from 'mobx-react'; import Head from './head'; -const PopupSettingsPageDelete = observer(class PopupSettingsPageDelete extends React.Component { +interface State { + error: string; +}; - refCheckbox = null; +const PopupSettingsPageDelete = observer(class PopupSettingsPageDelete extends React.Component { + + refCheckbox: any = null; refButton = null; - node = null; + node: any = null; + state = { + error: '', + }; constructor (props: I.PopupSettings) { super(props); @@ -19,6 +26,8 @@ const PopupSettingsPageDelete = observer(class PopupSettingsPageDelete extends R }; render () { + const { error } = this.state; + return (
this.node = node} @@ -38,7 +47,9 @@ const PopupSettingsPageDelete = observer(class PopupSettingsPageDelete extends R this.refCheckbox = ref} /> {translate('popupSettingsDeleteCheckboxLabel')}
-
); }; @@ -55,6 +66,7 @@ const PopupSettingsPageDelete = observer(class PopupSettingsPageDelete extends R C.AccountDelete((message: any) => { if (message.error.code) { + this.setState({ error: message.error.description }); return; }; diff --git a/src/ts/component/popup/page/settings/personal.tsx b/src/ts/component/popup/page/settings/personal.tsx index aeb0d5699c..b7714ccf00 100644 --- a/src/ts/component/popup/page/settings/personal.tsx +++ b/src/ts/component/popup/page/settings/personal.tsx @@ -1,46 +1,35 @@ import * as React from 'react'; import { observer } from 'mobx-react'; -import { Icon, Title, Label, Select } from 'Component'; -import { I, translate, analytics, Renderer, UtilObject, Action } from 'Lib'; -import { commonStore, menuStore, dbStore } from 'Store'; +import { Icon, Title, Label, Select, Switch } from 'Component'; +import { I, translate, UtilCommon, Action, Renderer } from 'Lib'; +import { commonStore } from 'Store'; import Constant from 'json/constant.json'; const PopupSettingsPagePersonal = observer(class PopupSettingsPagePersonal extends React.Component { constructor (props: I.PopupSettings) { super(props); - - this.onType = this.onType.bind(this); }; render () { - const { config } = commonStore; - const type = dbStore.getTypeById(commonStore.type); + const { config, interfaceLang } = commonStore; + const { languages, hideTray, hideMenuBar } = config; const interfaceLanguages = this.getInterfaceLanguages(); const spellingLanguages = this.getSpellinngLanguages(); + const canHideMenu = UtilCommon.isPlatformWindows() || UtilCommon.isPlatformLinux(); return ( <div className="actionItems"> - <div className="item"> - <Label text={translate('popupSettingsPersonalDefaultObjectType')} /> - - <div id="defaultType" className="select" onClick={this.onType}> - <div className="item"> - <div className="name">{type?.name || translate('commonSelect')}</div> - </div> - <Icon className="arrow black" /> - </div> - </div> <div className="item"> <Label text={translate('popupSettingsPersonalSpellcheckLanguage')} /> <Select id="spellcheck" - value={config.languages} + value={languages} options={spellingLanguages} onChange={v => Action.setSpellingLang(v)} arrowClassName="black" @@ -55,7 +44,7 @@ const PopupSettingsPagePersonal = observer(class PopupSettingsPagePersonal exten <Select id="interfaceLang" - value={commonStore.interfaceLang} + value={interfaceLang} options={interfaceLanguages} onChange={v => Action.setInterfaceLang(v)} arrowClassName="black" @@ -66,31 +55,24 @@ const PopupSettingsPagePersonal = observer(class PopupSettingsPagePersonal exten }} /> </div> + + <div className="item"> + <Label text={translate('electronMenuShowTray')} /> + <Switch className="big" value={!hideTray} onChange={(e: any, v: boolean) => Renderer.send('setHideTray', v)}/> + </div> + + {canHideMenu ? ( + <div className="item"> + <Label text={translate('electronMenuShowMenu')} /> + <Switch className="big" value={!hideMenuBar} onChange={(e: any, v: boolean) => Renderer.send('setMenuBarVisibility', v)}/> + </div> + ) : ''} </div> </React.Fragment> ); }; - onType (e: any) { - const { getId } = this.props; - - menuStore.open('typeSuggest', { - element: `#${getId()} #defaultType`, - horizontal: I.MenuDirection.Right, - data: { - filter: '', - filters: [ - { operator: I.FilterOperator.And, relationKey: 'recommendedLayout', condition: I.FilterCondition.In, value: UtilObject.getPageLayouts() }, - ], - onClick: (item: any) => { - commonStore.typeSet(item.uniqueKey); - analytics.event('DefaultTypeChange', { objectType: item.uniqueKey, route: 'Settings' }); - }, - } - }); - }; - getInterfaceLanguages () { const ret: any[] = []; const Locale = require('lib/json/locale.json'); diff --git a/src/ts/component/popup/page/settings/space/create.tsx b/src/ts/component/popup/page/settings/space/create.tsx index 1da9d920de..cb96ddab40 100644 --- a/src/ts/component/popup/page/settings/space/create.tsx +++ b/src/ts/component/popup/page/settings/space/create.tsx @@ -158,7 +158,7 @@ const PopupSettingsSpaceIndex = observer(class PopupSettingsSpaceIndex extends R this.setState({ isLoading: false }); if (!message.error.code) { - analytics.event('CreateSpace', { usecase }); + analytics.event('CreateSpace', { usecase, middleTime: message.middleTime, }); analytics.event('SelectUsecase', { type: usecase }); UtilRouter.switchSpace(message.objectId, '', () => close()); diff --git a/src/ts/component/popup/page/settings/space/index.tsx b/src/ts/component/popup/page/settings/space/index.tsx index 6fd94d5b67..2cba9bb388 100644 --- a/src/ts/component/popup/page/settings/space/index.tsx +++ b/src/ts/component/popup/page/settings/space/index.tsx @@ -1,19 +1,27 @@ import * as React from 'react'; -import { Icon, Title, Label, Input, IconObject, Button, ProgressBar } from 'Component'; -import { I, C, UtilObject, UtilMenu, UtilCommon, UtilFile, translate, Renderer, Preview, analytics, UtilDate, Action } from 'Lib'; +import { Icon, Title, Label, Input, IconObject, Button, ProgressBar, Error } from 'Component'; +import { I, C, UtilObject, UtilMenu, UtilCommon, UtilFile, translate, Renderer, Preview, analytics, UtilDate, Action, Storage } from 'Lib'; import { observer } from 'mobx-react'; -import { detailStore, menuStore, commonStore, authStore } from 'Store'; +import { detailStore, menuStore, commonStore, authStore, dbStore } from 'Store'; import Constant from 'json/constant.json'; import Url from 'json/url.json'; -const PopupSettingsSpaceIndex = observer(class PopupSettingsSpaceIndex extends React.Component<I.PopupSettings> { +interface State { + error: string; +}; + +const PopupSettingsSpaceIndex = observer(class PopupSettingsSpaceIndex extends React.Component<I.PopupSettings, State> { refName: any = null; + state = { + error: '', + }; constructor (props: any) { super(props); this.onDashboard = this.onDashboard.bind(this); + this.onType = this.onType.bind(this); this.onSelect = this.onSelect.bind(this); this.onUpload = this.onUpload.bind(this); this.onName = this.onName.bind(this); @@ -22,22 +30,30 @@ const PopupSettingsSpaceIndex = observer(class PopupSettingsSpaceIndex extends R render () { const { onPage, onSpaceTypeTooltip } = this.props; - const { localUsage, bytesUsed, bytesLimit } = commonStore.spaceStorage; + const { error } = this.state; + const { localUsage, bytesLimit } = commonStore.spaceStorage; + const spaces = dbStore.getSpaces(); const { account, accountSpaceId } = authStore; const space = UtilObject.getSpaceview(); - const name = this.checkName(space.name); const home = UtilObject.getSpaceDashboard(); + const type = dbStore.getTypeById(commonStore.type); - const percentageUsed = Math.floor(UtilCommon.getPercent(bytesUsed, bytesLimit)); - const currentUsage = String(UtilFile.size(bytesUsed)); - const limitUsage = String(UtilFile.size(bytesLimit)); - const isRed = (percentageUsed >= 90) || (localUsage > bytesLimit); const usageCn = [ 'item' ]; const canDelete = space.targetSpaceId != accountSpaceId; + let bytesUsed = 0; let extend = null; let createdDate = null; + const progressSegments = (spaces || []).map(space => { + const object: any = commonStore.spaceStorage.spaces.find(it => it.spaceId == space.targetSpaceId) || {}; + const usage = Number(object.bytesUsage) || 0; + + bytesUsed += usage; + return { name: space.name, caption: UtilFile.size(usage), percent: usage / bytesLimit, isActive: space.isActive }; + }).filter(it => it); + const isRed = (bytesUsed / bytesLimit >= 0.9) || (localUsage > bytesLimit); + if (isRed) { usageCn.push('red'); extend = <Label text={translate(`popupSettingsSpaceIndexRemoteStorageExtend`)} onClick={this.onExtend} className="extend" />; @@ -79,7 +95,7 @@ const PopupSettingsSpaceIndex = observer(class PopupSettingsSpaceIndex extends R <Label className="small" text={translate('popupSettingsSpaceIndexSpaceNameLabel')} /> <Input ref={ref => this.refName = ref} - value={name} + value={this.checkName(space.name)} onKeyUp={this.onName} placeholder={UtilObject.defaultName('Page')} /> @@ -101,7 +117,7 @@ const PopupSettingsSpaceIndex = observer(class PopupSettingsSpaceIndex extends R <div className="sectionContent"> <div className={usageCn.join(' ')}> - <div className="sides"> + <div className="sides alignTop"> <div className="side left"> <Title text={translate(`popupSettingsSpaceIndexRemoteStorageTitle`)} /> <div className="storageLabel"> @@ -115,7 +131,7 @@ const PopupSettingsSpaceIndex = observer(class PopupSettingsSpaceIndex extends R </div> </div> - <ProgressBar percent={percentageUsed} current={currentUsage} max={limitUsage} /> + <ProgressBar segments={progressSegments} current={UtilFile.size(bytesUsed)} max={UtilFile.size(bytesLimit)} /> </div> <div className="item"> @@ -136,6 +152,24 @@ const PopupSettingsSpaceIndex = observer(class PopupSettingsSpaceIndex extends R </div> </div> + <div className="item"> + <div className="sides"> + <div className="side left"> + <Title text={translate('popupSettingsPersonalDefaultObjectType')} /> + <Label text={translate('popupSettingsPersonalDefaultObjectTypeDescription')} /> + </div> + + <div className="side right"> + <div id="defaultType" className="select" onClick={this.onType}> + <div className="item"> + <div className="name">{type?.name || translate('commonSelect')}</div> + </div> + <Icon className="arrow black" /> + </div> + </div> + </div> + </div> + </div> </div> @@ -229,6 +263,8 @@ const PopupSettingsSpaceIndex = observer(class PopupSettingsSpaceIndex extends R <Button text={translate('commonDelete')} color="red c36" onClick={this.onDelete} /> </div> ) : ''} + + <Error text={error} /> </div> </React.Fragment> @@ -243,6 +279,26 @@ const PopupSettingsSpaceIndex = observer(class PopupSettingsSpaceIndex extends R UtilMenu.dashboardSelect(`#${this.props.getId()} #empty-dashboard-select`); }; + onType (e: any) { + const { getId } = this.props; + + menuStore.open('typeSuggest', { + element: `#${getId()} #defaultType`, + horizontal: I.MenuDirection.Right, + data: { + filter: '', + filters: [ + { operator: I.FilterOperator.And, relationKey: 'recommendedLayout', condition: I.FilterCondition.In, value: UtilObject.getPageLayouts() }, + ], + onClick: (item: any) => { + commonStore.typeSet(item.uniqueKey); + analytics.event('DefaultTypeChange', { objectType: item.uniqueKey, route: 'Settings' }); + this.forceUpdate(); + }, + } + }); + }; + onExtend () { const { account } = authStore; const { bytesLimit } = commonStore.spaceStorage; @@ -278,7 +334,11 @@ const PopupSettingsSpaceIndex = observer(class PopupSettingsSpaceIndex extends R }; onDelete () { - Action.removeSpace(commonStore.space, 'Settings'); + Action.removeSpace(commonStore.space, 'Settings', (message: any) => { + if (message.error.code) { + this.setState({ error: message.error.description }); + }; + }); }; checkName (v: string): string { diff --git a/src/ts/component/popup/shortcut.tsx b/src/ts/component/popup/shortcut.tsx index 53897d6762..5b736839b0 100644 --- a/src/ts/component/popup/shortcut.tsx +++ b/src/ts/component/popup/shortcut.tsx @@ -7,6 +7,23 @@ interface State { page: string; }; +interface Section { + id?: string; + name: string; + children: { + name?: string; + description?: string; + className?: string; + children: Item[]; + }[]; +}; + +interface Item { + com?: string; + mac?: string; + name: string; +}; + class PopupShortcut extends React.Component<I.Popup, State> { state = { @@ -17,22 +34,18 @@ class PopupShortcut extends React.Component<I.Popup, State> { render () { const { page } = this.state; const isMac = UtilCommon.isPlatformMac(); - const tabs = [ - { id: 'main', name: translate('popupShortcutMain') }, - { id: 'navigation', name: translate('popupShortcutNavigation') }, - { id: 'markdown', name: translate('popupShortcutMarkdown') }, - { id: 'command', name: translate('popupShortcutCommands') }, - ]; - const sections = this.getSections(page); + const sections = this.getSections(); + const section = sections.find(it => it.id == page); const Tab = (item: any) => ( - <div className={[ 'item', (item.id == page ? 'active' : '') ].join(' ')} onClick={(e: any) => { this.onPage(item.id); }}> + <div className={[ 'item', (item.id == page ? 'active' : '') ].join(' ')} onClick={() => this.onPage(item.id)}> {item.name} </div> ); const Section = (item: any) => { const cn = [ 'section' ]; + if (item.className) { cn.push(item.className); }; @@ -41,6 +54,7 @@ class PopupShortcut extends React.Component<I.Popup, State> { <div className={cn.join(' ')}> {item.name ? <div className="name">{item.name}</div> : ''} {item.description ? <div className="descr">{item.description}</div> : ''} + <div className="items"> {item.children.map((item: any, i: number) => ( <Item key={i} {...item} /> @@ -63,14 +77,14 @@ class PopupShortcut extends React.Component<I.Popup, State> { <div className="wrapper"> <div className="head"> <div className="tabs"> - {tabs.map((item: any, i: number) => ( + {sections.map((item: any, i: number) => ( <Tab key={i} {...item} /> ))} </div> </div> <div className="body scrollable"> - {sections.map((item: any, i: number) => ( + {(section.children || []).map((item: any, i: number) => ( <Section key={i} {...item} /> ))} </div> @@ -102,217 +116,232 @@ class PopupShortcut extends React.Component<I.Popup, State> { this.setState({ page: id }); }; - getSections (id: string) { + getSections (): Section[] { const cmd = keyboard.cmdSymbol(); const alt = keyboard.altSymbol(); - const sections = { + const sections = [ + { + id: 'main', + name: translate('popupShortcutMain'), + children: [ + { + name: translate('popupShortcutBasics'), children: [ + { com: `${cmd} + N`, name: translate('popupShortcutMainBasics1') }, + { com: `${cmd} + Shift + N`, name: translate('popupShortcutMainBasics2') }, + { com: `${cmd} + ${alt} + N`, name: translate('popupShortcutMainBasics3') }, + { com: `${cmd} + Enter`, name: translate('popupShortcutMainBasics4') }, + { com: `${cmd} + ${alt} + F`, name: translate('popupShortcutMainBasics5') }, + { com: `${cmd} + Z`, name: translate('popupShortcutMainBasics6') }, + { com: `${cmd} + Shift + Z`, name: translate('popupShortcutMainBasics7') }, + { com: `${cmd} + P`, name: translate('popupShortcutMainBasics8') }, + { com: `${cmd} + F`, name: translate('popupShortcutMainBasics9') }, + { com: `${cmd} + Q`, name: translate('popupShortcutMainBasics10') }, + { mac: `${cmd} + Y`, com: 'Ctrl + H', name: translate('popupShortcutMainBasics11') }, + { com: 'Shift + Click', name: translate('popupShortcutMainBasics12') }, + { com: `${cmd} + Click`, name: translate('popupShortcutMainBasics13') }, + { com: 'Ctrl + Space', name: translate('popupShortcutMainBasics14') }, + { com: `${cmd} + \\, ${cmd} + .`, name: translate('popupShortcutMainBasics15') }, + { com: `${cmd} + =`, name: translate('popupShortcutMainBasics16') }, + { com: `${cmd} + Minus`, name: translate('popupShortcutMainBasics17') }, + { com: `${cmd} + 0`, name: translate('popupShortcutMainBasics18') }, + ] + }, - main: [ - { - name: translate('popupShortcutBasics'), children: [ - { com: `${cmd} + N`, name: translate('popupShortcutMainBasics1') }, - { com: `${cmd} + Shift + N`, name: translate('popupShortcutMainBasics2') }, - { com: `${cmd} + ${alt} + N`, name: translate('popupShortcutMainBasics3') }, - { com: `${cmd} + Enter`, name: translate('popupShortcutMainBasics4') }, - { com: `${cmd} + ${alt} + F`, name: translate('popupShortcutMainBasics5') }, - { com: `${cmd} + Z`, name: translate('popupShortcutMainBasics6') }, - { com: `${cmd} + Shift + Z`, name: translate('popupShortcutMainBasics7') }, - { com: `${cmd} + P`, name: translate('popupShortcutMainBasics8') }, - { com: `${cmd} + F`, name: translate('popupShortcutMainBasics9') }, - { com: `${cmd} + Q`, name: translate('popupShortcutMainBasics10') }, - { mac: `${cmd} + Y`, com: 'Ctrl + H', name: translate('popupShortcutMainBasics11') }, - { com: 'Shift + Click', name: translate('popupShortcutMainBasics12') }, - { com: `${cmd} + Click`, name: translate('popupShortcutMainBasics13') }, - { com: 'Ctrl + Space', name: translate('popupShortcutMainBasics14') }, - { com: `${cmd} + \\, ${cmd} + .`, name: translate('popupShortcutMainBasics15') }, - { com: `${cmd} + =`, name: translate('popupShortcutMainBasics16') }, - { com: `${cmd} + Minus`, name: translate('popupShortcutMainBasics17') }, - { com: `${cmd} + 0`, name: translate('popupShortcutMainBasics18') }, - ] - }, + { + name: translate('popupShortcutMainStructuring'), children: [ + { com: 'Enter', name: translate('popupShortcutMainStructuring1') }, + { com: 'Shift + Enter', name: translate('popupShortcutMainStructuring2') }, + { com: 'Delete', name: translate('popupShortcutMainStructuring3') }, + { com: 'Tab', name: translate('popupShortcutMainStructuring4') }, + { com: 'Shift + Tab', name: translate('popupShortcutMainStructuring5') }, + ] + }, - { - name: translate('popupShortcutMainStructuring'), children: [ - { com: 'Enter', name: translate('popupShortcutMainStructuring1') }, - { com: 'Shift + Enter', name: translate('popupShortcutMainStructuring2') }, - { com: 'Delete', name: translate('popupShortcutMainStructuring3') }, - { com: 'Tab', name: translate('popupShortcutMainStructuring4') }, - { com: 'Shift + Tab', name: translate('popupShortcutMainStructuring5') }, - ] - }, + { + name: translate('popupShortcutMainSelection'), children: [ + { com: 'Double Click', name: translate('popupShortcutMainSelection1') }, + { com: 'Triple Click', name: translate('popupShortcutMainSelection2') }, + { com: `${cmd} + A`, name: translate('popupShortcutMainSelection3') }, + { com: 'Shift + ↑ or ↓', name: translate('popupShortcutMainSelection4') }, + { com: `${cmd} + Click`, name: translate('popupShortcutMainSelection5') }, + { com: 'Shift + Click', name: translate('popupShortcutMainSelection6') }, + ] + }, - { - name: translate('popupShortcutMainSelection'), children: [ - { com: 'Double Click', name: translate('popupShortcutMainSelection1') }, - { com: 'Triple Click', name: translate('popupShortcutMainSelection2') }, - { com: `${cmd} + A`, name: translate('popupShortcutMainSelection3') }, - { com: 'Shift + ↑ or ↓', name: translate('popupShortcutMainSelection4') }, - { com: `${cmd} + Click`, name: translate('popupShortcutMainSelection5') }, - { com: 'Shift + Click', name: translate('popupShortcutMainSelection6') }, - ] - }, + { + name: translate('popupShortcutMainActions'), children: [ + { com: '/', name: translate('popupShortcutMainActions1') }, + { com: `${cmd} + /`, name: translate('popupShortcutMainActions2') }, + { mac: `${cmd} + Delete`, com: 'Ctrl + Backspace', name: translate('popupShortcutMainActions3') }, + { com: `${cmd} + C`, name: translate('popupShortcutMainActions4') }, + { com: `${cmd} + X`, name: translate('popupShortcutMainActions5') }, + { com: `${cmd} + V`, name: translate('popupShortcutMainActions6') }, + { com: `${cmd} + D`, name: translate('popupShortcutMainActions7') }, + { com: `${cmd} + E`, name: translate('popupShortcutMainActions8') + ' 🏄‍♂' }, + ] + }, - { - name: translate('popupShortcutMainActions'), children: [ - { com: '/', name: translate('popupShortcutMainActions1') }, - { com: `${cmd} + /`, name: translate('popupShortcutMainActions2') }, - { mac: `${cmd} + Delete`, com: 'Ctrl + Backspace', name: translate('popupShortcutMainActions3') }, - { com: `${cmd} + C`, name: translate('popupShortcutMainActions4') }, - { com: `${cmd} + X`, name: translate('popupShortcutMainActions5') }, - { com: `${cmd} + V`, name: translate('popupShortcutMainActions6') }, - { com: `${cmd} + D`, name: translate('popupShortcutMainActions7') }, - { com: `${cmd} + E`, name: translate('popupShortcutMainActions8') + ' 🏄‍♂' }, - ] - }, + { + name: translate('popupShortcutMainTextStyle'), children: [ + { com: `${cmd} + B`, name: translate('popupShortcutMainTextStyle1') }, + { com: `${cmd} + I`, name: translate('popupShortcutMainTextStyle2') }, + { com: `${cmd} + U`, name: translate('popupShortcutMainTextStyle3') }, + { com: `${cmd} + Shift +S`, name: translate('popupShortcutMainTextStyle4') }, + { com: `${cmd} + K`, name: translate('popupShortcutMainTextStyle5') }, + { com: `${cmd} + L`, name: translate('popupShortcutMainTextStyle6') }, + { com: `${cmd} + Shift + C`, name: translate('popupShortcutMainTextStyle7') }, + { com: `${cmd} + Shift + H`, name: translate('popupShortcutMainTextStyle8') }, + ] + }, + ], + }, - { - name: translate('popupShortcutMainTextStyle'), children: [ - { com: `${cmd} + B`, name: translate('popupShortcutMainTextStyle1') }, - { com: `${cmd} + I`, name: translate('popupShortcutMainTextStyle2') }, - { com: `${cmd} + U`, name: translate('popupShortcutMainTextStyle3') }, - { com: `${cmd} + Shift +S`, name: translate('popupShortcutMainTextStyle4') }, - { com: `${cmd} + K`, name: translate('popupShortcutMainTextStyle5') }, - { com: `${cmd} + L`, name: translate('popupShortcutMainTextStyle6') }, - { com: `${cmd} + Shift + C`, name: translate('popupShortcutMainTextStyle7') }, - { com: `${cmd} + Shift + H`, name: translate('popupShortcutMainTextStyle8') }, - ] - }, - ], + { + id: 'navigation', + name: translate('popupShortcutNavigation'), + children: [ + { + name: translate('popupShortcutBasics'), children: [ + { com: `${cmd} + ,(comma)`, name: translate('popupShortcutNavigationBasics1') }, + { com: `${cmd} + O`, name: translate('popupShortcutNavigationBasics2') }, + { com: `${cmd} + ${alt} + O`, name: translate('popupShortcutNavigationBasics3') }, + { com: `${cmd} + S, ${cmd} + K`, name: translate('popupShortcutNavigationBasics4') }, + { com: `${cmd} + L`, name: translate('popupShortcutNavigationBasics5') }, + { com: `${alt} + H`, name: translate('popupShortcutNavigationBasics6') }, + { mac: `${cmd} + [, ${cmd} + ←`, com: 'Alt + ←', name: translate('popupShortcutNavigationBasics7') }, + { mac: `${cmd} + ], ${cmd} + →`, com: 'Alt + →', name: translate('popupShortcutNavigationBasics8') }, + { com: 'Ctrl + Tab', name: translate('popupShortcutNavigationBasics9') }, + ] + }, - navigation: [ - { - name: translate('popupShortcutBasics'), children: [ - { com: `${cmd} + ,(comma)`, name: translate('popupShortcutNavigationBasics1') }, - { com: `${cmd} + O`, name: translate('popupShortcutNavigationBasics2') }, - { com: `${cmd} + ${alt} + O`, name: translate('popupShortcutNavigationBasics3') }, - { com: `${cmd} + S, ${cmd} + K`, name: translate('popupShortcutNavigationBasics4') }, - { com: `${cmd} + L`, name: translate('popupShortcutNavigationBasics5') }, - { com: `${alt} + H`, name: translate('popupShortcutNavigationBasics6') }, - { mac: `${cmd} + [, ${cmd} + ←`, com: 'Alt + ←', name: translate('popupShortcutNavigationBasics7') }, - { mac: `${cmd} + ], ${cmd} + →`, com: 'Alt + →', name: translate('popupShortcutNavigationBasics8') }, - ] - }, + { + name: translate('popupShortcutNavigationMenu'), children: [ + { com: '↓ or Tab', name: translate('popupShortcutNavigationMenu1') }, + { com: '↑ or Shift + Tab', name: translate('popupShortcutNavigationMenu2') }, + { com: '←', name: translate('popupShortcutNavigationMenu3') }, + { com: '→', name: translate('popupShortcutNavigationMenu4') }, + { com: 'Enter', name: translate('popupShortcutNavigationMenu5') }, + ] + }, - { - name: translate('popupShortcutNavigationMenu'), children: [ - { com: '↓ or Tab', name: translate('popupShortcutNavigationMenu1') }, - { com: '↑ or Shift + Tab', name: translate('popupShortcutNavigationMenu2') }, - { com: '←', name: translate('popupShortcutNavigationMenu3') }, - { com: '→', name: translate('popupShortcutNavigationMenu4') }, - { com: 'Enter', name: translate('popupShortcutNavigationMenu5') }, - ] - }, + { + name: translate('popupShortcutNavigationPage'), children: [ + { com: `${cmd} + Shift + T`, name: translate('popupShortcutNavigationPage1') }, + { com: '↓', name: translate('popupShortcutNavigationPage2') }, + { com: '↑', name: translate('popupShortcutNavigationPage3') }, + { com: `${cmd} + ←`, name: translate('popupShortcutNavigationPage4') }, + { com: `${cmd} + →`, name: translate('popupShortcutNavigationPage5') }, + { com: `${cmd} + ↑`, name: translate('popupShortcutNavigationPage6') }, + { com: `${cmd} + ↓`, name: translate('popupShortcutNavigationPage7') }, + { com: `${cmd} + Shift + ↑↓`, name: translate('popupShortcutNavigationPage8') }, + { com: `${cmd} + Shift + R`, name: translate('popupShortcutNavigationPage9') }, + ] + }, + ], + }, - { - name: translate('popupShortcutNavigationPage'), children: [ - { com: `${cmd} + Shift + T`, name: translate('popupShortcutNavigationPage1') }, - { com: '↓', name: translate('popupShortcutNavigationPage2') }, - { com: '↑', name: translate('popupShortcutNavigationPage3') }, - { com: `${cmd} + ←`, name: translate('popupShortcutNavigationPage4') }, - { com: `${cmd} + →`, name: translate('popupShortcutNavigationPage5') }, - { com: `${cmd} + ↑`, name: translate('popupShortcutNavigationPage6') }, - { com: `${cmd} + ↓`, name: translate('popupShortcutNavigationPage7') }, - { com: `${cmd} + Shift + ↑↓`, name: translate('popupShortcutNavigationPage8') }, - { com: `${cmd} + Shift + R`, name: translate('popupShortcutNavigationPage9') }, - ] - }, - ], + { + id: 'markdown', + name: translate('popupShortcutMarkdown'), + children: [ + { + name: translate('popupShortcutMarkdownWhileTyping'), + children: [ + { com: '`', name: translate('popupShortcutMarkdownWhileTyping1') }, + { com: '** or __', name: translate('popupShortcutMarkdownWhileTyping2') }, + { com: '* or _', name: translate('popupShortcutMarkdownWhileTyping3') }, + { com: '~~', name: translate('popupShortcutMarkdownWhileTyping4') }, + { com: '-->', name: UtilCommon.sprintf(translate('popupShortcutMarkdownWhileTypingInserts'), '⟶') }, + { com: '<--', name: UtilCommon.sprintf(translate('popupShortcutMarkdownWhileTypingInserts'), '⟵') }, + { com: '<-->', name: UtilCommon.sprintf(translate('popupShortcutMarkdownWhileTypingInserts'), '⟷') }, + { com: '->', name: UtilCommon.sprintf(translate('popupShortcutMarkdownWhileTypingInserts'), '→') }, + { com: '<-', name: UtilCommon.sprintf(translate('popupShortcutMarkdownWhileTypingInserts'), '←') }, + { com: '--', name: UtilCommon.sprintf(translate('popupShortcutMarkdownWhileTypingInserts'), '—') }, + { com: '—>', name: UtilCommon.sprintf(translate('popupShortcutMarkdownWhileTypingInserts'), '⟶') }, + { com: '<—', name: UtilCommon.sprintf(translate('popupShortcutMarkdownWhileTypingInserts'), '⟵') }, + { com: '(c)', name: UtilCommon.sprintf(translate('popupShortcutMarkdownWhileTypingInserts'), '©') }, + { com: '(r)', name: UtilCommon.sprintf(translate('popupShortcutMarkdownWhileTypingInserts'), '®') }, + { com: '(tm)', name: UtilCommon.sprintf(translate('popupShortcutMarkdownWhileTypingInserts'), '™') }, + { com: '...', name: UtilCommon.sprintf(translate('popupShortcutMarkdownWhileTypingInserts'), '…') }, + ] + }, + { + name: translate('popupShortcutMarkdownBeginningOfLine'), + children: [ + { com: '# + Space', name: translate('popupShortcutMarkdownBeginningOfLine1') }, + { com: '# # + Space', name: translate('popupShortcutMarkdownBeginningOfLine2') }, + { com: '# # # + Space', name: translate('popupShortcutMarkdownBeginningOfLine3') }, + { com: '" + Space', name: translate('popupShortcutMarkdownBeginningOfLine4') }, + { com: '* or + or - and Space', name: translate('popupShortcutMarkdownBeginningOfLine5') }, + { com: '[] + Space', name: translate('popupShortcutMarkdownBeginningOfLine6') }, + { com: '1. + Space', name: translate('popupShortcutMarkdownBeginningOfLine7') }, + { com: '> + Space', name: translate('popupShortcutMarkdownBeginningOfLine8') }, + { com: '```', name: translate('popupShortcutMarkdownBeginningOfLine9') }, + { com: '---', name: translate('popupShortcutMarkdownBeginningOfLine10') }, + { com: '***', name: translate('popupShortcutMarkdownBeginningOfLine11') }, + ] + }, + ], + }, - markdown: [ - { - name: translate('popupShortcutMarkdownWhileTyping'), - children: [ - { com: '`', name: translate('popupShortcutMarkdownWhileTyping1') }, - { com: '** or __', name: translate('popupShortcutMarkdownWhileTyping2') }, - { com: '* or _', name: translate('popupShortcutMarkdownWhileTyping3') }, - { com: '~~', name: translate('popupShortcutMarkdownWhileTyping4') }, - { com: '-->', name: UtilCommon.sprintf(translate('popupShortcutMarkdownWhileTypingInserts'), '⟶') }, - { com: '<--', name: UtilCommon.sprintf(translate('popupShortcutMarkdownWhileTypingInserts'), '⟵') }, - { com: '<-->', name: UtilCommon.sprintf(translate('popupShortcutMarkdownWhileTypingInserts'), '⟷') }, - { com: '->', name: UtilCommon.sprintf(translate('popupShortcutMarkdownWhileTypingInserts'), '→') }, - { com: '<-', name: UtilCommon.sprintf(translate('popupShortcutMarkdownWhileTypingInserts'), '←') }, - { com: '--', name: UtilCommon.sprintf(translate('popupShortcutMarkdownWhileTypingInserts'), '—') }, - { com: '—>', name: UtilCommon.sprintf(translate('popupShortcutMarkdownWhileTypingInserts'), '⟶') }, - { com: '<—', name: UtilCommon.sprintf(translate('popupShortcutMarkdownWhileTypingInserts'), '⟵') }, - { com: '(c)', name: UtilCommon.sprintf(translate('popupShortcutMarkdownWhileTypingInserts'), '©') }, - { com: '(r)', name: UtilCommon.sprintf(translate('popupShortcutMarkdownWhileTypingInserts'), '®') }, - { com: '(tm)', name: UtilCommon.sprintf(translate('popupShortcutMarkdownWhileTypingInserts'), '™') }, - { com: '...', name: UtilCommon.sprintf(translate('popupShortcutMarkdownWhileTypingInserts'), '…') }, - ] - }, - { - name: translate('popupShortcutMarkdownBeginningOfLine'), - children: [ - { com: '# + Space', name: translate('popupShortcutMarkdownBeginningOfLine1') }, - { com: '# # + Space', name: translate('popupShortcutMarkdownBeginningOfLine2') }, - { com: '# # # + Space', name: translate('popupShortcutMarkdownBeginningOfLine3') }, - { com: '" + Space', name: translate('popupShortcutMarkdownBeginningOfLine4') }, - { com: '* or + or - and Space', name: translate('popupShortcutMarkdownBeginningOfLine5') }, - { com: '[] + Space', name: translate('popupShortcutMarkdownBeginningOfLine6') }, - { com: '1. + Space', name: translate('popupShortcutMarkdownBeginningOfLine7') }, - { com: '> + Space', name: translate('popupShortcutMarkdownBeginningOfLine8') }, - { com: '```', name: translate('popupShortcutMarkdownBeginningOfLine9') }, - { com: '---', name: translate('popupShortcutMarkdownBeginningOfLine10') }, - { com: '***', name: translate('popupShortcutMarkdownBeginningOfLine11') }, - ] - }, - ], + { + id: 'command', + name: translate('popupShortcutCommand'), + children: [ + { + name: translate('popupShortcutCommandMenu'), children: [ + { com: '/', name: translate('popupShortcutCommandMenu1') }, + { com: '↓ & ↑', name: translate('popupShortcutCommandMenu2') }, + { com: '→ & ←', name: translate('popupShortcutCommandMenu3') }, + { com: 'Esc or Clear /', name: translate('popupShortcutCommandMenu4') }, + ] + }, - command: [ - { - name: translate('popupShortcutCommandMenu'), children: [ - { com: '/', name: translate('popupShortcutCommandMenu1') }, - { com: '↓ & ↑', name: translate('popupShortcutCommandMenu2') }, - { com: '→ & ←', name: translate('popupShortcutCommandMenu3') }, - { com: 'Esc or Clear /', name: translate('popupShortcutCommandMenu4') }, - ] - }, + { description: translate('popupShortcutCommandDescription'), children: [], className: 'separator' }, + { + name: translate('popupShortcutCommandText'), children: [ + { com: '/text', name: translate('popupShortcutCommandText1') }, + { com: '/h1', name: translate('popupShortcutCommandText2') }, + { com: '/h2', name: translate('popupShortcutCommandText3') }, + { com: '/h3', name: translate('popupShortcutCommandText4') }, + { com: '/high', name: translate('popupShortcutCommandText5') }, + ] + }, - { description: translate('popupShortcutCommandDescription'), children: [], className: 'separator' }, - { - name: translate('popupShortcutCommandText'), children: [ - { com: '/text', name: translate('popupShortcutCommandText1') }, - { com: '/h1', name: translate('popupShortcutCommandText2') }, - { com: '/h2', name: translate('popupShortcutCommandText3') }, - { com: '/h3', name: translate('popupShortcutCommandText4') }, - { com: '/high', name: translate('popupShortcutCommandText5') }, - ] - }, + { + name: translate('popupShortcutCommandLists'), children: [ + { com: '/todo', name: translate('popupShortcutCommandLists1') }, + { com: '/bullet', name: translate('popupShortcutCommandLists2') }, + { com: '/num', name: translate('popupShortcutCommandLists3') }, + { com: '/toggle', name: translate('popupShortcutCommandLists4') }, + ] + }, - { - name: translate('popupShortcutCommandLists'), children: [ - { com: '/todo', name: translate('popupShortcutCommandLists1') }, - { com: '/bullet', name: translate('popupShortcutCommandLists2') }, - { com: '/num', name: translate('popupShortcutCommandLists3') }, - { com: '/toggle', name: translate('popupShortcutCommandLists4') }, - ] - }, + { + name: translate('popupShortcutCommandObjects'), children: [ + { com: '@today, @tomorrow', name: translate('popupShortcutCommandObjects1') }, + { com: '/page', name: translate('popupShortcutCommandObjects2') }, + { com: '/file', name: translate('popupShortcutCommandObjects3') }, + { com: '/image', name: translate('popupShortcutCommandObjects4') }, + { com: '/video', name: translate('popupShortcutCommandObjects5') }, + { com: '/bookmark', name: translate('popupShortcutCommandObjects6') }, + { com: '/link', name: translate('popupShortcutCommandObjects7') }, + ] + }, - { - name: translate('popupShortcutCommandObjects'), children: [ - { com: '@today, @tomorrow', name: translate('popupShortcutCommandObjects1') }, - { com: '/page', name: translate('popupShortcutCommandObjects2') }, - { com: '/file', name: translate('popupShortcutCommandObjects3') }, - { com: '/image', name: translate('popupShortcutCommandObjects4') }, - { com: '/video', name: translate('popupShortcutCommandObjects5') }, - { com: '/bookmark', name: translate('popupShortcutCommandObjects6') }, - { com: '/link', name: translate('popupShortcutCommandObjects7') }, - ] - }, + { + name: translate('popupShortcutCommandOther'), children: [ + { com: '/line', name: translate('popupShortcutCommandOther1') }, + { com: '/dots', name: translate('popupShortcutCommandOther2') }, + { com: '/code', name: translate('popupShortcutCommandOther3') }, + ] + }, + ], + }, + ]; - { - name: translate('popupShortcutCommandOther'), children: [ - { com: '/line', name: translate('popupShortcutCommandOther1') }, - { com: '/dots', name: translate('popupShortcutCommandOther2') }, - { com: '/code', name: translate('popupShortcutCommandOther3') }, - ] - }, - ] - - }; - - return sections[id] || []; + return sections; }; resize () { diff --git a/src/ts/component/util/progressBar.tsx b/src/ts/component/util/progressBar.tsx index f5b3792f10..4d3b3e4d6e 100644 --- a/src/ts/component/util/progressBar.tsx +++ b/src/ts/component/util/progressBar.tsx @@ -1,7 +1,9 @@ import * as React from 'react'; +import { Label } from 'Component'; +import { Preview } from 'Lib'; interface Props { - percent: number; + segments: { name: string; caption: string; percent: number; isActive: boolean; }[]; current?: string; max?: string; }; @@ -10,32 +12,53 @@ class ProgressBar extends React.Component<Props> { node: any = null; + constructor (props: Props) { + super(props); + + this.onTooltipShow = this.onTooltipShow.bind(this); + }; + render () { - const { percent, current, max } = this.props; - let currentLabel = null; - let maxLabel = null; + const { segments, current, max } = this.props; + const total = segments.reduce((res, current) => res += current.percent, 0); - if (current) { - currentLabel = <div className="label current">{current}</div>; - }; + const Item = (item: any) => { + const cn = [ 'fill' ]; + if (item.isActive) { + cn.push('isActive'); + }; - if (max) { - maxLabel = <div className="label max">{max}</div>; + return ( + <div + className={cn.join(' ')} + style={{ width: `${item.percent * 100}%` }} + onMouseEnter={e => this.onTooltipShow(e, item)} + onMouseLeave={() => Preview.tooltipHide(false)} + /> + ); }; return ( <div className="progressBar"> <div className="bar"> - <div className="fill" style={{ width: percent + '%' }} /> + {segments.map((item, i) => ( + <Item key={i} {...item} /> + ))} + <div className="fill empty" style={{ width: `${(1 - total) * 100}%` }} /> </div> <div className="labels"> - {currentLabel} - {maxLabel} + {current ? <Label className="current" text={current} /> : ''} + {max ? <Label className="max" text={max} /> : '' } </div> </div> ); }; + + onTooltipShow (e: any, item: any) { + const t = Preview.tooltipCaption(item.name, item.caption); + Preview.tooltipShow({ text: t, element: $(e.currentTarget) }); + }; }; diff --git a/src/ts/component/widget/index.tsx b/src/ts/component/widget/index.tsx index 3680f740d9..0b62d59a03 100644 --- a/src/ts/component/widget/index.tsx +++ b/src/ts/component/widget/index.tsx @@ -403,7 +403,7 @@ const WidgetIndex = observer(class WidgetIndex extends React.Component<Props> { }; case Constant.widgetId.recentEdit: { - filters.push({ operator: I.FilterOperator.And, relationKey: 'lastModifiedDate', condition: I.FilterCondition.Greater, value: space.createdDate + 60 }); + filters.push({ operator: I.FilterOperator.And, relationKey: 'lastModifiedDate', condition: I.FilterCondition.Greater, value: space.createdDate }); break; }; diff --git a/src/ts/docs/help/onboarding.ts b/src/ts/docs/help/onboarding.ts index b3f1bd0711..193469215b 100644 --- a/src/ts/docs/help/onboarding.ts +++ b/src/ts/docs/help/onboarding.ts @@ -1,4 +1,4 @@ -import { I, translate } from 'Lib'; +import { I, Onboarding, keyboard, translate } from 'Lib'; export default { mainGraph: () => ({ @@ -184,6 +184,9 @@ export default { dashboard: () => ({ category: translate('onboardingDashboard'), showConfetti: true, + onComplete: (force: boolean) => { + Onboarding.start('navigation', keyboard.isPopup(), force); + }, items: [ { description: ` @@ -353,4 +356,69 @@ export default { ], }), + setSettings: () => ( + { + items: [ + { + name: translate('onboardingDefaultTypeTitle'), + description: translate('onboardingDefaultTypeDescription'), + param: { + element: '#button-dataview-add-record-select', + horizontal: I.MenuDirection.Right, + offsetX: -4, + offsetY: 12, + }, + }, + + { + name: translate('onboardingCalendarTitle'), + description: translate('onboardingCalendarDescription'), + param: { + element: '#button-dataview-settings', + horizontal: I.MenuDirection.Right, + offsetX: -4, + offsetY: 12, + }, + }, + ], + } + ), + + templateSelect: () => ( + { + items: [ + { + name: translate('onboardingTemplateSelectTitle'), + description: translate('onboardingTemplateSelectDescription'), + }, + ], + + param: { + element: '#headerBanner', + horizontal: I.MenuDirection.Center, + offsetY: 12, + noButton: true, + }, + } + ), + + navigation: () => ( + { + items: [ + { + name: translate('onboardingSpaceSelectTitle'), + description: translate('onboardingSpaceSelectDescription'), + }, + ], + + param: { + element: '#navigationPanel #button-navigation-profile', + vertical: I.MenuDirection.Top, + horizontal: I.MenuDirection.Center, + offsetY: -24, + noButton: true, + }, + } + ), + }; diff --git a/src/ts/lib/action.ts b/src/ts/lib/action.ts index 7a3cdd156d..5defd3c7f7 100644 --- a/src/ts/lib/action.ts +++ b/src/ts/lib/action.ts @@ -221,10 +221,6 @@ class Action { return; }; - if (callBack) { - callBack(message); - }; - const { details } = message; const eventParam: any = { layout: object.layout }; @@ -255,6 +251,10 @@ class Action { detailStore.update(subId, { id: details.id, details }, false); analytics.event('ObjectInstall', eventParam); + + if (callBack) { + callBack(message); + }; }); }; @@ -545,16 +545,14 @@ class Action { const cb = () => { C.SpaceDelete(id, (message: any) => { - if (message.error.code) { - return; - }; - if (callBack) { callBack(message); }; - Preview.toastShow({ text: UtilCommon.sprintf(translate('spaceDeleteToast'), deleted.name) }); - analytics.event('DeleteSpace', { type: deleted.spaceType }); + if (!message.error.code) { + Preview.toastShow({ text: UtilCommon.sprintf(translate('spaceDeleteToast'), deleted.name) }); + analytics.event('DeleteSpace', { type: deleted.spaceType }); + }; }); }; diff --git a/src/ts/lib/api/command.ts b/src/ts/lib/api/command.ts index d0a0a4fc10..fe69f6c614 100644 --- a/src/ts/lib/api/command.ts +++ b/src/ts/lib/api/command.ts @@ -2,6 +2,7 @@ import Commands from 'protobuf/pb/protos/commands_pb'; import Model from 'protobuf/pkg/lib/pb/model/protos/models_pb'; import { detailStore } from 'Store'; import { I, UtilCommon, Mark, Storage, dispatcher, Encode, Mapper } from 'Lib'; +import Constant from 'json/constant.json'; const Rpc = Commands.Rpc; @@ -253,12 +254,11 @@ const FileListOffload = (ids: string[], notPinned: boolean, callBack?: (message: dispatcher.request(FileListOffload.name, request, callBack); }; -const FileSpaceUsage = (spaceId: string, callBack?: (message: any) => void) => { - const request = new Rpc.File.SpaceUsage.Request(); - request.setSpaceid(spaceId); +const FileNodeUsage = (callBack?: (message: any) => void) => { + const request = new Commands.Empty(); - dispatcher.request(FileSpaceUsage.name, request, callBack); + dispatcher.request(FileNodeUsage.name, request, callBack); }; const NavigationGetObjectInfoWithLinks = (pageId: string, callBack?: (message: any) => void) => { @@ -1173,7 +1173,7 @@ const ObjectCreate = (details: any, flags: I.ObjectFlag[], templateId: string, t request.setInternalflagsList(flags.map(Mapper.To.InternalFlag)); request.setTemplateid(templateId); request.setSpaceid(spaceId); - request.setObjecttypeuniquekey(typeKey); + request.setObjecttypeuniquekey(typeKey || Constant.default.typeKey); dispatcher.request(ObjectCreate.name, request, callBack); }; @@ -1607,7 +1607,6 @@ const ObjectApplyTemplate = (contextId: string, templateId: string, callBack?: ( dispatcher.request(ObjectApplyTemplate.name, request, callBack); }; - const ObjectShareByLink = (objectId: string, callBack?: (message: any) => void) => { const request = new Rpc.Object.ShareByLink.Request(); @@ -1826,7 +1825,7 @@ export { FileDownload, FileDrop, FileListOffload, - FileSpaceUsage, + FileNodeUsage, NavigationGetObjectInfoWithLinks, diff --git a/src/ts/lib/api/dispatcher.ts b/src/ts/lib/api/dispatcher.ts index 1d04a85764..a0ef69a7c4 100644 --- a/src/ts/lib/api/dispatcher.ts +++ b/src/ts/lib/api/dispatcher.ts @@ -1,6 +1,6 @@ import * as Sentry from '@sentry/browser'; import arrayMove from 'array-move'; -import { observable } from 'mobx'; +import { observable, set } from 'mobx'; import Commands from 'protobuf/pb/protos/commands_pb'; import Events from 'protobuf/pb/protos/events_pb'; import Service from 'protobuf/pb/protos/service/service_grpc_web_pb'; @@ -245,7 +245,16 @@ class Dispatcher { }; case 'fileSpaceUsage': { - commonStore.spaceStorageSet({ bytesUsed: data.getBytesusage() }); + const spaceId = data.getSpaceid(); + const { spaces } = commonStore.spaceStorage; + const space = spaces.find(it => it.spaceId == spaceId); + const bytesUsage = data.getBytesusage(); + + if (space) { + set(space, { bytesUsage }); + } else { + spaces.push({ spaceId, bytesUsage }); + }; break; }; @@ -255,7 +264,8 @@ class Dispatcher { }; case 'fileLimitReached': { - const { bytesUsed, bytesLimit, localUsage } = commonStore.spaceStorage; + const { bytesLimit, localUsage, spaces } = commonStore.spaceStorage; + const bytesUsed = spaces.reduce((res, current) => res += current.bytesUsage, 0); const percentageUsed = Math.floor(UtilCommon.getPercent(bytesUsed, bytesLimit)); if (percentageUsed >= 99) { @@ -1066,6 +1076,7 @@ class Dispatcher { if (undefined !== details.setOf) { blockStore.updateWidgetData(rootId); + $(window).trigger(`updateDataviewData.dataview`); }; blockStore.checkTypeSelect(rootId); diff --git a/src/ts/lib/api/response.ts b/src/ts/lib/api/response.ts index 770ecdb102..57c3f485f5 100644 --- a/src/ts/lib/api/response.ts +++ b/src/ts/lib/api/response.ts @@ -56,15 +56,24 @@ export const FileListOffload = (response: Rpc.File.ListOffload.Response) => { }; }; -export const FileSpaceUsage = (response: Rpc.File.SpaceUsage.Response) => { +export const FileNodeUsage = (response: Rpc.File.NodeUsage.Response) => { const usage = response.getUsage(); + + let res = {}; + + if (usage) { + res = Object.assign(res, { + bytesLimit: usage.getByteslimit(), + localUsage: usage.getLocalbytesusage(), + }); + }; return { - bytesUsed: usage.getBytesusage(), - bytesLeft: usage.getBytesleft(), - bytesLimit: usage.getByteslimit(), - filesCount: usage.getFilescount(), - localUsage: usage.getLocalbytesusage(), + ...res, + spaces: (response.getSpacesList() || []).map(it => ({ + spaceId: it.getSpaceid(), + bytesUsage: it.getBytesusage(), + })), }; }; diff --git a/src/ts/lib/onboarding.ts b/src/ts/lib/onboarding.ts index f2753e6b30..ffb6bfe19a 100644 --- a/src/ts/lib/onboarding.ts +++ b/src/ts/lib/onboarding.ts @@ -34,9 +34,11 @@ class Onboarding { noFlipY: true, noFlipX: true, onClose: () => { - this.start(this.getReminderKey(key), isPopup, force); - - Storage.setOnboarding(key); + Storage.setOnboarding(key); + + if (section.onComplete) { + section.onComplete(force); + }; }, data: { ...param.data, @@ -50,10 +52,6 @@ class Onboarding { }); }; - getReminderKey (key: string) { - return UtilCommon.toCamelCase([ key, 'reminder' ].join('-')); - }; - getParam (section: any, item: any, isPopup: boolean, force?: boolean): any { section.param = section.param || {}; item.param = item.param || {}; @@ -139,6 +137,10 @@ class Onboarding { return param; }; + + isCompleted (key: string): boolean { + return Storage.getOnboarding(key); + }; }; diff --git a/src/ts/lib/relation.ts b/src/ts/lib/relation.ts index f9a3c75414..cd9e13c95c 100644 --- a/src/ts/lib/relation.ts +++ b/src/ts/lib/relation.ts @@ -1,4 +1,4 @@ -import { I, UtilCommon, UtilFile, UtilDate, translate, Dataview } from 'Lib'; +import { I, UtilCommon, UtilFile, UtilDate, translate, Dataview, UtilObject } from 'Lib'; import { dbStore, detailStore } from 'Store'; import Constant from 'json/constant.json'; @@ -513,6 +513,35 @@ class Relation { return value; }; + getParamForNewObject (name: string, relation: any): { flags: I.ObjectFlag[], details: any } { + const details: any = { name }; + const flags: I.ObjectFlag[] = [ I.ObjectFlag.SelectTemplate ]; + const objectTypes = this.getArrayValue(relation.objectTypes); + + let type = null; + + if (objectTypes.length) { + const allowedTypes = objectTypes.map(id => dbStore.getTypeById(id)).filter(it => it && !UtilObject.isFileOrSystemLayout(it.recommendedLayout)); + const l = allowedTypes.length; + + if (l) { + type = allowedTypes[0]; + + if (l > 1) { + flags.push(I.ObjectFlag.SelectType); + }; + }; + }; + + if (type) { + details.type = type.id; + } else { + flags.push(I.ObjectFlag.SelectType); + }; + + return { flags, details } + }; + systemKeys () { return require('lib/json/generated/systemRelations.json'); }; diff --git a/src/ts/lib/storage.ts b/src/ts/lib/storage.ts index 274492d924..d67fe35fb8 100644 --- a/src/ts/lib/storage.ts +++ b/src/ts/lib/storage.ts @@ -5,6 +5,7 @@ const SPACE_KEYS = [ 'toggle', 'lastOpened', 'scroll', + 'defaultType', ]; class Storage { @@ -212,4 +213,4 @@ class Storage { }; -export default new Storage(); \ No newline at end of file +export default new Storage(); diff --git a/src/ts/lib/survey.ts b/src/ts/lib/survey.ts index c1e1104ab2..849eef3f9a 100644 --- a/src/ts/lib/survey.ts +++ b/src/ts/lib/survey.ts @@ -99,7 +99,7 @@ class Survey { return; }; - if (!popupStore.isOpen() && (cancelTime || !lastCompleted)) { + if (!popupStore.isOpen() && (cancelTime || !lastCompleted) && !completeTime) { this.show(I.SurveyType.Pmf); }; }; diff --git a/src/ts/lib/util/data.ts b/src/ts/lib/util/data.ts index babe3fb3db..0e545db975 100644 --- a/src/ts/lib/util/data.ts +++ b/src/ts/lib/util/data.ts @@ -219,7 +219,7 @@ class UtilData { keyboard.initPinCheck(); analytics.event('OpenAccount'); - C.FileSpaceUsage(space, (message: any) => { + C.FileNodeUsage((message: any) => { if (!message.error.code) { commonStore.spaceStorageSet(message); }; diff --git a/src/ts/lib/util/file.ts b/src/ts/lib/util/file.ts index 53406d2a92..282cbb0633 100644 --- a/src/ts/lib/util/file.ts +++ b/src/ts/lib/util/file.ts @@ -2,6 +2,15 @@ import loadImage from 'blueimp-load-image'; import { UtilCommon } from 'Lib'; import Constant from 'json/constant.json'; +const SIZE_UNIT = 1024; +const UNITS = { + 1: 'B', + 2: 'KB', + 3: 'MB', + 4: 'GB', + 5: 'TB', +}; + class UtilFile { fromPath (path: string) { @@ -15,27 +24,22 @@ class UtilFile { return file; }; - size (v: number) { + size (v: number): string { v = Number(v) || 0; - const trimmer = (n, afterComma) => { - return Number.isInteger(n) ? 0 : afterComma; + let ret = 0; + let unit = ''; + + for (let i = UtilCommon.objectLength(UNITS); i >= 1; --i) { + const n = v / Math.pow(SIZE_UNIT, i - 1); + if ((n >= 1) || (i == 1)) { + ret = n; + unit = UNITS[i]; + break; + }; }; - const unit = 1000; - const g = v / (unit * unit * unit); - const m = v / (unit * unit); - const k = v / unit; - if (g >= 1) { - v = UtilCommon.sprintf(`%0.${trimmer(g, 2)}fGB`, UtilCommon.round(g, trimmer(g, 2))); - } else if (m > 1) { - v = UtilCommon.sprintf(`%0.${trimmer(m, 1)}fMB`, UtilCommon.round(m, trimmer(m, 1))); - } else if (k > 1) { - v = UtilCommon.sprintf(`%0.${trimmer(k, 1)}fKB`, UtilCommon.round(k, trimmer(k, 1))); - } else { - v = UtilCommon.sprintf('%dB', UtilCommon.round(v, 0)); - }; - return v; + return UtilCommon.formatNumber(Number(UtilCommon.sprintf(`%0.2f`, ret))) + unit; }; icon (obj: any): string { diff --git a/src/ts/lib/util/object.ts b/src/ts/lib/util/object.ts index 1f3fcf8bd7..d690aa7dc9 100644 --- a/src/ts/lib/util/object.ts +++ b/src/ts/lib/util/object.ts @@ -399,6 +399,7 @@ class UtilObject { I.ObjectLayout.Relation, I.ObjectLayout.Option, I.ObjectLayout.Dashboard, + I.ObjectLayout.Space, I.ObjectLayout.SpaceView, ]; }; diff --git a/src/ts/lib/util/router.ts b/src/ts/lib/util/router.ts index 51694c1851..76fa4e4644 100644 --- a/src/ts/lib/util/router.ts +++ b/src/ts/lib/util/router.ts @@ -141,6 +141,7 @@ class UtilRouter { analytics.removeContext(); blockStore.clear(blockStore.widgets); + commonStore.defaultType = ''; Storage.set('spaceId', id); UtilData.onInfo(message.info); diff --git a/src/ts/model/block.ts b/src/ts/model/block.ts index 24ce52576e..b08ced1134 100644 --- a/src/ts/model/block.ts +++ b/src/ts/model/block.ts @@ -123,7 +123,7 @@ class Block implements I.Block { }; canBecomeWidget (): boolean { - return this.isLink() || this.isBookmark() || this.isFile() || this.isText(); + return this.isLink() || this.isBookmark() || this.isFile() || this.isText() || this.isDataview(); }; isSystem () { diff --git a/src/ts/store/common.ts b/src/ts/store/common.ts index f039aed0f1..093ad9906c 100644 --- a/src/ts/store/common.ts +++ b/src/ts/store/common.ts @@ -1,9 +1,8 @@ import { action, computed, intercept, makeObservable, observable, set } from 'mobx'; import $ from 'jquery'; -import { analytics, I, Storage, UtilCommon, UtilObject, Renderer } from 'Lib'; -import { blockStore, dbStore } from 'Store'; +import { I, Storage, UtilCommon, UtilObject, Renderer } from 'Lib'; +import { dbStore } from 'Store'; import Constant from 'json/constant.json'; -import * as Sentry from '@sentry/browser'; interface Filter { from: number; @@ -22,9 +21,12 @@ interface Graph { }; interface SpaceStorage { - bytesUsed: number; bytesLimit: number; localUsage: number; + spaces: { + spaceId: string; + bytesUsage: number; + }[], }; class CommonStore { @@ -68,9 +70,9 @@ class CommonStore { }; public spaceStorageObj: SpaceStorage = { - bytesUsed: 0, bytesLimit: 0, localUsage: 0, + spaces: [], }; constructor() { @@ -144,11 +146,11 @@ class CommonStore { }; get type(): string { - const key = String(this.defaultType || Storage.get('defaultType') || Constant.typeKey.note); + const key = String(this.defaultType || Storage.get('defaultType') || Constant.default.typeKey); let type = dbStore.getTypeByKey(key); if (!type || !type.isInstalled || !UtilObject.getPageLayouts().includes(type.recommendedLayout)) { - type = dbStore.getTypeByKey(Constant.typeKey.note); + type = dbStore.getTypeByKey(Constant.default.typeKey); }; return type ? type.id : ''; @@ -191,16 +193,8 @@ class CommonStore { }; get spaceStorage (): SpaceStorage { - let { bytesUsed, localUsage } = this.spaceStorageObj; - - if (bytesUsed <= 1024 * 1024) { - bytesUsed = 0; - }; - if (localUsage <= 1024 * 1024) { - localUsage = 0; - }; - - return { ...this.spaceStorageObj, bytesUsed, localUsage }; + const spaces = this.spaceStorageObj.spaces || []; + return { ...this.spaceStorageObj, spaces }; }; get interfaceLang (): string { diff --git a/src/ts/store/db.ts b/src/ts/store/db.ts index 317ffe1efd..51ee6a6934 100644 --- a/src/ts/store/db.ts +++ b/src/ts/store/db.ts @@ -1,6 +1,6 @@ import { observable, action, set, intercept, makeObservable } from 'mobx'; -import { I, M, UtilCommon, Dataview } from 'ts/lib'; -import { detailStore, commonStore } from 'ts/store'; +import { I, M, UtilCommon, UtilData, Dataview } from 'Lib'; +import { detailStore, commonStore, blockStore } from 'Store'; import Constant from 'json/constant.json'; enum KeyMapType { @@ -295,7 +295,25 @@ class DbStore { getRelations () { return dbStore.getRecords(Constant.subId.relation, '').map(id => this.getRelationById(id)). - filter(it => it && !it.isArchived); + filter(it => it && !it.isArchived && !it.isDeleted); + }; + + getSpaces () { + const subId = Constant.subId.space; + const { spaceview } = blockStore; + + let items = dbStore.getRecords(subId, '').map(id => detailStore.get(subId, id, UtilData.spaceRelationKeys())); + + items = items.filter(it => (it.spaceAccountStatus != I.SpaceStatus.Deleted) && (it.spaceLocalStatus == I.SpaceStatus.Ok)); + items = items.map(it => ({ ...it, isActive: spaceview == it.id })); + + items.sort((c1, c2) => { + if (c1.isActive && !c2.isActive) return -1; + if (!c1.isActive && c2.isActive) return 1; + return 0; + }); + + return items; }; getObjectRelationKeys (rootId: string, blockId: string): any[] {