From 6365105698d94f9bbd75cd642f6bb7f159d35771 Mon Sep 17 00:00:00 2001 From: Andrew Simachev Date: Fri, 11 Oct 2024 10:14:49 +0200 Subject: [PATCH 01/51] JS-5425: Sidebar right panel --- src/scss/component/header.scss | 6 +- src/scss/component/sidebar.scss | 5 +- src/scss/media/print.scss | 2 +- src/scss/page/auth.scss | 8 +- src/scss/page/main/onboarding.scss | 12 +-- src/scss/page/main/void.scss | 7 +- src/ts/app.tsx | 5 +- src/ts/component/drag/provider.tsx | 4 +- src/ts/component/index.tsx | 8 +- src/ts/component/page/index.tsx | 6 +- .../component/sidebar/{index.tsx => left.tsx} | 6 +- src/ts/component/sidebar/object.tsx | 8 +- src/ts/component/sidebar/right.tsx | 45 ++++++++++ src/ts/component/widget/tree/index.tsx | 2 +- src/ts/component/widget/view/list/index.tsx | 2 +- src/ts/lib/sidebar.ts | 83 +++++++++++-------- src/ts/store/common.ts | 12 +++ 17 files changed, 156 insertions(+), 65 deletions(-) rename src/ts/component/sidebar/{index.tsx => left.tsx} (97%) create mode 100644 src/ts/component/sidebar/right.tsx diff --git a/src/scss/component/header.scss b/src/scss/component/header.scss index a8ff19f100..cdc13e4e30 100644 --- a/src/scss/component/header.scss +++ b/src/scss/component/header.scss @@ -63,18 +63,18 @@ .side.left { transition: padding-left $transitionSidebarTime linear; } } -.header:not(.withSidebar) { +.header:not(.withSidebarLeft) { .side.left { padding-left: 120px; } } html:not(.platformMac) { - .header:not(.withSidebar) { + .header:not(.withSidebarLeft) { .side.left { padding-left: 52px; } } } body.isFullScreen { - .header:not(.withSidebar) { + .header:not(.withSidebarLeft) { .side.left { padding-left: 52px; } } } diff --git a/src/scss/component/sidebar.scss b/src/scss/component/sidebar.scss index 2c2d70dd1e..72fc487f21 100644 --- a/src/scss/component/sidebar.scss +++ b/src/scss/component/sidebar.scss @@ -15,11 +15,14 @@ #sidebarToggle.sidebarAnimation { transition: left $transitionSidebarTime linear; } #sidebarToggle:hover, #sidebarToggle.hover { background-color: var(--color-shape-highlight-medium) !important; background-image: url('~img/icon/widget/toggle1.svg'); } -.sidebar { position: fixed; z-index: 21; user-select: none; transition: none; top: 0px; left: 0px; height: 100%; } +.sidebar { position: fixed; z-index: 21; user-select: none; transition: none; top: 0px; height: 100%; } .sidebar.anim { transition-property: width; transition-duration: $transitionSidebarTime; transition-timing-function: linear; } .sidebar.withVault { left: $vaultWidthCollapsed; } .sidebar.isClosed { left: 0px !important; } +.sidebar.left { left: 0px; } +.sidebar.right { right: 0px; width: 336px; background: green; } + .sidebar { @import "./sidebar/widget"; @import "./sidebar/object"; diff --git a/src/scss/media/print.scss b/src/scss/media/print.scss index f348e5ad2e..25cb8bd01b 100644 --- a/src/scss/media/print.scss +++ b/src/scss/media/print.scss @@ -15,7 +15,7 @@ html.printMedia { .footer, .notifications, #navigationPanel, - #sidebar, + .sidebar, .sidebarDummy, .progress, .toast, diff --git a/src/scss/page/auth.scss b/src/scss/page/auth.scss index e6dfcfe31c..d1a494597c 100644 --- a/src/scss/page/auth.scss +++ b/src/scss/page/auth.scss @@ -25,7 +25,13 @@ html.bodyIndex, html.bodyAuth { --shadow: 0px 0px 0px 1px var(--color-button-stroke) !important; body { background: var(--color-bg-primary); color: var(--color-text-secondary); overflow: hidden; } - #navigationPanel, #notifications, #sidebar, #vault, #sidebarToggle { display: none !important; } + + #vault, + #navigationPanel, + #sidebarToggle, + #notifications, + .sidebar, + .sidebarDummy { display: none !important; } .popup { .innerWrap { background: var(--color-popup) !important;; box-shadow: var(--shadow) !important; color: var(--color-text-primary) !important; } diff --git a/src/scss/page/main/onboarding.scss b/src/scss/page/main/onboarding.scss index e38d23465f..6746a33616 100644 --- a/src/scss/page/main/onboarding.scss +++ b/src/scss/page/main/onboarding.scss @@ -1,13 +1,13 @@ @import "~scss/_mixins"; .bodyMain.bodyMainOnboarding { - #vault, - #sidebar, - #sidebarToggle, - #navigationPanel, - #sidebarDummy { display: none; } + #vault, + #navigationPanel, + #sidebarToggle, + .sidebar, + .sidebarDummy { display: none; } - body { background: #000; } + body { background: #000; } } $stepTransition: 1s $easeInQuint; diff --git a/src/scss/page/main/void.scss b/src/scss/page/main/void.scss index ab84b7ef63..7e8b9c7f09 100644 --- a/src/scss/page/main/void.scss +++ b/src/scss/page/main/void.scss @@ -1,7 +1,10 @@ @import "~scss/_mixins"; -.bodyMainVoid { - .navigationPanel, #sidebar { display: none; } +.bodyMain.bodyMainVoid { + #navigationPanel, + #sidebarToggle, + .sidebar, + .sidebarDummy { display: none; } } .pageMainVoid { diff --git a/src/ts/app.tsx b/src/ts/app.tsx index 8e5563885b..7c3861e216 100644 --- a/src/ts/app.tsx +++ b/src/ts/app.tsx @@ -8,7 +8,7 @@ import { Router, Route, Switch } from 'react-router-dom'; import { Provider } from 'mobx-react'; import { configure, spy } from 'mobx'; import { enableLogging } from 'mobx-logger'; -import { Page, SelectionProvider, DragProvider, Progress, Toast, Preview as PreviewIndex, Navigation, ListPopup, ListMenu, ListNotification, Sidebar, Vault, ShareTooltip, Loader } from 'Component'; +import { Page, SelectionProvider, DragProvider, Progress, Toast, Preview as PreviewIndex, Navigation, ListPopup, ListMenu, ListNotification, SidebarLeft, SidebarRight, Vault, ShareTooltip, Loader } from 'Component'; import { I, C, S, U, J, keyboard, Storage, analytics, dispatcher, translate, Renderer, focus, Preview, Mark, Animation, Onboarding, Survey, Encode, Decode, sidebar } from 'Lib'; require('pdfjs-dist/build/pdf.worker.entry.js'); @@ -139,7 +139,8 @@ class RoutePage extends React.Component { S.Common.refSet('navigation', ref)} key="navigation" {...this.props} /> - + S.Common.refSet('sidebarLeft', ref)} key="sidebarLeft" {...this.props} /> + S.Common.refSet('sidebarRight', ref)} key="sidebarRight" {...this.props} /> diff --git a/src/ts/component/drag/provider.tsx b/src/ts/component/drag/provider.tsx index a9514d61ef..5284d8872f 100644 --- a/src/ts/component/drag/provider.tsx +++ b/src/ts/component/drag/provider.tsx @@ -200,7 +200,7 @@ const DragProvider = observer(class DragProvider extends React.Component const win = $(window); const node = $(this.node); const container = U.Common.getScrollContainer(isPopup); - const sidebar = $('#sidebar'); + const sidebar = $('#sidebarLeft'); const layer = $('#dragLayer'); const body = $('body'); const dataTransfer = { rootId, dropType, ids, withAlt: e.altKey }; @@ -264,7 +264,7 @@ const DragProvider = observer(class DragProvider extends React.Component const isPopup = keyboard.isPopup(); const node = $(this.node); const container = U.Common.getScrollContainer(isPopup); - const sidebar = $('#sidebar'); + const sidebar = $('#sidebarLeft'); const body = $('body'); this.refLayer.hide(); diff --git a/src/ts/component/index.tsx b/src/ts/component/index.tsx index 20bbc6ded5..7080941c4e 100644 --- a/src/ts/component/index.tsx +++ b/src/ts/component/index.tsx @@ -21,10 +21,12 @@ import ListObjectManager from './list/objectManager'; import Header from './header'; import Footer from './footer'; -import Sidebar from './sidebar'; import Vault from './vault'; import Widget from './widget'; +import SidebarLeft from './sidebar/left'; +import SidebarRight from './sidebar/right'; + import Menu from './menu'; import MenuItemVertical from './menu/item/vertical'; @@ -162,7 +164,9 @@ export { Graph, Cell, - Sidebar, + SidebarLeft, + SidebarRight, + Vault, Widget, diff --git a/src/ts/component/page/index.tsx b/src/ts/component/page/index.tsx index 24d16bdb3c..00a486084b 100644 --- a/src/ts/component/page/index.tsx +++ b/src/ts/component/page/index.tsx @@ -76,7 +76,6 @@ const Page = observer(class Page extends React.Component { const { page, action } = this.getMatchParams(); const path = [ page, action ].join('/'); const isMain = this.isMain(); - const showSidebar = isMain; if (account) { const { status } = account || {}; @@ -103,13 +102,14 @@ const Page = observer(class Page extends React.Component { ); let content = null; - if (isPopup || !showSidebar) { + if (isPopup || !isMain) { content = wrap; } else { content = (
-
+
{wrap} +
); }; diff --git a/src/ts/component/sidebar/index.tsx b/src/ts/component/sidebar/left.tsx similarity index 97% rename from src/ts/component/sidebar/index.tsx rename to src/ts/component/sidebar/left.tsx index 19990926a6..235cf71c32 100644 --- a/src/ts/component/sidebar/index.tsx +++ b/src/ts/component/sidebar/left.tsx @@ -8,7 +8,7 @@ import { I, U, J, S, keyboard, Preview, sidebar } from 'Lib'; import SidebarWidget from './widget'; import SidebarObject from './object'; -const Sidebar = observer(class Sidebar extends React.Component { +const SidebarLeft = observer(class SidebarLeft extends React.Component { private _isMounted = false; node = null; @@ -50,7 +50,7 @@ const Sidebar = observer(class Sidebar extends React.Component {
this.node = node} - id="sidebar" + id="sidebarLeft" className={cn.join(' ')} > {showObject ? this.refObject = ref} {...this.props} /> : this.refWidget = ref} />} @@ -203,4 +203,4 @@ const Sidebar = observer(class Sidebar extends React.Component { }); -export default Sidebar; \ No newline at end of file +export default SidebarLeft; \ No newline at end of file diff --git a/src/ts/component/sidebar/object.tsx b/src/ts/component/sidebar/object.tsx index 4f35cf5768..e1a7215a47 100644 --- a/src/ts/component/sidebar/object.tsx +++ b/src/ts/component/sidebar/object.tsx @@ -468,7 +468,7 @@ const SidebarObject = observer(class SidebarObject extends React.Component<{}, S const { x, y } = keyboard.mouse.page; S.Menu.open('dataviewContext', { - element: `#sidebar #containerObject #item-${item.id}`, + element: `#sidebarLeft #containerObject #item-${item.id}`, rect: { width: 0, height: 0, x: x + 4, y }, data: { objectIds, @@ -487,7 +487,7 @@ const SidebarObject = observer(class SidebarObject extends React.Component<{}, S let menuContext = null; S.Menu.open('select', { - element: '#sidebar #containerObject #button-object-more', + element: '#sidebarLeft #containerObject #button-object-more', horizontal: I.MenuDirection.Right, offsetY: 4, className: 'fixed', @@ -645,7 +645,7 @@ const SidebarObject = observer(class SidebarObject extends React.Component<{}, S const width = node.width() - 32; S.Menu.open('dataviewCreateBookmark', { - element: '#sidebar #containerObject #button-object-create', + element: '#sidebarLeft #containerObject #button-object-create', offsetY: 4, width, className: 'fixed', @@ -664,7 +664,7 @@ const SidebarObject = observer(class SidebarObject extends React.Component<{}, S const width = node.width() - 32; S.Menu.open('blockRelationEdit', { - element: '#sidebar #containerObject #button-object-create', + element: '#sidebarLeft #containerObject #button-object-create', offsetY: 4, width, className: 'fixed', diff --git a/src/ts/component/sidebar/right.tsx b/src/ts/component/sidebar/right.tsx new file mode 100644 index 0000000000..db16277bd7 --- /dev/null +++ b/src/ts/component/sidebar/right.tsx @@ -0,0 +1,45 @@ +import * as React from 'react'; +import { observer } from 'mobx-react'; +import { S } from 'Lib'; + +const SidebarRight = observer(class SidebarRight extends React.Component { + + private _isMounted = false; + node = null; + + constructor (props) { + super(props); + + }; + + render() { + const { showSidebarRight } = S.Common; + + if (!showSidebarRight) { + return null; + }; + + return ( +
this.node = node} + id="sidebarRight" + className="sidebar right" + > +
+ ); + }; + + componentDidMount (): void { + this._isMounted = true; + }; + + componentDidUpdate (): void { + }; + + componentWillUnmount (): void { + this._isMounted = false; + }; + +}); + +export default SidebarRight; \ No newline at end of file diff --git a/src/ts/component/widget/tree/index.tsx b/src/ts/component/widget/tree/index.tsx index fd8cae5606..7e9c95dbee 100644 --- a/src/ts/component/widget/tree/index.tsx +++ b/src/ts/component/widget/tree/index.tsx @@ -468,7 +468,7 @@ const WidgetTree = observer(class WidgetTree extends React.Component { - const container = $('#sidebar #containerWidget #list'); + const container = $('#sidebarLeft #containerWidget #list'); const obj = $(`#widget-${parent.id}`); const node = $(this.node); const head = obj.find('.head'); diff --git a/src/ts/lib/sidebar.ts b/src/ts/lib/sidebar.ts index 02790c7027..6e6e4d6088 100644 --- a/src/ts/lib/sidebar.ts +++ b/src/ts/lib/sidebar.ts @@ -12,12 +12,16 @@ class Sidebar { width: 0, isClosed: false, }; - obj: JQuery = null; + + objLeft: JQuery = null; + objRight: JQuery = null; + dummyLeft: JQuery = null; + dummyRight: JQuery = null + page: JQuery = null; header: JQuery = null; footer: JQuery = null; loader: JQuery = null; - dummy: JQuery = null; toggleButton: JQuery = null; vault: JQuery = null; isAnimating = false; @@ -46,22 +50,25 @@ class Sidebar { if (this.data.isClosed) { vault.addClass('isClosed'); - this.obj.addClass('isClosed'); + this.objLeft.addClass('isClosed'); } else { vault.removeClass('isClosed'); - this.obj.removeClass('isClosed'); + this.objLeft.removeClass('isClosed'); }; }; initObjects () { const vault = S.Common.getRef('vault'); - this.obj = $('#sidebar'); + this.objLeft = $('#sidebarLeft'); + this.objRight = $('#sidebarRight'); + this.dummyLeft = $('#sidebarDummyLeft'); + this.dummyRight = $('#sidebarDummyRight'); + this.page = $('#page.isFull'); this.header = this.page.find('#header'); this.footer = this.page.find('#footer'); this.loader = this.page.find('#loader'); - this.dummy = $('#sidebarDummy'); this.toggleButton = $('#sidebarToggle'); if (vault) { @@ -72,11 +79,11 @@ class Sidebar { close (): void { const { width, isClosed } = this.data; - if (!this.obj || !this.obj.length || this.isAnimating || isClosed) { + if (!this.objLeft || !this.objLeft.length || this.isAnimating || isClosed) { return; }; - this.obj.addClass('anim'); + this.objLeft.addClass('anim'); this.setElementsWidth(width); this.setAnimating(true); this.setStyle({ width: 0 }); @@ -85,7 +92,7 @@ class Sidebar { this.vaultHide(); this.removeAnimation(() => { - this.obj.addClass('isClosed'); + this.objLeft.addClass('isClosed'); window.clearTimeout(this.timeoutAnim); this.timeoutAnim = window.setTimeout(() => { @@ -97,7 +104,7 @@ class Sidebar { }; open (width?: number): void { - if (!this.obj || !this.obj.length || this.isAnimating || !this.data.isClosed) { + if (!this.objLeft || !this.objLeft.length || this.isAnimating || !this.data.isClosed) { return; }; @@ -107,8 +114,8 @@ class Sidebar { window.clearTimeout(this.timeoutAnim); this.timeoutAnim = window.setTimeout(() => { - this.obj.removeClass('isClosed'); - this.obj.addClass('anim'); + this.objLeft.removeClass('isClosed'); + this.objLeft.addClass('anim'); this.setStyle({ width }); this.set({ isClosed: false }); @@ -133,9 +140,9 @@ class Sidebar { }; setElementsWidth (width: any): void { - this.obj.find('#head').css({ width }); - this.obj.find('#body').css({ width }); - this.obj.find('#shareBanner').css({ width: (width ? width - 24 : '') }); + this.objLeft.find('#head').css({ width }); + this.objLeft.find('#body').css({ width }); + this.objLeft.find('#shareBanner').css({ width: (width ? width - 24 : '') }); }; setWidth (w: number): void { @@ -146,13 +153,13 @@ class Sidebar { }; private removeAnimation (callBack?: () => void): void { - if (!this.obj || !this.obj.length) { + if (!this.objLeft || !this.objLeft.length) { return; }; window.clearTimeout(this.timeoutAnim); this.timeoutAnim = window.setTimeout(() => { - this.obj.removeClass('anim'); + this.objLeft.removeClass('anim'); this.setElementsWidth(''); if (callBack) { @@ -164,7 +171,7 @@ class Sidebar { onMouseMove (): void { const { showVault, hideSidebar } = S.Common; - if (!this.obj || !this.obj.length || keyboard.isDragging) { + if (!this.objLeft || !this.objLeft.length || keyboard.isDragging) { return; }; @@ -209,50 +216,60 @@ class Sidebar { }; }; - resizePage (width: number, animate: boolean): void { + resizePage (widthLeft: number, animate: boolean): void { this.initObjects(); - if ((width === null) && this.obj && this.obj.length) { - width = this.obj.outerWidth(); + let widthRight = 0; + let toggleX = 16; + + if ((widthLeft === null) && this.objLeft && this.objLeft.length) { + widthLeft = this.objLeft.outerWidth(); + }; + + if (this.objRight && this.objRight.length) { + widthRight = this.objRight.outerWidth(); }; if (!keyboard.isMain() || keyboard.isMainVoid()) { - width = 0; + widthLeft = 0; + widthRight = 0; }; const { isClosed } = this.data; const { showVault, isFullScreen } = S.Common; const { ww } = U.Common.getWindowDimensions(); const vw = isClosed || !showVault || !keyboard.isMain() ? 0 : J.Size.vault.width; - const pageWidth = ww - width - vw; + + widthLeft += vw; + + const pageWidth = ww - widthLeft - widthRight; const ho = keyboard.isMainHistory() ? J.Size.history.panel : 0; const navigation = S.Common.getRef('navigation'); - let toggleX = 16; - if ((width && showVault) || (U.Common.isPlatformMac() && !isFullScreen)) { + if ((widthLeft && showVault) || (U.Common.isPlatformMac() && !isFullScreen)) { toggleX = 84; }; - this.header.css({ width: '' }).removeClass('withSidebar'); + this.header.css({ width: '' }); this.footer.css({ width: '' }); - this.dummy.css({ width: width + vw }); + this.dummyLeft.css({ width: widthLeft }); if (animate) { this.header.addClass('sidebarAnimation'); this.page.addClass('sidebarAnimation'); this.footer.addClass('sidebarAnimation'); - this.dummy.addClass('sidebarAnimation'); + this.dummyLeft.addClass('sidebarAnimation'); this.toggleButton.addClass('sidebarAnimation'); } else { this.header.removeClass('sidebarAnimation'); this.page.removeClass('sidebarAnimation'); this.footer.removeClass('sidebarAnimation'); - this.dummy.removeClass('sidebarAnimation'); + this.dummyLeft.removeClass('sidebarAnimation'); this.toggleButton.removeClass('sidebarAnimation'); }; - navigation?.position(width + vw, animate); - width ? this.header.addClass('withSidebar') : this.header.removeClass('withSidebar'); + navigation?.position(widthLeft, animate); + widthLeft ? this.header.addClass('withSidebarLeft') : this.header.removeClass('withSidebarLeft'); this.page.css({ width: pageWidth }); this.loader.css({ width: pageWidth, right: 0 }); @@ -285,13 +302,13 @@ class Sidebar { }; private setStyle (v: Partial): void { - if (!this.obj || !this.obj.length) { + if (!this.objLeft || !this.objLeft.length) { return; }; const width = v.isClosed ? 0 : v.width; - this.obj.css({ width }); + this.objLeft.css({ width }); }; /** diff --git a/src/ts/store/common.ts b/src/ts/store/common.ts index 17445be19c..46972354db 100644 --- a/src/ts/store/common.ts +++ b/src/ts/store/common.ts @@ -42,6 +42,7 @@ class CommonStore { public isOnlineValue = false; public shareTooltipValue = false; public showVaultValue = null; + public showSidebarRightValue = null; public hideSidebarValue = null; public showObjectValue = null; public gallery = { @@ -105,6 +106,7 @@ class CommonStore { showObjectValue: observable, spaceId: observable, membershipTiersList: observable, + showSidebarRightValue: observable, config: computed, progress: computed, preview: computed, @@ -118,6 +120,7 @@ class CommonStore { isOnline: computed, shareTooltip: computed, showVault: computed, + showSidebarRight: computed, gatewaySet: action, progressSet: action, progressClear: action, @@ -138,6 +141,7 @@ class CommonStore { membershipTiersListSet: action, showVaultSet: action, showObjectSet: action, + showSidebarRightSet: action, }); intercept(this.configObj as any, change => U.Common.intercept(this.configObj, change)); @@ -204,6 +208,10 @@ class CommonStore { return this.boolGet('hideSidebar'); }; + get showSidebarRight (): boolean { + return Boolean(this.showSidebarRightValue); + }; + get showObject (): boolean { return this.showObjectValue; }; @@ -394,6 +402,10 @@ class CommonStore { this.boolSet('hideSidebar', v); }; + showSidebarRightSet (v: boolean) { + this.showSidebarRightValue = Boolean(v); + }; + showObjectSet (v: boolean) { this.showObjectValue = v; }; From a5b9d0fe3a2e7a1d9f05fb4dc54afb8edfcaac2d Mon Sep 17 00:00:00 2001 From: Andrew Simachev Date: Fri, 11 Oct 2024 10:19:09 +0200 Subject: [PATCH 02/51] JS-5425: Sidebar right panel --- src/scss/component/sidebar.scss | 4 ++-- src/scss/component/sidebar/object.scss | 2 +- src/scss/component/sidebar/widget.scss | 5 +---- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/scss/component/sidebar.scss b/src/scss/component/sidebar.scss index 72fc487f21..98454b5afa 100644 --- a/src/scss/component/sidebar.scss +++ b/src/scss/component/sidebar.scss @@ -15,13 +15,13 @@ #sidebarToggle.sidebarAnimation { transition: left $transitionSidebarTime linear; } #sidebarToggle:hover, #sidebarToggle.hover { background-color: var(--color-shape-highlight-medium) !important; background-image: url('~img/icon/widget/toggle1.svg'); } -.sidebar { position: fixed; z-index: 21; user-select: none; transition: none; top: 0px; height: 100%; } +.sidebar { position: fixed; z-index: 21; user-select: none; transition: none; top: 0px; height: 100%; background-color: var(--color-shape-tertiary); } .sidebar.anim { transition-property: width; transition-duration: $transitionSidebarTime; transition-timing-function: linear; } .sidebar.withVault { left: $vaultWidthCollapsed; } .sidebar.isClosed { left: 0px !important; } .sidebar.left { left: 0px; } -.sidebar.right { right: 0px; width: 336px; background: green; } +.sidebar.right { right: 0px; width: 348px; } .sidebar { @import "./sidebar/widget"; diff --git a/src/scss/component/sidebar/object.scss b/src/scss/component/sidebar/object.scss index 021a1ba34f..966a863cb4 100644 --- a/src/scss/component/sidebar/object.scss +++ b/src/scss/component/sidebar/object.scss @@ -1,4 +1,4 @@ -> #containerObject { width: 100%; height: 100%; overflow: hidden; background-color: var(--color-shape-tertiary); padding: 52px 12px 12px 12px; } +> #containerObject { width: 100%; height: 100%; overflow: hidden; padding: 52px 12px 12px 12px; } > #containerObject { > .inner { display: flex; flex-direction: column; width: 100%; height: 100%; background: var(--color-bg-primary); border-radius: 12px; } > .inner { diff --git a/src/scss/component/sidebar/widget.scss b/src/scss/component/sidebar/widget.scss index f299edfff5..1ed64ecedc 100644 --- a/src/scss/component/sidebar/widget.scss +++ b/src/scss/component/sidebar/widget.scss @@ -1,7 +1,4 @@ -> #containerWidget { - height: 100%; width: 100%; display: flex; flex-direction: column; overflow: hidden; position: relative; z-index: 1; flex-shrink: 0; - background-color: var(--color-shape-tertiary); -} +> #containerWidget { height: 100%; width: 100%; display: flex; flex-direction: column; overflow: hidden; position: relative; z-index: 1; flex-shrink: 0; } > #containerWidget { > .head { display: flex; flex-direction: row; align-items: center; justify-content: center; padding: 0px 12px; height: 52px; From 4b60b4ebfd7247802efb23f054c4f84a4b6aa85d Mon Sep 17 00:00:00 2001 From: Andrew Simachev Date: Fri, 11 Oct 2024 10:26:43 +0200 Subject: [PATCH 03/51] add type page --- src/ts/component/sidebar/page/type.tsx | 21 +++++++++++++++++++++ src/ts/component/sidebar/right.tsx | 24 +++++++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/ts/component/sidebar/page/type.tsx diff --git a/src/ts/component/sidebar/page/type.tsx b/src/ts/component/sidebar/page/type.tsx new file mode 100644 index 0000000000..d4c0f9672f --- /dev/null +++ b/src/ts/component/sidebar/page/type.tsx @@ -0,0 +1,21 @@ +import * as React from 'react'; +import { observer } from 'mobx-react'; + +const SidebarPageType = observer(class SidebarPageType extends React.Component { + + node = null; + + constructor (props) { + super(props); + + }; + + render() { + return ( +
Edit Type
+ ); + }; + +}); + +export default SidebarPageType; \ No newline at end of file diff --git a/src/ts/component/sidebar/right.tsx b/src/ts/component/sidebar/right.tsx index db16277bd7..2870572efa 100644 --- a/src/ts/component/sidebar/right.tsx +++ b/src/ts/component/sidebar/right.tsx @@ -2,10 +2,24 @@ import * as React from 'react'; import { observer } from 'mobx-react'; import { S } from 'Lib'; -const SidebarRight = observer(class SidebarRight extends React.Component { +import PageType from './page/type'; + +interface State { + page: string; +}; + +const Components = { + type: PageType, +}; + +const SidebarRight = observer(class SidebarRight extends React.Component<{}, State> { private _isMounted = false; node = null; + refChild = null; + state = { + page: '', + }; constructor (props) { super(props); @@ -14,17 +28,21 @@ const SidebarRight = observer(class SidebarRight extends React.Component { render() { const { showSidebarRight } = S.Common; + const { page } = this.state; if (!showSidebarRight) { return null; }; + const Component = Components[page]; + return (
this.node = node} id="sidebarRight" className="sidebar right" > + {Component ? this.refChild = ref} {...this.props} /> : ''}
); }; @@ -40,6 +58,10 @@ const SidebarRight = observer(class SidebarRight extends React.Component { this._isMounted = false; }; + setPage (page: string): void { + this.setState({ page }); + }; + }); export default SidebarRight; \ No newline at end of file From f8adb772864782d39b75c3a9bc5bc93594679ff2 Mon Sep 17 00:00:00 2001 From: Andrew Simachev Date: Fri, 11 Oct 2024 10:39:46 +0200 Subject: [PATCH 04/51] inner pages --- src/scss/component/sidebar.scss | 1 + src/scss/component/sidebar/page.scss | 2 ++ src/ts/component/header/main/object.tsx | 11 +++++++++-- src/ts/component/sidebar/right.tsx | 9 +++++++-- 4 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 src/scss/component/sidebar/page.scss diff --git a/src/scss/component/sidebar.scss b/src/scss/component/sidebar.scss index 98454b5afa..f31086b202 100644 --- a/src/scss/component/sidebar.scss +++ b/src/scss/component/sidebar.scss @@ -26,6 +26,7 @@ .sidebar { @import "./sidebar/widget"; @import "./sidebar/object"; + @import "./sidebar/page"; .resize-h { width: 10px; height: 100%; cursor: col-resize; z-index: 2; flex-shrink: 0; position: absolute; right: -5px; top: 0px; } .resize-h { diff --git a/src/scss/component/sidebar/page.scss b/src/scss/component/sidebar/page.scss new file mode 100644 index 0000000000..f65492a301 --- /dev/null +++ b/src/scss/component/sidebar/page.scss @@ -0,0 +1,2 @@ +> .sidebarPage { padding: 8px 16px; } +> .sidebarPage {} \ No newline at end of file diff --git a/src/ts/component/header/main/object.tsx b/src/ts/component/header/main/object.tsx index ef0a0fc493..603293ed7b 100644 --- a/src/ts/component/header/main/object.tsx +++ b/src/ts/component/header/main/object.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { observer } from 'mobx-react'; import { Icon, IconObject, Sync, ObjectName, Label } from 'Component'; -import { I, S, U, J, keyboard, translate } from 'Lib'; +import { I, S, U, J, keyboard, translate, sidebar } from 'Lib'; import HeaderBanner from 'Component/page/elements/head/banner'; interface State { @@ -154,7 +154,14 @@ const HeaderMainObject = observer(class HeaderMainObject extends React.Component const { rootId } = this.props; const object = S.Detail.get(rootId, rootId, [ 'isArchived' ]); - this.props.onRelation({}, { readonly: object.isArchived }); + //this.props.onRelation({}, { readonly: object.isArchived }); + + // TODO: tmp code + window.setTimeout(() => { + S.Common.showSidebarRightSet(!S.Common.showSidebarRight); + sidebar.resizePage(null, false); + S.Common.getRef('sidebarRight').setPage('type'); + }, 100); }; updateTemplatesCnt () { diff --git a/src/ts/component/sidebar/right.tsx b/src/ts/component/sidebar/right.tsx index 2870572efa..40065ff9fa 100644 --- a/src/ts/component/sidebar/right.tsx +++ b/src/ts/component/sidebar/right.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { observer } from 'mobx-react'; -import { S } from 'Lib'; +import { I, U, S } from 'Lib'; import PageType from './page/type'; @@ -35,6 +35,7 @@ const SidebarRight = observer(class SidebarRight extends React.Component<{}, Sta }; const Component = Components[page]; + const cn = [ 'sidebarPage', U.Common.toCamelCase(`page-${page}`) ]; return (
- {Component ? this.refChild = ref} {...this.props} /> : ''} + {Component ? ( +
+ this.refChild = ref} {...this.props} /> +
+ ): ''}
); }; From 5c2c5c5da604474e87c5fb0d82eddc8d86de9d0d Mon Sep 17 00:00:00 2001 From: Andrew Simachev Date: Fri, 11 Oct 2024 11:06:03 +0200 Subject: [PATCH 05/51] inner pages --- src/scss/component/headSimple.scss | 2 +- src/ts/component/header/main/object.tsx | 9 +----- .../component/page/elements/head/simple.tsx | 32 +++++++++++++++---- src/ts/component/page/main/type.tsx | 15 ++++++++- src/ts/component/sidebar/page/type.tsx | 12 ++++--- src/ts/component/sidebar/right.tsx | 31 +++++------------- src/ts/interface/common.ts | 4 +++ 7 files changed, 61 insertions(+), 44 deletions(-) diff --git a/src/scss/component/headSimple.scss b/src/scss/component/headSimple.scss index aa445cc06d..cc9b3f7379 100644 --- a/src/scss/component/headSimple.scss +++ b/src/scss/component/headSimple.scss @@ -18,7 +18,7 @@ > .descr { @include text-paragraph; } } - .side.right { flex-shrink: 0; text-align: right; } + .side.right { flex-shrink: 0; text-align: right; gap: 0px 16px; display: flex; flex-direction: row; align-items: center; justify-content: flex-end; } .side.right { .button { white-space: nowrap; } } diff --git a/src/ts/component/header/main/object.tsx b/src/ts/component/header/main/object.tsx index 603293ed7b..7088e82654 100644 --- a/src/ts/component/header/main/object.tsx +++ b/src/ts/component/header/main/object.tsx @@ -154,14 +154,7 @@ const HeaderMainObject = observer(class HeaderMainObject extends React.Component const { rootId } = this.props; const object = S.Detail.get(rootId, rootId, [ 'isArchived' ]); - //this.props.onRelation({}, { readonly: object.isArchived }); - - // TODO: tmp code - window.setTimeout(() => { - S.Common.showSidebarRightSet(!S.Common.showSidebarRight); - sidebar.resizePage(null, false); - S.Common.getRef('sidebarRight').setPage('type'); - }, 100); + this.props.onRelation({}, { readonly: object.isArchived }); }; updateTemplatesCnt () { diff --git a/src/ts/component/page/elements/head/simple.tsx b/src/ts/component/page/elements/head/simple.tsx index 9426363966..5006309bce 100644 --- a/src/ts/component/page/elements/head/simple.tsx +++ b/src/ts/component/page/elements/head/simple.tsx @@ -10,6 +10,7 @@ interface Props { readonly?: boolean; noIcon?: boolean; onCreate?: () => void; + onEdit?: () => void; }; const EDITORS = [ @@ -35,7 +36,7 @@ const HeadSimple = observer(class Controls extends React.Component { }; render (): any { - const { rootId, onCreate, isContextMenuDisabled, readonly, noIcon } = this.props; + const { rootId, isContextMenuDisabled, readonly, noIcon, onCreate, onEdit } = this.props; const check = U.Data.checkDetails(rootId); const object = S.Detail.get(rootId, rootId, [ 'featuredRelations' ]); const featuredRelations = Relation.getArrayValue(object.featuredRelations); @@ -44,6 +45,7 @@ const HeadSimple = observer(class Controls extends React.Component { const blockFeatured: any = new M.Block({ id: 'featuredRelations', type: I.BlockType.Featured, childrenIds: [], fields: {}, content: {} }); const isTypeOrRelation = U.Object.isTypeOrRelationLayout(object.layout); + const isType = U.Object.isTypeLayout(object.layout); const isRelation = U.Object.isRelationLayout(object.layout); const canEditIcon = allowDetails && !U.Object.isRelationLayout(object.layout); const cn = [ 'headSimple', check.className ]; @@ -51,6 +53,7 @@ const HeadSimple = observer(class Controls extends React.Component { title: this.props.placeholder, description: translate('placeholderBlockDescription'), }; + const buttons = []; const Editor = (item: any) => ( { /> ); - let button = null; + let buttonEdit = null; + let buttonCreate = null; let descr = null; let featured = null; @@ -78,6 +82,7 @@ const HeadSimple = observer(class Controls extends React.Component { if (featuredRelations.includes('description')) { descr = ; }; + featured = ( { const text = isRelation ? translate('pageHeadSimpleCreateSet') : translate('commonCreate'); const arrow = !isRelation; - button =
- {button ? ( -
{button}
+ {buttons.length ? ( +
+ {buttons.map((Component, i) => )} +
) : ''}
); diff --git a/src/ts/component/page/main/type.tsx b/src/ts/component/page/main/type.tsx index 64ef2e1993..c63a56bb28 100644 --- a/src/ts/component/page/main/type.tsx +++ b/src/ts/component/page/main/type.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import $ from 'jquery'; import { observer } from 'mobx-react'; import { Icon, Header, Footer, Loader, ListObjectPreview, ListObject, Select, Deleted } from 'Component'; -import { I, C, S, U, J, focus, Action, analytics, Relation, translate } from 'Lib'; +import { I, C, S, U, J, focus, Action, analytics, Relation, translate, sidebar } from 'Lib'; import Controls from 'Component/page/elements/head/controls'; import HeadSimple from 'Component/page/elements/head/simple'; @@ -35,6 +35,7 @@ const PageMainType = observer(class PageMainType extends React.Component {showTemplates ? ( @@ -389,6 +391,17 @@ const PageMainType = observer(class PageMainType extends React.Component { + sidebar.resizePage(null, false); + }, 10); + }; + onObjectAdd () { const rootId = this.getRootId(); const type = S.Record.getTypeById(rootId); diff --git a/src/ts/component/sidebar/page/type.tsx b/src/ts/component/sidebar/page/type.tsx index d4c0f9672f..fc5752b76a 100644 --- a/src/ts/component/sidebar/page/type.tsx +++ b/src/ts/component/sidebar/page/type.tsx @@ -1,18 +1,22 @@ import * as React from 'react'; import { observer } from 'mobx-react'; +import { I, S } from 'Lib'; -const SidebarPageType = observer(class SidebarPageType extends React.Component { +const SidebarPageType = observer(class SidebarPageType extends React.Component { node = null; - constructor (props) { + constructor (props: I.SidebarPageComponent) { super(props); }; - render() { + render () { + const { rootId } = this.props; + const type = S.Record.getTypeById(rootId); + return ( -
Edit Type
+
Edit Type {type.name}
); }; diff --git a/src/ts/component/sidebar/right.tsx b/src/ts/component/sidebar/right.tsx index 40065ff9fa..05fbaff2d6 100644 --- a/src/ts/component/sidebar/right.tsx +++ b/src/ts/component/sidebar/right.tsx @@ -6,6 +6,7 @@ import PageType from './page/type'; interface State { page: string; + rootId: string; }; const Components = { @@ -14,21 +15,16 @@ const Components = { const SidebarRight = observer(class SidebarRight extends React.Component<{}, State> { - private _isMounted = false; node = null; refChild = null; state = { page: '', - }; - - constructor (props) { - super(props); - + rootId: '', }; render() { const { showSidebarRight } = S.Common; - const { page } = this.state; + const { page, rootId } = this.state; if (!showSidebarRight) { return null; @@ -45,28 +41,17 @@ const SidebarRight = observer(class SidebarRight extends React.Component<{}, Sta > {Component ? (
- this.refChild = ref} {...this.props} /> + this.refChild = ref} + {...this.props} + rootId={rootId} + />
): ''}
); }; - componentDidMount (): void { - this._isMounted = true; - }; - - componentDidUpdate (): void { - }; - - componentWillUnmount (): void { - this._isMounted = false; - }; - - setPage (page: string): void { - this.setState({ page }); - }; - }); export default SidebarRight; \ No newline at end of file diff --git a/src/ts/interface/common.ts b/src/ts/interface/common.ts index 4fc0379633..b409ed5f40 100644 --- a/src/ts/interface/common.ts +++ b/src/ts/interface/common.ts @@ -189,6 +189,10 @@ export interface ButtonComponent { onMouseEnter?(e: any): void; }; +export interface SidebarPageComponent { + rootId?: string; +}; + export enum SurveyType { Register = 0, Delete = 1, From af812bc8e7c97a3556b2a90368ee0914ea38c78b Mon Sep 17 00:00:00 2001 From: Andrew Simachev Date: Mon, 28 Oct 2024 11:23:20 +0100 Subject: [PATCH 06/51] updates --- src/json/text.json | 6 ++ src/scss/component/sidebar/page.scss | 23 +++++++- src/scss/component/sidebar/page/type.scss | 12 ++++ src/ts/component/menu/block/align.tsx | 7 ++- src/ts/component/menu/block/layout.tsx | 1 + src/ts/component/sidebar/page/type.tsx | 27 ++++++++- src/ts/component/sidebar/section/layout.tsx | 61 +++++++++++++++++++++ src/ts/component/sidebar/section/title.tsx | 29 ++++++++++ src/ts/interface/common.ts | 4 ++ src/ts/lib/util/menu.ts | 4 ++ 10 files changed, 169 insertions(+), 5 deletions(-) create mode 100644 src/scss/component/sidebar/page/type.scss create mode 100644 src/ts/component/sidebar/section/layout.tsx create mode 100644 src/ts/component/sidebar/section/title.tsx diff --git a/src/json/text.json b/src/json/text.json index 4c86fa74ab..b3e64d3c9b 100644 --- a/src/json/text.json +++ b/src/json/text.json @@ -1821,6 +1821,12 @@ "sidebarObjectSortUpdated": "Date updated", "sidebarObjectSortLastUsed": "Date last used", + "sidebarTypeTitle": "Editing type", + "sidebarSectionLayoutName": "Layout", + "sidebarSectionLayoutType": "Layout type", + "sidebarSectionLayoutAlign": "Header position", + "sidebarSectionLayoutWidth": "Layout width", + "unsplashString": "Photo by %s on %s", "templateBannner": "You are editing a template", diff --git a/src/scss/component/sidebar/page.scss b/src/scss/component/sidebar/page.scss index f65492a301..699d37e2a8 100644 --- a/src/scss/component/sidebar/page.scss +++ b/src/scss/component/sidebar/page.scss @@ -1,2 +1,21 @@ -> .sidebarPage { padding: 8px 16px; } -> .sidebarPage {} \ No newline at end of file +> .sidebarPage { + .section { background: var(--color-bg-primary); border-radius: 12px; } + + .section { + .title { @include text-paragraph; font-weight: 600; } + .label { padding: 5px 16px; @include text-small; font-weight: 500; color: var(--color-text-secondary); } + } + + .section.sectionTitle { + display: flex; flex-direction: row; gap: 0px 8px; align-items: center; @include text-paragraph; font-weight: 600; padding: 16px; + } + + .section.sectionLayout { padding: 8px 0px; } + .section.sectionLayout { + .label { } + + .item { padding: 3px 16px; display: flex; flex-direction: row; align-items: center; } + } +} + +@import "./page/type.scss"; \ No newline at end of file diff --git a/src/scss/component/sidebar/page/type.scss b/src/scss/component/sidebar/page/type.scss new file mode 100644 index 0000000000..a8e1000e24 --- /dev/null +++ b/src/scss/component/sidebar/page/type.scss @@ -0,0 +1,12 @@ +> .sidebarPage.pageType { + .head { + display: flex; flex-direction: row; align-items: center; justify-content: space-between; -webkit-app-region: no-drag; + padding: 12px 12px 16px 12px; + } + .head { + .side.left { flex-grow: 1; font-weight: 500; } + .side.right { flex-shrink: 0; display: flex; flex-direction: row; gap: 0px 8px; } + } + + .body { padding: 0px 12px 12px 12px; overflow: scroll; display: flex; flex-direction: column; gap: 12px 0px; } +} \ No newline at end of file diff --git a/src/ts/component/menu/block/align.tsx b/src/ts/component/menu/block/align.tsx index 255b0453b1..2fbe1a3f0d 100644 --- a/src/ts/component/menu/block/align.tsx +++ b/src/ts/component/menu/block/align.tsx @@ -53,7 +53,12 @@ class MenuBlockHAlign extends React.Component { const { data } = param; const { rootId } = data; const blockIds = data.blockIds || []; - const restricted = []; + + let restricted = []; + + if (data.restricted) { + restricted = restricted.concat(data.restricted || []); + }; for (const id of blockIds) { const block = S.Block.getLeaf(rootId, id); diff --git a/src/ts/component/menu/block/layout.tsx b/src/ts/component/menu/block/layout.tsx index 575be4a9ac..f444aabfb3 100644 --- a/src/ts/component/menu/block/layout.tsx +++ b/src/ts/component/menu/block/layout.tsx @@ -159,6 +159,7 @@ class MenuBlockLayout extends React.Component { menuParam.data = Object.assign(menuParam.data, { value: object.layoutAlign, + restricted: [ I.BlockHAlign.Justify ], onSelect: (align: I.BlockHAlign) => { U.Object.setAlign(rootId, align); diff --git a/src/ts/component/sidebar/page/type.tsx b/src/ts/component/sidebar/page/type.tsx index fc5752b76a..50eb820409 100644 --- a/src/ts/component/sidebar/page/type.tsx +++ b/src/ts/component/sidebar/page/type.tsx @@ -1,6 +1,10 @@ import * as React from 'react'; import { observer } from 'mobx-react'; -import { I, S } from 'Lib'; +import { Label, Button } from 'Component'; +import { I, S, translate } from 'Lib'; + +import SectionTitle from 'Component/sidebar/section/title'; +import SectionLayout from 'Component/sidebar/section/layout'; const SidebarPageType = observer(class SidebarPageType extends React.Component { @@ -15,8 +19,27 @@ const SidebarPageType = observer(class SidebarPageType extends React.ComponentEdit Type {type.name}
+ +
+
+
+ +
+
+
+ +
+ + +
+
+
); }; diff --git a/src/ts/component/sidebar/section/layout.tsx b/src/ts/component/sidebar/section/layout.tsx new file mode 100644 index 0000000000..12525eb04d --- /dev/null +++ b/src/ts/component/sidebar/section/layout.tsx @@ -0,0 +1,61 @@ +import * as React from 'react'; +import { observer } from 'mobx-react'; +import { Label, Select } from 'Component'; +import { I, U, translate } from 'Lib'; + +const SidebarSectionLayout = observer(class SidebarSectionTitle extends React.Component { + + render () { + const { object } = this.props; + const layoutOptions = U.Menu.prepareForSelect(U.Menu.turnLayouts()); + const alignOptions = U.Menu.prepareForSelect(U.Menu.getHAlign([ I.BlockHAlign.Justify ])); + + return ( +
+
+ ); + }; + +}); + +export default SidebarSectionLayout; \ No newline at end of file diff --git a/src/ts/component/sidebar/section/title.tsx b/src/ts/component/sidebar/section/title.tsx new file mode 100644 index 0000000000..4ea799191c --- /dev/null +++ b/src/ts/component/sidebar/section/title.tsx @@ -0,0 +1,29 @@ +import * as React from 'react'; +import { observer } from 'mobx-react'; +import { IconObject, ObjectName } from 'Component'; +import { I } from 'Lib'; + +const SidebarSectionTitle = observer(class SidebarSectionTitle extends React.Component { + + render () { + const { object } = this.props; + + return ( +
+ + + +
+ ); + }; + +}); + +export default SidebarSectionTitle; \ No newline at end of file diff --git a/src/ts/interface/common.ts b/src/ts/interface/common.ts index 66fc68a48f..56f50e34f8 100644 --- a/src/ts/interface/common.ts +++ b/src/ts/interface/common.ts @@ -193,6 +193,10 @@ export interface SidebarPageComponent { rootId?: string; }; +export interface SidebarSectionComponent extends SidebarPageComponent { + object: any; +}; + export enum SurveyType { Register = 0, Delete = 1, diff --git a/src/ts/lib/util/menu.ts b/src/ts/lib/util/menu.ts index 3b07833b91..651ba53676 100644 --- a/src/ts/lib/util/menu.ts +++ b/src/ts/lib/util/menu.ts @@ -1058,6 +1058,10 @@ class UtilMenu { ]; }; + prepareForSelect (a: any[]) { + return a.map(it => ({ ...it, id: String(it.id) })) + }; + }; export default new UtilMenu(); From dd17d4af66b69cd3bf8769fe9b4f11ebc92ea4a9 Mon Sep 17 00:00:00 2001 From: Andrew Simachev Date: Mon, 28 Oct 2024 12:58:28 +0100 Subject: [PATCH 07/51] JS-5692: layout section --- src/scss/component/sidebar/page.scss | 27 ++++++++++++--- src/scss/form/select.scss | 1 + src/ts/component/form/drag.tsx | 13 ++++---- src/ts/component/sidebar/section/layout.tsx | 37 +++++++++++++++++++-- src/ts/store/detail.ts | 1 + 5 files changed, 65 insertions(+), 14 deletions(-) diff --git a/src/scss/component/sidebar/page.scss b/src/scss/component/sidebar/page.scss index 699d37e2a8..3a40fd7919 100644 --- a/src/scss/component/sidebar/page.scss +++ b/src/scss/component/sidebar/page.scss @@ -4,6 +4,28 @@ .section { .title { @include text-paragraph; font-weight: 600; } .label { padding: 5px 16px; @include text-small; font-weight: 500; color: var(--color-text-secondary); } + + .items { + .item { padding: 3px 16px; display: flex; flex-direction: row; align-items: center; justify-content: space-between; } + .item { + .value.flex { flex-direction: row; align-items: center; justify-content: space-between; gap: 0px 8px; } + + .select { border: 0px; color: var(--color-text-secondary); } + .select { + .item { + .icon { display: none; } + } + } + + .input-drag { width: 96px; height: 16px; box-shadow: 0px 0px 0px 1px var(--color-shape-primary) inset; border-radius: 8px; overflow: hidden; } + .input-drag { + .back { height: calc(100% - 2px); margin: 0px 0px 0px -1px; top: 1px; background: var(--color-shape-tertiary); border-radius: 0px 8px 8px 0px; } + .fill { height: calc(100% - 2px); margin: 0px 0px 0px 1px; top: 1px; border-radius: 8px 0px 0px 8px; } + .icon { width: 16px; height: 16px; border-radius: 0px; border: 0px; } + .bullet { width: 100%; height: 100%; border-radius: 50%; background: var(--color-bg-primary); border: 1px solid var(--color-shape-primary); } + } + } + } } .section.sectionTitle { @@ -11,11 +33,6 @@ } .section.sectionLayout { padding: 8px 0px; } - .section.sectionLayout { - .label { } - - .item { padding: 3px 16px; display: flex; flex-direction: row; align-items: center; } - } } @import "./page/type.scss"; \ No newline at end of file diff --git a/src/scss/form/select.scss b/src/scss/form/select.scss index 9516b86dcf..ef767e710f 100644 --- a/src/scss/form/select.scss +++ b/src/scss/form/select.scss @@ -17,6 +17,7 @@ .item { display: flex; background: none !important; padding: 0px !important; overflow: hidden; } .item { + .icon { width: 20px; height: 20px; } .icon, .iconObject { transition: none; margin-right: 6px; flex-shrink: 0; } .name { width: 100%; @include text-overflow-nw; } .caption, .note { display: none; } diff --git a/src/ts/component/form/drag.tsx b/src/ts/component/form/drag.tsx index 8bafec4e79..256f99a9d6 100644 --- a/src/ts/component/form/drag.tsx +++ b/src/ts/component/form/drag.tsx @@ -7,6 +7,7 @@ interface Props { value: number; snaps?: number[]; strictSnap?: boolean; + iconIsOutside?: boolean; onStart?(e: any, v: number): void; onMove?(e: any, v: number): void; onEnd?(e: any, v: number): void; @@ -21,6 +22,7 @@ class Drag extends React.Component { min: 0, max: 1, className: '', + iconIsOutside: true, }; value = null; @@ -118,11 +120,11 @@ class Drag extends React.Component { }; move (x: number) { - const { strictSnap } = this.props; + const { strictSnap, iconIsOutside } = this.props; const snaps = this.props.snaps || []; const node = $(this.node); - const nw = node.width(); - const iw = this.icon.width() / 2; + const nw = node.outerWidth(); + const iw = this.icon.outerWidth() / 2; const ib = parseInt(this.icon.css('border-width')); const mw = this.maxWidth(); @@ -148,11 +150,10 @@ class Drag extends React.Component { x = this.value * mw; - const w = Math.min(nw, x + iw); - + const w = Math.min(nw, x + (iconIsOutside ? iw : 0)); this.icon.css({ left: x }); this.back.css({ left: (w + iw + ib), width: (nw - w - iw - ib) }); - this.fill.css({ width: (w - ib) }); + this.fill.css({ width: (w + (iconIsOutside ? 0 : iw) - ib) }); }; end (e) { diff --git a/src/ts/component/sidebar/section/layout.tsx b/src/ts/component/sidebar/section/layout.tsx index 12525eb04d..08dc45cb6a 100644 --- a/src/ts/component/sidebar/section/layout.tsx +++ b/src/ts/component/sidebar/section/layout.tsx @@ -1,17 +1,23 @@ import * as React from 'react'; import { observer } from 'mobx-react'; -import { Label, Select } from 'Component'; +import { Label, Select, Drag } from 'Component'; import { I, U, translate } from 'Lib'; const SidebarSectionLayout = observer(class SidebarSectionTitle extends React.Component { + node = null; + render () { const { object } = this.props; const layoutOptions = U.Menu.prepareForSelect(U.Menu.turnLayouts()); const alignOptions = U.Menu.prepareForSelect(U.Menu.getHAlign([ I.BlockHAlign.Justify ])); + const percent = (1 + object.layoutWidth) * 100; return ( -
+
this.node = ref} + className="section sectionLayout" + >
@@ -39,6 +49,10 @@ const SidebarSectionLayout = observer(class SidebarSectionTitle extends React.Co id={`sidebar-layout-align-${object.id}`} options={alignOptions} value={object.layoutAlign} + arrowClassName="light" + menuParam={{ + horizontal: I.MenuDirection.Right, + }} />
@@ -48,7 +62,14 @@ const SidebarSectionLayout = observer(class SidebarSectionTitle extends React.Co {translate('sidebarSectionLayoutWidth')} -
+
+
{percent}%
+ this.onWidthMove(v)} + onEnd={(e, v) => this.onWidthEnd(v)} + iconIsOutside={false} + />
@@ -56,6 +77,16 @@ const SidebarSectionLayout = observer(class SidebarSectionTitle extends React.Co ); }; + onWidthMove (v: number) { + const node = $(this.node); + + node.find('#percent').text(`${U.Common.sprintf('%0.2f', (1 + v) * 100)}%`); + }; + + onWidthEnd (v: number) { + console.log('onWidthEnd', v); + }; + }); export default SidebarSectionLayout; \ No newline at end of file diff --git a/src/ts/store/detail.ts b/src/ts/store/detail.ts index 84e8db21b5..63e3cbdd23 100644 --- a/src/ts/store/detail.ts +++ b/src/ts/store/detail.ts @@ -193,6 +193,7 @@ class DetailStore { object.iconImage = Relation.getStringValue(object.iconImage); object.iconEmoji = Relation.getStringValue(object.iconEmoji); object.layoutAlign = Number(object.layoutAlign) || I.BlockHAlign.Left; + object.layoutWidth = Number(object.layoutWidth) || 0; object.coverX = Number(object.coverX) || 0; object.coverY = Number(object.coverY) || 0; object.coverScale = Number(object.coverScale) || 0; From 085ca70295b1da26164541b0c66cd6f07a42ee7b Mon Sep 17 00:00:00 2001 From: Andrew Simachev Date: Mon, 28 Oct 2024 13:12:33 +0100 Subject: [PATCH 08/51] refactoring --- src/ts/component/page/main/type.tsx | 6 +----- src/ts/component/sidebar/page/type.tsx | 18 ++++++++++++++---- src/ts/lib/sidebar.ts | 8 +++++++- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/ts/component/page/main/type.tsx b/src/ts/component/page/main/type.tsx index f9c77edbdd..84a9f9374d 100644 --- a/src/ts/component/page/main/type.tsx +++ b/src/ts/component/page/main/type.tsx @@ -390,12 +390,8 @@ const PageMainType = observer(class PageMainType extends React.Component { - sidebar.resizePage(null, false); - }, 10); }; onObjectAdd () { diff --git a/src/ts/component/sidebar/page/type.tsx b/src/ts/component/sidebar/page/type.tsx index 50eb820409..2e7850f6a1 100644 --- a/src/ts/component/sidebar/page/type.tsx +++ b/src/ts/component/sidebar/page/type.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { observer } from 'mobx-react'; import { Label, Button } from 'Component'; -import { I, S, translate } from 'Lib'; +import { I, S, translate, sidebar } from 'Lib'; import SectionTitle from 'Component/sidebar/section/title'; import SectionLayout from 'Component/sidebar/section/layout'; @@ -13,6 +13,8 @@ const SidebarPageType = observer(class SidebarPageType extends React.Component
-
@@ -41,7 +43,15 @@ const SidebarPageType = observer(class SidebarPageType extends React.Component ); - }; + }; + + onSave () { + sidebar.rightPanelToggle(false); + }; + + onCancel () { + sidebar.rightPanelToggle(false); + }; }); diff --git a/src/ts/lib/sidebar.ts b/src/ts/lib/sidebar.ts index 6e6e4d6088..d6b0617415 100644 --- a/src/ts/lib/sidebar.ts +++ b/src/ts/lib/sidebar.ts @@ -1,4 +1,5 @@ import $ from 'jquery'; +import raf from 'raf'; import { U, S, J, Storage, keyboard } from 'Lib'; interface SidebarData { @@ -353,6 +354,11 @@ class Sidebar { S.Common.showObjectSet(!S.Common.showObject); }; + rightPanelToggle (v: boolean) { + S.Common.showSidebarRightSet(v); + raf(() => this.resizePage(null, false)); + }; + }; -export const sidebar: Sidebar = new Sidebar(); +export const sidebar: Sidebar = new Sidebar(); \ No newline at end of file From 4ac8a684d0f8a899c4fc31670e700c81ebe396f2 Mon Sep 17 00:00:00 2001 From: Andrew Simachev Date: Mon, 28 Oct 2024 13:26:26 +0100 Subject: [PATCH 09/51] fields section --- src/json/text.json | 3 ++ src/scss/component/sidebar/page.scss | 13 +++++--- src/ts/component/sidebar/page/type.tsx | 7 +++-- .../sidebar/section/{ => type}/layout.tsx | 4 +-- .../sidebar/section/type/relation.tsx | 31 +++++++++++++++++++ .../sidebar/section/{ => type}/title.tsx | 4 +-- 6 files changed, 50 insertions(+), 12 deletions(-) rename src/ts/component/sidebar/section/{ => type}/layout.tsx (92%) create mode 100644 src/ts/component/sidebar/section/type/relation.tsx rename src/ts/component/sidebar/section/{ => type}/title.tsx (76%) diff --git a/src/json/text.json b/src/json/text.json index b3e64d3c9b..1a6db69044 100644 --- a/src/json/text.json +++ b/src/json/text.json @@ -1826,6 +1826,9 @@ "sidebarSectionLayoutType": "Layout type", "sidebarSectionLayoutAlign": "Header position", "sidebarSectionLayoutWidth": "Layout width", + "sidebarTypeRelation": "Fields", + "sidebarTypeRelationHeader": "Header", + "sidebarTypeRelationSidebar": "Sidebar", "unsplashString": "Photo by %s on %s", "templateBannner": "You are editing a template", diff --git a/src/scss/component/sidebar/page.scss b/src/scss/component/sidebar/page.scss index 3a40fd7919..5a3ad248c8 100644 --- a/src/scss/component/sidebar/page.scss +++ b/src/scss/component/sidebar/page.scss @@ -1,7 +1,13 @@ > .sidebarPage { - .section { background: var(--color-bg-primary); border-radius: 12px; } + .section { background: var(--color-bg-primary); border-radius: 12px; padding: 8px 0px; } .section { + .titleWrap { display: flex; flex-direction: row; align-items: center; justify-content: space-between; margin: 0px 0px 8px 0px; padding: 0px 8px 0px 16px; } + .titleWrap { + .icon.withBackground { width: 24px !important; height: 24px !important; } + .icon.plus { background-image: url('~img/icon/widget/plus.svg'); } + } + .title { @include text-paragraph; font-weight: 600; } .label { padding: 5px 16px; @include text-small; font-weight: 500; color: var(--color-text-secondary); } @@ -28,11 +34,8 @@ } } - .section.sectionTitle { - display: flex; flex-direction: row; gap: 0px 8px; align-items: center; @include text-paragraph; font-weight: 600; padding: 16px; - } + .section.sectionTitle { display: flex; flex-direction: row; gap: 0px 8px; align-items: center; @include text-paragraph; font-weight: 600; padding: 16px; } - .section.sectionLayout { padding: 8px 0px; } } @import "./page/type.scss"; \ No newline at end of file diff --git a/src/ts/component/sidebar/page/type.tsx b/src/ts/component/sidebar/page/type.tsx index 2e7850f6a1..bfffeb0f39 100644 --- a/src/ts/component/sidebar/page/type.tsx +++ b/src/ts/component/sidebar/page/type.tsx @@ -3,8 +3,9 @@ import { observer } from 'mobx-react'; import { Label, Button } from 'Component'; import { I, S, translate, sidebar } from 'Lib'; -import SectionTitle from 'Component/sidebar/section/title'; -import SectionLayout from 'Component/sidebar/section/layout'; +import SectionTitle from 'Component/sidebar/section/type/title'; +import SectionLayout from 'Component/sidebar/section/type/layout'; +import SectionRelation from 'Component/sidebar/section/type/relation'; const SidebarPageType = observer(class SidebarPageType extends React.Component { @@ -39,7 +40,7 @@ const SidebarPageType = observer(class SidebarPageType extends React.Component -
+ ); diff --git a/src/ts/component/sidebar/section/layout.tsx b/src/ts/component/sidebar/section/type/layout.tsx similarity index 92% rename from src/ts/component/sidebar/section/layout.tsx rename to src/ts/component/sidebar/section/type/layout.tsx index 08dc45cb6a..bed063a83a 100644 --- a/src/ts/component/sidebar/section/layout.tsx +++ b/src/ts/component/sidebar/section/type/layout.tsx @@ -3,7 +3,7 @@ import { observer } from 'mobx-react'; import { Label, Select, Drag } from 'Component'; import { I, U, translate } from 'Lib'; -const SidebarSectionLayout = observer(class SidebarSectionTitle extends React.Component { +const SidebarSectionTypeLayout = observer(class SidebarSectionTypeLayout extends React.Component { node = null; @@ -89,4 +89,4 @@ const SidebarSectionLayout = observer(class SidebarSectionTitle extends React.Co }); -export default SidebarSectionLayout; \ No newline at end of file +export default SidebarSectionTypeLayout; \ No newline at end of file diff --git a/src/ts/component/sidebar/section/type/relation.tsx b/src/ts/component/sidebar/section/type/relation.tsx new file mode 100644 index 0000000000..6425fefd81 --- /dev/null +++ b/src/ts/component/sidebar/section/type/relation.tsx @@ -0,0 +1,31 @@ +import * as React from 'react'; +import { observer } from 'mobx-react'; +import { Title, Label, Icon } from 'Component'; +import { I, translate } from 'Lib'; + +const SidebarSectionTypeRelation = observer(class SidebarSectionTypeRelation extends React.Component { + + render () { + const { object } = this.props; + + return ( +
+
+ + <Icon className="plus withBackground" /> + </div> + + <Label text={translate('sidebarTypeRelationHeader')} /> + <div className="items"> + </div> + + <Label text={translate('sidebarTypeRelationSidebar')} /> + <div className="items"> + </div> + </div> + ); + }; + +}); + +export default SidebarSectionTypeRelation; \ No newline at end of file diff --git a/src/ts/component/sidebar/section/title.tsx b/src/ts/component/sidebar/section/type/title.tsx similarity index 76% rename from src/ts/component/sidebar/section/title.tsx rename to src/ts/component/sidebar/section/type/title.tsx index 4ea799191c..fd02376a74 100644 --- a/src/ts/component/sidebar/section/title.tsx +++ b/src/ts/component/sidebar/section/type/title.tsx @@ -3,7 +3,7 @@ import { observer } from 'mobx-react'; import { IconObject, ObjectName } from 'Component'; import { I } from 'Lib'; -const SidebarSectionTitle = observer(class SidebarSectionTitle extends React.Component<I.SidebarSectionComponent> { +const SidebarSectionTypeTitle = observer(class SidebarSectionTypeTitle extends React.Component<I.SidebarSectionComponent> { render () { const { object } = this.props; @@ -26,4 +26,4 @@ const SidebarSectionTitle = observer(class SidebarSectionTitle extends React.Com }); -export default SidebarSectionTitle; \ No newline at end of file +export default SidebarSectionTypeTitle; \ No newline at end of file From 1e5b553c6a329185d003401a09bd2d5a878518d3 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Tue, 29 Oct 2024 11:36:26 +0100 Subject: [PATCH 10/51] component architecture update, data saving --- src/json/relation.ts | 1 + src/scss/component/sidebar/page.scss | 9 ++- .../component/page/elements/head/simple.tsx | 12 ---- src/ts/component/sidebar/page/type.tsx | 64 +++++++++++++++---- src/ts/component/sidebar/section/index.tsx | 57 +++++++++++++++++ .../component/sidebar/section/type/layout.tsx | 37 ++++++++--- .../sidebar/section/type/relation.tsx | 2 +- .../component/sidebar/section/type/title.tsx | 53 +++++++++++++-- src/ts/interface/common.ts | 1 + 9 files changed, 197 insertions(+), 39 deletions(-) create mode 100644 src/ts/component/sidebar/section/index.tsx diff --git a/src/json/relation.ts b/src/json/relation.ts index 47b7c0a5b3..9a2d181a76 100644 --- a/src/json/relation.ts +++ b/src/json/relation.ts @@ -97,6 +97,7 @@ export default { 'sourceObject', 'uniqueKey', 'defaultTemplateId', + 'layoutAlign', ], graph: [ diff --git a/src/scss/component/sidebar/page.scss b/src/scss/component/sidebar/page.scss index 5a3ad248c8..ad07ec6d5b 100644 --- a/src/scss/component/sidebar/page.scss +++ b/src/scss/component/sidebar/page.scss @@ -34,7 +34,14 @@ } } - .section.sectionTitle { display: flex; flex-direction: row; gap: 0px 8px; align-items: center; @include text-paragraph; font-weight: 600; padding: 16px; } + .section.typeTitle { padding: 16px; } + .section.typeTitle { + > .wrap { display: flex; flex-direction: row; gap: 0px 8px; align-items: center; @include text-paragraph; font-weight: 600; } + > .wrap { + .iconObject { flex-shrink: 0; } + .editableWrap { flex-grow: 1; } + } + } } diff --git a/src/ts/component/page/elements/head/simple.tsx b/src/ts/component/page/elements/head/simple.tsx index 98c865eceb..970f50a7b3 100644 --- a/src/ts/component/page/elements/head/simple.tsx +++ b/src/ts/component/page/elements/head/simple.tsx @@ -260,18 +260,6 @@ const HeadSimple = observer(class Controls extends React.Component<Props> { placeholderCheck (id: string) { if (this.refEditable[id]) { this.refEditable[id].placeholderCheck(); - }; - }; - - placeholderHide (id: string) { - if (this.refEditable[id]) { - this.refEditable[id].placeholderHide(); - }; - }; - - placeholderShow (id: string) { - if (this.refEditable[id]) { - this.refEditable[id].placeholderShow(); }; }; diff --git a/src/ts/component/sidebar/page/type.tsx b/src/ts/component/sidebar/page/type.tsx index bfffeb0f39..92e66bffc7 100644 --- a/src/ts/component/sidebar/page/type.tsx +++ b/src/ts/component/sidebar/page/type.tsx @@ -1,28 +1,26 @@ import * as React from 'react'; import { observer } from 'mobx-react'; import { Label, Button } from 'Component'; -import { I, S, translate, sidebar } from 'Lib'; +import { I, S, C, U, Relation, translate, sidebar } from 'Lib'; -import SectionTitle from 'Component/sidebar/section/type/title'; -import SectionLayout from 'Component/sidebar/section/type/layout'; -import SectionRelation from 'Component/sidebar/section/type/relation'; +import Section from 'Component/sidebar/section'; const SidebarPageType = observer(class SidebarPageType extends React.Component<I.SidebarPageComponent> { node = null; + details: any = {}; + sectionRefs: Map<string, any> = new Map(); constructor (props: I.SidebarPageComponent) { super(props); + this.onChange = this.onChange.bind(this); this.onSave = this.onSave.bind(this); this.onCancel = this.onCancel.bind(this); }; render () { - const { rootId } = this.props; - const type = S.Record.getTypeById(rootId); - - console.log(type); + const sections = this.getSections(); return ( <React.Fragment> @@ -38,15 +36,55 @@ const SidebarPageType = observer(class SidebarPageType extends React.Component<I </div> <div className="body customScrollbar"> - <SectionTitle {...this.props} object={type} /> - <SectionLayout {...this.props} object={type} /> - <SectionRelation {...this.props} object={type} /> + {sections.map((item, i) => ( + <Section + {...this.props} + ref={ref => this.sectionRefs.set(item.id, ref)} + key={item.id} + component={item.component} + object={this.details} + onChange={(key, value) => this.onChange(item.id, key, value)} + /> + ))} </div> </React.Fragment> ); }; + componentDidMount (): void { + const { rootId } = this.props; + const type = S.Record.getTypeById(rootId); + const sections = this.getSections(); + + this.details = U.Common.objectCopy(type); + sections.forEach(it => this.update(it.id)); + }; + + getSections () { + return [ + { id: 'title', component: 'type/title' }, + { id: 'layout', component: 'type/layout' }, + { id: 'relation', component: 'type/relation' }, + ]; + }; + + onChange (section: string, relationKey: string, value: any) { + const relation = S.Record.getRelationByKey(relationKey); + + this.details[relationKey] = Relation.formatValue(relation, value, true); + this.update(section); + }; + onSave () { + const { rootId } = this.props; + const update = []; + + for (const key in this.details) { + update.push({ key, value: this.details[key] }); + }; + + C.ObjectListSetDetails([ rootId ], update); + sidebar.rightPanelToggle(false); }; @@ -54,6 +92,10 @@ const SidebarPageType = observer(class SidebarPageType extends React.Component<I sidebar.rightPanelToggle(false); }; + update (id: string) { + this.sectionRefs.get(id)?.setObject(this.details); + }; + }); export default SidebarPageType; \ No newline at end of file diff --git a/src/ts/component/sidebar/section/index.tsx b/src/ts/component/sidebar/section/index.tsx new file mode 100644 index 0000000000..f148d7dfae --- /dev/null +++ b/src/ts/component/sidebar/section/index.tsx @@ -0,0 +1,57 @@ +import * as React from 'react'; +import { observer } from 'mobx-react'; +import { I, U } from 'Lib'; + +import TypeTitle from './type/title'; +import TypeLayout from './type/layout'; +import TypeRelation from './type/relation'; + +const Components = { + 'type/title': TypeTitle, + 'type/layout': TypeLayout, + 'type/relation': TypeRelation, +}; + +interface Props extends I.SidebarSectionComponent { + component: string; +}; + +interface State { + object: any; +}; + +const SidebarSectionIndex = observer(class SidebarSectionIndex extends React.Component<Props, State> { + + state = { + object: null, + }; + ref = null; + + render () { + const { object } = this.state; + const { component } = this.props; + const Component = Components[component]; + const cn = [ 'section', U.Common.toCamelCase(component.replace(/\//g, '-')) ]; + + if (!object || !Component) { + return null; + }; + + return ( + <div className={cn.join(' ')}> + <Component ref={ref => this.ref = ref} {...this.props} object={object} /> + </div> + ); + }; + + componentDidMount (): void { + this.setObject(this.props.object); + }; + + setObject (object: any): void { + this.setState({ object }, () => this.ref?.forceUpdate()); + }; + +}); + +export default SidebarSectionIndex; \ No newline at end of file diff --git a/src/ts/component/sidebar/section/type/layout.tsx b/src/ts/component/sidebar/section/type/layout.tsx index bed063a83a..084c67cce9 100644 --- a/src/ts/component/sidebar/section/type/layout.tsx +++ b/src/ts/component/sidebar/section/type/layout.tsx @@ -6,18 +6,18 @@ import { I, U, translate } from 'Lib'; const SidebarSectionTypeLayout = observer(class SidebarSectionTypeLayout extends React.Component<I.SidebarSectionComponent> { node = null; + refLayout = null; + refAlign = null; + refWidth = null; render () { - const { object } = this.props; + const { object, onChange } = this.props; const layoutOptions = U.Menu.prepareForSelect(U.Menu.turnLayouts()); const alignOptions = U.Menu.prepareForSelect(U.Menu.getHAlign([ I.BlockHAlign.Justify ])); const percent = (1 + object.layoutWidth) * 100; return ( - <div - ref={ref => this.node = ref} - className="section sectionLayout" - > + <div ref={ref => this.node = ref} className="wrap"> <Label text={translate('sidebarSectionLayoutName')} /> <div className="items"> @@ -28,10 +28,12 @@ const SidebarSectionTypeLayout = observer(class SidebarSectionTypeLayout extends <div className="value"> <Select + ref={ref => this.refLayout = ref} id={`sidebar-layout-type-${object.id}`} options={layoutOptions} value={object.recommendedLayout} arrowClassName="light" + onChange={id => onChange('recommendedLayout', id)} menuParam={{ horizontal: I.MenuDirection.Right, }} @@ -46,10 +48,12 @@ const SidebarSectionTypeLayout = observer(class SidebarSectionTypeLayout extends <div className="value"> <Select + ref={ref => this.refAlign = ref} id={`sidebar-layout-align-${object.id}`} options={alignOptions} value={object.layoutAlign} arrowClassName="light" + onChange={id => onChange('layoutAlign', id)} menuParam={{ horizontal: I.MenuDirection.Right, }} @@ -65,6 +69,7 @@ const SidebarSectionTypeLayout = observer(class SidebarSectionTypeLayout extends <div className="value flex"> <div id="percent">{percent}%</div> <Drag + ref={ref => this.refWidth = ref} value={object.layoutWidth} onMove={(e, v) => this.onWidthMove(v)} onEnd={(e, v) => this.onWidthEnd(v)} @@ -77,14 +82,28 @@ const SidebarSectionTypeLayout = observer(class SidebarSectionTypeLayout extends ); }; - onWidthMove (v: number) { - const node = $(this.node); + componentDidMount (): void { + this.setValue(); + }; + + componentDidUpdate (): void { + this.setValue(); + }; - node.find('#percent').text(`${U.Common.sprintf('%0.2f', (1 + v) * 100)}%`); + setValue () { + const { object } = this.props; + + this.refLayout.setValue(object.recommendedLayout); + this.refAlign.setValue(object.layoutAlign); + this.refWidth.setValue(object.layoutWidth); + }; + + onWidthMove (v: number) { + $(this.node).find('#percent').text(`${U.Common.sprintf('%0.2f', (1 + v) * 100)}%`); }; onWidthEnd (v: number) { - console.log('onWidthEnd', v); + this.props.onChange('layoutWidth', v); }; }); diff --git a/src/ts/component/sidebar/section/type/relation.tsx b/src/ts/component/sidebar/section/type/relation.tsx index 6425fefd81..67409f91a1 100644 --- a/src/ts/component/sidebar/section/type/relation.tsx +++ b/src/ts/component/sidebar/section/type/relation.tsx @@ -9,7 +9,7 @@ const SidebarSectionTypeRelation = observer(class SidebarSectionTypeRelation ext const { object } = this.props; return ( - <div className="section sectionRelation"> + <div className="wrap"> <div className="titleWrap"> <Title text={translate('sidebarTypeRelation')} /> <Icon className="plus withBackground" /> diff --git a/src/ts/component/sidebar/section/type/title.tsx b/src/ts/component/sidebar/section/type/title.tsx index fd02376a74..415e4cead6 100644 --- a/src/ts/component/sidebar/section/type/title.tsx +++ b/src/ts/component/sidebar/section/type/title.tsx @@ -1,29 +1,72 @@ import * as React from 'react'; import { observer } from 'mobx-react'; -import { IconObject, ObjectName } from 'Component'; -import { I } from 'Lib'; +import { IconObject, Editable } from 'Component'; +import { I, translate } from 'Lib'; const SidebarSectionTypeTitle = observer(class SidebarSectionTypeTitle extends React.Component<I.SidebarSectionComponent> { + refName = null; + + constructor (props: I.SidebarSectionComponent) { + super(props); + + this.onSelect = this.onSelect.bind(this); + this.onChange = this.onChange.bind(this); + }; + render () { const { object } = this.props; return ( - <div className="section sectionTitle"> + <div className="wrap"> <IconObject id={`sidebar-icon-title-${object.id}`} - object={object} size={24} + object={object} + size={24} canEdit={!object.isReadonly} + onSelect={this.onSelect} menuParam={{ horizontal: I.MenuDirection.Center, }} /> - <ObjectName object={object} /> + <Editable + ref={ref => this.refName = ref} + onBlur={this.onChange} + placeholder={translate('defaultNameType')} + /> </div> ); }; + componentDidMount(): void { + this.setValue(); + }; + + componentDidUpdate () { + this.setValue(); + }; + + setValue () { + const { object } = this.props; + + let text = String(object.name || ''); + if (text == translate('defaultNamePage')) { + text = ''; + }; + + this.refName.setValue(text); + this.refName.placeholderCheck(); + }; + + onSelect (icon: string) { + this.props.onChange('iconEmoji', icon); + }; + + onChange () { + this.props.onChange('name', this.refName?.getTextValue()); + }; + }); export default SidebarSectionTypeTitle; \ No newline at end of file diff --git a/src/ts/interface/common.ts b/src/ts/interface/common.ts index 56f50e34f8..430c17892e 100644 --- a/src/ts/interface/common.ts +++ b/src/ts/interface/common.ts @@ -195,6 +195,7 @@ export interface SidebarPageComponent { export interface SidebarSectionComponent extends SidebarPageComponent { object: any; + onChange?(key: string, value: any): void; }; export enum SurveyType { From fd0113aa0bd8ef17b6be2efa5d3e647c17116293 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Tue, 29 Oct 2024 11:43:04 +0100 Subject: [PATCH 11/51] refactoring --- src/ts/component/page/main/navigation.tsx | 2 +- src/ts/component/sidebar/left.tsx | 4 ++-- src/ts/component/sidebar/{ => page}/object.tsx | 4 ++-- src/ts/component/sidebar/{ => page}/object/item.tsx | 0 src/ts/component/sidebar/{ => page}/widget.tsx | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) rename src/ts/component/sidebar/{ => page}/object.tsx (99%) rename src/ts/component/sidebar/{ => page}/object/item.tsx (100%) rename src/ts/component/sidebar/{ => page}/widget.tsx (98%) diff --git a/src/ts/component/page/main/navigation.tsx b/src/ts/component/page/main/navigation.tsx index 13ca397990..7717e831fa 100644 --- a/src/ts/component/page/main/navigation.tsx +++ b/src/ts/component/page/main/navigation.tsx @@ -6,7 +6,7 @@ import { AutoSizer, CellMeasurer, InfiniteLoader, List, CellMeasurerCache } from import { Button, Cover, Loader, IconObject, Header, Footer, ObjectName, ObjectDescription } from 'Component'; import { I, C, S, U, keyboard, focus, translate } from 'Lib'; -import Item from 'Component/sidebar/object/item'; +import Item from 'Component/sidebar/page/object/item'; interface State { loading: boolean; diff --git a/src/ts/component/sidebar/left.tsx b/src/ts/component/sidebar/left.tsx index 235cf71c32..6969d51127 100644 --- a/src/ts/component/sidebar/left.tsx +++ b/src/ts/component/sidebar/left.tsx @@ -5,8 +5,8 @@ import { observer } from 'mobx-react'; import { Icon } from 'Component'; import { I, U, J, S, keyboard, Preview, sidebar } from 'Lib'; -import SidebarWidget from './widget'; -import SidebarObject from './object'; +import SidebarWidget from './page/widget'; +import SidebarObject from './page/object'; const SidebarLeft = observer(class SidebarLeft extends React.Component { diff --git a/src/ts/component/sidebar/object.tsx b/src/ts/component/sidebar/page/object.tsx similarity index 99% rename from src/ts/component/sidebar/object.tsx rename to src/ts/component/sidebar/page/object.tsx index 165d8e4a82..63a367aedd 100644 --- a/src/ts/component/sidebar/object.tsx +++ b/src/ts/component/sidebar/page/object.tsx @@ -15,7 +15,7 @@ const HEIGHT_SECTION = 28; const HEIGHT_ITEM_DEFAULT = 64; const HEIGHT_ITEM_COMPACT = 36; -const SidebarObject = observer(class SidebarObject extends React.Component<{}, State> { +const SidebarPageObject = observer(class SidebarPageObject extends React.Component<{}, State> { state = { isLoading: false, @@ -1111,4 +1111,4 @@ const SidebarObject = observer(class SidebarObject extends React.Component<{}, S }); -export default SidebarObject; +export default SidebarPageObject; \ No newline at end of file diff --git a/src/ts/component/sidebar/object/item.tsx b/src/ts/component/sidebar/page/object/item.tsx similarity index 100% rename from src/ts/component/sidebar/object/item.tsx rename to src/ts/component/sidebar/page/object/item.tsx diff --git a/src/ts/component/sidebar/widget.tsx b/src/ts/component/sidebar/page/widget.tsx similarity index 98% rename from src/ts/component/sidebar/widget.tsx rename to src/ts/component/sidebar/page/widget.tsx index 82a3576c87..336c838b7e 100644 --- a/src/ts/component/sidebar/widget.tsx +++ b/src/ts/component/sidebar/page/widget.tsx @@ -9,7 +9,7 @@ type State = { previewId: string; }; -const SidebarWidget = observer(class SidebarWidget extends React.Component<{}, State> { +const SidebarPageWidget = observer(class SidebarPageWidget extends React.Component<{}, State> { state: State = { isEditing: false, @@ -494,4 +494,4 @@ const SidebarWidget = observer(class SidebarWidget extends React.Component<{}, S }); -export default SidebarWidget; +export default SidebarPageWidget; \ No newline at end of file From 4e0ba5158017761d568d813451ffaecd0ed8f8bd Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Tue, 29 Oct 2024 12:15:55 +0100 Subject: [PATCH 12/51] JS-5693: relations section --- src/img/icon/sidebar/dnd.svg | 8 ++++++ src/img/icon/sidebar/eye0.svg | 4 +++ src/img/icon/sidebar/eye1.svg | 3 +++ src/scss/component/sidebar/page.scss | 9 ------- src/scss/component/sidebar/page/type.scss | 25 +++++++++++++++++++ .../sidebar/section/type/relation.tsx | 24 ++++++++++++++++-- 6 files changed, 62 insertions(+), 11 deletions(-) create mode 100644 src/img/icon/sidebar/dnd.svg create mode 100644 src/img/icon/sidebar/eye0.svg create mode 100644 src/img/icon/sidebar/eye1.svg diff --git a/src/img/icon/sidebar/dnd.svg b/src/img/icon/sidebar/dnd.svg new file mode 100644 index 0000000000..9460e93cc7 --- /dev/null +++ b/src/img/icon/sidebar/dnd.svg @@ -0,0 +1,8 @@ +<svg width="20" height="21" viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg"> +<rect x="11" y="4.98584" width="2" height="2" rx="1" fill="#B6B6B6"/> +<rect x="11" y="9.98584" width="2" height="2" rx="1" fill="#B6B6B6"/> +<rect x="11" y="14.9858" width="2" height="2" rx="1" fill="#B6B6B6"/> +<rect x="6" y="4.98584" width="2" height="2" rx="1" fill="#B6B6B6"/> +<rect x="6" y="9.98584" width="2" height="2" rx="1" fill="#B6B6B6"/> +<rect x="6" y="14.9858" width="2" height="2" rx="1" fill="#B6B6B6"/> +</svg> diff --git a/src/img/icon/sidebar/eye0.svg b/src/img/icon/sidebar/eye0.svg new file mode 100644 index 0000000000..3a3dec459d --- /dev/null +++ b/src/img/icon/sidebar/eye0.svg @@ -0,0 +1,4 @@ +<svg width="20" height="21" viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M17.0303 3.46967C17.3232 3.76256 17.3232 4.23744 17.0303 4.53033L4.03033 17.5303C3.73744 17.8232 3.26256 17.8232 2.96967 17.5303C2.67678 17.2374 2.67678 16.7626 2.96967 16.4697L15.9697 3.46967C16.2626 3.17678 16.7374 3.17678 17.0303 3.46967Z" fill="#B6B6B6"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M10 4.5C5.2 4.5 2.66667 8.5 2 10.5C2.45485 11.8645 3.77861 14.1601 6.09832 15.481L7.58304 13.9963C6.47545 13.2292 5.75 11.9493 5.75 10.5C5.75 8.15279 7.65279 6.25 10 6.25C11.4493 6.25 12.7292 6.97545 13.4963 8.08304L15.1702 6.40916C13.8883 5.32307 12.1774 4.5 10 4.5ZM16.2317 7.46897L14.1448 9.5559C14.2136 9.85954 14.25 10.1755 14.25 10.5C14.25 12.8472 12.3472 14.75 10 14.75C9.67552 14.75 9.35954 14.7136 9.0559 14.6448L7.57163 16.129C8.30557 16.3638 9.11419 16.5 10 16.5C14.8 16.5 17.3333 12.5 18 10.5C17.7287 9.68609 17.1482 8.54095 16.2317 7.46897ZM12.7055 10.9951C12.5016 12.117 11.617 13.0016 10.4951 13.2055L12.7055 10.9951ZM12.4082 9.17114C11.9396 8.32379 11.0368 7.75 10 7.75C8.48122 7.75 7.25 8.98122 7.25 10.5C7.25 11.5368 7.82379 12.4396 8.67114 12.9082L12.4082 9.17114Z" fill="#B6B6B6"/> +</svg> \ No newline at end of file diff --git a/src/img/icon/sidebar/eye1.svg b/src/img/icon/sidebar/eye1.svg new file mode 100644 index 0000000000..0fe59f7cec --- /dev/null +++ b/src/img/icon/sidebar/eye1.svg @@ -0,0 +1,3 @@ +<svg width="20" height="21" viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M2 10.9849C2.66667 8.98486 5.2 4.98486 10 4.98486C14.8 4.98486 17.3333 8.98486 18 10.9849C17.3333 12.9849 14.8 16.9849 10 16.9849C5.2 16.9849 2.66667 12.9849 2 10.9849ZM7.25 10.9849C7.25 9.46608 8.48122 8.23486 10 8.23486C11.5188 8.23486 12.75 9.46608 12.75 10.9849C12.75 12.5036 11.5188 13.7349 10 13.7349C8.48122 13.7349 7.25 12.5036 7.25 10.9849ZM10 6.73486C7.65279 6.73486 5.75 8.63765 5.75 10.9849C5.75 13.3321 7.65279 15.2349 10 15.2349C12.3472 15.2349 14.25 13.3321 14.25 10.9849C14.25 8.63765 12.3472 6.73486 10 6.73486Z" fill="#B6B6B6"/> +</svg> \ No newline at end of file diff --git a/src/scss/component/sidebar/page.scss b/src/scss/component/sidebar/page.scss index ad07ec6d5b..92ce1eae3d 100644 --- a/src/scss/component/sidebar/page.scss +++ b/src/scss/component/sidebar/page.scss @@ -34,15 +34,6 @@ } } - .section.typeTitle { padding: 16px; } - .section.typeTitle { - > .wrap { display: flex; flex-direction: row; gap: 0px 8px; align-items: center; @include text-paragraph; font-weight: 600; } - > .wrap { - .iconObject { flex-shrink: 0; } - .editableWrap { flex-grow: 1; } - } - } - } @import "./page/type.scss"; \ No newline at end of file diff --git a/src/scss/component/sidebar/page/type.scss b/src/scss/component/sidebar/page/type.scss index a8e1000e24..37aebdf456 100644 --- a/src/scss/component/sidebar/page/type.scss +++ b/src/scss/component/sidebar/page/type.scss @@ -9,4 +9,29 @@ } .body { padding: 0px 12px 12px 12px; overflow: scroll; display: flex; flex-direction: column; gap: 12px 0px; } + + + .section.typeTitle { padding: 16px; } + .section.typeTitle { + > .wrap { display: flex; flex-direction: row; gap: 0px 8px; align-items: center; @include text-paragraph; font-weight: 600; } + > .wrap { + .iconObject { flex-shrink: 0; } + .editableWrap { flex-grow: 1; } + } + } + + .section.typeRelation { + .item { padding-left: 10px; } + .item { + .icon { width: 20px; height: 20px; flex-shrink: 0; } + .icon.dnd { background-image: url('~img/icon/sidebar/dnd.svg'); cursor: grab; } + .icon.eye { background-image: url('~img/icon/sidebar/eye0.svg'); } + .icon.eye.active { background-image: url('~img/icon/sidebar/eye1.svg'); } + + .iconObject { margin: 0px 6px 0px 0px; flex-shrink: 0; } + + .side.left { display: flex; flex-direction: row; align-items: center; flex-grow: 1; } + .side.right { flex-shrink: 0; } + } + } } \ No newline at end of file diff --git a/src/ts/component/sidebar/section/type/relation.tsx b/src/ts/component/sidebar/section/type/relation.tsx index 67409f91a1..c06ad1e210 100644 --- a/src/ts/component/sidebar/section/type/relation.tsx +++ b/src/ts/component/sidebar/section/type/relation.tsx @@ -1,12 +1,27 @@ import * as React from 'react'; import { observer } from 'mobx-react'; -import { Title, Label, Icon } from 'Component'; -import { I, translate } from 'Lib'; +import { Title, Label, Icon, ObjectName, IconObject } from 'Component'; +import { I, S, Relation, translate } from 'Lib'; const SidebarSectionTypeRelation = observer(class SidebarSectionTypeRelation extends React.Component<I.SidebarSectionComponent> { render () { const { object } = this.props; + const recommendedRelations = Relation.getArrayValue(object.recommendedRelations); + const recommendedKeys = recommendedRelations.map(id => S.Record.getRelationById(id)).map(it => it && it.relationKey); + + const Item = (item: any) => ( + <div className="item"> + <div className="side left"> + <Icon className="dnd" /> + <IconObject object={item} /> + <ObjectName object={item} /> + </div> + <div className="side right"> + <Icon className="eye" /> + </div> + </div> + ); return ( <div className="wrap"> @@ -21,6 +36,11 @@ const SidebarSectionTypeRelation = observer(class SidebarSectionTypeRelation ext <Label text={translate('sidebarTypeRelationSidebar')} /> <div className="items"> + {recommendedKeys.map(key => { + const relation = S.Record.getRelationByKey(key); + + return <Item key={`sidebar-${key}`} {...relation} />; + })} </div> </div> ); From d971fdb4251692afa309a09c512be8ca81195d00 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Tue, 29 Oct 2024 12:18:52 +0100 Subject: [PATCH 13/51] JS-5693: relations section --- src/scss/component/sidebar/page.scss | 3 ++- src/scss/component/sidebar/page/type.scss | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/scss/component/sidebar/page.scss b/src/scss/component/sidebar/page.scss index 92ce1eae3d..d3cfdf1261 100644 --- a/src/scss/component/sidebar/page.scss +++ b/src/scss/component/sidebar/page.scss @@ -11,8 +11,9 @@ .title { @include text-paragraph; font-weight: 600; } .label { padding: 5px 16px; @include text-small; font-weight: 500; color: var(--color-text-secondary); } + .items { padding: 0px 8px; } .items { - .item { padding: 3px 16px; display: flex; flex-direction: row; align-items: center; justify-content: space-between; } + .item { padding: 3px 8px; display: flex; flex-direction: row; align-items: center; justify-content: space-between; position: relative; } .item { .value.flex { flex-direction: row; align-items: center; justify-content: space-between; gap: 0px 8px; } diff --git a/src/scss/component/sidebar/page/type.scss b/src/scss/component/sidebar/page/type.scss index 37aebdf456..9d990095ac 100644 --- a/src/scss/component/sidebar/page/type.scss +++ b/src/scss/component/sidebar/page/type.scss @@ -21,7 +21,7 @@ } .section.typeRelation { - .item { padding-left: 10px; } + .item { padding-left: 4px; } .item { .icon { width: 20px; height: 20px; flex-shrink: 0; } .icon.dnd { background-image: url('~img/icon/sidebar/dnd.svg'); cursor: grab; } @@ -33,5 +33,11 @@ .side.left { display: flex; flex-direction: row; align-items: center; flex-grow: 1; } .side.right { flex-shrink: 0; } } + + .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; border-radius: 6px; + } + .item:hover::before { background: var(--color-shape-highlight-medium); } } } \ No newline at end of file From 5f62a3d835bce442812b3e5653230bc6f23d9287 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Tue, 29 Oct 2024 12:43:41 +0100 Subject: [PATCH 14/51] drag and drop fixes --- src/json/relation.ts | 1 + src/scss/component/sidebar/page.scss | 7 +- src/scss/component/sidebar/page/type.scss | 2 +- src/ts/component/header/main/object.tsx | 2 +- .../sidebar/section/type/relation.tsx | 75 +++++++++++++++---- 5 files changed, 69 insertions(+), 18 deletions(-) diff --git a/src/json/relation.ts b/src/json/relation.ts index 9a2d181a76..8e03081fb7 100644 --- a/src/json/relation.ts +++ b/src/json/relation.ts @@ -92,6 +92,7 @@ export default { ], type: [ + 'featuredRelations', 'recommendedRelations', 'recommendedLayout', 'sourceObject', diff --git a/src/scss/component/sidebar/page.scss b/src/scss/component/sidebar/page.scss index d3cfdf1261..e5cb306bde 100644 --- a/src/scss/component/sidebar/page.scss +++ b/src/scss/component/sidebar/page.scss @@ -13,7 +13,12 @@ .items { padding: 0px 8px; } .items { - .item { padding: 3px 8px; display: flex; flex-direction: row; align-items: center; justify-content: space-between; position: relative; } + .item { + padding: 3px 8px; display: flex; flex-direction: row; align-items: center; justify-content: space-between; position: relative; + background-color: var(--color-bg-primary); border-radius: 6px; + } + .item.isDragging { z-index: 2; box-shadow: 0px 1px 5px rgba(0, 0, 0, 0.2); } + .item { .value.flex { flex-direction: row; align-items: center; justify-content: space-between; gap: 0px 8px; } diff --git a/src/scss/component/sidebar/page/type.scss b/src/scss/component/sidebar/page/type.scss index 9d990095ac..0521fba03b 100644 --- a/src/scss/component/sidebar/page/type.scss +++ b/src/scss/component/sidebar/page/type.scss @@ -36,7 +36,7 @@ .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; border-radius: 6px; + pointer-events: none; border-radius: inherit; } .item:hover::before { background: var(--color-shape-highlight-medium); } } diff --git a/src/ts/component/header/main/object.tsx b/src/ts/component/header/main/object.tsx index 7088e82654..c2d99b78a5 100644 --- a/src/ts/component/header/main/object.tsx +++ b/src/ts/component/header/main/object.tsx @@ -35,7 +35,7 @@ const HeaderMainObject = observer(class HeaderMainObject extends React.Component const object = S.Detail.get(rootId, rootId, J.Relation.template); const isLocked = root ? root.isLocked() : false; - const showMenu = !U.Object.isTypeOrRelationLayout(object.layout); + const showMenu = true; const canSync = showMenu && !object.templateIsBundled && !U.Object.isParticipantLayout(object.layout); const cmd = keyboard.cmdSymbol(); const allowedTemplateSelect = (object.internalFlags || []).includes(I.ObjectFlag.SelectTemplate); diff --git a/src/ts/component/sidebar/section/type/relation.tsx b/src/ts/component/sidebar/section/type/relation.tsx index c06ad1e210..e3ab4c2a87 100644 --- a/src/ts/component/sidebar/section/type/relation.tsx +++ b/src/ts/component/sidebar/section/type/relation.tsx @@ -1,19 +1,31 @@ import * as React from 'react'; import { observer } from 'mobx-react'; +import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc'; import { Title, Label, Icon, ObjectName, IconObject } from 'Component'; -import { I, S, Relation, translate } from 'Lib'; +import { I, S, Relation, translate, keyboard } from 'Lib'; const SidebarSectionTypeRelation = observer(class SidebarSectionTypeRelation extends React.Component<I.SidebarSectionComponent> { + constructor (props: I.SidebarSectionComponent) { + super(props); + + this.onSortStart = this.onSortStart.bind(this); + this.onSortEnd = this.onSortEnd.bind(this); + }; + render () { const { object } = this.props; - const recommendedRelations = Relation.getArrayValue(object.recommendedRelations); - const recommendedKeys = recommendedRelations.map(id => S.Record.getRelationById(id)).map(it => it && it.relationKey); + const featured = Relation.getArrayValue(object.featuredRelations).map(key => S.Record.getRelationByKey(key)); + const recommended = Relation.getArrayValue(object.recommendedRelations).map(id => S.Record.getRelationById(id)); - const Item = (item: any) => ( + const Handle = SortableHandle(() => ( + <Icon className="dnd" /> + )); + + const Item = SortableElement((item: any) => ( <div className="item"> <div className="side left"> - <Icon className="dnd" /> + <Handle /> <IconObject object={item} /> <ObjectName object={item} /> </div> @@ -21,7 +33,19 @@ const SidebarSectionTypeRelation = observer(class SidebarSectionTypeRelation ext <Icon className="eye" /> </div> </div> - ); + )); + + const ListFeatured = SortableContainer(() => ( + <div id="section-relation-featured" className="items"> + {featured.map((item, i) => <Item key={`sidebar-${item.relationKey}`} {...item} index={i} />)} + </div> + )); + + const ListRecommended = SortableContainer(() => ( + <div id="section-relation-recommended" className="items"> + {recommended.map((item, i) => <Item key={`sidebar-${item.relationKey}`} {...item} index={i} />)} + </div> + )); return ( <div className="wrap"> @@ -31,21 +55,42 @@ const SidebarSectionTypeRelation = observer(class SidebarSectionTypeRelation ext </div> <Label text={translate('sidebarTypeRelationHeader')} /> - <div className="items"> - </div> + <ListFeatured + axis="y" + transitionDuration={150} + distance={10} + useDragHandle={true} + onSortStart={this.onSortStart} + onSortEnd={this.onSortEnd} + helperClass="isDragging" + lockToContainerEdges={false} + helperContainer={() => $(`#sidebarRight #section-relation-featured`).get(0)} + /> <Label text={translate('sidebarTypeRelationSidebar')} /> - <div className="items"> - {recommendedKeys.map(key => { - const relation = S.Record.getRelationByKey(key); - - return <Item key={`sidebar-${key}`} {...relation} />; - })} - </div> + <ListRecommended + axis="y" + transitionDuration={150} + distance={10} + useDragHandle={true} + onSortStart={this.onSortStart} + onSortEnd={this.onSortEnd} + helperClass="isDragging" + lockToContainerEdges={false} + helperContainer={() => $(`#sidebarRight #section-relation-recommended`).get(0)} + /> </div> ); }; + onSortStart () { + keyboard.disableSelection(true); + }; + + onSortEnd (result: any) { + keyboard.disableSelection(false); + }; + }); export default SidebarSectionTypeRelation; \ No newline at end of file From fc232f66d85c171a99e4e42168095b680af722ea Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Tue, 29 Oct 2024 12:57:45 +0100 Subject: [PATCH 15/51] refactoring and updates --- src/scss/component/sidebar/page/type.scss | 3 +++ src/ts/component/page/main/type.tsx | 5 +--- src/ts/component/sidebar/page/type.tsx | 26 +++++++++++-------- .../sidebar/section/type/relation.tsx | 12 ++++++--- .../component/sidebar/section/type/title.tsx | 11 +++++++- 5 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/scss/component/sidebar/page/type.scss b/src/scss/component/sidebar/page/type.scss index 0521fba03b..41d482836f 100644 --- a/src/scss/component/sidebar/page/type.scss +++ b/src/scss/component/sidebar/page/type.scss @@ -21,6 +21,9 @@ } .section.typeRelation { + .items { margin: 0px 0px 8px 0px; } + .items:last-child { margin: 0px; } + .item { padding-left: 4px; } .item { .icon { width: 20px; height: 20px; flex-shrink: 0; } diff --git a/src/ts/component/page/main/type.tsx b/src/ts/component/page/main/type.tsx index 84a9f9374d..78fe928028 100644 --- a/src/ts/component/page/main/type.tsx +++ b/src/ts/component/page/main/type.tsx @@ -83,11 +83,8 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC if (!it) { return false; }; - if (Relation.systemKeysWithoutUser().includes(it.relationKey)) { - return false; - }; return config.debug.hiddenObject ? true : !it.isHidden; - }).sort(U.Data.sortByName); + }); const isFileType = U.Object.isInFileLayouts(object.recommendedLayout); const columns: any[] = [ diff --git a/src/ts/component/sidebar/page/type.tsx b/src/ts/component/sidebar/page/type.tsx index 92e66bffc7..5520c52ee1 100644 --- a/src/ts/component/sidebar/page/type.tsx +++ b/src/ts/component/sidebar/page/type.tsx @@ -8,7 +8,8 @@ import Section from 'Component/sidebar/section'; const SidebarPageType = observer(class SidebarPageType extends React.Component<I.SidebarPageComponent> { node = null; - details: any = {}; + object: any = {}; + update: any = {}; sectionRefs: Map<string, any> = new Map(); constructor (props: I.SidebarPageComponent) { @@ -42,7 +43,7 @@ const SidebarPageType = observer(class SidebarPageType extends React.Component<I ref={ref => this.sectionRefs.set(item.id, ref)} key={item.id} component={item.component} - object={this.details} + object={this.object} onChange={(key, value) => this.onChange(item.id, key, value)} /> ))} @@ -56,8 +57,8 @@ const SidebarPageType = observer(class SidebarPageType extends React.Component<I const type = S.Record.getTypeById(rootId); const sections = this.getSections(); - this.details = U.Common.objectCopy(type); - sections.forEach(it => this.update(it.id)); + this.object = U.Common.objectCopy(type); + sections.forEach(it => this.updateObject(it.id)); }; getSections () { @@ -71,20 +72,23 @@ const SidebarPageType = observer(class SidebarPageType extends React.Component<I onChange (section: string, relationKey: string, value: any) { const relation = S.Record.getRelationByKey(relationKey); - this.details[relationKey] = Relation.formatValue(relation, value, true); - this.update(section); + value = Relation.formatValue(relation, value, false); + + this.object[relationKey] = value; + this.update[relationKey] = value; + this.updateObject(section); }; onSave () { const { rootId } = this.props; const update = []; - for (const key in this.details) { - update.push({ key, value: this.details[key] }); + for (const key in this.update) { + update.push({ key, value: this.object[key] }); }; - C.ObjectListSetDetails([ rootId ], update); + this.update = {}; sidebar.rightPanelToggle(false); }; @@ -92,8 +96,8 @@ const SidebarPageType = observer(class SidebarPageType extends React.Component<I sidebar.rightPanelToggle(false); }; - update (id: string) { - this.sectionRefs.get(id)?.setObject(this.details); + updateObject (id: string) { + this.sectionRefs.get(id)?.setObject(this.object); }; }); diff --git a/src/ts/component/sidebar/section/type/relation.tsx b/src/ts/component/sidebar/section/type/relation.tsx index e3ab4c2a87..34549c8e8e 100644 --- a/src/ts/component/sidebar/section/type/relation.tsx +++ b/src/ts/component/sidebar/section/type/relation.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import { observer } from 'mobx-react'; +import arrayMove from 'array-move'; import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc'; import { Title, Label, Icon, ObjectName, IconObject } from 'Component'; import { I, S, Relation, translate, keyboard } from 'Lib'; @@ -61,7 +62,7 @@ const SidebarSectionTypeRelation = observer(class SidebarSectionTypeRelation ext distance={10} useDragHandle={true} onSortStart={this.onSortStart} - onSortEnd={this.onSortEnd} + onSortEnd={result => this.onSortEnd('featuredRelations', result)} helperClass="isDragging" lockToContainerEdges={false} helperContainer={() => $(`#sidebarRight #section-relation-featured`).get(0)} @@ -74,7 +75,7 @@ const SidebarSectionTypeRelation = observer(class SidebarSectionTypeRelation ext distance={10} useDragHandle={true} onSortStart={this.onSortStart} - onSortEnd={this.onSortEnd} + onSortEnd={result => this.onSortEnd('recommendedRelations', result)} helperClass="isDragging" lockToContainerEdges={false} helperContainer={() => $(`#sidebarRight #section-relation-recommended`).get(0)} @@ -87,7 +88,12 @@ const SidebarSectionTypeRelation = observer(class SidebarSectionTypeRelation ext keyboard.disableSelection(true); }; - onSortEnd (result: any) { + onSortEnd (relationKey: string, result: any) { + const { oldIndex, newIndex } = result; + const { object, onChange } = this.props; + const value = arrayMove(Relation.getArrayValue(object[relationKey]), oldIndex, newIndex); + + onChange(relationKey, value); keyboard.disableSelection(false); }; diff --git a/src/ts/component/sidebar/section/type/title.tsx b/src/ts/component/sidebar/section/type/title.tsx index 415e4cead6..194fd421e3 100644 --- a/src/ts/component/sidebar/section/type/title.tsx +++ b/src/ts/component/sidebar/section/type/title.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { observer } from 'mobx-react'; import { IconObject, Editable } from 'Component'; -import { I, translate } from 'Lib'; +import { I, keyboard, translate } from 'Lib'; const SidebarSectionTypeTitle = observer(class SidebarSectionTypeTitle extends React.Component<I.SidebarSectionComponent> { @@ -12,6 +12,7 @@ const SidebarSectionTypeTitle = observer(class SidebarSectionTypeTitle extends R this.onSelect = this.onSelect.bind(this); this.onChange = this.onChange.bind(this); + this.onKeyDown = this.onKeyDown.bind(this); }; render () { @@ -33,6 +34,7 @@ const SidebarSectionTypeTitle = observer(class SidebarSectionTypeTitle extends R <Editable ref={ref => this.refName = ref} onBlur={this.onChange} + onKeyDown={this.onKeyDown} placeholder={translate('defaultNameType')} /> </div> @@ -67,6 +69,13 @@ const SidebarSectionTypeTitle = observer(class SidebarSectionTypeTitle extends R this.props.onChange('name', this.refName?.getTextValue()); }; + onKeyDown (e: any) { + keyboard.shortcut('enter', e, () => { + e.preventDefault(); + this.onChange(); + }); + }; + }); export default SidebarSectionTypeTitle; \ No newline at end of file From 8d094c63856918270c06e952863bbb150ccef172 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Tue, 29 Oct 2024 13:26:14 +0100 Subject: [PATCH 16/51] JS-5603: add sort to ListObject initial --- src/ts/component/list/object.tsx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/ts/component/list/object.tsx b/src/ts/component/list/object.tsx index 52821e11ee..af5fe221d1 100644 --- a/src/ts/component/list/object.tsx +++ b/src/ts/component/list/object.tsx @@ -22,10 +22,15 @@ interface Props { relationKeys?: string[]; }; +interface State { + sortId: string; + sortType: I.SortType; +}; + const PREFIX = 'listObject'; const LIMIT = 50; -const ListObject = observer(class ListObject extends React.Component<Props> { +const ListObject = observer(class ListObject extends React.Component<Props, State> { public static defaultProps: Props = { spaceId: '', @@ -36,6 +41,11 @@ const ListObject = observer(class ListObject extends React.Component<Props> { filters: [], }; + state = { + sortId: 'lastModifiedDate', + sortType: I.SortType.Desc, + }; + render () { const { subId, rootId, columns } = this.props; const items = this.getItems(); From dc3a304f804fc4db5cf56e665a3356c9e81c4377 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Tue, 29 Oct 2024 13:43:02 +0100 Subject: [PATCH 17/51] JS-5712: edit relations --- src/scss/component/sidebar/page/type.scss | 2 +- .../sidebar/section/type/relation.tsx | 94 ++++++++++++------- 2 files changed, 62 insertions(+), 34 deletions(-) diff --git a/src/scss/component/sidebar/page/type.scss b/src/scss/component/sidebar/page/type.scss index 41d482836f..2efb05c6ad 100644 --- a/src/scss/component/sidebar/page/type.scss +++ b/src/scss/component/sidebar/page/type.scss @@ -41,6 +41,6 @@ content: ""; position: absolute; left: 0px; top: 0px; width: 100%; height: 100%; background: rgba(79,79,79,0); z-index: 1; pointer-events: none; border-radius: inherit; } - .item:hover::before { background: var(--color-shape-highlight-medium); } + .item:hover::before, .item.hover::before { background: var(--color-shape-highlight-medium); } } } \ No newline at end of file diff --git a/src/ts/component/sidebar/section/type/relation.tsx b/src/ts/component/sidebar/section/type/relation.tsx index 34549c8e8e..8b1399fe53 100644 --- a/src/ts/component/sidebar/section/type/relation.tsx +++ b/src/ts/component/sidebar/section/type/relation.tsx @@ -3,7 +3,7 @@ import { observer } from 'mobx-react'; import arrayMove from 'array-move'; import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc'; import { Title, Label, Icon, ObjectName, IconObject } from 'Component'; -import { I, S, Relation, translate, keyboard } from 'Lib'; +import { I, C, S, Relation, translate, keyboard } from 'Lib'; const SidebarSectionTypeRelation = observer(class SidebarSectionTypeRelation extends React.Component<I.SidebarSectionComponent> { @@ -24,7 +24,11 @@ const SidebarSectionTypeRelation = observer(class SidebarSectionTypeRelation ext )); const Item = SortableElement((item: any) => ( - <div className="item"> + <div + id={`item-${item.id}`} + className="item" + onClick={e => this.onEdit(e, item.container, item.id)} + > <div className="side left"> <Handle /> <IconObject object={item} /> @@ -36,27 +40,22 @@ const SidebarSectionTypeRelation = observer(class SidebarSectionTypeRelation ext </div> )); - const ListFeatured = SortableContainer(() => ( - <div id="section-relation-featured" className="items"> - {featured.map((item, i) => <Item key={`sidebar-${item.relationKey}`} {...item} index={i} />)} - </div> - )); - - const ListRecommended = SortableContainer(() => ( - <div id="section-relation-recommended" className="items"> - {recommended.map((item, i) => <Item key={`sidebar-${item.relationKey}`} {...item} index={i} />)} - </div> - )); - - return ( - <div className="wrap"> - <div className="titleWrap"> - <Title text={translate('sidebarTypeRelation')} /> - <Icon className="plus withBackground" /> + const List = (list: any) => { + const SortableList = SortableContainer(() => ( + <div id={list.container} className="items"> + {list.data.map((item, i) => ( + <Item + key={[ list.container, item.id ].join('-')} + {...item} + container={list.container} + index={i} + /> + ))} </div> + )); - <Label text={translate('sidebarTypeRelationHeader')} /> - <ListFeatured + return ( + <SortableList axis="y" transitionDuration={150} distance={10} @@ -65,21 +64,23 @@ const SidebarSectionTypeRelation = observer(class SidebarSectionTypeRelation ext onSortEnd={result => this.onSortEnd('featuredRelations', result)} helperClass="isDragging" lockToContainerEdges={false} - helperContainer={() => $(`#sidebarRight #section-relation-featured`).get(0)} + helperContainer={() => $(`#sidebarRight #${list.container}`).get(0)} /> + ); + }; + + return ( + <div className="wrap"> + <div className="titleWrap"> + <Title text={translate('sidebarTypeRelation')} /> + <Icon className="plus withBackground" /> + </div> + + <Label text={translate('sidebarTypeRelationHeader')} /> + <List data={featured} container="section-relation-featured" /> <Label text={translate('sidebarTypeRelationSidebar')} /> - <ListRecommended - axis="y" - transitionDuration={150} - distance={10} - useDragHandle={true} - onSortStart={this.onSortStart} - onSortEnd={result => this.onSortEnd('recommendedRelations', result)} - helperClass="isDragging" - lockToContainerEdges={false} - helperContainer={() => $(`#sidebarRight #section-relation-recommended`).get(0)} - /> + <List data={recommended} container="section-relation-recommended" /> </div> ); }; @@ -97,6 +98,33 @@ const SidebarSectionTypeRelation = observer(class SidebarSectionTypeRelation ext keyboard.disableSelection(false); }; + onEdit (e: any, container: string, id: string) { + const { object } = this.props; + const allowed = S.Block.isAllowed(object.restrictions, [ I.RestrictionObject.Relation ]); + const relation = S.Record.getRelationById(id); + + S.Menu.open('blockRelationEdit', { + element: `#sidebarRight #${container} #item-${id}`, + offsetX: 32, + data: { + rootId: object.id, + relationId: id, + readonly: !allowed, + ref: 'type', + addCommand: (rootId: string, blockId: string, relation: any, onChange?: (relation: any) => void) => { + C.ObjectTypeRelationAdd(rootId, [ relation.relationKey ], () => { + if (onChange) { + onChange(relation.relationKey); + }; + }); + }, + deleteCommand: () => { + C.ObjectTypeRelationRemove(object.id, [ relation.relationKey ]); + }, + } + }); + }; + }); export default SidebarSectionTypeRelation; \ No newline at end of file From 2e57e14836461b76b86079c1f1fc76a546d276a7 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Tue, 29 Oct 2024 13:45:19 +0100 Subject: [PATCH 18/51] JS-5712: edit relations --- src/ts/component/sidebar/section/type/relation.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ts/component/sidebar/section/type/relation.tsx b/src/ts/component/sidebar/section/type/relation.tsx index 8b1399fe53..9563c89837 100644 --- a/src/ts/component/sidebar/section/type/relation.tsx +++ b/src/ts/component/sidebar/section/type/relation.tsx @@ -35,7 +35,7 @@ const SidebarSectionTypeRelation = observer(class SidebarSectionTypeRelation ext <ObjectName object={item} /> </div> <div className="side right"> - <Icon className="eye" /> + <Icon className="eye" onClick={e => this.onToggle(e, item.container, item.id)} /> </div> </div> )); @@ -98,6 +98,10 @@ const SidebarSectionTypeRelation = observer(class SidebarSectionTypeRelation ext keyboard.disableSelection(false); }; + onToggle (e: any, container: string, id: string) { + e.stopPropagation(); + }; + onEdit (e: any, container: string, id: string) { const { object } = this.props; const allowed = S.Block.isAllowed(object.restrictions, [ I.RestrictionObject.Relation ]); From 2a5c8674d4d1ccb440c9253c14f8c8bf6793c6d6 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Tue, 29 Oct 2024 13:50:45 +0100 Subject: [PATCH 19/51] JS-5517: remove widgetContainer #list --- src/scss/component/sidebar/widget.scss | 129 ++++++++++---------- src/ts/component/sidebar/page/widget.tsx | 34 +++--- src/ts/component/widget/tree/index.tsx | 2 +- src/ts/component/widget/view/list/index.tsx | 2 +- src/ts/docs/help/onboarding.ts | 2 +- 5 files changed, 82 insertions(+), 87 deletions(-) diff --git a/src/scss/component/sidebar/widget.scss b/src/scss/component/sidebar/widget.scss index ea51e0c6f8..74fe868687 100644 --- a/src/scss/component/sidebar/widget.scss +++ b/src/scss/component/sidebar/widget.scss @@ -11,7 +11,10 @@ .name { opacity: 1; transform: translate3d(0px,0px,0px); } } - > .body { height: calc(100% - 52px); padding: 0px 6px 12px 12px; position: relative; flex-grow: 1; overflow: scroll; overscroll-behavior: none; } + > .body { + height: calc(100% - 52px); padding: 0px 6px 12px 12px; position: relative; flex-grow: 1; overflow: scroll; overscroll-behavior: none; + display: flex; flex-direction: column; gap: 12px 0px; + } > .body { @keyframes shake1 { 0% { transform: rotate(-0.5deg); } @@ -23,82 +26,80 @@ 100% { transform: rotate(-0.5deg); } } - .list { display: flex; flex-direction: column; gap: 12px 0px; } - .list { - > .buttons { display: flex; justify-content: center; width: 100%; gap: 0px 8px; } - > .buttons { - .button { - box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.2); border-radius: 8px; width: 100%; min-width: 60px; max-width: 200px; background-color: var(--color-bg-primary); - color: var(--color-text-secondary); font-weight: 400; white-space: nowrap; - } - .button:hover { background-color: var(--color-shape-tertiary); } - - .button.disabled { background: var(--color-shape-tertiary); max-width: 80px; } - .button.grey { - box-shadow: 0px 0px; background: var(--color-shape-highlight-medium); border-radius: 6px; @include text-common; color: var(--color-text-primary); line-height: 26px; width: auto; - padding: 0px 10px; - } + > .buttons { display: flex; justify-content: center; width: 100%; gap: 0px 8px; } + > .buttons { + .button { + box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.2); border-radius: 8px; width: 100%; min-width: 60px; max-width: 200px; background-color: var(--color-bg-primary); + color: var(--color-text-secondary); font-weight: 400; white-space: nowrap; } + .button:hover { background-color: var(--color-shape-tertiary); } - > .dropTarget.firstTarget, - > .dropTarget.lastTarget - { position: relative; } - - > .dropTarget.lastTarget { display: flex; flex-direction: column; gap: 12px 0px; } + .button.disabled { background: var(--color-shape-tertiary); max-width: 80px; } + .button.grey { + box-shadow: 0px 0px; background: var(--color-shape-highlight-medium); border-radius: 6px; @include text-common; color: var(--color-text-primary); line-height: 26px; width: auto; + padding: 0px 10px; + } + } - > .dropTarget.firstTarget.isOver, - > .dropTarget.lastTarget.isOver - { box-shadow: 0px 0px !important; } + > .dropTarget.firstTarget, + > .dropTarget.lastTarget + { position: relative; } - > .dropTarget.firstTarget.isOver::before, - > .dropTarget.lastTarget.isOver::before { - content: ""; position: absolute; background: var(--color-system-accent-100); width: calc(100% - 28px); height: 2px; border-radius: 2px; left: 12px; - } + > .dropTarget.lastTarget { display: flex; flex-direction: column; gap: 12px 0px; } - > .dropTarget.firstTarget.isOver::before { bottom: -7px; } - > .dropTarget.lastTarget.isOver::before { top: -7px; } + > .dropTarget.firstTarget.isOver, + > .dropTarget.lastTarget.isOver + { box-shadow: 0px 0px !important; } - .widget.isEditable.isOver::before { - content: ""; position: absolute; background: var(--color-system-accent-100); height: 2px; width: calc(100% - 24px); border-radius: 2px; - left: 12px; - } - .widget.isEditable.isOver.top::before { top: -7px; } - .widget.isEditable.isOver.bottom::before { bottom: -7px; } + > .dropTarget.firstTarget.isOver::before, + > .dropTarget.lastTarget.isOver::before { + content: ""; position: absolute; background: var(--color-system-accent-100); width: calc(100% - 28px); height: 2px; border-radius: 2px; left: 12px; } - .list.isEditing { - > .buttons { position: sticky; bottom: 0px; left: 0px; padding: 0px 16px; } - - .widget:not(.isEditable) { opacity: 0.5; } - .widget:not(.isEditable) { - .dimmer { cursor: default; } - } + > .dropTarget.firstTarget.isOver::before { bottom: -7px; } + > .dropTarget.lastTarget.isOver::before { top: -7px; } - .widget { - .icon.remove { display: block; } - } - .widget { - .dimmer { display: block; } - } + .widget.isEditable.isOver::before { + content: ""; position: absolute; background: var(--color-system-accent-100); height: 2px; width: calc(100% - 24px); border-radius: 2px; + left: 12px; + } + .widget.isEditable.isOver.top::before { top: -7px; } + .widget.isEditable.isOver.bottom::before { bottom: -7px; } + } - .widget.widgetSpace:hover { - .side.left { width: 100%; } - .side.right { display: none; } - } + > .body.withShareBanner { margin-top: -10px; } - .widget.isEditable:nth-child(2n + 1) { animation: shake1 0.2s linear infinite alternate; } - .widget.isEditable:nth-child(2n + 2) { animation: shake2 0.2s linear infinite alternate; } - .widget.isEditable:hover { - .head { - > .buttons { display: flex; } - .iconWrap.options { display: none; } - } - } + > .body.isEditing { + > .buttons { position: sticky; bottom: 0px; left: 0px; padding: 0px 16px; } + + .widget:not(.isEditable) { opacity: 0.5; } + .widget:not(.isEditable) { + .dimmer { cursor: default; } + } + + .widget { + .icon.remove { display: block; } + } + .widget { + .dimmer { display: block; } + } - .widget.button { cursor: default; animation: none; } + .widget.widgetSpace:hover { + .side.left { width: 100%; } + .side.right { display: none; } } - .list.isListPreview { overflow: hidden; height: 100%; } + .widget.isEditable:nth-child(2n + 1) { animation: shake1 0.2s linear infinite alternate; } + .widget.isEditable:nth-child(2n + 2) { animation: shake2 0.2s linear infinite alternate; } + .widget.isEditable:hover { + .head { + > .buttons { display: flex; } + .iconWrap.options { display: none; } + } + } + + .widget.button { cursor: default; animation: none; } } - > .body.withShareBanner { margin-top: -10px; } + + > .body.isListPreview { overflow: hidden; height: 100%; } } diff --git a/src/ts/component/sidebar/page/widget.tsx b/src/ts/component/sidebar/page/widget.tsx index 336c838b7e..ff911e6477 100644 --- a/src/ts/component/sidebar/page/widget.tsx +++ b/src/ts/component/sidebar/page/widget.tsx @@ -39,11 +39,18 @@ const SidebarPageWidget = observer(class SidebarPageWidget extends React.Compone render (): React.ReactNode { const { isEditing, previewId } = this.state; const { widgets } = S.Block; - const cn = [ 'list' ]; - const bodyCn = [ 'body' ]; + const cn = [ 'body' ]; const space = U.Space.getSpaceview(); const canWrite = U.Space.canMyParticipantWrite(); + if (isEditing) { + cn.push('isEditing'); + }; + + if (U.Space.isShareBanner()) { + cn.push('withShareBanner'); + }; + let content = null; if (previewId) { @@ -97,10 +104,6 @@ const SidebarPageWidget = observer(class SidebarPageWidget extends React.Compone last = blocks[blocks.length - 1]; }; - if (isEditing) { - cn.push('isEditing'); - }; - if (isEditing) { if (blocks.length <= J.Constant.limit.widgets) { buttons.push({ id: 'widget-list-add', text: translate('commonAdd'), onMouseDown: e => this.onAdd(e, analytics.route.addWidgetEditor) }); @@ -115,10 +118,6 @@ const SidebarPageWidget = observer(class SidebarPageWidget extends React.Compone ]); }; - if (U.Space.isShareBanner()) { - bodyCn.push('withShareBanner'); - }; - content = ( <React.Fragment> {space && !space._empty_ ? ( @@ -188,18 +187,13 @@ const SidebarPageWidget = observer(class SidebarPageWidget extends React.Compone </div> <div id="body" - className={bodyCn.join(' ')} + className={cn.join(' ')} onScroll={this.onScroll} + onDrop={this.onDrop} + onDragOver={e => e.preventDefault()} + onContextMenu={this.onContextMenu} > - <div - id="list" - className={cn.join(' ')} - onDrop={this.onDrop} - onDragOver={e => e.preventDefault()} - onContextMenu={this.onContextMenu} - > - {content} - </div> + {content} </div> </div> ); diff --git a/src/ts/component/widget/tree/index.tsx b/src/ts/component/widget/tree/index.tsx index 7e9c95dbee..a8f97ddffe 100644 --- a/src/ts/component/widget/tree/index.tsx +++ b/src/ts/component/widget/tree/index.tsx @@ -468,7 +468,7 @@ const WidgetTree = observer(class WidgetTree extends React.Component<I.WidgetCom if (isPreview) { const head = $(`#widget-${parent.id} .head`); - const maxHeight = $('#sidebarLeft #containerWidget #list').height() - head.outerHeight(true); + const maxHeight = $('#sidebarLeft #containerWidget #body').height() - head.outerHeight(true); css.height = Math.min(maxHeight, css.height); }; diff --git a/src/ts/component/widget/view/list/index.tsx b/src/ts/component/widget/view/list/index.tsx index edc81c3b7d..20e41f683e 100644 --- a/src/ts/component/widget/view/list/index.tsx +++ b/src/ts/component/widget/view/list/index.tsx @@ -215,7 +215,7 @@ const WidgetViewList = observer(class WidgetViewList extends React.Component<I.W const length = this.getItems().length; raf(() => { - const container = $('#sidebarLeft #containerWidget #list'); + const container = $('#sidebarLeft #containerWidget #body'); const obj = $(`#widget-${parent.id}`); const node = $(this.node); const head = obj.find('.head'); diff --git a/src/ts/docs/help/onboarding.ts b/src/ts/docs/help/onboarding.ts index 543b9d5ce1..18a04d1391 100644 --- a/src/ts/docs/help/onboarding.ts +++ b/src/ts/docs/help/onboarding.ts @@ -82,7 +82,7 @@ export default { offsetX: -312, noClose: true, highlightElements: [], - hiddenElements: [ '#widget-buttons', '.widget', '#containerWidget #list .buttons' ], + hiddenElements: [ '#widget-buttons', '.widget', '#containerWidget #body .buttons' ], }, items: [ { From bcd1f105781067d532b8acf51c96778d60fd4355 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Tue, 29 Oct 2024 15:06:11 +0100 Subject: [PATCH 20/51] add relations --- src/ts/component/sidebar/page/type.tsx | 16 +++++- .../sidebar/section/type/relation.tsx | 51 ++++++++++++++++--- 2 files changed, 57 insertions(+), 10 deletions(-) diff --git a/src/ts/component/sidebar/page/type.tsx b/src/ts/component/sidebar/page/type.tsx index 5520c52ee1..28290acda5 100644 --- a/src/ts/component/sidebar/page/type.tsx +++ b/src/ts/component/sidebar/page/type.tsx @@ -21,6 +21,7 @@ const SidebarPageType = observer(class SidebarPageType extends React.Component<I }; render () { + const type = this.getObject(); const sections = this.getSections(); return ( @@ -53,13 +54,24 @@ const SidebarPageType = observer(class SidebarPageType extends React.Component<I }; componentDidMount (): void { - const { rootId } = this.props; - const type = S.Record.getTypeById(rootId); + this.init(); + }; + + componentDidUpdate (): void { + this.init(); + }; + + init () { + const type = this.getObject(); const sections = this.getSections(); this.object = U.Common.objectCopy(type); sections.forEach(it => this.updateObject(it.id)); }; + + getObject () { + return S.Record.getTypeById(this.props.rootId); + }; getSections () { return [ diff --git a/src/ts/component/sidebar/section/type/relation.tsx b/src/ts/component/sidebar/section/type/relation.tsx index 9563c89837..7436241ce6 100644 --- a/src/ts/component/sidebar/section/type/relation.tsx +++ b/src/ts/component/sidebar/section/type/relation.tsx @@ -12,12 +12,12 @@ const SidebarSectionTypeRelation = observer(class SidebarSectionTypeRelation ext this.onSortStart = this.onSortStart.bind(this); this.onSortEnd = this.onSortEnd.bind(this); + this.onAdd = this.onAdd.bind(this); }; render () { - const { object } = this.props; - const featured = Relation.getArrayValue(object.featuredRelations).map(key => S.Record.getRelationByKey(key)); - const recommended = Relation.getArrayValue(object.recommendedRelations).map(id => S.Record.getRelationById(id)); + const featured = this.getFeatured(); + const recommended = this.getRecommended(); const Handle = SortableHandle(() => ( <Icon className="dnd" /> @@ -61,7 +61,7 @@ const SidebarSectionTypeRelation = observer(class SidebarSectionTypeRelation ext distance={10} useDragHandle={true} onSortStart={this.onSortStart} - onSortEnd={result => this.onSortEnd('featuredRelations', result)} + onSortEnd={result => this.onSortEnd(list.relationKey, result)} helperClass="isDragging" lockToContainerEdges={false} helperContainer={() => $(`#sidebarRight #${list.container}`).get(0)} @@ -73,14 +73,14 @@ const SidebarSectionTypeRelation = observer(class SidebarSectionTypeRelation ext <div className="wrap"> <div className="titleWrap"> <Title text={translate('sidebarTypeRelation')} /> - <Icon className="plus withBackground" /> + <Icon id="section-relation-plus" className="plus withBackground" onClick={this.onAdd} /> </div> <Label text={translate('sidebarTypeRelationHeader')} /> - <List data={featured} container="section-relation-featured" /> + <List data={featured} container="section-relation-featured" relationKey="featuredRelations" /> <Label text={translate('sidebarTypeRelationSidebar')} /> - <List data={recommended} container="section-relation-recommended" /> + <List data={recommended} container="section-relation-recommended" relationKey="recommendedRelations" /> </div> ); }; @@ -102,6 +102,42 @@ const SidebarSectionTypeRelation = observer(class SidebarSectionTypeRelation ext e.stopPropagation(); }; + getFeatured () { + return Relation.getArrayValue(this.props.object.featuredRelations).map(key => S.Record.getRelationByKey(key)).filter(it => it); + }; + + getRecommended () { + return Relation.getArrayValue(this.props.object.recommendedRelations).map(id => S.Record.getRelationById(id)).filter(it => it); + }; + + onAdd (e: any) { + const { object } = this.props; + const skipSystemKeys = [ 'tag', 'description', 'source' ]; + const recommendedKeys = this.getRecommended().map(it => it.relationKey); + const systemKeys = Relation.systemKeys().filter(it => !skipSystemKeys.includes(it)); + + S.Menu.open('relationSuggest', { + element: '#sidebarRight #section-relation-plus', + horizontal: I.MenuDirection.Right, + data: { + filter: '', + rootId: object.id, + ref: 'type', + menuIdEdit: 'blockRelationEdit', + skipKeys: recommendedKeys.concat(systemKeys), + addCommand: (rootId: string, blockId: string, relation: any, onChange: (message: any) => void) => { + C.ObjectTypeRelationAdd(rootId, [ relation.relationKey ], (message: any) => { + S.Menu.close('relationSuggest'); + + if (onChange) { + onChange(message); + }; + }); + }, + } + }); + }; + onEdit (e: any, container: string, id: string) { const { object } = this.props; const allowed = S.Block.isAllowed(object.restrictions, [ I.RestrictionObject.Relation ]); @@ -109,7 +145,6 @@ const SidebarSectionTypeRelation = observer(class SidebarSectionTypeRelation ext S.Menu.open('blockRelationEdit', { element: `#sidebarRight #${container} #item-${id}`, - offsetX: 32, data: { rootId: object.id, relationId: id, From d82704f1dd127dab7a81700eb81d5db43f39c519 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Tue, 29 Oct 2024 15:08:10 +0100 Subject: [PATCH 21/51] add relations --- src/ts/component/sidebar/section/type/relation.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ts/component/sidebar/section/type/relation.tsx b/src/ts/component/sidebar/section/type/relation.tsx index 7436241ce6..57d252ebb8 100644 --- a/src/ts/component/sidebar/section/type/relation.tsx +++ b/src/ts/component/sidebar/section/type/relation.tsx @@ -145,6 +145,7 @@ const SidebarSectionTypeRelation = observer(class SidebarSectionTypeRelation ext S.Menu.open('blockRelationEdit', { element: `#sidebarRight #${container} #item-${id}`, + horizontal: I.MenuDirection.Center, data: { rootId: object.id, relationId: id, From 622945661cec50916b604dae7af0232f0cd41918 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Tue, 29 Oct 2024 15:35:28 +0100 Subject: [PATCH 22/51] JS-5603: add sort to ListObject --- src/img/icon/sortArrow.svg | 4 ++ src/scss/list/object.scss | 11 ++--- src/ts/component/list/object.tsx | 70 +++++++++++++++++++++----------- 3 files changed, 56 insertions(+), 29 deletions(-) create mode 100644 src/img/icon/sortArrow.svg diff --git a/src/img/icon/sortArrow.svg b/src/img/icon/sortArrow.svg new file mode 100644 index 0000000000..47acff2910 --- /dev/null +++ b/src/img/icon/sortArrow.svg @@ -0,0 +1,4 @@ +<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> +<rect x="9.5" y="5" width="1" height="10" fill="#949494"/> +<path d="M6 11L10 15L14 11" stroke="#949494"/> +</svg> \ No newline at end of file diff --git a/src/scss/list/object.scss b/src/scss/list/object.scss index 46213be0ab..6795b9f4df 100644 --- a/src/scss/list/object.scss +++ b/src/scss/list/object.scss @@ -5,9 +5,7 @@ .table { .selectionTarget { display: grid; grid-template-columns: minmax(0, 1fr) 20% 20%; } - .row.isHead { - display: grid; grid-template-columns: minmax(0, 1fr) 20% 20%; color: var(--color-text-secondary); - } + .row.isHead { display: grid; grid-template-columns: minmax(0, 1fr) 20% 20%; color: var(--color-text-secondary); } .row.isHead { .cell { text-align: left; padding: 14px 0px 14px 14px; white-space: nowrap; font-weight: 400; line-height: 20px; position: relative; @@ -15,9 +13,12 @@ } .cell { .name { - display: inline-block; line-height: 20px; height: 20px; vertical-align: top; width: 100%; @include text-overflow-nw; - border-right: 1px solid var(--color-shape-secondary); + display: flex; flex-direction: row; align-items: center; line-height: 20px; height: 20px; vertical-align: top; width: 100%; + @include text-overflow-nw; border-right: 1px solid var(--color-shape-secondary); } + + .icon.sortArrow { width: 20px; height: 20px; margin: 0px; background-image: url('~img/icon/sortArrow.svg'); } + .icon.sortArrow.c1 { transform: rotateZ(180deg); } } .cell:last-child { .name { border: 0px; } diff --git a/src/ts/component/list/object.tsx b/src/ts/component/list/object.tsx index af5fe221d1..24a457819f 100644 --- a/src/ts/component/list/object.tsx +++ b/src/ts/component/list/object.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { observer } from 'mobx-react'; +import { IconObject, Pager, ObjectName, Cell, SelectionTarget, Icon } from 'Component'; import { I, C, S, U, J, Relation, translate, keyboard } from 'Lib'; -import { IconObject, Pager, ObjectName, Cell, SelectionTarget } from 'Component'; interface Column { relationKey: string; @@ -47,9 +47,11 @@ const ListObject = observer(class ListObject extends React.Component<Props, Stat }; render () { - const { subId, rootId, columns } = this.props; + const { subId, rootId } = this.props; + const { sortId, sortType } = this.state; const items = this.getItems(); const { offset, total } = S.Record.getMeta(subId, ''); + const columns = this.getColumns(); let pager = null; if (total && items.length) { @@ -86,16 +88,8 @@ const ListObject = observer(class ListObject extends React.Component<Props, Stat className={cn.join(' ')} onContextMenu={e => this.onContext(e, item.id)} > - <div className="cell isName"> - <div className="cellContent isName" onClick={() => U.Object.openConfig(item)}> - <div className="flex"> - <IconObject object={item} /> - <ObjectName object={item} /> - </div> - </div> - </div> - {columns.map(column => { + const cn = [ 'cell' ]; const cnc = [ 'cellContent' ]; const value = item[column.relationKey]; @@ -108,7 +102,16 @@ const ListObject = observer(class ListObject extends React.Component<Props, Stat if (value) { if (column.isObject) { - const object = S.Detail.get(subId, value, []); + let object = null; + + if (column.relationKey == 'name') { + object = item; + cn.push('isName'); + cnc.push('isName'); + } else { + object = S.Detail.get(subId, value, []); + }; + if (!object._empty_) { onClick = () => U.Object.openConfig(object); content = ( @@ -142,7 +145,7 @@ const ListObject = observer(class ListObject extends React.Component<Props, Stat }; return ( - <div key={`cell-${column.relationKey}`} className="cell"> + <div key={`cell-${column.relationKey}`} className={cn.join(' ')}> {content ? <div className={cnc.join(' ')} onClick={onClick}>{content}</div> : ''} </div> ); @@ -155,15 +158,19 @@ const ListObject = observer(class ListObject extends React.Component<Props, Stat <div className="listObject"> <div className="table"> <div className="row isHead"> - <div className="cell"> - <div className="name">{translate('commonName')}</div> - </div> + {columns.map(column => { + let arrow = null; - {columns.map(column => ( - <div key={`head-${column.relationKey}`} className="cell isHead"> - <div className="name">{column.name}</div> - </div> - ))} + if (sortId == column.relationKey) { + arrow = <Icon className={`sortArrow c${sortType}`} />; + }; + + return ( + <div key={`head-${column.relationKey}`} className="cell isHead" onClick={() => this.onSort(column.relationKey)}> + <div className="name">{column.name}{arrow}</div> + </div> + ); + })} </div> {!items.length ? ( @@ -192,6 +199,10 @@ const ListObject = observer(class ListObject extends React.Component<Props, Stat C.ObjectSearchUnsubscribe([ this.props.subId ]); }; + getColumns (): Column[] { + return ([ { relationKey: 'name', name: translate('commonName'), isObject: true } ] as any[]).concat(this.props.columns || []); + }; + getItems () { return S.Record.getRecords(this.props.subId, this.getKeys()); }; @@ -201,6 +212,7 @@ const ListObject = observer(class ListObject extends React.Component<Props, Stat }; getData (page: number, callBack?: (message: any) => void) { + const { sortId, sortType } = this.state; const { spaceId, subId, sources } = this.props; const offset = (page - 1) * LIMIT; const filters = [ @@ -212,9 +224,7 @@ const ListObject = observer(class ListObject extends React.Component<Props, Stat U.Data.searchSubscribe({ spaceId, subId, - sorts: [ - { relationKey: 'lastModifiedDate', type: I.SortType.Desc } - ], + sorts: [ { relationKey: sortId, type: sortType } ], keys: this.getKeys(), sources, filters, @@ -252,6 +262,18 @@ const ListObject = observer(class ListObject extends React.Component<Props, Stat }); }; + onSort (relationKey: string): void { + const { sortId, sortType } = this.state; + + let type = I.SortType.Asc; + + if (sortId == relationKey) { + type = sortType == I.SortType.Asc ? I.SortType.Desc : I.SortType.Asc; + }; + + this.setState({ sortId: relationKey, sortType: type }, () => this.getData(1)); + }; + }); export default ListObject; \ No newline at end of file From 30998ea2b64a3f3ed06f1db7057220753fc36047 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Tue, 29 Oct 2024 15:41:09 +0100 Subject: [PATCH 23/51] remove redundant code from PageMainType --- src/json/text.json | 1 - src/ts/component/page/main/type.tsx | 136 +--------------------------- 2 files changed, 1 insertion(+), 136 deletions(-) diff --git a/src/json/text.json b/src/json/text.json index bb9632bae8..22fd6c0414 100644 --- a/src/json/text.json +++ b/src/json/text.json @@ -446,7 +446,6 @@ "pageMainNavigationItemEmptyTitle": "Object can not be shown", - "pageMainTypeRecommendedLayout": "Recommended layout", "pageMainTypeNewSetOfObjects": "New Set of Objects", "pageMainTypeNoTemplates": "This Object Type doesn't have Templates", diff --git a/src/ts/component/page/main/type.tsx b/src/ts/component/page/main/type.tsx index 78fe928028..3754f38081 100644 --- a/src/ts/component/page/main/type.tsx +++ b/src/ts/component/page/main/type.tsx @@ -32,11 +32,9 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC this.onTemplateAdd = this.onTemplateAdd.bind(this); this.onObjectAdd = this.onObjectAdd.bind(this); - this.onRelationAdd = this.onRelationAdd.bind(this); this.onSetAdd = this.onSetAdd.bind(this); this.onCreate = this.onCreate.bind(this); this.onEdit = this.onEdit.bind(this); - this.onLayout = this.onLayout.bind(this); }; render () { @@ -46,7 +44,6 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC return <Deleted {...this.props} />; }; - const { config } = S.Common; const rootId = this.getRootId(); const check = U.Data.checkDetails(rootId); const object = S.Detail.get(rootId, rootId, J.Relation.type); @@ -60,32 +57,17 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC const canWrite = U.Space.canMyParticipantWrite(); const isTemplate = object.uniqueKey == J.Constant.typeKey.template; - const layout: any = U.Menu.getLayouts().find(it => it.id == object.recommendedLayout) || {}; const showTemplates = !U.Object.getLayoutsWithoutTemplates().includes(object.recommendedLayout) && !isTemplate; const recommendedRelations = Relation.getArrayValue(object.recommendedRelations); const recommendedKeys = recommendedRelations.map(id => S.Record.getRelationById(id)).map(it => it && it.relationKey); const allowedObject = object.isInstalled && U.Object.isInPageLayouts(object.recommendedLayout); - const allowedDetails = object.isInstalled && S.Block.checkFlags(rootId, rootId, [ I.RestrictionObject.Details ]); - const allowedRelation = object.isInstalled && S.Block.checkFlags(rootId, rootId, [ I.RestrictionObject.Relation ]) && !U.Object.isParticipantLayout(object.recommendedLayout); const allowedTemplate = object.isInstalled && allowedObject && showTemplates && canWrite && !isTemplate; - const allowedLayout = ![ I.ObjectLayout.Bookmark, I.ObjectLayout.Chat, I.ObjectLayout.Participant ].includes(object.recommendedLayout); const subIdObject = this.getSubIdObject(); const totalObject = S.Record.getMeta(subIdObject, '').total; const totalTemplate = templates.length + (allowedTemplate ? 1 : 0); - if (!recommendedRelations.includes('rel-description')) { - recommendedRelations.push('rel-description'); - }; - - const relations = recommendedRelations.map(id => S.Record.getRelationById(id)).filter(it => { - if (!it) { - return false; - }; - return config.debug.hiddenObject ? true : !it.isHidden; - }); - const isFileType = U.Object.isInFileLayouts(object.recommendedLayout); const columns: any[] = [ { @@ -98,25 +80,6 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC columns.push({ relationKey: 'creator', name: translate('commonOwner'), isObject: true }); }; - const ItemRelation = (item: any) => ( - <div id={'item-' + item.id} className={[ 'item', (item.isHidden ? 'isHidden' : ''), 'canEdit' ].join(' ')}> - <div className="clickable" onClick={e => this.onRelationEdit(e, item.id)}> - <Icon className={[ 'relation', Relation.className(item.format) ].join(' ')} /> - <div className="name">{item.name}</div> - </div> - </div> - ); - - const ItemAdd = () => ( - <div id="item-add" className="item add" onClick={this.onRelationAdd}> - <div className="clickable"> - <Icon className="plus" /> - <div className="name">{translate('commonAddRelation')}</div> - </div> - <div className="value" /> - </div> - ); - return ( <div> <Header @@ -174,38 +137,6 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC </div> ) : ''} - {allowedLayout ? ( - <div className="section layout"> - <div className="title">{translate('pageMainTypeRecommendedLayout')}</div> - <div className="content"> - {allowedDetails ? ( - <Select - id="recommendedLayout" - value={object.recommendedLayout} - options={U.Menu.turnLayouts()} - arrowClassName="light" - onChange={this.onLayout} - /> - ) : ( - <React.Fragment> - <Icon className={layout.icon} /> - <div className="name">{layout.name}</div> - </React.Fragment> - )} - </div> - </div> - ) : ''} - - <div className="section relation"> - <div className="title">{relations.length} {U.Common.plural(relations.length, translate('pluralRelation'))}</div> - <div className="content"> - {relations.map((item: any, i: number) => ( - <ItemRelation key={i} {...item} /> - ))} - {allowedRelation ? <ItemAdd /> : ''} - </div> - </div> - {object.isInstalled && !object._empty_ ? ( <div className="section set"> <div className="title">{totalObject} {U.Common.plural(totalObject, translate('pluralObject'))}</div> @@ -444,71 +375,6 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC }); }; - onRelationAdd (e: any) { - const rootId = this.getRootId(); - const object = S.Detail.get(rootId, rootId); - const skipSystemKeys = [ 'tag', 'description', 'source' ]; - const recommendedKeys = object.recommendedRelations.map(id => S.Record.getRelationById(id)).map(it => it && it.relationKey); - const systemKeys = Relation.systemKeys().filter(it => !skipSystemKeys.includes(it)); - - S.Menu.open('relationSuggest', { - element: '#page .section.relation #item-add', - offsetX: 32, - data: { - filter: '', - rootId, - ref: 'type', - menuIdEdit: 'blockRelationEdit', - skipKeys: recommendedKeys.concat(systemKeys), - addCommand: (rootId: string, blockId: string, relation: any, onChange: (message: any) => void) => { - C.ObjectTypeRelationAdd(rootId, [ relation.relationKey ], (message: any) => { - S.Menu.close('relationSuggest'); - - if (onChange) { - onChange(message); - }; - }); - }, - } - }); - }; - - onRelationEdit (e: any, id: string) { - const rootId = this.getRootId(); - const allowed = S.Block.checkFlags(rootId, rootId, [ I.RestrictionObject.Relation ]); - const relation = S.Record.getRelationById(id); - - S.Menu.open('blockRelationEdit', { - element: `#page .section.relation #item-${id}`, - offsetX: 32, - data: { - rootId, - relationId: id, - readonly: !allowed, - ref: 'type', - addCommand: (rootId: string, blockId: string, relation: any, onChange?: (relation: any) => void) => { - C.ObjectTypeRelationAdd(rootId, [ relation.relationKey ], () => { - if (onChange) { - onChange(relation.relationKey); - }; - }); - }, - deleteCommand: () => { - C.ObjectTypeRelationRemove(rootId, [ relation.relationKey ]); - }, - } - }); - }; - - onLayout (layout: string) { - const rootId = this.getRootId(); - - C.ObjectListSetDetails([ rootId ], [ - { key: 'recommendedLayout', value: Number(layout) || I.ObjectLayout.Page } - ]); - analytics.event('ChangeRecommendedLayout', { objectType: rootId, layout: layout }); - }; - onMenu (item: any) { if (S.Menu.isOpen('dataviewTemplateContext', item.id)) { S.Menu.close('dataviewTemplateContext'); @@ -582,4 +448,4 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC }); -export default PageMainType; +export default PageMainType; \ No newline at end of file From 5a69b776cca52fc3b45b5ddbdaaeb402d2f5abe0 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Tue, 29 Oct 2024 16:21:13 +0100 Subject: [PATCH 24/51] JS-5588: PageMainType updates --- src/img/icon/plus/template.svg | 3 + src/img/icon/plus/template0.svg | 4 -- src/img/icon/plus/template1.svg | 4 -- src/json/text.json | 4 +- src/scss/list/object.scss | 4 +- src/scss/list/previewObject.scss | 18 ++--- src/scss/page/main/type.scss | 66 ++++--------------- src/scss/theme/dark/common.scss | 2 +- src/scss/theme/dark/page.scss | 2 +- src/ts/component/index.tsx | 2 - .../{previewObject.tsx => objectPreview.tsx} | 4 +- .../component/page/elements/head/banner.tsx | 2 +- .../component/page/elements/head/simple.tsx | 2 +- src/ts/component/page/main/type.tsx | 33 +++++++--- 14 files changed, 61 insertions(+), 89 deletions(-) create mode 100644 src/img/icon/plus/template.svg delete mode 100644 src/img/icon/plus/template0.svg delete mode 100644 src/img/icon/plus/template1.svg rename src/ts/component/list/{previewObject.tsx => objectPreview.tsx} (99%) diff --git a/src/img/icon/plus/template.svg b/src/img/icon/plus/template.svg new file mode 100644 index 0000000000..2d38fe0d0b --- /dev/null +++ b/src/img/icon/plus/template.svg @@ -0,0 +1,3 @@ +<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M10 2C9.58579 2 9.25 2.33579 9.25 2.75V9.25H2.75C2.33579 9.25 2 9.58579 2 10C2 10.4142 2.33579 10.75 2.75 10.75H9.25V17.25C9.25 17.6642 9.58579 18 10 18C10.4142 18 10.75 17.6642 10.75 17.25V10.75H17.25C17.6642 10.75 18 10.4142 18 10C18 9.58579 17.6642 9.25 17.25 9.25H10.75V2.75C10.75 2.33579 10.4142 2 10 2Z" fill="#B6B6B6"/> +</svg> \ No newline at end of file diff --git a/src/img/icon/plus/template0.svg b/src/img/icon/plus/template0.svg deleted file mode 100644 index b309123f91..0000000000 --- a/src/img/icon/plus/template0.svg +++ /dev/null @@ -1,4 +0,0 @@ -<svg width="20" height="21" viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg"> -<rect x="9.25" y="3.99902" width="1.5" height="14" rx="0.75" fill="#b6b6b6"/> -<path d="M16.25 10.249C16.6642 10.249 17 10.5848 17 10.999C17 11.4132 16.6642 11.749 16.25 11.749H3.75C3.33579 11.749 3 11.4132 3 10.999C3 10.5848 3.33579 10.249 3.75 10.249H16.25Z" fill="#b6b6b6"/> -</svg> diff --git a/src/img/icon/plus/template1.svg b/src/img/icon/plus/template1.svg deleted file mode 100644 index 0606bf30b4..0000000000 --- a/src/img/icon/plus/template1.svg +++ /dev/null @@ -1,4 +0,0 @@ -<svg width="20" height="21" viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg"> -<rect x="9.25" y="3.99902" width="1.5" height="14" rx="0.75" fill="#252525"/> -<path d="M16.25 10.249C16.6642 10.249 17 10.5848 17 10.999C17 11.4132 16.6642 11.749 16.25 11.749H3.75C3.33579 11.749 3 11.4132 3 10.999C3 10.5848 3.33579 10.249 3.75 10.249H16.25Z" fill="#252525"/> -</svg> diff --git a/src/json/text.json b/src/json/text.json index 22fd6c0414..40e3c410ee 100644 --- a/src/json/text.json +++ b/src/json/text.json @@ -157,6 +157,7 @@ "commonCreateObjectWithName": "Create Object \"%s\"", "commonCreateObjectTypeWithName": "Create Object Type \"%s\"", "commonCreateObject": "Create Object", + "commonCreateNewTemplate": "Create new Template", "commonUrl": "Url", "commonEdit": "Edit", "commonShare": "Share", @@ -174,7 +175,8 @@ "pluralDay": "day|days", "pluralObject": "Object|Objects", "pluralLCObject": "object|objects", - "pluralTemplate": "template|templates", + "pluralTemplate": "Template|Templates", + "pluralLCTemplate": "template|templates", "pluralRelation": "Relation|Relations", "pluralBlock": "Block|Blocks", "pluralObjectType": "Object Type|Object Types", diff --git a/src/scss/list/object.scss b/src/scss/list/object.scss index 6795b9f4df..638d956bf0 100644 --- a/src/scss/list/object.scss +++ b/src/scss/list/object.scss @@ -32,7 +32,9 @@ .row.isSelectionSelected { background-color: var(--color-system-selection); } .row { - .cell { padding: 14px; vertical-align: top; position: relative; word-break: break-word; } + .cell { padding: 9px 14px; vertical-align: top; position: relative; word-break: break-word; } + .cell:first-child { padding-left: 0px; } + .cell:last-child { padding-right: 0px; } .cellContent { width: 100%; overflow: hidden; height: 20px; line-height: 20px; } .cellContent { diff --git a/src/scss/list/previewObject.scss b/src/scss/list/previewObject.scss index 6cda5959e1..a7dde75889 100644 --- a/src/scss/list/previewObject.scss +++ b/src/scss/list/previewObject.scss @@ -1,11 +1,11 @@ @import "~scss/_mixins"; -.listPreviewObject { white-space: nowrap; position: relative; } -.listPreviewObject { +.listObjectPreview { white-space: nowrap; position: relative; } +.listObjectPreview { .wrap { overflow: hidden; border-radius: 8px; } - .scroll { transition: transform $transitionCommon; display: inline-block; } + .scroll { transition: transform 0.3s $easeInQuint; display: flex; flex-direction: row; gap: 0px 16px; } - .item { display: inline-block; vertical-align: top; margin-right: 16px; position: relative; } + .item { position: relative; flex-shrink: 0; } .item { .hoverArea { height: 100%; } .hoverArea:before { @@ -19,7 +19,7 @@ padding: 1px 4px; border-radius: 4px; background: var(--color-shape-tertiary); color: var(--color-text-secondary); } - .previewObject { width: 344px; height: 216px; } + .previewObject { width: 224px; height: 160px; } .icon.plus { width: 28px; height: 28px; position: absolute; left: 50%; top: 50%; margin: -14px 0px 0px -14px; background-image: url('~img/icon/plus/templateBig.svg'); } } @@ -35,17 +35,13 @@ } .item:last-child { margin-right: 0px; } - .item.add { border: 1px solid var(--color-shape-secondary); border-radius: 8px; width: 344px; height: 216px; } + .item.add { border: 1px solid var(--color-shape-secondary); border-radius: 8px; width: 224px; height: 160px; } .icon.arrow { - position: absolute; top: 0px; width: 32px; height: 216px; background-image: url('~img/arrow/template0.svg'); background-size: 8px 32px; z-index: 10; + position: absolute; top: 0px; width: 32px; height: 160px; background-image: url('~img/arrow/template0.svg'); background-size: 8px 32px; z-index: 10; } .icon.arrow:hover { background-image: url('~img/arrow/template1.svg'); } .icon.arrow.disabled:hover { background-image: url('~img/arrow/template0.svg'); } .icon.arrow.left { left: 0px; transform: rotateY(-180deg); } .icon.arrow.right { right: 0px; } - - .content { white-space: nowrap; position: relative; } - .wrap { overflow: hidden; border-radius: 8px; } - .scroll { transition: transform $transitionCommon; display: inline-block; } } \ No newline at end of file diff --git a/src/scss/page/main/type.scss b/src/scss/page/main/type.scss index 402da37e8a..7ec0bb487a 100644 --- a/src/scss/page/main/type.scss +++ b/src/scss/page/main/type.scss @@ -1,7 +1,7 @@ @import "~scss/_mixins"; .pageMainType { - .wrapper { width: 704px; margin: 0px auto; padding: 0px 0px 80px 0px; user-select: none; } + .wrapper { width: 704px; margin: 0px auto; padding: 0px 0px 90px 0px; user-select: none; } .wrapper.withIcon { .editorControls { @@ -16,69 +16,31 @@ } .block.blockFeatured { padding: 0px; margin: 0px; line-height: 28px; } - .section { margin-bottom: 32px; } + .section { margin-bottom: 44px; } .section:last-child { margin: 0px; } .editorControls { margin-bottom: 8px; } .section { - .title { @include text-header3; margin-bottom: 14px; position: relative; } - } - - .section.template { - .btn { - position: absolute; right: 0px; top: 50%; margin-top: -10px; @include text-common; line-height: 20px; font-weight: normal; color: var(--color-text-secondary); - transition: $transitionAllCommon; - } - .btn { - .icon.plus { vertical-align: top; width: 20px; height: 20px; background-image: url('~img/icon/plus/template0.svg'); } - } - .btn:hover { color: var(--color-text-primary); } - .btn:hover { - .icon.plus { background-image: url('~img/icon/plus/template1.svg'); } + .title { + @include text-paragraph; margin-bottom: 14px; position: relative; display: flex; flex-direction: row; align-items: center; + justify-content: space-between; } + .title { + .side.left { display: flex; flex-direction: row; align-items: center; gap: 0px 6px; } + .side.right { display: flex; justify-content: flex-end; } - .listPreviewObject { - .icon.arrow.left { left: -32px; } - .icon.arrow.right { right: -32px; } + .icon.plus { background-image: url('~img/icon/plus/template.svg'); } + .cnt { color: var(--color-text-secondary); } } } - .section.relation { - .item { display: flex; } - .item { - .icon.plus { background-image: url('~img/icon/plus/menu0.svg'); } - - .clickable { width: 228px; padding: 4px; display: flex; transition: $transitionAllCommon; border-radius: 4px; } - - .icon { flex-shrink: 0; width: 20px; height: 20px; margin-right: 8px; } - .name { width: 200px; @include text-overflow-nw; line-height: 20px; color: var(--color-text-secondary); } - } - .item.canEdit { - .clickable:hover { background: var(--color-shape-highlight-light); } - } - - .item.add { line-height: 20px; } - .item.add { - .icon { transition: $transitionAllCommon; } - .name { color: var(--color-text-secondary); transition: $transitionAllCommon; } - - .clickable:hover { - .name { color: var(--color-text-primary); } - .icon.plus { background-image: url('~img/icon/plus/menu1.svg'); } - } + .section.template { + .listObjectPreview { + .icon.arrow.left { left: -32px; } + .icon.arrow.right { right: -32px; } } } - - .section.layout { - .title { margin-bottom: 10px; } - .content { line-height: 20px; color: var(--color-text-secondary); } - .select { border: 0px; padding: 3px 20px 3px 4px; cursor: default; } - .select:hover, .select.isFocused { background: var(--color-shape-highlight-light); } - - .icon { width: 20px; height: 20px; margin-right: 6px; } - .name { display: inline-block; vertical-align: middle; } - } } } diff --git a/src/scss/theme/dark/common.scss b/src/scss/theme/dark/common.scss index b5681ac10b..d9f4a484d0 100644 --- a/src/scss/theme/dark/common.scss +++ b/src/scss/theme/dark/common.scss @@ -177,7 +177,7 @@ html.themeDark { .number { color: var(--color-text-primary); } } - .listPreviewObject { + .listObjectPreview { .icon.arrow { background-image: url('#{$themePath}/arrow/template0.svg'); } .icon.arrow:hover { background-image: url('#{$themePath}/arrow/template1.svg'); } .icon.arrow.disabled:hover { background-image: url('#{$themePath}/arrow/template0.svg'); } diff --git a/src/scss/theme/dark/page.scss b/src/scss/theme/dark/page.scss index a488e32c7b..08972fb5ce 100644 --- a/src/scss/theme/dark/page.scss +++ b/src/scss/theme/dark/page.scss @@ -23,7 +23,7 @@ .icon.plus { background-image: url('#{$themePath}/icon/plus/template1.svg'); } } - .listPreviewObject { + .listObjectPreview { .icon.arrow.left { left: -32px; } .icon.arrow.right { right: -32px; } } diff --git a/src/ts/component/index.tsx b/src/ts/component/index.tsx index 7080941c4e..62758aec47 100644 --- a/src/ts/component/index.tsx +++ b/src/ts/component/index.tsx @@ -15,7 +15,6 @@ import ListPopup from './list/popup'; import ListMenu from './list/menu'; import ListNotification from './list/notification'; import ListChildren from './list/children'; -import ListObjectPreview from './list/previewObject'; import ListObject from './list/object'; import ListObjectManager from './list/objectManager'; @@ -111,7 +110,6 @@ export { ListPopup, ListMenu, ListChildren, - ListObjectPreview, ListObject, ListObjectManager, ListNotification, diff --git a/src/ts/component/list/previewObject.tsx b/src/ts/component/list/objectPreview.tsx similarity index 99% rename from src/ts/component/list/previewObject.tsx rename to src/ts/component/list/objectPreview.tsx index ad93b7fbcd..a05587da9d 100644 --- a/src/ts/component/list/previewObject.tsx +++ b/src/ts/component/list/objectPreview.tsx @@ -16,7 +16,7 @@ interface Props { onMenu?: (e: any, item: any) => void; }; -const WIDTH = 344; +const WIDTH = 224; class ListObjectPreview extends React.Component<Props> { @@ -110,7 +110,7 @@ class ListObjectPreview extends React.Component<Props> { return ( <div ref={node => this.node = node} - className="listPreviewObject" + className="listObjectPreview" > <div className="wrap"> <div id="scroll" className="scroll"> diff --git a/src/ts/component/page/elements/head/banner.tsx b/src/ts/component/page/elements/head/banner.tsx index ddb15f90e9..5c17f3b74b 100644 --- a/src/ts/component/page/elements/head/banner.tsx +++ b/src/ts/component/page/elements/head/banner.tsx @@ -56,7 +56,7 @@ class HeaderBanner extends React.Component<Props> { cn.push('withMenu'); if (count) { - label = U.Common.sprintf(translate('selectTemplateBannerWithNumber'), count, U.Common.plural(count, translate('pluralTemplate'))); + label = U.Common.sprintf(translate('selectTemplateBannerWithNumber'), count, U.Common.plural(count, translate('pluralLCTemplate'))); } else { label = translate('selectTemplateBanner'); }; diff --git a/src/ts/component/page/elements/head/simple.tsx b/src/ts/component/page/elements/head/simple.tsx index 970f50a7b3..f2a64cc837 100644 --- a/src/ts/component/page/elements/head/simple.tsx +++ b/src/ts/component/page/elements/head/simple.tsx @@ -104,7 +104,7 @@ const HeadSimple = observer(class Controls extends React.Component<Props> { const arrow = !isRelation; if (isType) { - buttonEdit = <Button id="button-edit" color="blank" className="c36" text={translate('commonEdit')} onClick={onEdit} />; + buttonEdit = <Button id="button-edit" color="blank" className="c28" text={translate('commonEdit')} onClick={onEdit} />; }; buttonCreate = <Button id="button-create" className="c36" text={text} arrow={arrow} onClick={onCreate} />; diff --git a/src/ts/component/page/main/type.tsx b/src/ts/component/page/main/type.tsx index 3754f38081..8e6f4c0adc 100644 --- a/src/ts/component/page/main/type.tsx +++ b/src/ts/component/page/main/type.tsx @@ -1,10 +1,12 @@ import * as React from 'react'; import $ from 'jquery'; import { observer } from 'mobx-react'; -import { Icon, Header, Footer, Loader, ListObjectPreview, ListObject, Select, Deleted } from 'Component'; +import { Icon, Header, Footer, Loader, ListObject, Deleted } from 'Component'; import { I, C, S, U, J, focus, Action, analytics, Relation, translate, sidebar } from 'Lib'; + import Controls from 'Component/page/elements/head/controls'; import HeadSimple from 'Component/page/elements/head/simple'; +import ListObjectPreview from 'Component/list/objectPreview'; interface State { isLoading: boolean; @@ -105,13 +107,20 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC {showTemplates ? ( <div className="section template"> <div className="title"> - {totalTemplate} {U.Common.plural(totalTemplate, translate('pluralTemplate'))} + <div className="side left"> + {U.Common.plural(totalTemplate, translate('pluralTemplate'))} + <span className="cnt">{totalTemplate}</span> + </div> - {allowedTemplate ? ( - <div className="btn" onClick={this.onTemplateAdd}> - <Icon className="plus" />{translate('commonNew')} - </div> - ) : ''} + <div className="side right"> + {allowedTemplate ? ( + <Icon + className="plus withBackground" + tooltip={translate('commonCreateNewTemplate')} + onClick={this.onTemplateAdd} + /> + ) : ''} + </div> </div> {totalTemplate ? ( @@ -139,7 +148,15 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC {object.isInstalled && !object._empty_ ? ( <div className="section set"> - <div className="title">{totalObject} {U.Common.plural(totalObject, translate('pluralObject'))}</div> + <div className="title"> + <div className="side left"> + {U.Common.plural(totalObject, translate('pluralObject'))} + <span className="cnt">{totalObject}</span> + </div> + + <div className="side right"> + </div> + </div> <div className="content"> <ListObject {...this.props} From 7a9e142d20d96088f122cb3e9621f7d6381ccf0e Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Tue, 29 Oct 2024 17:56:20 +0100 Subject: [PATCH 25/51] JS-5588: fix --- src/scss/page/main/type.scss | 6 +- .../component/page/elements/head/simple.tsx | 7 +- src/ts/component/page/main/type.tsx | 185 ++++++++++-------- 3 files changed, 111 insertions(+), 87 deletions(-) diff --git a/src/scss/page/main/type.scss b/src/scss/page/main/type.scss index 7ec0bb487a..cab53047bb 100644 --- a/src/scss/page/main/type.scss +++ b/src/scss/page/main/type.scss @@ -1,7 +1,7 @@ @import "~scss/_mixins"; .pageMainType { - .wrapper { width: 704px; margin: 0px auto; padding: 0px 0px 90px 0px; user-select: none; } + .wrapper { width: 704px; margin: 0px auto; padding: 40px 0px 90px 0px; user-select: none; } .wrapper.withIcon { .editorControls { @@ -28,9 +28,11 @@ } .title { .side.left { display: flex; flex-direction: row; align-items: center; gap: 0px 6px; } - .side.right { display: flex; justify-content: flex-end; } + .side.right { display: flex; flex-direction: row; align-items: center; justify-content: flex-end; gap: 0px 8px; } .icon.plus { background-image: url('~img/icon/plus/template.svg'); } + .icon.more { background-image: url('~img/icon/menu/action/more0.svg'); } + .cnt { color: var(--color-text-secondary); } } } diff --git a/src/ts/component/page/elements/head/simple.tsx b/src/ts/component/page/elements/head/simple.tsx index f2a64cc837..884b6396dd 100644 --- a/src/ts/component/page/elements/head/simple.tsx +++ b/src/ts/component/page/elements/head/simple.tsx @@ -100,14 +100,11 @@ const HeadSimple = observer(class Controls extends React.Component<Props> { if (isTypeOrRelation) { if (object.isInstalled) { - const text = isRelation ? translate('pageHeadSimpleCreateSet') : translate('commonCreate'); - const arrow = !isRelation; - if (isType) { buttonEdit = <Button id="button-edit" color="blank" className="c28" text={translate('commonEdit')} onClick={onEdit} />; + } else { + buttonCreate = <Button id="button-create" className="c36" text={translate('pageHeadSimpleCreateSet')} arrow={true} onClick={onCreate} />; }; - - buttonCreate = <Button id="button-create" className="c36" text={text} arrow={arrow} onClick={onCreate} />; } else { const cn = [ 'c36' ]; const isInstalled = this.isInstalled(); diff --git a/src/ts/component/page/main/type.tsx b/src/ts/component/page/main/type.tsx index 8e6f4c0adc..fe503db315 100644 --- a/src/ts/component/page/main/type.tsx +++ b/src/ts/component/page/main/type.tsx @@ -4,7 +4,6 @@ import { observer } from 'mobx-react'; import { Icon, Header, Footer, Loader, ListObject, Deleted } from 'Component'; import { I, C, S, U, J, focus, Action, analytics, Relation, translate, sidebar } from 'Lib'; -import Controls from 'Component/page/elements/head/controls'; import HeadSimple from 'Component/page/elements/head/simple'; import ListObjectPreview from 'Component/list/objectPreview'; @@ -21,7 +20,6 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC refHead: any = null; refControls: any = null; refListPreview: any = null; - timeout = 0; page = 0; state = { @@ -36,6 +34,7 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC this.onObjectAdd = this.onObjectAdd.bind(this); this.onSetAdd = this.onSetAdd.bind(this); this.onCreate = this.onCreate.bind(this); + this.onMore = this.onMore.bind(this); this.onEdit = this.onEdit.bind(this); }; @@ -48,29 +47,29 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC const rootId = this.getRootId(); const check = U.Data.checkDetails(rootId); - const object = S.Detail.get(rootId, rootId, J.Relation.type); + const type = this.getObject(); - if (!object) { + if (!type) { return null; }; const subIdTemplate = this.getSubIdTemplate(); const templates = S.Record.getRecordIds(subIdTemplate, ''); const canWrite = U.Space.canMyParticipantWrite(); - const isTemplate = object.uniqueKey == J.Constant.typeKey.template; + const isTemplate = type.uniqueKey == J.Constant.typeKey.template; - const showTemplates = !U.Object.getLayoutsWithoutTemplates().includes(object.recommendedLayout) && !isTemplate; - const recommendedRelations = Relation.getArrayValue(object.recommendedRelations); + const showTemplates = !U.Object.getLayoutsWithoutTemplates().includes(type.recommendedLayout) && !isTemplate; + const recommendedRelations = Relation.getArrayValue(type.recommendedRelations); const recommendedKeys = recommendedRelations.map(id => S.Record.getRelationById(id)).map(it => it && it.relationKey); - const allowedObject = object.isInstalled && U.Object.isInPageLayouts(object.recommendedLayout); - const allowedTemplate = object.isInstalled && allowedObject && showTemplates && canWrite && !isTemplate; + const allowedObject = this.isAllowedObject(); + const allowedTemplate = type.isInstalled && allowedObject && showTemplates && canWrite && !isTemplate; const subIdObject = this.getSubIdObject(); const totalObject = S.Record.getMeta(subIdObject, '').total; const totalTemplate = templates.length + (allowedTemplate ? 1 : 0); - const isFileType = U.Object.isInFileLayouts(object.recommendedLayout); + const isFileType = U.Object.isInFileLayouts(type.recommendedLayout); const columns: any[] = [ { relationKey: 'lastModifiedDate', name: translate('commonUpdated'), @@ -94,13 +93,11 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC {isLoading ? <Loader id="loader" /> : ''} <div className={[ 'blocks', 'wrapper', check.className ].join(' ')}> - <Controls ref={ref => this.refControls = ref} key="editorControls" {...this.props} rootId={rootId} resize={() => {}} /> <HeadSimple {...this.props} ref={ref => this.refHead = ref} placeholder={translate('defaultNameType')} rootId={rootId} - onCreate={this.onCreate} onEdit={this.onEdit} /> @@ -135,7 +132,7 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC onClick={(e: any, item: any) => this.templateOpen(item)} withBlank={true} blankId={J.Constant.templateId.blank} - defaultId={object.defaultTemplateId || J.Constant.templateId.blank} + defaultId={type.defaultTemplateId || J.Constant.templateId.blank} /> </div> ) : ( @@ -146,7 +143,7 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC </div> ) : ''} - {object.isInstalled && !object._empty_ ? ( + {type.isInstalled ? ( <div className="section set"> <div className="title"> <div className="side left"> @@ -155,13 +152,26 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC </div> <div className="side right"> + <Icon + id="button-create" + className="more withBackground" + onClick={this.onMore} + /> + + {allowedObject ? ( + <Icon + className="plus withBackground" + tooltip={translate('commonCreateNewObject')} + onClick={this.onCreate} + /> + ) : ''} </div> </div> <div className="content"> <ListObject {...this.props} sources={[ rootId ]} - spaceId={this.getSpaceId()} + spaceId={type.spaceId} subId={subIdObject} rootId={rootId} columns={columns} @@ -221,23 +231,6 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC }); }; - loadTemplates () { - const rootId = this.getRootId(); - - U.Data.searchSubscribe({ - spaceId: this.getSpaceId(), - subId: this.getSubIdTemplate(), - filters: [ - { relationKey: 'targetObjectType', condition: I.FilterCondition.Equal, value: rootId }, - ], - sorts: [ - { relationKey: 'lastModifiedDate', type: I.SortType.Desc }, - ], - keys: [ 'id' ], - ignoreDeleted: true, - }); - }; - close () { if (!this.id) { return; @@ -255,21 +248,44 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC }; }; + loadTemplates () { + const type = this.getObject(); + if (!type) { + return; + }; + + U.Data.searchSubscribe({ + spaceId: type.spaceId, + subId: this.getSubIdTemplate(), + filters: [ + { relationKey: 'targetObjectType', condition: I.FilterCondition.Equal, value: type.id }, + ], + sorts: [ + { relationKey: 'lastModifiedDate', type: I.SortType.Desc }, + ], + keys: [ 'id' ], + ignoreDeleted: true, + }); + }; + onTemplateAdd () { - const rootId = this.getRootId(); - const object = S.Detail.get(rootId, rootId); + const type = this.getObject(); + if (!type) { + return; + }; + const details: any = { - targetObjectType: rootId, - layout: object.recommendedLayout, + targetObjectType: type.id, + layout: type.recommendedLayout, }; - C.ObjectCreate(details, [], '', J.Constant.typeKey.template, S.Common.space, (message) => { + C.ObjectCreate(details, [], '', J.Constant.typeKey.template, S.Common.space, message => { if (message.error.code) { return; }; focus.clear(true); - analytics.event('CreateTemplate', { objectType: rootId, route: analytics.route.store }); + analytics.event('CreateTemplate', { objectType: type.id, route: analytics.route.store }); this.templateOpen(message.details); }); @@ -281,47 +297,55 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC }); }; - onCreate () { - const rootId = this.getRootId(); - const type = S.Record.getTypeById(rootId); - if (!type) { - return; + isAllowedObject (): boolean { + const type = this.getObject(); + + if (!type || !type.isInstalled) { + return false; }; const layout = type.recommendedLayout; - const options = []; - - let allowedObject = + + let ret = ( U.Object.isInPageLayouts(layout) || U.Object.isInSetLayouts(layout) || U.Object.isBookmarkLayout(layout) || - U.Object.isChatLayout(layout); + U.Object.isChatLayout(layout) + ); if (type.uniqueKey == J.Constant.typeKey.template) { - allowedObject = false; + ret = false; + }; + + return ret; + }; + + onCreate () { + const type = this.getObject(); + if (!type) { + return; }; - if (allowedObject) { - options.push({ id: 'object', name: translate('commonNewObject') }); + if (U.Object.isBookmarkLayout(type.recommendedLayout)) { + this.onBookmarkAdd(); + } else { + this.onObjectAdd(); }; + }; - options.push({ id: 'set', name: translate('pageMainTypeNewSetOfObjects') }); + onMore () { + const options = [ + { id: 'set', name: translate('pageMainTypeNewSetOfObjects') } + ]; S.Menu.open('select', { element: `#button-create`, offsetY: 8, horizontal: I.MenuDirection.Center, data: { - options: options, + options, onSelect: (e: any, item: any) => { switch (item.id) { - case 'object': - if (U.Object.isBookmarkLayout(type.recommendedLayout)) { - this.onBookmarkAdd(); - } else { - this.onObjectAdd(); - }; - break; case 'set': this.onSetAdd(); @@ -340,9 +364,7 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC }; onObjectAdd () { - const rootId = this.getRootId(); - const type = S.Record.getTypeById(rootId); - + const type = this.getObject(); if (!type) { return; }; @@ -377,14 +399,17 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC }; onSetAdd () { - const rootId = this.getRootId(); - const object = S.Detail.get(rootId, rootId); + const type = this.getObject(); + if (!type) { + return; + }; + const details = { - name: U.Common.sprintf(translate('commonSetName'), object.name), - iconEmoji: object.iconEmoji, + name: U.Common.sprintf(translate('commonSetName'), type.name), + iconEmoji: type.iconEmoji, }; - C.ObjectCreateSet([ rootId ], details, '', S.Common.space, (message: any) => { + C.ObjectCreateSet([ type.id ], details, '', S.Common.space, (message: any) => { if (!message.error.code) { focus.clear(true); U.Object.openConfig(message.details); @@ -398,15 +423,18 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC return; }; - const rootId = this.getRootId(); - const object = S.Detail.get(rootId, rootId); - const { defaultTemplateId } = object; - const template: any = { id: item.id, typeId: rootId }; + const type = this.getObject(); + if (!type) { + return; + }; + + const { defaultTemplateId } = type; + const template: any = { id: item.id, typeId: type.id }; if (template.id == J.Constant.templateId.blank) { template.isBlank = true; - if (!object.defaultTemplateId) { + if (!defaultTemplateId) { template.isDefault = true; }; } else @@ -424,18 +452,18 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC onClose: () => $(`#item-${item.id}`).removeClass('active'), data: { template, - typeId: rootId, + typeId: type.id, templateId: defaultTemplateId, route: analytics.route.type, onSetDefault: () => { - U.Object.setDefaultTemplateId(rootId, template.id); + U.Object.setDefaultTemplateId(type.id, template.id); }, onDuplicate: (object: any) => { this.templateOpen(object); }, onArchive: () => { if (template.isDefault) { - U.Object.setDefaultTemplateId(rootId, J.Constant.templateId.blank); + U.Object.setDefaultTemplateId(type.id, J.Constant.templateId.blank); }; } } @@ -448,11 +476,8 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC return rootId ? rootId : match.params.id; }; - getSpaceId () { - const rootId = this.getRootId(); - const object = S.Detail.get(rootId, rootId, [ 'spaceId' ], true); - - return object.spaceId; + getObject () { + return S.Record.getTypeById(this.getRootId()); }; getSubIdTemplate () { From b3486c2fa6a111d171d2660d90b357d3fdff9a0f Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Tue, 29 Oct 2024 18:04:30 +0100 Subject: [PATCH 26/51] refactoring --- src/ts/component/page/elements/head/simple.tsx | 1 - src/ts/component/page/main/type.tsx | 3 +-- src/ts/lib/util/data.ts | 1 + 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ts/component/page/elements/head/simple.tsx b/src/ts/component/page/elements/head/simple.tsx index 884b6396dd..f7a4a4b5da 100644 --- a/src/ts/component/page/elements/head/simple.tsx +++ b/src/ts/component/page/elements/head/simple.tsx @@ -46,7 +46,6 @@ const HeadSimple = observer(class Controls extends React.Component<Props> { const blockFeatured: any = new M.Block({ id: 'featuredRelations', type: I.BlockType.Featured, childrenIds: [], fields: {}, content: {} }); const isTypeOrRelation = U.Object.isTypeOrRelationLayout(object.layout); const isType = U.Object.isTypeLayout(object.layout); - const isRelation = U.Object.isRelationLayout(object.layout); const canEditIcon = allowDetails && !U.Object.isRelationLayout(object.layout); const cn = [ 'headSimple', check.className ]; const placeholder = { diff --git a/src/ts/component/page/main/type.tsx b/src/ts/component/page/main/type.tsx index fe503db315..f11afc0d93 100644 --- a/src/ts/component/page/main/type.tsx +++ b/src/ts/component/page/main/type.tsx @@ -46,7 +46,6 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC }; const rootId = this.getRootId(); - const check = U.Data.checkDetails(rootId); const type = this.getObject(); if (!type) { @@ -92,7 +91,7 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC {isLoading ? <Loader id="loader" /> : ''} - <div className={[ 'blocks', 'wrapper', check.className ].join(' ')}> + <div className="blocks wrapper"> <HeadSimple {...this.props} ref={ref => this.refHead = ref} diff --git a/src/ts/lib/util/data.ts b/src/ts/lib/util/data.ts index 5e327679ce..08eff971a8 100644 --- a/src/ts/lib/util/data.ts +++ b/src/ts/lib/util/data.ts @@ -636,6 +636,7 @@ class UtilData { case I.ObjectLayout.Human: case I.ObjectLayout.Participant: + case I.ObjectLayout.Type: case I.ObjectLayout.Relation: { ret.withIcon = true; break; From 760f36f467fce033bef164ee7083adf7dc50b056 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Tue, 29 Oct 2024 18:25:26 +0100 Subject: [PATCH 27/51] select fixes --- src/scss/menu/select.scss | 1 - src/ts/component/menu/dataview/filter/list.tsx | 1 - src/ts/component/menu/dataview/filter/values.tsx | 2 +- src/ts/component/menu/index.tsx | 4 ++-- src/ts/component/menu/select.tsx | 10 +++++----- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/scss/menu/select.scss b/src/scss/menu/select.scss index 6177ac3a4e..71cc433689 100644 --- a/src/scss/menu/select.scss +++ b/src/scss/menu/select.scss @@ -4,7 +4,6 @@ .menu.menuSelect { .content { transition: none; overflow: hidden; padding: 0px; } .items { height: 100%; overflow: auto; } - .item.empty { margin-top: 8px; } .item { display: flex; align-items: center; } .item { diff --git a/src/ts/component/menu/dataview/filter/list.tsx b/src/ts/component/menu/dataview/filter/list.tsx index aa47c7adde..b7daa46a73 100644 --- a/src/ts/component/menu/dataview/filter/list.tsx +++ b/src/ts/component/menu/dataview/filter/list.tsx @@ -212,7 +212,6 @@ const MenuFilterList = observer(class MenuFilterList extends React.Component<I.M const condition = conditions.length ? conditions[0].id : I.FilterCondition.None; const newItem = { relationKey: first.id, - condition: condition as I.FilterCondition, value: Relation.formatValue(first, null, false), }; diff --git a/src/ts/component/menu/dataview/filter/values.tsx b/src/ts/component/menu/dataview/filter/values.tsx index e2adf07925..e1ab2ea10d 100644 --- a/src/ts/component/menu/dataview/filter/values.tsx +++ b/src/ts/component/menu/dataview/filter/values.tsx @@ -473,7 +473,7 @@ const MenuDataviewFilterValues = observer(class MenuDataviewFilterValues extends noVirtualisation: true, rebind: this.rebind, value: item[item.id], - options, + options: U.Menu.prepareForSelect(options), onSelect: (e: any, el: any) => { this.onChange(item.id, el.id); } diff --git a/src/ts/component/menu/index.tsx b/src/ts/component/menu/index.tsx index 04acc63c08..dd16db18a0 100644 --- a/src/ts/component/menu/index.tsx +++ b/src/ts/component/menu/index.tsx @@ -854,7 +854,7 @@ const Menu = observer(class Menu extends React.Component<I.Menu, State> { return; }; - if ((item.isDiv || item.isSection) && (items.length > 1)) { + if ((item.isDiv || item.isSection || item.isEmpty) && (items.length > 1)) { onArrow(dir); return; }; @@ -957,7 +957,7 @@ const Menu = observer(class Menu extends React.Component<I.Menu, State> { return; }; - if (next.isDiv || next.isSection) { + if (next.isDiv || next.isSection || next.isEmpty) { this.ref.n++; if (items[this.ref.n]) { this.setActive(items[this.ref.n], scroll); diff --git a/src/ts/component/menu/select.tsx b/src/ts/component/menu/select.tsx index a4b8d27cea..e1ac1b9bb6 100644 --- a/src/ts/component/menu/select.tsx +++ b/src/ts/component/menu/select.tsx @@ -174,10 +174,6 @@ const MenuSelect = observer(class MenuSelect extends React.Component<I.Menu> { <Label className="menuLabel" text={menuLabel} /> ) : ''} - {!items.length ? ( - <div className="item empty">{translate('menuSelectEmpty')}</div> - ) : ''} - <div className="items"> {content} </div> @@ -307,6 +303,10 @@ const MenuSelect = observer(class MenuSelect extends React.Component<I.Menu> { items = items.filter(it => String(it.name || '').match(filter)); }; + if (!items.length) { + items.push({ id: 'empty', name: translate('menuSelectEmpty'), className: 'empty', isEmpty: true }); + }; + if (withAdd) { items = items.concat([ { isDiv: true }, @@ -431,7 +431,7 @@ const MenuSelect = observer(class MenuSelect extends React.Component<I.Menu> { if (!noScroll) { let height = 0; if (withFilter) { - height += 60; + height += 52; }; if (!withFilter || noScroll) { height += 16; From 545652786d7217308365ec5b24e11b589ae6e03b Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Wed, 30 Oct 2024 09:43:09 +0100 Subject: [PATCH 28/51] refactoring --- src/scss/component/preview/object.scss | 8 ++---- src/ts/component/list/objectPreview.tsx | 2 +- src/ts/component/page/main/type.tsx | 37 ++++++++++++++++++------- src/ts/component/preview/object.tsx | 5 ++-- 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/scss/component/preview/object.scss b/src/scss/component/preview/object.scss index ec7c1459d3..0deee0d70d 100644 --- a/src/scss/component/preview/object.scss +++ b/src/scss/component/preview/object.scss @@ -19,11 +19,9 @@ .heading { display: block; margin-bottom: 14px; position: relative; z-index: 1; } .heading { - .iconObject { display: inline-block; background-color: var(--color-shape-tertiary); border-radius: 8px; margin: 0px 0px 2px 0px; box-shadow: 0px 0px 0px 2px var(--color-bg-primary) inset; } - .iconObject { - .iconImage { border: 2px solid var(--color-bg-primary); } - } + .iconObject { display: inline-block; background-color: var(--color-shape-tertiary); border-radius: 8px; margin: 0px 0px 6px 0px; box-shadow: 0px 0px 0px 2px var(--color-bg-primary); } .iconObject.isTask { background: none; position: absolute; top: 2px; left: -24px; box-shadow: 0px 0px !important; } + .name { display: block; @include text-paragraph; @include text-overflow-nw; font-weight: 700; position: relative; width: 100%; } .description { @include text-small; @include text-overflow-nw; } @@ -195,7 +193,7 @@ } /* PreviewObject Medium */ -.previewObject.medium { width: 224px; height: 158px; } +.previewObject.medium { width: 224px; height: 160px; } .previewObject.medium { .cover { height: 72px; } .scroller { padding: 32px 24px; } diff --git a/src/ts/component/list/objectPreview.tsx b/src/ts/component/list/objectPreview.tsx index a05587da9d..1b2931ac86 100644 --- a/src/ts/component/list/objectPreview.tsx +++ b/src/ts/component/list/objectPreview.tsx @@ -84,7 +84,7 @@ class ListObjectPreview extends React.Component<Props> { content = ( <PreviewObject ref={ref => this.refObj[item.id] = ref} - size={I.PreviewSize.Large} + size={I.PreviewSize.Medium} rootId={item.id} onClick={e => this.onClick(e, item)} onMore={onMenu ? e => onMenu(e, item) : null} diff --git a/src/ts/component/page/main/type.tsx b/src/ts/component/page/main/type.tsx index f11afc0d93..06f68baf2e 100644 --- a/src/ts/component/page/main/type.tsx +++ b/src/ts/component/page/main/type.tsx @@ -52,21 +52,18 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC return null; }; + const recommended = Relation.getArrayValue(type.recommendedRelations).map(id => S.Record.getRelationById(id)).filter(it => it).map(it => it.relationKey); + const subIdTemplate = this.getSubIdTemplate(); - const templates = S.Record.getRecordIds(subIdTemplate, ''); - const canWrite = U.Space.canMyParticipantWrite(); - const isTemplate = type.uniqueKey == J.Constant.typeKey.template; + const subIdObject = this.getSubIdObject(); - const showTemplates = !U.Object.getLayoutsWithoutTemplates().includes(type.recommendedLayout) && !isTemplate; - const recommendedRelations = Relation.getArrayValue(type.recommendedRelations); - const recommendedKeys = recommendedRelations.map(id => S.Record.getRelationById(id)).map(it => it && it.relationKey); + const showTemplates = this.showTemplates(); const allowedObject = this.isAllowedObject(); - const allowedTemplate = type.isInstalled && allowedObject && showTemplates && canWrite && !isTemplate; + const allowedTemplate = this.isAllowedTemplate(); - const subIdObject = this.getSubIdObject(); const totalObject = S.Record.getMeta(subIdObject, '').total; - const totalTemplate = templates.length + (allowedTemplate ? 1 : 0); + const totalTemplate = S.Record.getMeta(subIdTemplate, '').total + (allowedTemplate ? 1 : 0); const isFileType = U.Object.isInFileLayouts(type.recommendedLayout); const columns: any[] = [ @@ -174,7 +171,7 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC subId={subIdObject} rootId={rootId} columns={columns} - relationKeys={recommendedKeys} + relationKeys={recommended} /> </div> </div> @@ -296,6 +293,21 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC }); }; + showTemplates (): boolean { + const type = this.getObject(); + if (!type) { + return false; + }; + + return !U.Object.getLayoutsWithoutTemplates().includes(type.recommendedLayout) && (type.uniqueKey != J.Constant.typeKey.template); + }; + + isAllowedTemplate (): boolean { + const type = this.getObject(); + + return type?.isInstalled && this.isAllowedObject() && this.showTemplates(); + }; + isAllowedObject (): boolean { const type = this.getObject(); @@ -303,6 +315,11 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC return false; }; + const canWrite = U.Space.canMyParticipantWrite(); + if (!canWrite) { + return false; + }; + const layout = type.recommendedLayout; let ret = ( diff --git a/src/ts/component/preview/object.tsx b/src/ts/component/preview/object.tsx index a6fb0c8e97..135b7ea531 100644 --- a/src/ts/component/preview/object.tsx +++ b/src/ts/component/preview/object.tsx @@ -336,11 +336,10 @@ const PreviewObject = observer(class PreviewObject extends React.Component<Props <div onClick={onClick}> <div className="scroller"> {object.templateIsBundled ? <Icon className="logo" tooltip={translate('previewObjectTemplateIsBundled')} /> : ''} - - {(coverType != I.CoverType.None) && coverId ? <Cover type={coverType} id={coverId} image={coverId} className={coverId} x={coverX} y={coverY} scale={coverScale} withScale={true} /> : ''} + {check.withCover ? <Cover type={coverType} id={coverId} image={coverId} className={coverId} x={coverX} y={coverY} scale={coverScale} withScale={true} /> : ''} <div className="heading"> - <IconObject size={size} object={object} /> + {check.withIcon ? <IconObject size={size} object={object} /> : ''} <div className="name">{name}</div> <div className="featured" /> </div> From ee7855fd54e2466149ea551c5fe491ada0dacebc Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Wed, 30 Oct 2024 09:50:12 +0100 Subject: [PATCH 29/51] refactoring --- src/ts/component/page/main/type.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ts/component/page/main/type.tsx b/src/ts/component/page/main/type.tsx index 06f68baf2e..b4a4e53506 100644 --- a/src/ts/component/page/main/type.tsx +++ b/src/ts/component/page/main/type.tsx @@ -61,9 +61,10 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC const allowedObject = this.isAllowedObject(); const allowedTemplate = this.isAllowedTemplate(); - + + const templates = S.Record.getRecordIds(subIdTemplate, ''); const totalObject = S.Record.getMeta(subIdObject, '').total; - const totalTemplate = S.Record.getMeta(subIdTemplate, '').total + (allowedTemplate ? 1 : 0); + const totalTemplate = templates.length + (allowedTemplate ? 1 : 0); const isFileType = U.Object.isInFileLayouts(type.recommendedLayout); const columns: any[] = [ @@ -250,11 +251,14 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC return; }; + const template = S.Record.getTemplateType(); + U.Data.searchSubscribe({ spaceId: type.spaceId, subId: this.getSubIdTemplate(), filters: [ { relationKey: 'targetObjectType', condition: I.FilterCondition.Equal, value: type.id }, + { relationKey: 'type', condition: I.FilterCondition.Equal, value: template.id }, ], sorts: [ { relationKey: 'lastModifiedDate', type: I.SortType.Desc }, From 40bfd5f33a21b5c96b9a22e534bb500741645462 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Wed, 30 Oct 2024 10:09:59 +0100 Subject: [PATCH 30/51] refactoring --- src/scss/component/sidebar/page.scss | 14 ++++++++++ src/scss/component/sidebar/page/type.scss | 12 -------- src/ts/component/page/main/navigation.tsx | 2 +- src/ts/component/sidebar/left.tsx | 28 ++++++++++++++----- .../page/{object.tsx => allObject.tsx} | 2 +- .../page/{object => allObject}/item.tsx | 0 .../sidebar/page/object/relation.tsx | 20 +++++++++++++ src/ts/component/sidebar/page/type.tsx | 3 +- src/ts/component/sidebar/right.tsx | 2 +- src/ts/lib/sidebar.ts | 8 +++++- src/ts/store/common.ts | 11 -------- 11 files changed, 66 insertions(+), 36 deletions(-) rename src/ts/component/sidebar/page/{object.tsx => allObject.tsx} (99%) rename src/ts/component/sidebar/page/{object => allObject}/item.tsx (100%) create mode 100644 src/ts/component/sidebar/page/object/relation.tsx diff --git a/src/scss/component/sidebar/page.scss b/src/scss/component/sidebar/page.scss index e5cb306bde..139482b838 100644 --- a/src/scss/component/sidebar/page.scss +++ b/src/scss/component/sidebar/page.scss @@ -1,4 +1,18 @@ > .sidebarPage { + .head { + display: flex; flex-direction: row; align-items: center; justify-content: space-between; -webkit-app-region: no-drag; + padding: 12px 12px 16px 12px; + } + .head { + .side.left { flex-grow: 1; font-weight: 500; } + .side.right { flex-shrink: 0; display: flex; flex-direction: row; gap: 0px 8px; } + } + + .body { + padding: 0px 12px 12px 12px; overflow: scroll; display: flex; flex-direction: column; gap: 12px 0px; overscroll-behavior: none; + scrollbar-gutter: stable both-edges; + } + .section { background: var(--color-bg-primary); border-radius: 12px; padding: 8px 0px; } .section { diff --git a/src/scss/component/sidebar/page/type.scss b/src/scss/component/sidebar/page/type.scss index 2efb05c6ad..412b180d9f 100644 --- a/src/scss/component/sidebar/page/type.scss +++ b/src/scss/component/sidebar/page/type.scss @@ -1,16 +1,4 @@ > .sidebarPage.pageType { - .head { - display: flex; flex-direction: row; align-items: center; justify-content: space-between; -webkit-app-region: no-drag; - padding: 12px 12px 16px 12px; - } - .head { - .side.left { flex-grow: 1; font-weight: 500; } - .side.right { flex-shrink: 0; display: flex; flex-direction: row; gap: 0px 8px; } - } - - .body { padding: 0px 12px 12px 12px; overflow: scroll; display: flex; flex-direction: column; gap: 12px 0px; } - - .section.typeTitle { padding: 16px; } .section.typeTitle { > .wrap { display: flex; flex-direction: row; gap: 0px 8px; align-items: center; @include text-paragraph; font-weight: 600; } diff --git a/src/ts/component/page/main/navigation.tsx b/src/ts/component/page/main/navigation.tsx index 7717e831fa..03a47f9d7d 100644 --- a/src/ts/component/page/main/navigation.tsx +++ b/src/ts/component/page/main/navigation.tsx @@ -6,7 +6,7 @@ import { AutoSizer, CellMeasurer, InfiniteLoader, List, CellMeasurerCache } from import { Button, Cover, Loader, IconObject, Header, Footer, ObjectName, ObjectDescription } from 'Component'; import { I, C, S, U, keyboard, focus, translate } from 'Lib'; -import Item from 'Component/sidebar/page/object/item'; +import Item from 'Component/sidebar/page/allObject/item'; interface State { loading: boolean; diff --git a/src/ts/component/sidebar/left.tsx b/src/ts/component/sidebar/left.tsx index c0f83a1602..4d66b147a0 100644 --- a/src/ts/component/sidebar/left.tsx +++ b/src/ts/component/sidebar/left.tsx @@ -6,9 +6,18 @@ import { Icon } from 'Component'; import { I, U, J, S, keyboard, Preview, sidebar } from 'Lib'; import SidebarWidget from './page/widget'; -import SidebarObject from './page/object'; +import SidebarObject from './page/allObject'; -const SidebarLeft = observer(class SidebarLeft extends React.Component { +interface State { + page: string; +}; + +const Components = { + object: SidebarObject, + widget: SidebarWidget, +}; + +const SidebarLeft = observer(class SidebarLeft extends React.Component<{}, State> { private _isMounted = false; node = null; @@ -18,8 +27,11 @@ const SidebarLeft = observer(class SidebarLeft extends React.Component { frame = 0; width = 0; movedX = false; - refWidget = null; - refObject = null; + refChild = null; + + state = { + page: 'widget', + }; constructor (props) { super(props); @@ -33,9 +45,11 @@ const SidebarLeft = observer(class SidebarLeft extends React.Component { }; render() { - const { showVault, showObject } = S.Common; + const { showVault } = S.Common; + const page = this.state.page || 'widget'; const cn = [ 'sidebar' ]; const cmd = keyboard.cmdSymbol(); + const Component = Components[page]; return ( <React.Fragment> @@ -53,7 +67,7 @@ const SidebarLeft = observer(class SidebarLeft extends React.Component { id="sidebarLeft" className={cn.join(' ')} > - {showObject ? <SidebarObject ref={ref => this.refObject = ref} {...this.props} /> : <SidebarWidget {...this.props} ref={ref => this.refWidget = ref} />} + <Component ref={ref => this.refChild = ref} {...this.props} /> <div className="resize-h" draggable={true} onDragStart={this.onResizeStart}> <div className="resize-handle" onClick={this.onHandleClick} /> </div> @@ -172,7 +186,7 @@ const SidebarLeft = observer(class SidebarLeft extends React.Component { }; this.width = w; - this.refObject?.resize(); + this.refChild.resize(); }); }; diff --git a/src/ts/component/sidebar/page/object.tsx b/src/ts/component/sidebar/page/allObject.tsx similarity index 99% rename from src/ts/component/sidebar/page/object.tsx rename to src/ts/component/sidebar/page/allObject.tsx index 7560d32be4..a6fa62b2d2 100644 --- a/src/ts/component/sidebar/page/object.tsx +++ b/src/ts/component/sidebar/page/allObject.tsx @@ -4,7 +4,7 @@ import { AutoSizer, CellMeasurer, InfiniteLoader, List, CellMeasurerCache } from import { Title, Filter, Icon, Button, Label, EmptySearch } from 'Component'; import { I, U, J, S, translate, Storage, sidebar, keyboard, analytics, Action, Relation } from 'Lib'; -import Item from './object/item'; +import Item from './allObject/item'; interface State { isLoading: boolean; diff --git a/src/ts/component/sidebar/page/object/item.tsx b/src/ts/component/sidebar/page/allObject/item.tsx similarity index 100% rename from src/ts/component/sidebar/page/object/item.tsx rename to src/ts/component/sidebar/page/allObject/item.tsx diff --git a/src/ts/component/sidebar/page/object/relation.tsx b/src/ts/component/sidebar/page/object/relation.tsx new file mode 100644 index 0000000000..2837882ea5 --- /dev/null +++ b/src/ts/component/sidebar/page/object/relation.tsx @@ -0,0 +1,20 @@ +import * as React from 'react'; +import { observer } from 'mobx-react'; +import { I } from 'Lib'; + +const SidebarPageObjectRelation = observer(class SidebarPageObjectRelation extends React.Component<I.SidebarPageComponent> { + + constructor (props: I.SidebarPageComponent) { + super(props); + }; + + render () { + return ( + <React.Fragment> + </React.Fragment> + ); + }; + +}); + +export default SidebarPageObjectRelation; \ No newline at end of file diff --git a/src/ts/component/sidebar/page/type.tsx b/src/ts/component/sidebar/page/type.tsx index 28290acda5..378e7c5161 100644 --- a/src/ts/component/sidebar/page/type.tsx +++ b/src/ts/component/sidebar/page/type.tsx @@ -7,7 +7,6 @@ import Section from 'Component/sidebar/section'; const SidebarPageType = observer(class SidebarPageType extends React.Component<I.SidebarPageComponent> { - node = null; object: any = {}; update: any = {}; sectionRefs: Map<string, any> = new Map(); @@ -24,7 +23,7 @@ const SidebarPageType = observer(class SidebarPageType extends React.Component<I const type = this.getObject(); const sections = this.getSections(); - return ( + return ( <React.Fragment> <div className="head"> <div className="side left"> diff --git a/src/ts/component/sidebar/right.tsx b/src/ts/component/sidebar/right.tsx index 05fbaff2d6..8fb03fb262 100644 --- a/src/ts/component/sidebar/right.tsx +++ b/src/ts/component/sidebar/right.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { observer } from 'mobx-react'; -import { I, U, S } from 'Lib'; +import { U, S } from 'Lib'; import PageType from './page/type'; diff --git a/src/ts/lib/sidebar.ts b/src/ts/lib/sidebar.ts index d6b0617415..2c9274d97b 100644 --- a/src/ts/lib/sidebar.ts +++ b/src/ts/lib/sidebar.ts @@ -351,7 +351,13 @@ class Sidebar { }; objectContainerToggle () { - S.Common.showObjectSet(!S.Common.showObject); + const ref = S.Common.getRef('sidebarLeft'); + if (!ref) { + return; + }; + + const page = ref.state.page; + ref.setState({ page: (page == 'object' ? '' : 'object') }); }; rightPanelToggle (v: boolean) { diff --git a/src/ts/store/common.ts b/src/ts/store/common.ts index fa2c81e50a..6bdb8cbe22 100644 --- a/src/ts/store/common.ts +++ b/src/ts/store/common.ts @@ -44,7 +44,6 @@ class CommonStore { public showVaultValue = null; public showSidebarRightValue = null; public hideSidebarValue = null; - public showObjectValue = null; public gallery = { categories: [], list: [], @@ -103,7 +102,6 @@ class CommonStore { shareTooltipValue: observable, showVaultValue: observable, hideSidebarValue: observable, - showObjectValue: observable, spaceId: observable, membershipTiersList: observable, showSidebarRightValue: observable, @@ -140,7 +138,6 @@ class CommonStore { shareTooltipSet: action, membershipTiersListSet: action, showVaultSet: action, - showObjectSet: action, showSidebarRightSet: action, }); @@ -212,10 +209,6 @@ class CommonStore { return Boolean(this.showSidebarRightValue); }; - get showObject (): boolean { - return this.showObjectValue; - }; - get theme (): string { return String(this.themeId || ''); }; @@ -406,10 +399,6 @@ class CommonStore { this.showSidebarRightValue = Boolean(v); }; - showObjectSet (v: boolean) { - this.showObjectValue = v; - }; - fullscreenSet (v: boolean) { const body = $('body'); From c714f02da581cedfe86fedaed54c1ee03009a4bd Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Wed, 30 Oct 2024 12:05:25 +0100 Subject: [PATCH 31/51] JS-5587: relations in object --- src/json/text.json | 1 + src/scss/block/common.scss | 1 - .../{block/dataview => component}/cell.scss | 0 src/scss/component/common.scss | 1 + src/scss/component/sidebar/page.scss | 11 ++- src/scss/component/sidebar/page/object.scss | 81 +++++++++++++++++++ .../block/dataview/view/board/column.tsx | 3 +- .../{block/dataview => }/cell/checkbox.tsx | 0 .../{block/dataview => }/cell/file.tsx | 0 .../{block/dataview => }/cell/index.tsx | 0 .../{block/dataview => }/cell/item/object.tsx | 0 .../{block/dataview => }/cell/object.tsx | 0 .../{block/dataview => }/cell/select.tsx | 0 .../{block/dataview => }/cell/text.tsx | 0 src/ts/component/header/main/object.tsx | 5 +- src/ts/component/index.tsx | 2 +- src/ts/component/page/main/type.tsx | 2 +- .../sidebar/page/object/relation.tsx | 72 ++++++++++++++++- src/ts/component/sidebar/page/type.tsx | 1 + src/ts/component/sidebar/right.tsx | 8 +- src/ts/component/sidebar/section/index.tsx | 23 +++++- .../sidebar/section/object/relation.tsx | 71 ++++++++++++++++ src/ts/component/widget/view/board/group.tsx | 3 +- src/ts/interface/common.ts | 1 + src/ts/lib/sidebar.ts | 4 + src/ts/lib/util/common.ts | 3 + 26 files changed, 275 insertions(+), 18 deletions(-) rename src/scss/{block/dataview => component}/cell.scss (100%) create mode 100644 src/scss/component/sidebar/page/object.scss rename src/ts/component/{block/dataview => }/cell/checkbox.tsx (100%) rename src/ts/component/{block/dataview => }/cell/file.tsx (100%) rename src/ts/component/{block/dataview => }/cell/index.tsx (100%) rename src/ts/component/{block/dataview => }/cell/item/object.tsx (100%) rename src/ts/component/{block/dataview => }/cell/object.tsx (100%) rename src/ts/component/{block/dataview => }/cell/select.tsx (100%) rename src/ts/component/{block/dataview => }/cell/text.tsx (100%) create mode 100644 src/ts/component/sidebar/section/object/relation.tsx diff --git a/src/json/text.json b/src/json/text.json index 40e3c410ee..ea5afe81f7 100644 --- a/src/json/text.json +++ b/src/json/text.json @@ -1830,6 +1830,7 @@ "sidebarTypeRelation": "Fields", "sidebarTypeRelationHeader": "Header", "sidebarTypeRelationSidebar": "Sidebar", + "sidebarObjectRelationSetUp": "Set up", "unsplashString": "Photo by %s on %s", "templateBannner": "You are editing a template", diff --git a/src/scss/block/common.scss b/src/scss/block/common.scss index 284d0366c5..8189f7e5b0 100644 --- a/src/scss/block/common.scss +++ b/src/scss/block/common.scss @@ -112,7 +112,6 @@ @import "./bookmark"; @import "./cover"; @import "./dataview"; -@import "./dataview/cell"; @import "./dataview/view/board"; @import "./dataview/view/common"; @import "./dataview/view/gallery"; diff --git a/src/scss/block/dataview/cell.scss b/src/scss/component/cell.scss similarity index 100% rename from src/scss/block/dataview/cell.scss rename to src/scss/component/cell.scss diff --git a/src/scss/component/common.scss b/src/scss/component/common.scss index 0f179ea555..65338b4901 100644 --- a/src/scss/component/common.scss +++ b/src/scss/component/common.scss @@ -27,6 +27,7 @@ @import "./hightlight"; @import "./progressBar"; @import "./share"; +@import "./cell"; @import "./preview/common"; @import "./media/common"; \ No newline at end of file diff --git a/src/scss/component/sidebar/page.scss b/src/scss/component/sidebar/page.scss index 139482b838..9a2d98cfc0 100644 --- a/src/scss/component/sidebar/page.scss +++ b/src/scss/component/sidebar/page.scss @@ -1,16 +1,20 @@ +> .sidebarPage { display: flex; flex-direction: column; height: 100%; } > .sidebarPage { .head { display: flex; flex-direction: row; align-items: center; justify-content: space-between; -webkit-app-region: no-drag; - padding: 12px 12px 16px 12px; + padding: 12px 12px 16px 12px; flex-shrink: 0; } .head { .side.left { flex-grow: 1; font-weight: 500; } .side.right { flex-shrink: 0; display: flex; flex-direction: row; gap: 0px 8px; } + + .button.simple { @include text-common; font-weight: 500; color: var(--color-text-secondary); } + .button.simple:hover { color: var(--color-text-primary); } } .body { padding: 0px 12px 12px 12px; overflow: scroll; display: flex; flex-direction: column; gap: 12px 0px; overscroll-behavior: none; - scrollbar-gutter: stable both-edges; + scrollbar-gutter: stable both-edges; flex-grow: 1; } .section { background: var(--color-bg-primary); border-radius: 12px; padding: 8px 0px; } @@ -56,4 +60,5 @@ } -@import "./page/type.scss"; \ No newline at end of file +@import "./page/type.scss"; +@import "./page/object.scss"; \ No newline at end of file diff --git a/src/scss/component/sidebar/page/object.scss b/src/scss/component/sidebar/page/object.scss new file mode 100644 index 0000000000..af18768db1 --- /dev/null +++ b/src/scss/component/sidebar/page/object.scss @@ -0,0 +1,81 @@ +> .sidebarPage.pageObjectRelation { + .section.objectRelation { padding: 12px 16px; display: flex; flex-direction: column; } + .section.objectRelation { + > .wrap { + > .name { color: var(--color-text-secondary); } + + .cell { border-radius: 4px; line-height: 22px; transition: background $transitionCommon; position: relative; } + .cell.canEdit { + .cellContent { + .empty { display: block; } + } + } + + .cell.c-select, + .cell.c-object, + .cell.c-file { + .over { overflow: visible !important; width: 100%; flex-wrap: wrap; gap: 4px 6px; } + } + + .cell.c-object { + .element { max-width: 150px; } + } + + .cell.c-select { + .over { margin-top: 2px; } + } + + .cell.c-shortText { + .name { width: 100%; } + } + + .cell.c-longText { + .name, span { @include clamp3; word-wrap: break-word; line-height: 22px; } + } + + .cell.isEditing { padding: 0px; } + .cell.isEditing { + .cellContent { position: relative; height: auto !important; min-height: 32px; border-radius: 4px; } + .cellContent.isName .input { height: 20px; line-height: 20px; } + .icon.clear { right: 8px; } + } + + .cell.isEditing.c-select { + .empty { display: inline-block; } + .cellContent, .placeholder { padding: 5px 8px 1px 8px; } + } + .cell.isEditing.c-select.isSelect { + .over { width: calc(100% - 26px); } + } + + .cell.isEditing.c-shortText, + .cell.isEditing.c-number, + .cell.isEditing.c-url, + .cell.isEditing.c-phone, + .cell.isEditing.c-email, + .cell.isEditing.c-date, + .cell.isEditing.c-longText, + .cell.isEditing.c-file + { + .cellContent { padding: 5px 8px !important; } + .placeholder { padding: 5px 8px; } + } + + .cell.isEditing.c-object { + .cellContent, .placeholder { padding: 5px 8px !important; } + } + + .cell.isEditing.c-longText { + .cellContent { box-shadow: 0px 0px; visibility: hidden; } + .cellContent span:empty { height: 22px; } + } + + .cellContent { min-height: 22px; } + .cellContent { + .name { line-height: 22px; } + .more { line-height: 22px; } + } + .cellContent.isName { display: flex; align-items: center; } + } + } +} \ No newline at end of file diff --git a/src/ts/component/block/dataview/view/board/column.tsx b/src/ts/component/block/dataview/view/board/column.tsx index f7ac9c7110..bd69152529 100644 --- a/src/ts/component/block/dataview/view/board/column.tsx +++ b/src/ts/component/block/dataview/view/board/column.tsx @@ -1,10 +1,9 @@ import * as React from 'react'; import $ from 'jquery'; import { observer } from 'mobx-react'; -import { Icon, LoadMore } from 'Component'; +import { Icon, LoadMore, Cell } from 'Component'; import { I, S, U, translate, Dataview } from 'Lib'; import Card from './card'; -import Cell from 'Component/block/dataview/cell'; interface Props extends I.ViewComponent { id: string; diff --git a/src/ts/component/block/dataview/cell/checkbox.tsx b/src/ts/component/cell/checkbox.tsx similarity index 100% rename from src/ts/component/block/dataview/cell/checkbox.tsx rename to src/ts/component/cell/checkbox.tsx diff --git a/src/ts/component/block/dataview/cell/file.tsx b/src/ts/component/cell/file.tsx similarity index 100% rename from src/ts/component/block/dataview/cell/file.tsx rename to src/ts/component/cell/file.tsx diff --git a/src/ts/component/block/dataview/cell/index.tsx b/src/ts/component/cell/index.tsx similarity index 100% rename from src/ts/component/block/dataview/cell/index.tsx rename to src/ts/component/cell/index.tsx diff --git a/src/ts/component/block/dataview/cell/item/object.tsx b/src/ts/component/cell/item/object.tsx similarity index 100% rename from src/ts/component/block/dataview/cell/item/object.tsx rename to src/ts/component/cell/item/object.tsx diff --git a/src/ts/component/block/dataview/cell/object.tsx b/src/ts/component/cell/object.tsx similarity index 100% rename from src/ts/component/block/dataview/cell/object.tsx rename to src/ts/component/cell/object.tsx diff --git a/src/ts/component/block/dataview/cell/select.tsx b/src/ts/component/cell/select.tsx similarity index 100% rename from src/ts/component/block/dataview/cell/select.tsx rename to src/ts/component/cell/select.tsx diff --git a/src/ts/component/block/dataview/cell/text.tsx b/src/ts/component/cell/text.tsx similarity index 100% rename from src/ts/component/block/dataview/cell/text.tsx rename to src/ts/component/cell/text.tsx diff --git a/src/ts/component/header/main/object.tsx b/src/ts/component/header/main/object.tsx index c2d99b78a5..d9052f4deb 100644 --- a/src/ts/component/header/main/object.tsx +++ b/src/ts/component/header/main/object.tsx @@ -154,7 +154,10 @@ const HeaderMainObject = observer(class HeaderMainObject extends React.Component const { rootId } = this.props; const object = S.Detail.get(rootId, rootId, [ 'isArchived' ]); - this.props.onRelation({}, { readonly: object.isArchived }); + sidebar.rightPanelToggle(!S.Common.showSidebarRight); + sidebar.rightPanelSwitch('object/relation', { rootId }); + + //this.props.onRelation({}, { readonly: object.isArchived }); }; updateTemplatesCnt () { diff --git a/src/ts/component/index.tsx b/src/ts/component/index.tsx index 62758aec47..cc47277c92 100644 --- a/src/ts/component/index.tsx +++ b/src/ts/component/index.tsx @@ -77,7 +77,7 @@ import PreviewDefault from './preview/default'; import Graph from './util/graph'; -import Cell from './block/dataview/cell'; +import Cell from './cell'; import ObjectName from './util/object/name'; import ObjectDescription from './util/object/description'; diff --git a/src/ts/component/page/main/type.tsx b/src/ts/component/page/main/type.tsx index b4a4e53506..eb15bdaa01 100644 --- a/src/ts/component/page/main/type.tsx +++ b/src/ts/component/page/main/type.tsx @@ -380,7 +380,7 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC const rootId = this.getRootId(); sidebar.rightPanelToggle(!S.Common.showSidebarRight); - S.Common.getRef('sidebarRight').setState({ page: 'type', rootId }); + sidebar.rightPanelSwitch('type', { rootId }); }; onObjectAdd () { diff --git a/src/ts/component/sidebar/page/object/relation.tsx b/src/ts/component/sidebar/page/object/relation.tsx index 2837882ea5..e1f688daf7 100644 --- a/src/ts/component/sidebar/page/object/relation.tsx +++ b/src/ts/component/sidebar/page/object/relation.tsx @@ -1,20 +1,90 @@ import * as React from 'react'; import { observer } from 'mobx-react'; -import { I } from 'Lib'; +import { Label, Button } from 'Component'; +import { I, S, C, sidebar, translate } from 'Lib'; + +import Section from 'Component/sidebar/section'; + +const TRACE = 'sidebarObjectRelation'; const SidebarPageObjectRelation = observer(class SidebarPageObjectRelation extends React.Component<I.SidebarPageComponent> { + sectionRefs: Map<string, any> = new Map(); + constructor (props: I.SidebarPageComponent) { super(props); + + this.onSetUp = this.onSetUp.bind(this); }; render () { + const rootId = this.getRootId(); + const object = this.getObject(); + const relations = this.getRelations(); + return ( <React.Fragment> + <div className="head"> + <div className="side left"> + <Label text={translate('sidebarTypeRelation')} /> + </div> + + <div className="side right"> + <Button color="blank" text={translate('sidebarObjectRelationSetUp')} className="simple" onClick={this.onSetUp} /> + </div> + </div> + + <div className="body customScrollbar"> + {relations.map((item, i) => ( + <Section + {...this.props} + ref={ref => this.sectionRefs.set(item.id, ref)} + key={item.id} + component="object/relation" + rootId={rootId} + object={object} + item={item} + onChange={(key, value) => {}} + /> + ))} + </div> </React.Fragment> ); }; + componentDidMount (): void { + this.load(); + }; + + load () { + const { space } = S.Common; + const { rootId } = this.props; + + C.ObjectShow(rootId, TRACE, space, () => this.forceUpdate()); + }; + + getRootId () { + return [ this.props.rootId, TRACE ].join('-'); + }; + + getObject () { + return S.Detail.get(this.getRootId(), this.props.rootId); + }; + + getRelations () { + const { config } = S.Common; + + return S.Record.getObjectRelations(this.getRootId(), this.props.rootId).filter((it: any) => { + return !config.debug.hiddenObject ? !it.isHidden : true; + }); + }; + + onSetUp () { + const object = this.getObject(); + + sidebar.rightPanelSwitch('type', { rootId: object.type }); + }; + }); export default SidebarPageObjectRelation; \ No newline at end of file diff --git a/src/ts/component/sidebar/page/type.tsx b/src/ts/component/sidebar/page/type.tsx index 378e7c5161..fd1db065fb 100644 --- a/src/ts/component/sidebar/page/type.tsx +++ b/src/ts/component/sidebar/page/type.tsx @@ -44,6 +44,7 @@ const SidebarPageType = observer(class SidebarPageType extends React.Component<I key={item.id} component={item.component} object={this.object} + withState={true} onChange={(key, value) => this.onChange(item.id, key, value)} /> ))} diff --git a/src/ts/component/sidebar/right.tsx b/src/ts/component/sidebar/right.tsx index 8fb03fb262..f1fc389900 100644 --- a/src/ts/component/sidebar/right.tsx +++ b/src/ts/component/sidebar/right.tsx @@ -3,6 +3,7 @@ import { observer } from 'mobx-react'; import { U, S } from 'Lib'; import PageType from './page/type'; +import PageObjectRelation from './page/object/relation'; interface State { page: string; @@ -10,7 +11,8 @@ interface State { }; const Components = { - type: PageType, + 'type': PageType, + 'object/relation': PageObjectRelation, }; const SidebarRight = observer(class SidebarRight extends React.Component<{}, State> { @@ -31,7 +33,9 @@ const SidebarRight = observer(class SidebarRight extends React.Component<{}, Sta }; const Component = Components[page]; - const cn = [ 'sidebarPage', U.Common.toCamelCase(`page-${page}`) ]; + const cn = [ 'sidebarPage', U.Common.toCamelCase(`page-${page.replace(/\//g, '-')}`) ]; + + console.log(page, cn); return ( <div diff --git a/src/ts/component/sidebar/section/index.tsx b/src/ts/component/sidebar/section/index.tsx index f148d7dfae..7a5936c21e 100644 --- a/src/ts/component/sidebar/section/index.tsx +++ b/src/ts/component/sidebar/section/index.tsx @@ -6,14 +6,19 @@ import TypeTitle from './type/title'; import TypeLayout from './type/layout'; import TypeRelation from './type/relation'; +import ObjectRelation from './object/relation'; + const Components = { 'type/title': TypeTitle, 'type/layout': TypeLayout, 'type/relation': TypeRelation, + + 'object/relation': ObjectRelation, }; interface Props extends I.SidebarSectionComponent { component: string; + withState?: boolean; }; interface State { @@ -28,24 +33,34 @@ const SidebarSectionIndex = observer(class SidebarSectionIndex extends React.Com ref = null; render () { - const { object } = this.state; const { component } = this.props; + const object = this.state.object || this.props.object; const Component = Components[component]; const cn = [ 'section', U.Common.toCamelCase(component.replace(/\//g, '-')) ]; - if (!object || !Component) { + if (!object) { return null; }; return ( <div className={cn.join(' ')}> - <Component ref={ref => this.ref = ref} {...this.props} object={object} /> + {Component ? ( + <Component + ref={ref => this.ref = ref} + {...this.props} + object={object} + /> + ): component} </div> ); }; componentDidMount (): void { - this.setObject(this.props.object); + const { withState } = this.props; + + if (withState) { + this.setObject(this.props.object); + }; }; setObject (object: any): void { diff --git a/src/ts/component/sidebar/section/object/relation.tsx b/src/ts/component/sidebar/section/object/relation.tsx new file mode 100644 index 0000000000..db76af2b60 --- /dev/null +++ b/src/ts/component/sidebar/section/object/relation.tsx @@ -0,0 +1,71 @@ +import * as React from 'react'; +import { observer } from 'mobx-react'; +import { Cell } from 'Component'; +import { I, S, U, Relation } from 'Lib'; + +const PREFIX = 'sidebarObjectRelation'; + +const SidebarSectionObjectRelation = observer(class SidebarSectionObjectRelation extends React.Component<I.SidebarSectionComponent> { + + refCell = null; + + constructor (props: I.SidebarSectionComponent) { + super(props); + + this.onCellClick = this.onCellClick.bind(this); + }; + + render () { + const { rootId, object } = this.props; + const relation = this.props.item; + const block = S.Block.getLeaf(rootId, object.id); + const id = Relation.cellId(PREFIX, relation.relationKey, object.id); + const cn = [ 'cell', Relation.className(relation.format) ]; + + const readonly = false; + const allowedValue = true; + const canEdit = !readonly && allowedValue; + + if (canEdit) { + cn.push('canEdit'); + }; + + return ( + <div className="wrap"> + <div className="name">{relation.name}</div> + + <div + id={id} + className={cn.join(' ')} + onClick={this.onCellClick} + > + <Cell + ref={ref => this.refCell = ref} + rootId={rootId} + subId={rootId} + block={block} + relationKey={relation.relationKey} + getRecord={() => object} + viewType={I.ViewType.Grid} + readonly={false} + idPrefix={PREFIX} + menuClassNameWrap="fromSidebar" + menuClassName="fixed" + onCellChange={this.onCellChange} + pageContainer={U.Common.getCellContainer('sidebarRight')} + /> + </div> + </div> + ); + }; + + onCellClick (e: any) { + this.refCell?.onClick(e); + }; + + onCellChange (key: string, value: any) { + }; + +}); + +export default SidebarSectionObjectRelation; \ No newline at end of file diff --git a/src/ts/component/widget/view/board/group.tsx b/src/ts/component/widget/view/board/group.tsx index 9bf61af536..41defb80a7 100644 --- a/src/ts/component/widget/view/board/group.tsx +++ b/src/ts/component/widget/view/board/group.tsx @@ -1,8 +1,7 @@ import * as React from 'react'; import { observer } from 'mobx-react'; -import { Icon } from 'Component'; +import { Icon, Cell } from 'Component'; import { I, S, U, J, translate, Dataview, Storage } from 'Lib'; -import Cell from 'Component/block/dataview/cell'; import Item from './item'; const ANIMATION = 200; diff --git a/src/ts/interface/common.ts b/src/ts/interface/common.ts index d93fe3be53..5d8b83905a 100644 --- a/src/ts/interface/common.ts +++ b/src/ts/interface/common.ts @@ -195,6 +195,7 @@ export interface SidebarPageComponent { export interface SidebarSectionComponent extends SidebarPageComponent { object: any; + item?: any; onChange?(key: string, value: any): void; }; diff --git a/src/ts/lib/sidebar.ts b/src/ts/lib/sidebar.ts index 2c9274d97b..71bddc9e97 100644 --- a/src/ts/lib/sidebar.ts +++ b/src/ts/lib/sidebar.ts @@ -365,6 +365,10 @@ class Sidebar { raf(() => this.resizePage(null, false)); }; + rightPanelSwitch (page: string, param: any) { + S.Common.getRef('sidebarRight').setState({ page, ...param }); + }; + }; export const sidebar: Sidebar = new Sidebar(); \ No newline at end of file diff --git a/src/ts/lib/util/common.ts b/src/ts/lib/util/common.ts index b24593a3b5..a85f43994a 100644 --- a/src/ts/lib/util/common.ts +++ b/src/ts/lib/util/common.ts @@ -666,6 +666,9 @@ class UtilCommon { case 'popupRelation': return `#${type}-innerWrap`; + + case 'sidebarRight': + return `#sidebarRight`; }; }; From 2ac31403da04ab8405f4b6730f9648a4d2b8c685 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Wed, 30 Oct 2024 12:12:19 +0100 Subject: [PATCH 32/51] JS-5587: relations in object --- src/scss/component/sidebar/page/object.scss | 27 ++++----------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/src/scss/component/sidebar/page/object.scss b/src/scss/component/sidebar/page/object.scss index af18768db1..cb2e783399 100644 --- a/src/scss/component/sidebar/page/object.scss +++ b/src/scss/component/sidebar/page/object.scss @@ -1,10 +1,11 @@ > .sidebarPage.pageObjectRelation { - .section.objectRelation { padding: 12px 16px; display: flex; flex-direction: column; } + .section.objectRelation { padding: 12px 16px; } .section.objectRelation { + > .wrap { display: flex; flex-direction: row; flex-wrap: wrap; gap: 0px 10px; } > .wrap { > .name { color: var(--color-text-secondary); } - .cell { border-radius: 4px; line-height: 22px; transition: background $transitionCommon; position: relative; } + .cell { line-height: 22px; transition: background $transitionCommon; position: relative; } .cell.canEdit { .cellContent { .empty { display: block; } @@ -35,38 +36,20 @@ .cell.isEditing { padding: 0px; } .cell.isEditing { - .cellContent { position: relative; height: auto !important; min-height: 32px; border-radius: 4px; } + .cellContent { position: relative; height: auto !important; box-shadow: 0px 0px; } .cellContent.isName .input { height: 20px; line-height: 20px; } .icon.clear { right: 8px; } } .cell.isEditing.c-select { .empty { display: inline-block; } - .cellContent, .placeholder { padding: 5px 8px 1px 8px; } } .cell.isEditing.c-select.isSelect { .over { width: calc(100% - 26px); } } - .cell.isEditing.c-shortText, - .cell.isEditing.c-number, - .cell.isEditing.c-url, - .cell.isEditing.c-phone, - .cell.isEditing.c-email, - .cell.isEditing.c-date, - .cell.isEditing.c-longText, - .cell.isEditing.c-file - { - .cellContent { padding: 5px 8px !important; } - .placeholder { padding: 5px 8px; } - } - - .cell.isEditing.c-object { - .cellContent, .placeholder { padding: 5px 8px !important; } - } - .cell.isEditing.c-longText { - .cellContent { box-shadow: 0px 0px; visibility: hidden; } + .cellContent { visibility: hidden; } .cellContent span:empty { height: 22px; } } From 03330453be34c9da2d25cb2ee5581f566e2f49ad Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Wed, 30 Oct 2024 12:17:04 +0100 Subject: [PATCH 33/51] JS-5587: relations in object --- src/scss/component/sidebar/page/object.scss | 10 +--------- .../component/sidebar/section/object/relation.tsx | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/scss/component/sidebar/page/object.scss b/src/scss/component/sidebar/page/object.scss index cb2e783399..e63e04ab99 100644 --- a/src/scss/component/sidebar/page/object.scss +++ b/src/scss/component/sidebar/page/object.scss @@ -5,7 +5,7 @@ > .wrap { > .name { color: var(--color-text-secondary); } - .cell { line-height: 22px; transition: background $transitionCommon; position: relative; } + .cell { line-height: 22px; transition: background $transitionCommon; position: relative; flex-grow: 1; } .cell.canEdit { .cellContent { .empty { display: block; } @@ -18,14 +18,6 @@ .over { overflow: visible !important; width: 100%; flex-wrap: wrap; gap: 4px 6px; } } - .cell.c-object { - .element { max-width: 150px; } - } - - .cell.c-select { - .over { margin-top: 2px; } - } - .cell.c-shortText { .name { width: 100%; } } diff --git a/src/ts/component/sidebar/section/object/relation.tsx b/src/ts/component/sidebar/section/object/relation.tsx index db76af2b60..3d71ada824 100644 --- a/src/ts/component/sidebar/section/object/relation.tsx +++ b/src/ts/component/sidebar/section/object/relation.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { observer } from 'mobx-react'; import { Cell } from 'Component'; -import { I, S, U, Relation } from 'Lib'; +import { I, S, U, C, Relation, analytics } from 'Lib'; const PREFIX = 'sidebarObjectRelation'; @@ -13,6 +13,7 @@ const SidebarSectionObjectRelation = observer(class SidebarSectionObjectRelation super(props); this.onCellClick = this.onCellClick.bind(this); + this.onCellChange = this.onCellChange.bind(this); }; render () { @@ -47,7 +48,7 @@ const SidebarSectionObjectRelation = observer(class SidebarSectionObjectRelation relationKey={relation.relationKey} getRecord={() => object} viewType={I.ViewType.Grid} - readonly={false} + readonly={!canEdit} idPrefix={PREFIX} menuClassNameWrap="fromSidebar" menuClassName="fixed" @@ -63,7 +64,15 @@ const SidebarSectionObjectRelation = observer(class SidebarSectionObjectRelation this.refCell?.onClick(e); }; - onCellChange (key: string, value: any) { + onCellChange (id: string, relationKey: string, value: any, callBack?: (message: any) => void) { + const { object } = this.props; + const relation = S.Record.getRelationByKey(relationKey); + + C.ObjectListSetDetails([ object.id ], [ { key: relationKey, value: Relation.formatValue(relation, value, true) } ], callBack); + + if ((undefined !== object[relationKey]) && !U.Common.compareJSON(object[relationKey], value)) { + analytics.changeRelationValue(relation, value, { type: 'menu', id: 'Single' }); + }; }; }); From 7fcb9c133f849985f79acece8007e073a729a777 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Wed, 30 Oct 2024 12:27:31 +0100 Subject: [PATCH 34/51] relation page update --- src/scss/page/common.scss | 3 +- src/scss/page/main/relation.scss | 30 -------- src/scss/page/main/type.scss | 3 +- .../component/page/elements/head/simple.tsx | 2 - src/ts/component/page/main/relation.tsx | 69 ++++++++++++++++--- 5 files changed, 63 insertions(+), 44 deletions(-) delete mode 100644 src/scss/page/main/relation.scss diff --git a/src/scss/page/common.scss b/src/scss/page/common.scss index 2e85b30323..ac0b832ca6 100644 --- a/src/scss/page/common.scss +++ b/src/scss/page/common.scss @@ -4,7 +4,6 @@ @import "./main/history"; @import "./main/media"; @import "./main/navigation"; -@import "./main/relation"; @import "./main/set"; @import "./main/type"; @import "./main/archive"; @@ -15,4 +14,4 @@ @import "./main/membership"; @import "./main/onboarding"; @import "./main/chat"; -@import "./main/void"; +@import "./main/void"; \ No newline at end of file diff --git a/src/scss/page/main/relation.scss b/src/scss/page/main/relation.scss deleted file mode 100644 index f257aa7c28..0000000000 --- a/src/scss/page/main/relation.scss +++ /dev/null @@ -1,30 +0,0 @@ -@import "~scss/_mixins"; - -.pageMainRelation { user-select: none; } -.pageMainRelation { - .wrapper { width: 704px; margin: 0px auto; padding: 74px 0px 80px 0px; } - .wrapper { - .editorControls { margin-bottom: 8px; } - - .headSimple { - .title { -webkit-user-modify: read-only; } - .descr { -webkit-user-modify: read-only; } - .descr:empty { display: none; } - } - - .block { - .wrapMenu { display: none; } - .wrapContent { width: 100%; } - } - .block.blockFeatured { padding: 0px; margin: 0px; line-height: 28px; } - - .section { margin-bottom: 32px; } - .section:last-child { margin: 0px; } - - .section { - .title { @include text-header3; margin-bottom: 14px; } - } - } -} - -.pageMainRelation > div > #loader { position: fixed; top: 0px; width: 100%; height: 100%; background: var(--color-bg-primary); z-index: 5; } \ No newline at end of file diff --git a/src/scss/page/main/type.scss b/src/scss/page/main/type.scss index cab53047bb..7cf4056139 100644 --- a/src/scss/page/main/type.scss +++ b/src/scss/page/main/type.scss @@ -1,6 +1,7 @@ @import "~scss/_mixins"; -.pageMainType { +.pageMainType, +.pageMainRelation { .wrapper { width: 704px; margin: 0px auto; padding: 40px 0px 90px 0px; user-select: none; } .wrapper.withIcon { diff --git a/src/ts/component/page/elements/head/simple.tsx b/src/ts/component/page/elements/head/simple.tsx index f7a4a4b5da..210bf7cfa2 100644 --- a/src/ts/component/page/elements/head/simple.tsx +++ b/src/ts/component/page/elements/head/simple.tsx @@ -101,8 +101,6 @@ const HeadSimple = observer(class Controls extends React.Component<Props> { if (object.isInstalled) { if (isType) { buttonEdit = <Button id="button-edit" color="blank" className="c28" text={translate('commonEdit')} onClick={onEdit} />; - } else { - buttonCreate = <Button id="button-create" className="c36" text={translate('pageHeadSimpleCreateSet')} arrow={true} onClick={onCreate} />; }; } else { const cn = [ 'c36' ]; diff --git a/src/ts/component/page/main/relation.tsx b/src/ts/component/page/main/relation.tsx index 6c6532beac..7adf38f7cd 100644 --- a/src/ts/component/page/main/relation.tsx +++ b/src/ts/component/page/main/relation.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { observer } from 'mobx-react'; -import { Header, Footer, Loader, ListObject, Deleted } from 'Component'; +import { Header, Footer, Loader, ListObject, Deleted, Icon } from 'Component'; import { I, C, S, U, Action, translate } from 'Lib'; import HeadSimple from 'Component/page/elements/head/simple'; @@ -25,7 +25,7 @@ const PageMainRelation = observer(class PageMainRelation extends React.Component constructor (props: I.PageComponent) { super(props); - this.onCreate = this.onCreate.bind(this); + this.onMore = this.onMore.bind(this); }; render () { @@ -36,7 +36,7 @@ const PageMainRelation = observer(class PageMainRelation extends React.Component }; const rootId = this.getRootId(); - const object = S.Detail.get(rootId, rootId); + const object = this.getObject(); const subIdType = S.Record.getSubId(rootId, 'type'); const totalType = S.Record.getMeta(subIdType, '').total; const subIdObject = S.Record.getSubId(rootId, 'object'); @@ -70,13 +70,19 @@ const PageMainRelation = observer(class PageMainRelation extends React.Component {...this.props} ref={ref => this.refHead = ref} placeholder={translate('defaultNameRelation')} - rootId={rootId} onCreate={this.onCreate} + rootId={rootId} /> {!object._empty_ ? ( <React.Fragment> <div className="section set"> - <div className="title">{totalType} {U.Common.plural(totalType, translate('pluralObjectType'))}</div> + <div className="title"> + <div className="side left"> + {U.Common.plural(totalType, translate('pluralObjectType'))} + <span className="cnt">{totalType}</span> + </div> + </div> + <div className="content"> <ListObject ref={ref => this.refListType = ref} @@ -92,7 +98,26 @@ const PageMainRelation = observer(class PageMainRelation extends React.Component {object.isInstalled ? ( <div className="section set"> - <div className="title">{totalObject} {U.Common.sprintf(translate('pageMainRelationObjectsCreated'), U.Common.plural(totalObject, translate('pluralObject')))}</div> + <div className="title"> + {totalObject} + {U.Common.sprintf(translate('pageMainRelationObjectsCreated'), U.Common.plural(totalObject, translate('pluralObject')))} + </div> + + <div className="title"> + <div className="side left"> + {U.Common.plural(totalObject, translate('pluralObject'))} + <span className="cnt">{totalObject}</span> + </div> + + <div className="side right"> + <Icon + id="button-create" + className="more withBackground" + onClick={this.onMore} + /> + </div> + </div> + <div className="content"> <ListObject ref={ref => this.refListObject = ref} @@ -176,17 +201,43 @@ const PageMainRelation = observer(class PageMainRelation extends React.Component return rootId ? rootId : match.params.id; }; - onCreate () { + getObject () { const rootId = this.getRootId(); - const object = S.Detail.get(rootId, rootId); + return S.Detail.get(rootId, rootId); + }; - C.ObjectCreateSet([ rootId ], { name: object.name + ' set' }, '', S.Common.space, (message: any) => { + onSetAdd () { + const object = this.getObject(); + + C.ObjectCreateSet([ object.id ], { name: object.name + ' set' }, '', S.Common.space, (message: any) => { if (!message.error.code) { U.Object.openConfig(message.details); }; }); }; + onMore () { + const options = [ + { id: 'set', name: translate('pageMainTypeNewSetOfObjects') } + ]; + + S.Menu.open('select', { + element: `#button-create`, + offsetY: 8, + horizontal: I.MenuDirection.Center, + data: { + options, + onSelect: (e: any, item: any) => { + switch (item.id) { + case 'set': + this.onSetAdd(); + break; + }; + }, + }, + }); + }; + }); export default PageMainRelation; \ No newline at end of file From bb60ad17ad49160f347d64e3b63e1213513f08c2 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Wed, 30 Oct 2024 12:28:11 +0100 Subject: [PATCH 35/51] relation page update --- src/ts/component/page/main/relation.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/ts/component/page/main/relation.tsx b/src/ts/component/page/main/relation.tsx index 7adf38f7cd..74f56a4c18 100644 --- a/src/ts/component/page/main/relation.tsx +++ b/src/ts/component/page/main/relation.tsx @@ -98,11 +98,6 @@ const PageMainRelation = observer(class PageMainRelation extends React.Component {object.isInstalled ? ( <div className="section set"> - <div className="title"> - {totalObject} - {U.Common.sprintf(translate('pageMainRelationObjectsCreated'), U.Common.plural(totalObject, translate('pluralObject')))} - </div> - <div className="title"> <div className="side left"> {U.Common.plural(totalObject, translate('pluralObject'))} From 51852fa06e62ce7c566b3feeb00cbbec6029f8a5 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Wed, 30 Oct 2024 13:51:57 +0100 Subject: [PATCH 36/51] JS-5590: panel animation --- src/scss/component/sidebar.scss | 5 +- src/ts/component/block/cover.tsx | 7 +-- src/ts/component/editor/page.tsx | 2 +- src/ts/component/footer/index.tsx | 4 +- src/ts/component/header/index.tsx | 4 +- src/ts/component/header/main/object.tsx | 3 +- src/ts/component/page/index.tsx | 2 +- src/ts/component/page/main/type.tsx | 3 +- src/ts/component/sidebar/right.tsx | 8 +-- .../sidebar/section/object/relation.tsx | 8 ++- src/ts/component/vault/index.tsx | 4 +- src/ts/interface/common.ts | 1 + src/ts/lib/sidebar.ts | 50 +++++++++++++++---- src/ts/lib/util/menu.ts | 2 +- 14 files changed, 67 insertions(+), 36 deletions(-) diff --git a/src/scss/component/sidebar.scss b/src/scss/component/sidebar.scss index f31086b202..769bf634e9 100644 --- a/src/scss/component/sidebar.scss +++ b/src/scss/component/sidebar.scss @@ -16,12 +16,13 @@ #sidebarToggle:hover, #sidebarToggle.hover { background-color: var(--color-shape-highlight-medium) !important; background-image: url('~img/icon/widget/toggle1.svg'); } .sidebar { position: fixed; z-index: 21; user-select: none; transition: none; top: 0px; height: 100%; background-color: var(--color-shape-tertiary); } -.sidebar.anim { transition-property: width; transition-duration: $transitionSidebarTime; transition-timing-function: linear; } .sidebar.withVault { left: $vaultWidthCollapsed; } .sidebar.isClosed { left: 0px !important; } .sidebar.left { left: 0px; } -.sidebar.right { right: 0px; width: 348px; } +.sidebar.left.anim { transition-property: width; transition-duration: $transitionSidebarTime; transition-timing-function: linear; } + +.sidebar.right { right: 0px; width: 348px; transform: translate3d(100%,0px,0px); transition: transform 0.18s linear; } .sidebar { @import "./sidebar/widget"; diff --git a/src/ts/component/block/cover.tsx b/src/ts/component/block/cover.tsx index aaf867a39e..98ce8992b8 100644 --- a/src/ts/component/block/cover.tsx +++ b/src/ts/component/block/cover.tsx @@ -328,10 +328,7 @@ const BlockCover = observer(class BlockCover extends React.Component<I.BlockComp }; const cb = () => { - if (this.refDrag) { - this.refDrag.setValue(coverScale); - }; - + this.refDrag?.setValue(coverScale); this.rect = (node.get(0) as Element).getBoundingClientRect(); this.onScaleMove($.Event('resize'), coverScale); this.cover.css({ opacity: 1 }); @@ -505,7 +502,7 @@ const BlockCover = observer(class BlockCover extends React.Component<I.BlockComp const px = x / this.rect.cw * 100; const py = y / this.rect.ch * 100; const css: any = { transform: `translate3d(${px}%,${py}%,0px)` }; - + if (this.rect.ch < this.rect.height) { css.transform = 'translate3d(0px,0px,0px)'; css.height = this.rect.height; diff --git a/src/ts/component/editor/page.tsx b/src/ts/component/editor/page.tsx index 1ec5132d70..4297e06a9c 100644 --- a/src/ts/component/editor/page.tsx +++ b/src/ts/component/editor/page.tsx @@ -168,7 +168,7 @@ const EditorPage = observer(class EditorPage extends React.Component<Props, Stat focus.apply(); S.Block.updateNumbers(rootId); - sidebar.resizePage(null, false); + sidebar.resizePage(null, null, false); if (resizable.length) { resizable.trigger('resizeInit'); diff --git a/src/ts/component/footer/index.tsx b/src/ts/component/footer/index.tsx index e501e9d63c..14387ca395 100644 --- a/src/ts/component/footer/index.tsx +++ b/src/ts/component/footer/index.tsx @@ -43,11 +43,11 @@ class Footer extends React.Component<Props> { }; componentDidMount () { - sidebar.resizePage(null, false); + sidebar.resizePage(null, null, false); }; componentDidUpdate () { - sidebar.resizePage(null, false); + sidebar.resizePage(null, null, false); this.refChild.forceUpdate(); }; diff --git a/src/ts/component/header/index.tsx b/src/ts/component/header/index.tsx index 0a380b7410..cf22e5d3f4 100644 --- a/src/ts/component/header/index.tsx +++ b/src/ts/component/header/index.tsx @@ -72,11 +72,11 @@ class Header extends React.Component<Props> { }; componentDidMount () { - sidebar.resizePage(null, false); + sidebar.resizePage(null, null, false); }; componentDidUpdate () { - sidebar.resizePage(null, false); + sidebar.resizePage(null, null, false); this.refChild.forceUpdate(); }; diff --git a/src/ts/component/header/main/object.tsx b/src/ts/component/header/main/object.tsx index d9052f4deb..44c678d5cd 100644 --- a/src/ts/component/header/main/object.tsx +++ b/src/ts/component/header/main/object.tsx @@ -154,8 +154,7 @@ const HeaderMainObject = observer(class HeaderMainObject extends React.Component const { rootId } = this.props; const object = S.Detail.get(rootId, rootId, [ 'isArchived' ]); - sidebar.rightPanelToggle(!S.Common.showSidebarRight); - sidebar.rightPanelSwitch('object/relation', { rootId }); + sidebar.rightPanelToggle(!S.Common.showSidebarRight, 'object/relation', { rootId }); //this.props.onRelation({}, { readonly: object.isArchived }); }; diff --git a/src/ts/component/page/index.tsx b/src/ts/component/page/index.tsx index 00a486084b..42903c2640 100644 --- a/src/ts/component/page/index.tsx +++ b/src/ts/component/page/index.tsx @@ -357,7 +357,7 @@ const Page = observer(class Page extends React.Component<I.PageComponent> { this.refChild.resize(); }; - sidebar.resizePage(null, false); + sidebar.resizePage(null, null, false); }); }; diff --git a/src/ts/component/page/main/type.tsx b/src/ts/component/page/main/type.tsx index eb15bdaa01..54817e564f 100644 --- a/src/ts/component/page/main/type.tsx +++ b/src/ts/component/page/main/type.tsx @@ -379,8 +379,7 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC onEdit () { const rootId = this.getRootId(); - sidebar.rightPanelToggle(!S.Common.showSidebarRight); - sidebar.rightPanelSwitch('type', { rootId }); + sidebar.rightPanelToggle(!S.Common.showSidebarRight, 'type', { rootId }); }; onObjectAdd () { diff --git a/src/ts/component/sidebar/right.tsx b/src/ts/component/sidebar/right.tsx index f1fc389900..cb5fb063df 100644 --- a/src/ts/component/sidebar/right.tsx +++ b/src/ts/component/sidebar/right.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { observer } from 'mobx-react'; -import { U, S } from 'Lib'; +import { U, S, keyboard } from 'Lib'; import PageType from './page/type'; import PageObjectRelation from './page/object/relation'; @@ -34,8 +34,7 @@ const SidebarRight = observer(class SidebarRight extends React.Component<{}, Sta const Component = Components[page]; const cn = [ 'sidebarPage', U.Common.toCamelCase(`page-${page.replace(/\//g, '-')}`) ]; - - console.log(page, cn); + const isPopup = keyboard.isPopup(); return ( <div @@ -48,7 +47,8 @@ const SidebarRight = observer(class SidebarRight extends React.Component<{}, Sta <Component ref={ref => this.refChild = ref} {...this.props} - rootId={rootId} + rootId={rootId} + isPopup={isPopup} /> </div> ): ''} diff --git a/src/ts/component/sidebar/section/object/relation.tsx b/src/ts/component/sidebar/section/object/relation.tsx index 3d71ada824..581479086d 100644 --- a/src/ts/component/sidebar/section/object/relation.tsx +++ b/src/ts/component/sidebar/section/object/relation.tsx @@ -17,11 +17,15 @@ const SidebarSectionObjectRelation = observer(class SidebarSectionObjectRelation }; render () { - const { rootId, object } = this.props; + const { rootId, object, isPopup } = this.props; const relation = this.props.item; const block = S.Block.getLeaf(rootId, object.id); const id = Relation.cellId(PREFIX, relation.relationKey, object.id); const cn = [ 'cell', Relation.className(relation.format) ]; + const container = [ + U.Common.getCellContainer('sidebarRight'), + U.Common.getCellContainer(isPopup ? 'popup' : 'page') + ].join(', '); const readonly = false; const allowedValue = true; @@ -53,7 +57,7 @@ const SidebarSectionObjectRelation = observer(class SidebarSectionObjectRelation menuClassNameWrap="fromSidebar" menuClassName="fixed" onCellChange={this.onCellChange} - pageContainer={U.Common.getCellContainer('sidebarRight')} + pageContainer={container} /> </div> </div> diff --git a/src/ts/component/vault/index.tsx b/src/ts/component/vault/index.tsx index 728b970d08..d423725b4f 100644 --- a/src/ts/component/vault/index.tsx +++ b/src/ts/component/vault/index.tsx @@ -136,7 +136,7 @@ const Vault = observer(class Vault extends React.Component { if (!sidebar.isAnimating) { if (!showVault) { S.Common.showVaultSet(true); - sidebar.resizePage(width, false); + sidebar.resizePage(width, null, false); this.closeVault = true; }; @@ -184,7 +184,7 @@ const Vault = observer(class Vault extends React.Component { if (!sidebar.isAnimating) { if (this.closeVault) { S.Common.showVaultSet(false); - sidebar.resizePage(width, false); + sidebar.resizePage(width, null, false); this.closeVault = false; }; diff --git a/src/ts/interface/common.ts b/src/ts/interface/common.ts index 5d8b83905a..5656c61aa4 100644 --- a/src/ts/interface/common.ts +++ b/src/ts/interface/common.ts @@ -191,6 +191,7 @@ export interface ButtonComponent { export interface SidebarPageComponent { rootId?: string; + isPopup?: boolean; }; export interface SidebarSectionComponent extends SidebarPageComponent { diff --git a/src/ts/lib/sidebar.ts b/src/ts/lib/sidebar.ts index 71bddc9e97..1b69905f8d 100644 --- a/src/ts/lib/sidebar.ts +++ b/src/ts/lib/sidebar.ts @@ -46,7 +46,7 @@ class Sidebar { isClosed: false, }); - this.resizePage(J.Size.sidebar.width.default, false); + this.resizePage(J.Size.sidebar.width.default, null, false); }; if (this.data.isClosed) { @@ -89,7 +89,7 @@ class Sidebar { this.setAnimating(true); this.setStyle({ width: 0 }); this.set({ isClosed: true }); - this.resizePage(0, true); + this.resizePage(0, null, true); this.vaultHide(); this.removeAnimation(() => { @@ -120,7 +120,7 @@ class Sidebar { this.setStyle({ width }); this.set({ isClosed: false }); - this.resizePage(width, true); + this.resizePage(width, null, true); this.removeAnimation(() => { $(window).trigger('resize'); @@ -150,7 +150,7 @@ class Sidebar { w = this.limitWidth(w); this.set({ width: w, isClosed: false }); - this.resizePage(w, false); + this.resizePage(w, null, false); }; private removeAnimation (callBack?: () => void): void { @@ -217,17 +217,16 @@ class Sidebar { }; }; - resizePage (widthLeft: number, animate: boolean): void { + resizePage (widthLeft: number, widthRight: number, animate: boolean): void { this.initObjects(); - let widthRight = 0; let toggleX = 16; if ((widthLeft === null) && this.objLeft && this.objLeft.length) { widthLeft = this.objLeft.outerWidth(); }; - if (this.objRight && this.objRight.length) { + if ((widthRight === null) && this.objRight && this.objRight.length) { widthRight = this.objRight.outerWidth(); }; @@ -360,9 +359,40 @@ class Sidebar { ref.setState({ page: (page == 'object' ? '' : 'object') }); }; - rightPanelToggle (v: boolean) { - S.Common.showSidebarRightSet(v); - raf(() => this.resizePage(null, false)); + rightPanelToggle (v: boolean, page?: string, param?: any) { + if (v) { + S.Common.showSidebarRightSet(v); + + if (page) { + this.rightPanelSwitch(page, param); + }; + }; + + window.setTimeout(() => { + this.initObjects(); + + const cssStart: any = {}; + const cssEnd: any = {}; + + if (v) { + cssStart.transform = 'translate3d(100%,0px,0px)'; + cssEnd.transform = 'translate3d(0%,0px,0px)'; + } else { + cssStart.transform = 'translate3d(0%,0px,0px)'; + cssEnd.transform = 'translate3d(100%,0px,0px)'; + }; + + this.objRight.css(cssStart); + + raf(() => { + this.objRight.css(cssEnd); + this.resizePage(null, v ? null : 0, true); + }); + }); + + if (!v) { + window.setTimeout(() => S.Common.showSidebarRightSet(v), J.Constant.delay.sidebar); + }; }; rightPanelSwitch (page: string, param: any) { diff --git a/src/ts/lib/util/menu.ts b/src/ts/lib/util/menu.ts index 651ba53676..b6c4b6b7d2 100644 --- a/src/ts/lib/util/menu.ts +++ b/src/ts/lib/util/menu.ts @@ -975,7 +975,7 @@ class UtilMenu { if (isClosed) { sidebar.open(width); } else { - sidebar.resizePage(width, false); + sidebar.resizePage(width, null, false); }; break; }; From c90184257b9607692ca6249dc347bd43597ee616 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Wed, 30 Oct 2024 14:51:11 +0100 Subject: [PATCH 37/51] animation fixes --- src/scss/component/sidebar.scss | 6 ++++-- src/ts/component/menu/block/relation/view.tsx | 3 +-- .../component/sidebar/page/object/relation.tsx | 4 ++++ .../sidebar/section/object/relation.tsx | 17 +++++++++++++---- src/ts/interface/common.ts | 1 + src/ts/lib/sidebar.ts | 12 ++++++++---- 6 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/scss/component/sidebar.scss b/src/scss/component/sidebar.scss index 769bf634e9..4393cc9fa8 100644 --- a/src/scss/component/sidebar.scss +++ b/src/scss/component/sidebar.scss @@ -16,13 +16,15 @@ #sidebarToggle:hover, #sidebarToggle.hover { background-color: var(--color-shape-highlight-medium) !important; background-image: url('~img/icon/widget/toggle1.svg'); } .sidebar { position: fixed; z-index: 21; user-select: none; transition: none; top: 0px; height: 100%; background-color: var(--color-shape-tertiary); } +.sidebar.anim { transition-duration: $transitionSidebarTime; transition-timing-function: linear; } .sidebar.withVault { left: $vaultWidthCollapsed; } .sidebar.isClosed { left: 0px !important; } .sidebar.left { left: 0px; } -.sidebar.left.anim { transition-property: width; transition-duration: $transitionSidebarTime; transition-timing-function: linear; } +.sidebar.left.anim { transition-property: width; } -.sidebar.right { right: 0px; width: 348px; transform: translate3d(100%,0px,0px); transition: transform 0.18s linear; } +.sidebar.right { right: 0px; width: 348px; transform: translateX(100%); } +.sidebar.right.anim { transition-property: transform; } .sidebar { @import "./sidebar/widget"; diff --git a/src/ts/component/menu/block/relation/view.tsx b/src/ts/component/menu/block/relation/view.tsx index de238f2f56..09876d7b2b 100644 --- a/src/ts/component/menu/block/relation/view.tsx +++ b/src/ts/component/menu/block/relation/view.tsx @@ -34,8 +34,7 @@ const MenuBlockRelationView = observer(class MenuBlockRelationView extends React }; const sections = this.getSections(); - const isLocked = root.isLocked(); - const readonly = data.readonly || isLocked; + const readonly = data.readonly || root.isLocked(); const diffKeys = this.getDiffKeys(); let allowedBlock = S.Block.checkFlags(rootId, rootId, [ I.RestrictionObject.Block ]); diff --git a/src/ts/component/sidebar/page/object/relation.tsx b/src/ts/component/sidebar/page/object/relation.tsx index e1f688daf7..0ff1ee2a00 100644 --- a/src/ts/component/sidebar/page/object/relation.tsx +++ b/src/ts/component/sidebar/page/object/relation.tsx @@ -56,6 +56,10 @@ const SidebarPageObjectRelation = observer(class SidebarPageObjectRelation exten this.load(); }; + componentDidUpdate (): void { + console.log('UPDATE', this.getRootId(), this.getObject().name); + }; + load () { const { space } = S.Common; const { rootId } = this.props; diff --git a/src/ts/component/sidebar/section/object/relation.tsx b/src/ts/component/sidebar/section/object/relation.tsx index 581479086d..44c691d5c7 100644 --- a/src/ts/component/sidebar/section/object/relation.tsx +++ b/src/ts/component/sidebar/section/object/relation.tsx @@ -19,16 +19,25 @@ const SidebarSectionObjectRelation = observer(class SidebarSectionObjectRelation render () { const { rootId, object, isPopup } = this.props; const relation = this.props.item; - const block = S.Block.getLeaf(rootId, object.id); + const root = S.Block.getLeaf(rootId, object.id); + + if (!relation || !root) { + return null; + }; + const id = Relation.cellId(PREFIX, relation.relationKey, object.id); const cn = [ 'cell', Relation.className(relation.format) ]; + const readonly = this.props.readonly || root.isLocked(); const container = [ U.Common.getCellContainer('sidebarRight'), U.Common.getCellContainer(isPopup ? 'popup' : 'page') ].join(', '); - const readonly = false; - const allowedValue = true; + let allowedValue = S.Block.checkFlags(rootId, rootId, [ I.RestrictionObject.Details ]); + if (readonly) { + allowedValue = false; + }; + const canEdit = !readonly && allowedValue; if (canEdit) { @@ -48,7 +57,7 @@ const SidebarSectionObjectRelation = observer(class SidebarSectionObjectRelation ref={ref => this.refCell = ref} rootId={rootId} subId={rootId} - block={block} + block={root} relationKey={relation.relationKey} getRecord={() => object} viewType={I.ViewType.Grid} diff --git a/src/ts/interface/common.ts b/src/ts/interface/common.ts index 5656c61aa4..914400c58e 100644 --- a/src/ts/interface/common.ts +++ b/src/ts/interface/common.ts @@ -192,6 +192,7 @@ export interface ButtonComponent { export interface SidebarPageComponent { rootId?: string; isPopup?: boolean; + readonly?: boolean; }; export interface SidebarSectionComponent extends SidebarPageComponent { diff --git a/src/ts/lib/sidebar.ts b/src/ts/lib/sidebar.ts index 1b69905f8d..68fa4c15ea 100644 --- a/src/ts/lib/sidebar.ts +++ b/src/ts/lib/sidebar.ts @@ -385,14 +385,18 @@ class Sidebar { this.objRight.css(cssStart); raf(() => { - this.objRight.css(cssEnd); + this.objRight.addClass('anim').css(cssEnd); this.resizePage(null, v ? null : 0, true); }); }); - if (!v) { - window.setTimeout(() => S.Common.showSidebarRightSet(v), J.Constant.delay.sidebar); - }; + window.setTimeout(() => { + this.objRight.removeClass('anim'); + + if (!v) { + S.Common.showSidebarRightSet(v); + }; + }, J.Constant.delay.sidebar); }; rightPanelSwitch (page: string, param: any) { From c5e251c60f1ae2e53abef8635f703e42ead1ddbd Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Wed, 30 Oct 2024 15:07:30 +0100 Subject: [PATCH 38/51] sidebar updates --- src/ts/app.tsx | 1 - src/ts/component/page/index.tsx | 51 +++++++++---------- .../sidebar/page/object/relation.tsx | 8 ++- src/ts/lib/sidebar.ts | 2 +- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/ts/app.tsx b/src/ts/app.tsx index 1199bcb430..dce34ed0d5 100644 --- a/src/ts/app.tsx +++ b/src/ts/app.tsx @@ -140,7 +140,6 @@ class RoutePage extends React.Component<RouteComponentProps> { <Navigation ref={ref => S.Common.refSet('navigation', ref)} key="navigation" {...this.props} /> <SidebarLeft ref={ref => S.Common.refSet('sidebarLeft', ref)} key="sidebarLeft" {...this.props} /> - <SidebarRight ref={ref => S.Common.refSet('sidebarRight', ref)} key="sidebarRight" {...this.props} /> <Page {...this.props} /> </DragProvider> </SelectionProvider> diff --git a/src/ts/component/page/index.tsx b/src/ts/component/page/index.tsx index 42903c2640..74012e3511 100644 --- a/src/ts/component/page/index.tsx +++ b/src/ts/component/page/index.tsx @@ -2,8 +2,8 @@ import * as React from 'react'; import $ from 'jquery'; import raf from 'raf'; import { observer } from 'mobx-react'; +import { Label, Frame, SidebarRight } from 'Component'; import { I, S, U, Onboarding, Storage, analytics, keyboard, sidebar, Preview, Highlight, translate } from 'Lib'; -import { Label, Frame } from 'Component'; import PageAuthSelect from './auth/select'; import PageAuthLogin from './auth/login'; @@ -76,6 +76,7 @@ const Page = observer(class Page extends React.Component<I.PageComponent> { const { page, action } = this.getMatchParams(); const path = [ page, action ].join('/'); const isMain = this.isMain(); + const Component = Components[path]; if (account) { const { status } = account || {}; @@ -86,34 +87,22 @@ const Page = observer(class Page extends React.Component<I.PageComponent> { return null; }; - const Component = Components[path]; - if (!Component) { - return ( - <Frame> - <Label text={U.Common.sprintf(translate('pageMainIndexComponentNotFound'), path)} /> - </Frame> - ); - }; - - const wrap = ( - <div id="page" className={`page ${this.getClass('page')}`}> - <Component ref={ref => this.refChild = ref} {...this.props} /> - </div> - ); - - let content = null; - if (isPopup || !isMain) { - content = wrap; - } else { - content = ( - <div id="pageFlex" className="pageFlex"> - <div id="sidebarDummyLeft" className="sidebarDummy" /> - {wrap} - <div id="sidebarDummyRight" className="sidebarDummy" /> + return ( + <div id="pageFlex" className="pageFlex"> + <div id="sidebarDummyLeft" className="sidebarDummy" /> + <div id="page" className={`page ${this.getClass('page')}`}> + {Component ? ( + <Component ref={ref => this.refChild = ref} {...this.props} /> + ) : ( + <Frame> + <Label text={U.Common.sprintf(translate('pageMainIndexComponentNotFound'), path)} /> + </Frame> + )} </div> - ); - }; - return content; + <div id="sidebarDummyRight" className="sidebarDummy" /> + <SidebarRight ref={ref => S.Common.refSet('sidebarRight', ref)} key="sidebarRight" {...this.props} /> + </div> + );; }; componentDidMount () { @@ -190,6 +179,7 @@ const Page = observer(class Page extends React.Component<I.PageComponent> { init () { const { account } = S.Auth; const { isPopup } = this.props; + const { showSidebarRight } = S.Common; const match = this.getMatch(); const { page, action } = this.getMatchParams(); const isIndex = this.isIndex(); @@ -201,6 +191,7 @@ const Page = observer(class Page extends React.Component<I.PageComponent> { const path = [ page, action ].join('/'); const Component = Components[path]; const routeParam = { replace: true }; + const refSidebar = S.Common.getRef('sidebarRight'); Preview.tooltipHide(true); Preview.previewHide(true); @@ -225,6 +216,10 @@ const Page = observer(class Page extends React.Component<I.PageComponent> { return; }; + if (refSidebar && showSidebarRight) { + refSidebar.setState({ rootId: this.getRootId() }); + }; + this.setBodyClass(); this.resize(); this.event(); diff --git a/src/ts/component/sidebar/page/object/relation.tsx b/src/ts/component/sidebar/page/object/relation.tsx index 0ff1ee2a00..ea9d913a31 100644 --- a/src/ts/component/sidebar/page/object/relation.tsx +++ b/src/ts/component/sidebar/page/object/relation.tsx @@ -10,6 +10,7 @@ const TRACE = 'sidebarObjectRelation'; const SidebarPageObjectRelation = observer(class SidebarPageObjectRelation extends React.Component<I.SidebarPageComponent> { sectionRefs: Map<string, any> = new Map(); + id = ''; constructor (props: I.SidebarPageComponent) { super(props); @@ -57,13 +58,18 @@ const SidebarPageObjectRelation = observer(class SidebarPageObjectRelation exten }; componentDidUpdate (): void { - console.log('UPDATE', this.getRootId(), this.getObject().name); + this.load(); }; load () { const { space } = S.Common; const { rootId } = this.props; + if (this.id == rootId) { + return; + }; + + this.id = rootId; C.ObjectShow(rootId, TRACE, space, () => this.forceUpdate()); }; diff --git a/src/ts/lib/sidebar.ts b/src/ts/lib/sidebar.ts index 68fa4c15ea..26729f02b9 100644 --- a/src/ts/lib/sidebar.ts +++ b/src/ts/lib/sidebar.ts @@ -400,7 +400,7 @@ class Sidebar { }; rightPanelSwitch (page: string, param: any) { - S.Common.getRef('sidebarRight').setState({ page, ...param }); + S.Common.getRef('sidebarRight')?.setState({ page, ...param }); }; }; From dd97368754acc42c0bc2f68e5ce8878af64a2ce1 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Wed, 30 Oct 2024 15:10:20 +0100 Subject: [PATCH 39/51] sidebar updates --- src/ts/lib/sidebar.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ts/lib/sidebar.ts b/src/ts/lib/sidebar.ts index 26729f02b9..b98605bd20 100644 --- a/src/ts/lib/sidebar.ts +++ b/src/ts/lib/sidebar.ts @@ -396,6 +396,8 @@ class Sidebar { if (!v) { S.Common.showSidebarRightSet(v); }; + + $(window).trigger('resize'); }, J.Constant.delay.sidebar); }; From 12ee7b7997cfb1891c409ee922208b2bd2f6d368 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Wed, 30 Oct 2024 15:34:10 +0100 Subject: [PATCH 40/51] small fixes --- src/scss/component/sidebar/page.scss | 9 +++------ src/scss/popup/page.scss | 2 ++ src/ts/lib/sidebar.ts | 15 ++++++++++++--- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/scss/component/sidebar/page.scss b/src/scss/component/sidebar/page.scss index 9a2d98cfc0..4bab499be7 100644 --- a/src/scss/component/sidebar/page.scss +++ b/src/scss/component/sidebar/page.scss @@ -1,18 +1,15 @@ > .sidebarPage { display: flex; flex-direction: column; height: 100%; } > .sidebarPage { - .head { - display: flex; flex-direction: row; align-items: center; justify-content: space-between; -webkit-app-region: no-drag; - padding: 12px 12px 16px 12px; flex-shrink: 0; - } + .head { display: flex; flex-direction: row; align-items: center; justify-content: space-between; -webkit-app-region: no-drag; padding: 12px; flex-shrink: 0; } .head { .side.left { flex-grow: 1; font-weight: 500; } .side.right { flex-shrink: 0; display: flex; flex-direction: row; gap: 0px 8px; } - .button.simple { @include text-common; font-weight: 500; color: var(--color-text-secondary); } + .button.simple { @include text-common; font-weight: 500; color: var(--color-text-secondary); height: 28px; } .button.simple:hover { color: var(--color-text-primary); } } - .body { + .body { padding: 0px 12px 12px 12px; overflow: scroll; display: flex; flex-direction: column; gap: 12px 0px; overscroll-behavior: none; scrollbar-gutter: stable both-edges; flex-grow: 1; } diff --git a/src/scss/popup/page.scss b/src/scss/popup/page.scss index 419fd1b983..8e47c30787 100644 --- a/src/scss/popup/page.scss +++ b/src/scss/popup/page.scss @@ -4,6 +4,8 @@ .popup.popupPage { .innerWrap { width: 1096px; height: calc(100% - 164px); padding: 0px; } + #sidebarRight { position: absolute; } + @media (max-width: 1128px) { .innerWrap { width: calc(100% - 32px); left: 16px; margin-left: 0px !important; } } diff --git a/src/ts/lib/sidebar.ts b/src/ts/lib/sidebar.ts index b98605bd20..b10efd3549 100644 --- a/src/ts/lib/sidebar.ts +++ b/src/ts/lib/sidebar.ts @@ -218,6 +218,11 @@ class Sidebar { }; resizePage (widthLeft: number, widthRight: number, animate: boolean): void { + const isPopup = keyboard.isPopup(); + const isMain = keyboard.isMain(); + const isMainVoid = keyboard.isMainVoid(); + const isMainHistory = keyboard.isMainHistory(); + this.initObjects(); let toggleX = 16; @@ -230,20 +235,24 @@ class Sidebar { widthRight = this.objRight.outerWidth(); }; - if (!keyboard.isMain() || keyboard.isMainVoid()) { + if (!isMain || isMainVoid) { widthLeft = 0; widthRight = 0; }; + if (isPopup) { + widthLeft = 0; + }; + const { isClosed } = this.data; const { showVault, isFullScreen } = S.Common; const { ww } = U.Common.getWindowDimensions(); - const vw = isClosed || !showVault || !keyboard.isMain() ? 0 : J.Size.vault.width; + const vw = isClosed || !showVault || !isMain || isPopup ? 0 : J.Size.vault.width; widthLeft += vw; const pageWidth = ww - widthLeft - widthRight; - const ho = keyboard.isMainHistory() ? J.Size.history.panel : 0; + const ho = isMainHistory ? J.Size.history.panel : 0; const navigation = S.Common.getRef('navigation'); if ((widthLeft && showVault) || (U.Common.isPlatformMac() && !isFullScreen)) { From c885eba30cae991b433d38337d7ab474260ee9ea Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Wed, 30 Oct 2024 17:27:47 +0100 Subject: [PATCH 41/51] fix sentry crash --- src/ts/component/cell/text.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/ts/component/cell/text.tsx b/src/ts/component/cell/text.tsx index 4e1c9037f0..7a516e3f11 100644 --- a/src/ts/component/cell/text.tsx +++ b/src/ts/component/cell/text.tsx @@ -449,6 +449,8 @@ const CellText = observer(class CellText extends React.Component<I.Cell, State> }; fixDateValue (v: any) { + v = String(v || '').replace(/_/g, ''); + const { relation, getView } = this.props; let view = null; @@ -457,10 +459,13 @@ const CellText = observer(class CellText extends React.Component<I.Cell, State> if (getView) { view = getView(); viewRelation = view.getRelation(relation.relationKey); + + if (v && viewRelation) { + v = U.Date.parseDate(v, viewRelation.dateFormat); + }; }; - v = String(v || '').replace(/_/g, ''); - return v ? U.Date.parseDate(v, viewRelation.dateFormat) : null; + return v ? v : null; }; onCompositionStart () { From 0a1ee3de58bb44546499e56b2a7d214fd1568780 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Thu, 31 Oct 2024 08:46:01 +0100 Subject: [PATCH 42/51] fix sentry crash --- src/ts/component/menu/dataview/relation/edit.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ts/component/menu/dataview/relation/edit.tsx b/src/ts/component/menu/dataview/relation/edit.tsx index 4dd8882987..4773ca96c9 100644 --- a/src/ts/component/menu/dataview/relation/edit.tsx +++ b/src/ts/component/menu/dataview/relation/edit.tsx @@ -82,7 +82,7 @@ const MenuRelationEdit = observer(class MenuRelationEdit extends React.Component readonly={readonly} withSwitch={true} switchValue={viewRelation?.includeTime} - onSwitch={(e: any, v: boolean) => { this.onChangeTime(v); }} + onSwitch={(e: any, v: boolean) => this.onChangeTime(v)} /> <MenuItemVertical @@ -557,7 +557,9 @@ const MenuRelationEdit = observer(class MenuRelationEdit extends React.Component const view = getView(); const relation = this.getViewRelation(); - C.BlockDataviewViewRelationReplace(rootId, blockId, view.id, relation.relationKey, { ...relation, includeTime: v }); + if (view && relation) { + C.BlockDataviewViewRelationReplace(rootId, blockId, view.id, relation.relationKey, { ...relation, includeTime: v }); + }; }; onSubmit (e: any) { From df2e4c5a2037a7f20e0577a17b157716527253cb Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Thu, 31 Oct 2024 09:00:03 +0100 Subject: [PATCH 43/51] fix sentry crash --- src/ts/component/util/graph.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ts/component/util/graph.tsx b/src/ts/component/util/graph.tsx index 6d1041d056..6bdb2d8bbe 100644 --- a/src/ts/component/util/graph.tsx +++ b/src/ts/component/util/graph.tsx @@ -309,15 +309,15 @@ const Graph = observer(class Graph extends React.Component<Props> { const settings = S.Common.getGraph(storageKey); const { id, data } = e.data; const node = $(this.node); - const { left, top } = node.offset(); + if (!node || !node.length) { + return; + }; + + const { left, top } = node.offset(); const menuParam = { - onOpen: () => { - this.isPreviewDisabled = true; - }, - onClose: () => { - this.isPreviewDisabled = false; - }, + onOpen: () => this.isPreviewDisabled = true, + onClose: () => this.isPreviewDisabled = false, recalcRect: () => ({ width: 0, height: 0, From 56d75cfa53d9062d5aa87ad27c1fa691f4edf220 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Fri, 1 Nov 2024 08:51:06 +0100 Subject: [PATCH 44/51] fix confirm --- src/scss/menu/common.scss | 14 ++------------ src/scss/menu/select.scss | 2 +- src/scss/page/auth.scss | 2 ++ src/ts/component/form/select.tsx | 4 ++-- 4 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/scss/menu/common.scss b/src/scss/menu/common.scss index 4d8762f9f0..8ba9a79387 100644 --- a/src/scss/menu/common.scss +++ b/src/scss/menu/common.scss @@ -160,18 +160,8 @@ } .item.withNote { - .info { display: flex; align-items: center; gap: 0px 20px; } - - .note { position: relative; flex-shrink: 0; width: 20px; height: 20px; background: url('~img/icon/menu/important.svg'); } - .note { - .noteMessage { - display: none; position: absolute; z-index: 2; bottom: 24px; right: 0px; width: 196px; padding: 4px 8px; border-radius: 4px; - @include text-small; background-color: var(--color-bg-secondary); color: var(--color-text-inversion); - } - } - .note:hover { - .noteMessage { display: block; } - } + .info { display: flex; align-items: center; gap: 0px 20px; width: 100%; } + .icon.note { position: relative; flex-shrink: 0; width: 20px; height: 20px; margin: 0px; background: url('~img/icon/menu/important.svg'); } } .item.withCaption { display: flex; align-items: center; justify-content: space-between; gap: 0px 6px; } diff --git a/src/scss/menu/select.scss b/src/scss/menu/select.scss index 71cc433689..8ccac8e984 100644 --- a/src/scss/menu/select.scss +++ b/src/scss/menu/select.scss @@ -42,7 +42,7 @@ } .menu.menuSelect.withFullDescripion { - .content { overflow: auto; padding: 8px 0px; } + .content { overflow: auto; padding: 0px; } .item.withDescription { height: auto; } .item.withDescription { diff --git a/src/scss/page/auth.scss b/src/scss/page/auth.scss index 8882644fe8..aad21802c3 100644 --- a/src/scss/page/auth.scss +++ b/src/scss/page/auth.scss @@ -9,6 +9,7 @@ html.bodyIndex, html.bodyAuth { --color-text-tertiary: #606060 !important; --color-shape-tertiary: #2b2b2b !important; + --color-shape-highlight-medium: rgba(255, 255, 255, 0.05) !important; --color-button-stroke: #252525 !important; --color-button-black-hover: rgba(37, 37, 37, 0.8); @@ -65,6 +66,7 @@ html.bodyIndex, html.bodyAuth { .menu.vertical { background: var(--color-popup) !important; box-shadow: var(--shadow) !important; } .menu.vertical { .item { background: var(--color-popup) !important; } + .item.hover::before { background: var(--color-shape-highlight-medium) !important; } } .menu.menuAccountPath { .label { color: var(--color-text-secondary) !important; } diff --git a/src/ts/component/form/select.tsx b/src/ts/component/form/select.tsx index 111fc48b11..8e2361b3e8 100644 --- a/src/ts/component/form/select.tsx +++ b/src/ts/component/form/select.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import $ from 'jquery'; -import { I, S, Relation } from 'Lib'; +import { I, S, U, Relation } from 'Lib'; import { Icon, MenuItemVertical } from 'Component'; interface Props { @@ -208,7 +208,7 @@ class Select extends React.Component<Props, State> { noFilter, noClose: true, value, - options, + options: U.Menu.prepareForSelect(options), onSelect: (e: any, item: any) => { let { value } = this.state; From 44a0f25e4eec9f452d642ac5e49c1272fbaeafe1 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Fri, 1 Nov 2024 09:13:46 +0100 Subject: [PATCH 45/51] #1026: fix --- .../component/popup/settings/onboarding.tsx | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/ts/component/popup/settings/onboarding.tsx b/src/ts/component/popup/settings/onboarding.tsx index 85c985a344..6f30af3d35 100644 --- a/src/ts/component/popup/settings/onboarding.tsx +++ b/src/ts/component/popup/settings/onboarding.tsx @@ -26,21 +26,7 @@ const PopupSettingsOnboarding = observer(class PopupSettingsOnboarding extends R const { interfaceLang } = S.Common; const interfaceLanguages = U.Menu.getInterfaceLanguages(); const isDefault = path == U.Common.getElectron().defaultPath(); - const networkModes: any[] = ([ - { id: I.NetworkMode.Default }, - { id: I.NetworkMode.Local }, - { id: I.NetworkMode.Custom }, - ] as any[]).map(it => { - it.name = translate(`networkMode${it.id}Title`); - it.description = translate(`networkMode${it.id}Text`); - it.withDescription = true; - - if (it.id == I.NetworkMode.Local) { - it.note = translate('popupSettingsOnboardingLocalOnlyNote'); - }; - - return it; - }); + const networkModes = this.getNetworkModes(); return ( <div className="mainSides"> @@ -127,6 +113,24 @@ const PopupSettingsOnboarding = observer(class PopupSettingsOnboarding extends R this.forceUpdate(); }; + getNetworkModes () { + return ([ + { id: I.NetworkMode.Default }, + { id: I.NetworkMode.Local }, + { id: I.NetworkMode.Custom }, + ] as any[]).map(it => { + it.name = translate(`networkMode${it.id}Title`); + it.description = translate(`networkMode${it.id}Text`); + it.withDescription = true; + + if (it.id == I.NetworkMode.Local) { + it.note = translate('popupSettingsOnboardingLocalOnlyNote'); + }; + + return it; + }); + }; + onChange (key: string, value: any) { this.config[key] = value; this.forceUpdate(); @@ -156,7 +160,7 @@ const PopupSettingsOnboarding = observer(class PopupSettingsOnboarding extends R }; S.Auth.networkConfigSet(this.config); - this.props.close(); + window.setTimeout(() => this.props.close(), S.Popup.getTimeout()); }; if (this.config.mode == I.NetworkMode.Local) { From 65e38490abfe0ba3bb809999f5b7e5cd2814634c Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Fri, 1 Nov 2024 11:01:37 +0100 Subject: [PATCH 46/51] fix import --- src/ts/component/sidebar/section/type/layout.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ts/component/sidebar/section/type/layout.tsx b/src/ts/component/sidebar/section/type/layout.tsx index 084c67cce9..7c5494fb59 100644 --- a/src/ts/component/sidebar/section/type/layout.tsx +++ b/src/ts/component/sidebar/section/type/layout.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { observer } from 'mobx-react'; -import { Label, Select, Drag } from 'Component'; +import { Label, Select, DragHorizontal } from 'Component'; import { I, U, translate } from 'Lib'; const SidebarSectionTypeLayout = observer(class SidebarSectionTypeLayout extends React.Component<I.SidebarSectionComponent> { @@ -68,7 +68,7 @@ const SidebarSectionTypeLayout = observer(class SidebarSectionTypeLayout extends <div className="value flex"> <div id="percent">{percent}%</div> - <Drag + <DragHorizontal ref={ref => this.refWidth = ref} value={object.layoutWidth} onMove={(e, v) => this.onWidthMove(v)} From 5fa4a8646dd9bdbc53ed47776bea080a9efb1675 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Fri, 1 Nov 2024 11:21:07 +0100 Subject: [PATCH 47/51] fix drag styles --- src/scss/component/sidebar/page.scss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/scss/component/sidebar/page.scss b/src/scss/component/sidebar/page.scss index 4bab499be7..d1c996edb4 100644 --- a/src/scss/component/sidebar/page.scss +++ b/src/scss/component/sidebar/page.scss @@ -44,10 +44,10 @@ } } - .input-drag { width: 96px; height: 16px; box-shadow: 0px 0px 0px 1px var(--color-shape-primary) inset; border-radius: 8px; overflow: hidden; } - .input-drag { + .input-drag-horizontal { width: 96px; height: 16px; box-shadow: 0px 0px 0px 1px var(--color-shape-primary) inset; border-radius: 8px; overflow: hidden; } + .input-drag-horizontal { .back { height: calc(100% - 2px); margin: 0px 0px 0px -1px; top: 1px; background: var(--color-shape-tertiary); border-radius: 0px 8px 8px 0px; } - .fill { height: calc(100% - 2px); margin: 0px 0px 0px 1px; top: 1px; border-radius: 8px 0px 0px 8px; } + .fill { height: calc(100% - 2px); margin: 0px 0px 0px 1px; top: 1px; border-radius: 8px 0px 0px 8px; background: var(--color-bg-primary); } .icon { width: 16px; height: 16px; border-radius: 0px; border: 0px; } .bullet { width: 100%; height: 100%; border-radius: 50%; background: var(--color-bg-primary); border: 1px solid var(--color-shape-primary); } } From 7d3073bd595ba84df73e7c446f658ac850c73976 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Wed, 6 Nov 2024 10:46:59 +0100 Subject: [PATCH 48/51] fix dragndrop --- src/scss/component/sidebar.scss | 4 ++-- src/ts/lib/sidebar.ts | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/scss/component/sidebar.scss b/src/scss/component/sidebar.scss index 4393cc9fa8..c2b6919b3b 100644 --- a/src/scss/component/sidebar.scss +++ b/src/scss/component/sidebar.scss @@ -23,8 +23,8 @@ .sidebar.left { left: 0px; } .sidebar.left.anim { transition-property: width; } -.sidebar.right { right: 0px; width: 348px; transform: translateX(100%); } -.sidebar.right.anim { transition-property: transform; } +.sidebar.right { right: -348px; width: 348px; } +.sidebar.right.anim { transition-property: right; } .sidebar { @import "./sidebar/widget"; diff --git a/src/ts/lib/sidebar.ts b/src/ts/lib/sidebar.ts index b10efd3549..4479e53d30 100644 --- a/src/ts/lib/sidebar.ts +++ b/src/ts/lib/sidebar.ts @@ -380,15 +380,16 @@ class Sidebar { window.setTimeout(() => { this.initObjects(); + const width = this.objRight.outerWidth(); const cssStart: any = {}; const cssEnd: any = {}; if (v) { - cssStart.transform = 'translate3d(100%,0px,0px)'; - cssEnd.transform = 'translate3d(0%,0px,0px)'; + cssStart.right = -width; + cssEnd.right = 0; } else { - cssStart.transform = 'translate3d(0%,0px,0px)'; - cssEnd.transform = 'translate3d(100%,0px,0px)'; + cssStart.right = 0; + cssEnd.right = -width; }; this.objRight.css(cssStart); From 76b48ec73d58ba0f4f48a5094349fcfff8951e28 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Wed, 6 Nov 2024 12:07:26 +0100 Subject: [PATCH 49/51] fixes and debug --- src/scss/component/editor.scss | 1 - src/ts/component/page/main/type.tsx | 3 ++- src/ts/component/sidebar/section/index.tsx | 15 ++++++++++++++- src/ts/component/sidebar/section/type/layout.tsx | 10 +++++++--- .../component/sidebar/section/type/relation.tsx | 3 ++- src/ts/interface/common.ts | 1 + src/ts/lib/util/data.ts | 2 ++ src/ts/store/detail.ts | 1 + src/ts/store/record.ts | 2 +- 9 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/scss/component/editor.scss b/src/scss/component/editor.scss index bafeb09294..d71eff4df0 100644 --- a/src/scss/component/editor.scss +++ b/src/scss/component/editor.scss @@ -164,7 +164,6 @@ .controlButtons { left: 144px !important; } } - &.withIconAndCover { padding-top: 214px; } &.withIconAndCover { .controlButtons { bottom: 26px; } } diff --git a/src/ts/component/page/main/type.tsx b/src/ts/component/page/main/type.tsx index 54817e564f..ff85b027a9 100644 --- a/src/ts/component/page/main/type.tsx +++ b/src/ts/component/page/main/type.tsx @@ -496,7 +496,8 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC }; getObject () { - return S.Record.getTypeById(this.getRootId()); + const rootId = this.getRootId(); + return S.Detail.get(rootId, rootId, U.Data.typeRelationKeys()); }; getSubIdTemplate () { diff --git a/src/ts/component/sidebar/section/index.tsx b/src/ts/component/sidebar/section/index.tsx index 7a5936c21e..43369e7ff9 100644 --- a/src/ts/component/sidebar/section/index.tsx +++ b/src/ts/component/sidebar/section/index.tsx @@ -34,9 +34,10 @@ const SidebarSectionIndex = observer(class SidebarSectionIndex extends React.Com render () { const { component } = this.props; - const object = this.state.object || this.props.object; + const object = this.getObject(); const Component = Components[component]; const cn = [ 'section', U.Common.toCamelCase(component.replace(/\//g, '-')) ]; + const readonly = this.isReadonly(); if (!object) { return null; @@ -49,6 +50,7 @@ const SidebarSectionIndex = observer(class SidebarSectionIndex extends React.Com ref={ref => this.ref = ref} {...this.props} object={object} + readonly={readonly} /> ): component} </div> @@ -63,10 +65,21 @@ const SidebarSectionIndex = observer(class SidebarSectionIndex extends React.Com }; }; + getObject (): any { + return this.state.object || this.props.object; + }; + setObject (object: any): void { this.setState({ object }, () => this.ref?.forceUpdate()); }; + isReadonly (): boolean { + const { readonly } = this.props; + const object = this.getObject(); + + return readonly || object?.isArchived; + }; + }); export default SidebarSectionIndex; \ No newline at end of file diff --git a/src/ts/component/sidebar/section/type/layout.tsx b/src/ts/component/sidebar/section/type/layout.tsx index 7c5494fb59..d5dad9bca4 100644 --- a/src/ts/component/sidebar/section/type/layout.tsx +++ b/src/ts/component/sidebar/section/type/layout.tsx @@ -14,7 +14,6 @@ const SidebarSectionTypeLayout = observer(class SidebarSectionTypeLayout extends const { object, onChange } = this.props; const layoutOptions = U.Menu.prepareForSelect(U.Menu.turnLayouts()); const alignOptions = U.Menu.prepareForSelect(U.Menu.getHAlign([ I.BlockHAlign.Justify ])); - const percent = (1 + object.layoutWidth) * 100; return ( <div ref={ref => this.node = ref} className="wrap"> @@ -67,7 +66,7 @@ const SidebarSectionTypeLayout = observer(class SidebarSectionTypeLayout extends </div> <div className="value flex"> - <div id="percent">{percent}%</div> + <div id="percent">{this.getPercent(object.layoutWidth)}%</div> <DragHorizontal ref={ref => this.refWidth = ref} value={object.layoutWidth} @@ -99,13 +98,18 @@ const SidebarSectionTypeLayout = observer(class SidebarSectionTypeLayout extends }; onWidthMove (v: number) { - $(this.node).find('#percent').text(`${U.Common.sprintf('%0.2f', (1 + v) * 100)}%`); + $(this.node).find('#percent').text(`${this.getPercent(v)}%`); }; onWidthEnd (v: number) { this.props.onChange('layoutWidth', v); }; + getPercent (v: number): string { + v = Number(v) || 0; + return U.Common.sprintf('%0.2f', (1 + v) * 100); + }; + }); export default SidebarSectionTypeLayout; \ No newline at end of file diff --git a/src/ts/component/sidebar/section/type/relation.tsx b/src/ts/component/sidebar/section/type/relation.tsx index 57d252ebb8..156d597c5e 100644 --- a/src/ts/component/sidebar/section/type/relation.tsx +++ b/src/ts/component/sidebar/section/type/relation.tsx @@ -16,6 +16,7 @@ const SidebarSectionTypeRelation = observer(class SidebarSectionTypeRelation ext }; render () { + const { readonly } = this.props; const featured = this.getFeatured(); const recommended = this.getRecommended(); @@ -30,7 +31,7 @@ const SidebarSectionTypeRelation = observer(class SidebarSectionTypeRelation ext onClick={e => this.onEdit(e, item.container, item.id)} > <div className="side left"> - <Handle /> + {!readonly ? <Handle /> : ''} <IconObject object={item} /> <ObjectName object={item} /> </div> diff --git a/src/ts/interface/common.ts b/src/ts/interface/common.ts index 914400c58e..83d7a28f16 100644 --- a/src/ts/interface/common.ts +++ b/src/ts/interface/common.ts @@ -198,6 +198,7 @@ export interface SidebarPageComponent { export interface SidebarSectionComponent extends SidebarPageComponent { object: any; item?: any; + readonly?: boolean; onChange?(key: string, value: any): void; }; diff --git a/src/ts/lib/util/data.ts b/src/ts/lib/util/data.ts index ef443c645d..3bf77b3288 100644 --- a/src/ts/lib/util/data.ts +++ b/src/ts/lib/util/data.ts @@ -381,6 +381,7 @@ class UtilData { noDeps: true, ignoreDeleted: true, ignoreHidden: false, + withArchived: true, onSubscribe: () => { S.Record.getTypes().forEach(it => S.Record.typeKeyMapSet(it.spaceId, it.uniqueKey, it.id)); } @@ -409,6 +410,7 @@ class UtilData { noDeps: true, ignoreDeleted: true, ignoreHidden: false, + withArchived: true, onSubscribe: () => { S.Record.getRelations().forEach(it => S.Record.relationKeyMapSet(it.spaceId, it.relationKey, it.id)); }, diff --git a/src/ts/store/detail.ts b/src/ts/store/detail.ts index 4ca6170a3f..ae7071d353 100644 --- a/src/ts/store/detail.ts +++ b/src/ts/store/detail.ts @@ -232,6 +232,7 @@ class DetailStore { object.sourceObject = Relation.getStringValue(object.sourceObject); object.uniqueKey = Relation.getStringValue(object.uniqueKey); object.defaultTemplateId = Relation.getStringValue(object.defaultTemplateId); + object.layoutWidth = Number(object.layoutWidth) || 0; if (object.isDeleted) { object.name = translate('commonDeletedType'); diff --git a/src/ts/store/record.ts b/src/ts/store/record.ts index 521d71e51f..7b3294aacc 100644 --- a/src/ts/store/record.ts +++ b/src/ts/store/record.ts @@ -359,7 +359,7 @@ class RecordStore { }; getRecords (subId: string, keys?: string[], forceKeys?: boolean): any[] { - return this.getRecordIds(subId, '').map(id => S.Detail.get(subId, id, keys)); + return this.getRecordIds(subId, '').map(id => S.Detail.get(subId, id, keys, forceKeys)); }; getGroups (rootId: string, blockId: string) { From 6f2b7ed9f6bf2b9c1c255501d3472ee8ec64953b Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Tue, 12 Nov 2024 09:49:07 +0100 Subject: [PATCH 50/51] JS-5725: description updates --- dist/img/icon/relation/description.svg | 5 ++++ src/ts/component/menu/block/layout.tsx | 26 ++----------------- .../component/menu/dataview/relation/list.tsx | 6 ++--- src/ts/component/util/iconObject.tsx | 11 ++++++-- 4 files changed, 19 insertions(+), 29 deletions(-) create mode 100644 dist/img/icon/relation/description.svg diff --git a/dist/img/icon/relation/description.svg b/dist/img/icon/relation/description.svg new file mode 100644 index 0000000000..29162b52f3 --- /dev/null +++ b/dist/img/icon/relation/description.svg @@ -0,0 +1,5 @@ +<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> +<circle cx="10" cy="10" r="7.75" stroke="#B6B6B6" stroke-width="1.5"/> +<path d="M10.748 8.5V14.999H9.24976V8.5H10.748Z" fill="#B6B6B6"/> +<path d="M10 7C9.44772 7 9 6.55228 9 6C9 5.44772 9.44772 5 10 5C10.5523 5 11 5.44772 11 6C11 6.55228 10.5523 7 10 7Z" fill="#B6B6B6"/> +</svg> \ No newline at end of file diff --git a/src/ts/component/menu/block/layout.tsx b/src/ts/component/menu/block/layout.tsx index f444aabfb3..3cfb057841 100644 --- a/src/ts/component/menu/block/layout.tsx +++ b/src/ts/component/menu/block/layout.tsx @@ -70,7 +70,6 @@ class MenuBlockLayout extends React.Component<I.Menu> { const { param } = this.props; const { data } = param; const { rootId } = data; - const allowedLayout = S.Block.checkFlags(rootId, rootId, [ I.RestrictionObject.Layout ]); const allowedDetails = S.Block.checkFlags(rootId, rootId, [ I.RestrictionObject.Details ]); const object = S.Detail.get(rootId, rootId, [ 'layoutAlign' ]); @@ -84,17 +83,7 @@ class MenuBlockLayout extends React.Component<I.Menu> { resize = null; }; - let sections = []; - if (allowedLayout) { - sections.push({ name: translate('menuBlockLayoutChooseLayoutType'), children: U.Menu.turnLayouts() }); - }; - - sections.push({ - children: [ - resize, - align, - ] - }); + let sections = [ { children: [ resize, align ] } ]; sections = sections.filter((section: any) => { section.children = section.children.filter(it => it); @@ -178,10 +167,7 @@ class MenuBlockLayout extends React.Component<I.Menu> { }; onClick (e: any, item: any) { - const { param, close } = this.props; - const { data } = param; - const { rootId, onLayoutSelect } = data; - const object = S.Detail.get(rootId, rootId, []); + const { close } = this.props; if (item.arrow) { return; @@ -193,14 +179,6 @@ class MenuBlockLayout extends React.Component<I.Menu> { this.onResize(e); analytics.event('SetLayoutWidth'); - } else { - U.Object.setLayout(rootId, item.id, (message: any) => { - if (onLayoutSelect) { - onLayoutSelect(item.id); - }; - }); - - analytics.event('ChangeLayout', { objectType: object.type, layout: item.id }); }; }; diff --git a/src/ts/component/menu/dataview/relation/list.tsx b/src/ts/component/menu/dataview/relation/list.tsx index 71f810b29f..24b036d3c1 100644 --- a/src/ts/component/menu/dataview/relation/list.tsx +++ b/src/ts/component/menu/dataview/relation/list.tsx @@ -4,8 +4,8 @@ import { observer } from 'mobx-react'; import arrayMove from 'array-move'; import { AutoSizer, CellMeasurer, InfiniteLoader, List as VList, CellMeasurerCache } from 'react-virtualized'; import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc'; -import { Icon, Switch } from 'Component'; -import { I, C, S, J, Relation, keyboard, Dataview, translate } from 'Lib'; +import { Icon, IconObject, Switch } from 'Component'; +import { I, C, S, J, keyboard, Dataview, translate } from 'Lib'; const HEIGHT = 28; const LIMIT = 20; @@ -62,7 +62,7 @@ const MenuRelationList = observer(class MenuRelationList extends React.Component > {!isReadonly ? <Handle /> : ''} <span className="clickable" onClick={e => this.onClick(e, item)}> - <Icon className={`relation ${Relation.className(item.relation.format)}`} /> + <IconObject object={item.relation} /> <div className="name">{item.relation.name}</div> </span> {canHide ? ( diff --git a/src/ts/component/util/iconObject.tsx b/src/ts/component/util/iconObject.tsx index 7f5fc0ba2e..639870aae5 100644 --- a/src/ts/component/util/iconObject.tsx +++ b/src/ts/component/util/iconObject.tsx @@ -135,7 +135,7 @@ const IconObject = observer(class IconObject extends React.Component<Props> { const { theme } = S.Common; const object = this.getObject(); const layout = Number(object.layout) || I.ObjectLayout.Page; - const { id, name, iconEmoji, iconImage, iconOption, iconClass, done, relationFormat, isDeleted } = object || {}; + const { id, name, iconEmoji, iconImage, iconOption, iconClass, done, relationFormat, relationKey, isDeleted } = object || {}; const cn = [ 'iconObject', 'c' + size, U.Data.layoutClass(object.id, layout) ]; const iconSize = this.iconSize(); const tc = S.Common.getThemeClass(); @@ -239,8 +239,15 @@ const IconObject = observer(class IconObject extends React.Component<Props> { break; }; + let src = ''; + if (relationKey == 'description') { + src = 'description'; + } else { + src = Relation.typeName(relationFormat); + }; + icn = icn.concat([ 'iconCommon', 'c' + iconSize ]); - icon = <img src={`./img/icon/relation/${Relation.typeName(relationFormat)}.svg`} className={icn.join(' ')} />; + icon = <img src={`./img/icon/relation/${src}.svg`} className={icn.join(' ')} />; break; }; From ff85d47090fb68ba938e9ebd471b8346aba1a3d7 Mon Sep 17 00:00:00 2001 From: Andrew Simachev <andrew.simachev@gmail.com> Date: Tue, 12 Nov 2024 10:48:25 +0100 Subject: [PATCH 51/51] JS-5725: description updates --- src/img/icon/add/description0.svg | 5 ++++ src/img/icon/add/description1.svg | 5 ++++ src/img/icon/add/layout0.svg | 8 ++---- src/img/icon/add/layout1.svg | 8 ++---- src/json/text.json | 10 ++++--- src/scss/block/cover.scss | 14 +++++----- src/scss/component/editor.scss | 16 +++++++----- src/ts/component/block/cover.tsx | 13 +++------- src/ts/component/block/link.tsx | 2 +- src/ts/component/menu/block/relation/view.tsx | 12 +++------ .../page/elements/head/controlButtons.tsx | 26 +++++++++++++++---- .../component/page/elements/head/controls.tsx | 13 +++------- src/ts/lib/action.ts | 16 ++++++++++++ 13 files changed, 86 insertions(+), 62 deletions(-) create mode 100644 src/img/icon/add/description0.svg create mode 100644 src/img/icon/add/description1.svg diff --git a/src/img/icon/add/description0.svg b/src/img/icon/add/description0.svg new file mode 100644 index 0000000000..8003f30613 --- /dev/null +++ b/src/img/icon/add/description0.svg @@ -0,0 +1,5 @@ +<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> +<circle cx="10" cy="10" r="8" fill="#B6B6B6"/> +<path d="M10.748 8.5V14.999H9.24976V8.5H10.748Z" fill="white"/> +<path d="M9.99902 6.96777C9.44674 6.96777 8.99902 6.52006 8.99902 5.96777C8.99902 5.41549 9.44674 4.96777 9.99902 4.96777C10.5513 4.96777 10.999 5.41549 10.999 5.96777C10.999 6.52006 10.5513 6.96777 9.99902 6.96777Z" fill="white"/> +</svg> \ No newline at end of file diff --git a/src/img/icon/add/description1.svg b/src/img/icon/add/description1.svg new file mode 100644 index 0000000000..d56c8398e9 --- /dev/null +++ b/src/img/icon/add/description1.svg @@ -0,0 +1,5 @@ +<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> +<circle cx="10" cy="10" r="8" fill="#252525"/> +<path d="M10.748 8.5V14.999H9.24976V8.5H10.748Z" fill="white"/> +<path d="M9.99902 6.96777C9.44674 6.96777 8.99902 6.52006 8.99902 5.96777C8.99902 5.41549 9.44674 4.96777 9.99902 4.96777C10.5513 4.96777 10.999 5.41549 10.999 5.96777C10.999 6.52006 10.5513 6.96777 9.99902 6.96777Z" fill="white"/> +</svg> \ No newline at end of file diff --git a/src/img/icon/add/layout0.svg b/src/img/icon/add/layout0.svg index 1532023a35..715467eb51 100644 --- a/src/img/icon/add/layout0.svg +++ b/src/img/icon/add/layout0.svg @@ -1,7 +1,3 @@ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M3 15.625C3 15.4179 3.16789 15.25 3.375 15.25H16.625C16.8321 15.25 17 15.4179 17 15.625V16.375C17 16.5821 16.8321 16.75 16.625 16.75H3.375C3.16789 16.75 3 16.5821 3 16.375V15.625Z" fill="#b6b6b6"/> -<path d="M3 11.625C3 11.4179 3.16789 11.25 3.375 11.25H16.625C16.8321 11.25 17 11.4179 17 11.625V12.375C17 12.5821 16.8321 12.75 16.625 12.75H3.375C3.16789 12.75 3 12.5821 3 12.375V11.625Z" fill="#b6b6b6"/> -<path d="M11 7.625C11 7.41789 11.1679 7.25 11.375 7.25H16.625C16.8321 7.25 17 7.41789 17 7.625V8.375C17 8.58211 16.8321 8.75 16.625 8.75H11.375C11.1679 8.75 11 8.58211 11 8.375V7.625Z" fill="#b6b6b6"/> -<path d="M11 3.625C11 3.41789 11.1679 3.25 11.375 3.25H16.625C16.8321 3.25 17 3.41789 17 3.625V4.375C17 4.58211 16.8321 4.75 16.625 4.75H11.375C11.1679 4.75 11 4.58211 11 4.375V3.625Z" fill="#b6b6b6"/> -<path d="M3 4.25C3 3.55964 3.55964 3 4.25 3H7.75C8.44036 3 9 3.55964 9 4.25V7.75C9 8.44036 8.44036 9 7.75 9H4.25C3.55964 9 3 8.44036 3 7.75V4.25Z" fill="#b6b6b6"/> -</svg> +<path fill-rule="evenodd" clip-rule="evenodd" d="M10 18C14.4183 18 18 14.4183 18 10C18 5.58172 14.4183 2 10 2C5.58172 2 2 5.58172 2 10C2 14.4183 5.58172 18 10 18ZM5.99902 10.9678C6.55131 10.9678 6.99902 10.5201 6.99902 9.96777C6.99902 9.41549 6.55131 8.96777 5.99902 8.96777C5.44674 8.96777 4.99902 9.41549 4.99902 9.96777C4.99902 10.5201 5.44674 10.9678 5.99902 10.9678ZM9.99902 10.9678C10.5513 10.9678 10.999 10.5201 10.999 9.96777C10.999 9.41549 10.5513 8.96777 9.99902 8.96777C9.44674 8.96777 8.99902 9.41549 8.99902 9.96777C8.99902 10.5201 9.44674 10.9678 9.99902 10.9678ZM14.999 9.96777C14.999 10.5201 14.5513 10.9678 13.999 10.9678C13.4467 10.9678 12.999 10.5201 12.999 9.96777C12.999 9.41549 13.4467 8.96777 13.999 8.96777C14.5513 8.96777 14.999 9.41549 14.999 9.96777Z" fill="#B6B6B6"/> +</svg> \ No newline at end of file diff --git a/src/img/icon/add/layout1.svg b/src/img/icon/add/layout1.svg index 4f00ec4c6b..d07d27910b 100644 --- a/src/img/icon/add/layout1.svg +++ b/src/img/icon/add/layout1.svg @@ -1,7 +1,3 @@ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M3 15.625C3 15.4179 3.16789 15.25 3.375 15.25H16.625C16.8321 15.25 17 15.4179 17 15.625V16.375C17 16.5821 16.8321 16.75 16.625 16.75H3.375C3.16789 16.75 3 16.5821 3 16.375V15.625Z" fill="#252525"/> -<path d="M3 11.625C3 11.4179 3.16789 11.25 3.375 11.25H16.625C16.8321 11.25 17 11.4179 17 11.625V12.375C17 12.5821 16.8321 12.75 16.625 12.75H3.375C3.16789 12.75 3 12.5821 3 12.375V11.625Z" fill="#252525"/> -<path d="M11 7.625C11 7.41789 11.1679 7.25 11.375 7.25H16.625C16.8321 7.25 17 7.41789 17 7.625V8.375C17 8.58211 16.8321 8.75 16.625 8.75H11.375C11.1679 8.75 11 8.58211 11 8.375V7.625Z" fill="#252525"/> -<path d="M11 3.625C11 3.41789 11.1679 3.25 11.375 3.25H16.625C16.8321 3.25 17 3.41789 17 3.625V4.375C17 4.58211 16.8321 4.75 16.625 4.75H11.375C11.1679 4.75 11 4.58211 11 4.375V3.625Z" fill="#252525"/> -<path d="M3 4.25C3 3.55964 3.55964 3 4.25 3H7.75C8.44036 3 9 3.55964 9 4.25V7.75C9 8.44036 8.44036 9 7.75 9H4.25C3.55964 9 3 8.44036 3 7.75V4.25Z" fill="#252525"/> -</svg> +<path fill-rule="evenodd" clip-rule="evenodd" d="M10 18C14.4183 18 18 14.4183 18 10C18 5.58172 14.4183 2 10 2C5.58172 2 2 5.58172 2 10C2 14.4183 5.58172 18 10 18ZM5.99902 10.9678C6.55131 10.9678 6.99902 10.5201 6.99902 9.96777C6.99902 9.41549 6.55131 8.96777 5.99902 8.96777C5.44674 8.96777 4.99902 9.41549 4.99902 9.96777C4.99902 10.5201 5.44674 10.9678 5.99902 10.9678ZM9.99902 10.9678C10.5513 10.9678 10.999 10.5201 10.999 9.96777C10.999 9.41549 10.5513 8.96777 9.99902 8.96777C9.44674 8.96777 8.99902 9.41549 8.99902 9.96777C8.99902 10.5201 9.44674 10.9678 9.99902 10.9678ZM14.999 9.96777C14.999 10.5201 14.5513 10.9678 13.999 10.9678C13.4467 10.9678 12.999 10.5201 12.999 9.96777C12.999 9.41549 13.4467 8.96777 13.999 8.96777C14.5513 8.96777 14.999 9.41549 14.999 9.96777Z" fill="#252525"/> +</svg> \ No newline at end of file diff --git a/src/json/text.json b/src/json/text.json index 3a76119c75..0de8ccdfd5 100644 --- a/src/json/text.json +++ b/src/json/text.json @@ -495,10 +495,14 @@ "pageHeadSimpleCreateSet": "Create Set", "pageHeadSimpleInstall": "Install", - "editorControlIcon": "Icon", - "editorControlCover": "Cover", - "editorControlLayout": "Layout", + "editorControlIcon0": "Add icon", + "editorControlIcon1": "Icon", + "editorControlCover0": "Add cover", + "editorControlCover1": "Cover", + "editorControlLayout": "Settings", "editorControlRelation": "Relations", + "editorControlDescription0": "Add description", + "editorControlDescription1": "Hide description", "editorPagePasteLink": "Paste as link", "editorPageCreateBookmarkObject": "Create Bookmark Object", diff --git a/src/scss/block/cover.scss b/src/scss/block/cover.scss index 3e4d1e8a88..aa5cd7b388 100644 --- a/src/scss/block/cover.scss +++ b/src/scss/block/cover.scss @@ -37,11 +37,10 @@ .author a { color: var(--color-bg-primary); } .elements { - .controlButtons { position: absolute; left: 0px; bottom: 18px; } + .controlButtons { position: absolute; left: 0px; bottom: 18px; display: flex; align-items: center; gap: 0px 8px; } .controlButtons.small { .btn { padding: 0px 6px; } .btn { - .icon { margin: 0px; } .txt { display: none; } } } @@ -53,10 +52,9 @@ } .btn { - font-weight: 500; font-size: var(--font-size-common); height: 28px; line-height: 28px; display: inline-block; - padding: 0px 8px; border-radius: 6px; margin-right: 8px; white-space: nowrap; transition: background $transitionCommon; + font-weight: 500; font-size: var(--font-size-common); height: 28px; line-height: 28px; display: flex; align-items: center; gap: 0px 4px; + padding: 0px 8px; border-radius: 6px; white-space: nowrap; transition: background $transitionCommon; } - .btn:last-child { margin: 0px; } .btn.white { background: rgba(255,255,255,0.7); } .btn.white:hover, .btn.white.hover { background: rgba(255,255,255,0.9); } @@ -64,14 +62,16 @@ .btn.black { color: var(--color-bg-primary); background: rgba(0,0,0,0.5); line-height: 22px; } .btn.black:hover, .btn.black.active { background: rgba(0,0,0,0.7); } - .btn.withIcon { padding: 0px 8px 0px 6px; line-height: 26px; } + .btn.withIcon { padding: 0px 8px 0px 6px; } + .btn.small { padding: 0px 6px; } .btn { - .icon { width: 20px; height: 20px; margin: 0px 4px 0px 0px; vertical-align: middle; } + .icon { width: 20px; height: 20px; } .icon.icon { background-image: url('~img/icon/add/icon1.svg'); } .icon.addCover { background-image: url('~img/icon/add/cover1.svg'); } .icon.layout { background-image: url('~img/icon/add/layout1.svg'); } .icon.relation { background-image: url('~img/icon/add/relation1.svg'); } + .icon.description { background-image: url('~img/icon/add/description1.svg'); } } .btn.drag { position: absolute; cursor: grab; width: 210px; top: 50%; left: 50%; margin: -12px 0px 0px -105px; } diff --git a/src/scss/component/editor.scss b/src/scss/component/editor.scss index d71eff4df0..65980c0335 100644 --- a/src/scss/component/editor.scss +++ b/src/scss/component/editor.scss @@ -51,24 +51,28 @@ } .btn { - background: var(--color-bg-primary); font-weight: 500; font-size: var(--font-size-common); color: var(--color-control-active); display: inline-block; - transition: background $transitionCommon, color $transitionCommon; height: 28px; padding: 0px 8px 0px 6px; border-radius: 6px; display: flex; - flex-direction: row; align-items: center; + background: var(--color-bg-primary); font-weight: 500; font-size: var(--font-size-common); color: var(--color-control-active); display: flex; + transition: background $transitionCommon, color $transitionCommon; height: 28px; padding: 0px 8px 0px 6px; border-radius: 6px; + flex-direction: row; align-items: center; gap: 0px 4px; } .btn:hover, .btn.hover { background: var(--color-shape-highlight-medium); color: var(--color-text-primary); } + + .btn.small { padding: 0px 6px; } .btn { - .icon { width: 20px; height: 20px; margin-right: 4px; } + .icon { width: 20px; height: 20px; } .icon.icon { background-image: url('~img/icon/add/icon0.svg'); } .icon.addCover { background-image: url('~img/icon/add/cover0.svg'); } .icon.layout { background-image: url('~img/icon/add/layout0.svg'); } - .icon.relation { background-image: url('~img/icon/add/relation0.svg'); } + .icon.relation { background-image: url('~img/icon/add/relation0.svg'); } + .icon.description { background-image: url('~img/icon/add/description0.svg'); } } .btn:hover, .btn.hover { .icon.icon { background-image: url('~img/icon/add/icon1.svg'); } .icon.addCover { background-image: url('~img/icon/add/cover1.svg'); } .icon.layout { background-image: url('~img/icon/add/layout1.svg'); } - .icon.relation { background-image: url('~img/icon/add/relation1.svg'); } + .icon.relation { background-image: url('~img/icon/add/relation1.svg'); } + .icon.description { background-image: url('~img/icon/add/description1.svg'); } } } .editorControls:hover, .editorControls.hover, .editorControls.active { opacity: 1; } diff --git a/src/ts/component/block/cover.tsx b/src/ts/component/block/cover.tsx index eea4134bd9..ea86f4abc6 100644 --- a/src/ts/component/block/cover.tsx +++ b/src/ts/component/block/cover.tsx @@ -197,25 +197,18 @@ const BlockCover = observer(class BlockCover extends React.Component<I.BlockComp }); }; - onLayout (e: any) { + onLayout () { const { rootId, block } = this.props; const node = $(this.node); const elements = node.find('#elements'); - const object = S.Detail.get(rootId, rootId, []); S.Menu.open('blockLayout', { element: `#block-${block.id} #button-layout`, - horizontal: I.MenuDirection.Center, - onOpen: () => { - elements.addClass('hover'); - }, - onClose: () => { - elements.removeClass('hover'); - }, + onOpen: () => elements.addClass('hover'), + onClose: () => elements.removeClass('hover'), subIds: J.Menu.layout, data: { rootId: rootId, - value: object.layout, } }); }; diff --git a/src/ts/component/block/link.tsx b/src/ts/component/block/link.tsx index 341fb8dd75..cb50484dcb 100644 --- a/src/ts/component/block/link.tsx +++ b/src/ts/component/block/link.tsx @@ -20,7 +20,7 @@ const BlockLink = observer(class BlockLink extends React.Component<I.BlockCompon this.onMouseLeave = this.onMouseLeave.bind(this); }; - render() { + render () { const { rootId, block } = this.props; const object = S.Detail.get(rootId, block.getTargetObjectId(), J.Relation.cover); const { _empty_, isArchived, isDeleted, done, layout, coverId, coverType, coverX, coverY, coverScale } = object; diff --git a/src/ts/component/menu/block/relation/view.tsx b/src/ts/component/menu/block/relation/view.tsx index 09876d7b2b..b3a4df9b75 100644 --- a/src/ts/component/menu/block/relation/view.tsx +++ b/src/ts/component/menu/block/relation/view.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import $ from 'jquery'; import { observer } from 'mobx-react'; import { Icon } from 'Component'; -import { I, C, S, U, J, Relation, analytics, keyboard, translate } from 'Lib'; +import { I, C, S, U, J, Relation, analytics, keyboard, translate, Action } from 'Lib'; import Item from 'Component/menu/item/relationView'; const PREFIX = 'menuBlockRelationView'; @@ -228,14 +228,10 @@ const MenuBlockRelationView = observer(class MenuBlockRelationView extends React const items = this.getItems(); const object = S.Detail.get(rootId, rootId, [ 'featuredRelations' ], true); const featured = U.Common.objectCopy(object.featuredRelations || []); - const idx = featured.findIndex(it => it == relationKey); - const relation = S.Record.getRelationByKey(relationKey); - if (idx < 0) { + if (!featured.includes(relationKey)) { const item = items.find(it => it.relationKey == relationKey); - const cb = () => { - C.ObjectRelationAddFeatured(rootId, [ relationKey ], () => analytics.event('FeatureRelation', { relationKey, format: relation.format })); - }; + const cb = () => Action.toggleFeatureRelation(rootId, relationKey); if (item.scope == I.RelationScope.Type) { C.ObjectRelationAdd(rootId, [ relationKey ], cb); @@ -243,7 +239,7 @@ const MenuBlockRelationView = observer(class MenuBlockRelationView extends React cb(); }; } else { - C.ObjectRelationRemoveFeatured(rootId, [ relationKey ], () => analytics.event('UnfeatureRelation', { relationKey, format: relation.format })); + Action.toggleFeatureRelation(rootId, relationKey) }; }; diff --git a/src/ts/component/page/elements/head/controlButtons.tsx b/src/ts/component/page/elements/head/controlButtons.tsx index 837aba26ab..dd06ef9b1f 100644 --- a/src/ts/component/page/elements/head/controlButtons.tsx +++ b/src/ts/component/page/elements/head/controlButtons.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import $ from 'jquery'; import { observer } from 'mobx-react'; import { Icon } from 'Component'; -import { I, S, U, J, translate, analytics, focus, Renderer } from 'Lib'; +import { I, S, U, J, translate, analytics, focus, Renderer, Relation, Action } from 'Lib'; interface Props { rootId: string; @@ -28,6 +28,7 @@ const ControlButtons = observer(class ControlButtons extends React.Component<Pro this.onIcon = this.onIcon.bind(this); this.onCover = this.onCover.bind(this); this.onLayout = this.onLayout.bind(this); + this.onDescription = this.onDescription.bind(this); }; render (): any { @@ -38,6 +39,8 @@ const ControlButtons = observer(class ControlButtons extends React.Component<Pro return null; }; + const check = U.Data.checkDetails(rootId); + const object = S.Detail.get(rootId, rootId, [ 'featuredRelations' ], true); const checkType = S.Block.checkBlockTypeExists(rootId); const allowedDetails = S.Block.checkFlags(rootId, rootId, [ I.RestrictionObject.Details ]); const isInSets = U.Object.isInSetLayouts(root.layout); @@ -46,15 +49,18 @@ const ControlButtons = observer(class ControlButtons extends React.Component<Pro const isBookmark = U.Object.isBookmarkLayout(root.layout); const isChat = U.Object.isChatLayout(root.layout); const isType = U.Object.isTypeLayout(root.layout); + const hasDescription = Relation.getArrayValue(object.featuredRelations).includes('description'); let allowedLayout = !checkType && allowedDetails && !isInSets && !isChat && !isType; let allowedIcon = !checkType && allowedDetails && !isTask && !isNote && !isBookmark; let allowedCover = !checkType && allowedDetails && !isNote && !isType; + let allowedDescription = !checkType && allowedDetails && !isNote; if (root.isLocked() || readonly) { allowedIcon = false; allowedLayout = false; allowedCover = false; + allowedDescription = false; }; return ( @@ -65,21 +71,27 @@ const ControlButtons = observer(class ControlButtons extends React.Component<Pro {allowedIcon ? ( <div id="button-icon" className="btn white withIcon" onClick={this.onIcon}> <Icon className="icon" /> - <div className="txt">{translate('editorControlIcon')}</div> + <div className="txt">{translate(`editorControlIcon${Number(check.withIcon)}`)}</div> </div> ) : ''} {allowedCover ? ( <div id="button-cover" className="btn white withIcon" onClick={this.onCover}> <Icon className="addCover" /> - <div className="txt">{translate('editorControlCover')}</div> + <div className="txt">{translate(`editorControlCover${Number(check.withCover)}`)}</div> + </div> + ) : ''} + + {allowedDescription ? ( + <div id="button-description" className="btn white withIcon" onClick={this.onDescription}> + <Icon className="description" /> + <div className="txt">{translate(`editorControlDescription${Number(hasDescription)}`)}</div> </div> ) : ''} {allowedLayout ? ( - <div id="button-layout" className="btn white withIcon" onClick={this.onLayout}> + <div id="button-layout" className="btn white withIcon small" onClick={this.onLayout}> <Icon className="layout" /> - <div className="txt">{translate('editorControlLayout')}</div> </div> ) : ''} </div> @@ -120,6 +132,10 @@ const ControlButtons = observer(class ControlButtons extends React.Component<Pro this.props.onLayout(e); }; + onDescription (e: any) { + Action.toggleFeatureRelation(this.props.rootId, 'description'); + }; + onCover (e: any) { e.preventDefault(); e.stopPropagation(); diff --git a/src/ts/component/page/elements/head/controls.tsx b/src/ts/component/page/elements/head/controls.tsx index ca74da7f7e..f42addd816 100644 --- a/src/ts/component/page/elements/head/controls.tsx +++ b/src/ts/component/page/elements/head/controls.tsx @@ -137,24 +137,17 @@ const Controls = observer(class Controls extends React.Component<Props, State> { U.Object.setCover(rootId, item.type, item.id, item.coverX, item.coverY, item.coverScale); }; - onLayout (e: any) { + onLayout () { const { rootId, onLayoutSelect } = this.props; const node = $(this.node); - const object = S.Detail.get(rootId, rootId, []); S.Menu.open('blockLayout', { element: '.editorControls #button-layout', - horizontal: I.MenuDirection.Center, - onOpen: () => { - node.addClass('hover'); - }, - onClose: () => { - node.removeClass('hover'); - }, + onOpen: () => node.addClass('hover'), + onClose: () => node.removeClass('hover'), subIds: J.Menu.layout, data: { rootId, - value: object.layout, onLayoutSelect, } }); diff --git a/src/ts/lib/action.ts b/src/ts/lib/action.ts index 822cc99a38..bb4e4bc33c 100644 --- a/src/ts/lib/action.ts +++ b/src/ts/lib/action.ts @@ -810,6 +810,22 @@ class Action { analytics.event('ThemeSet', { id }); }; + toggleFeatureRelation (rootId: string, relationKey: string) { + const object = S.Detail.get(rootId, rootId, [ 'featuredRelations' ], true); + const featured = U.Common.objectCopy(object.featuredRelations || []); + const relation = S.Record.getRelationByKey(relationKey); + + if (!relation) { + return null; + }; + + if (!featured.includes(relationKey)) { + C.ObjectRelationAddFeatured(rootId, [ relationKey ], () => analytics.event('FeatureRelation', { relationKey, format: relation.format })); + } else { + C.ObjectRelationRemoveFeatured(rootId, [ relationKey ], () => analytics.event('UnfeatureRelation', { relationKey, format: relation.format })); + }; + }; + }; export default new Action();