diff --git a/dist/img/icon/default/date.svg b/dist/img/icon/default/date.svg new file mode 100644 index 0000000000..3b7acf787d --- /dev/null +++ b/dist/img/icon/default/date.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/electron/js/menu.js b/electron/js/menu.js index 95fbf2d97b..4492b86d45 100644 --- a/electron/js/menu.js +++ b/electron/js/menu.js @@ -199,7 +199,7 @@ class MenuManager { config.debug[i] = !config.debug[i]; Api.setConfig(this.win, { debug: config.debug }); - if ([ 'ho' ].includes(i)) { + if ([ 'hiddenObject' ].includes(i)) { this.win.reload(); }; } diff --git a/package-lock.json b/package-lock.json index 95e41e9752..0fd597d588 100644 --- a/package-lock.json +++ b/package-lock.json @@ -61,7 +61,7 @@ "react-dom": "^17.0.2", "react-minimal-pie-chart": "^8.3.0", "react-pdf": "^6.2.2", - "react-router-dom": "^5.2.0", + "react-router-dom": "^5.3.4", "react-sortable-hoc": "^2.0.0", "react-virtualized": "^9.22.3", "regedit": "^5.1.3", @@ -87,7 +87,7 @@ "@types/raf": "^3.4.0", "@types/react": "^16.14.31", "@types/react-dom": "^16.9.16", - "@types/react-router-dom": "^4.3.5", + "@types/react-router-dom": "^5.3.3", "@typescript-eslint/eslint-plugin": "^6.18.1", "@typescript-eslint/parser": "^6.18.1", "cross-env": "^7.0.2", @@ -2691,12 +2691,12 @@ } }, "node_modules/@types/react-router-dom": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-4.3.5.tgz", - "integrity": "sha512-eFajSUASYbPHg2BDM1G8Btx+YqGgvROPIg6sBhl3O4kbDdYXdFdfrgQFf/pcBuQVObjfT9AL/dd15jilR5DIEA==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", "dev": true, "dependencies": { - "@types/history": "*", + "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router": "*" } diff --git a/package.json b/package.json index d70c6a2ff2..a9f9a98755 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@types/raf": "^3.4.0", "@types/react": "^16.14.31", "@types/react-dom": "^16.9.16", - "@types/react-router-dom": "^4.3.5", + "@types/react-router-dom": "^5.3.3", "@typescript-eslint/eslint-plugin": "^6.18.1", "@typescript-eslint/parser": "^6.18.1", "cross-env": "^7.0.2", @@ -141,7 +141,7 @@ "react-dom": "^17.0.2", "react-minimal-pie-chart": "^8.3.0", "react-pdf": "^6.2.2", - "react-router-dom": "^5.2.0", + "react-router-dom": "^5.3.4", "react-sortable-hoc": "^2.0.0", "react-virtualized": "^9.22.3", "regedit": "^5.1.3", diff --git a/src/img/arrow/dateSelectLight.svg b/src/img/arrow/dateSelectLight.svg new file mode 100644 index 0000000000..7a51b0f8b2 --- /dev/null +++ b/src/img/arrow/dateSelectLight.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/img/icon/mention.svg b/src/img/icon/mention.svg new file mode 100644 index 0000000000..2fe792b284 --- /dev/null +++ b/src/img/icon/mention.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/json/relation.ts b/src/json/relation.ts index 72e0323c82..c45114b2f9 100644 --- a/src/json/relation.ts +++ b/src/json/relation.ts @@ -22,7 +22,8 @@ export default { 'sizeInBytes', 'restrictions', 'defaultTemplateId', - 'createdDate' + 'createdDate', + 'timestamp', ], sidebar: [ @@ -49,7 +50,8 @@ export default { 'restrictions', 'source', 'lastModifiedDate', - 'lastOpenedDate' + 'lastOpenedDate', + 'timestamp' ], relation: [ diff --git a/src/json/text.json b/src/json/text.json index d7b42cd059..3adfb308fa 100644 --- a/src/json/text.json +++ b/src/json/text.json @@ -89,6 +89,7 @@ "commonComment": "Comment", "commonIcon": "Icon", "commonObjects": "Objects", + "commonDates": "Dates", "commonPreferences": "Preferences", "commonDuplicate": "Duplicate", "commonRemoveFromFavorites": "Remove from Favorites", @@ -173,6 +174,7 @@ "commonMenu": "Menu", "commonSignUp": "Sign Up", "commonNotFound": "Not found", + "commonCalculate": "Calculate", "pluralDay": "day|days", "pluralObject": "Object|Objects", @@ -616,8 +618,8 @@ "blockDataviewHeadMenuChange": "Change source %s", "blockDataviewHeadMenuOpen": "Open source %s", - "blockDataviewBoardRelationDeletedTitle": "Relation has been deleted", - "blockDataviewBoardRelationDeletedDescription": "Choose another Relation to group your Kanban", + "blockDataviewBoardRelationDeletedTitle": "No Relation", + "blockDataviewBoardRelationDeletedDescription": "Choose Relation to group your Kanban", "blockDataviewBoardOpenViewMenu": "Open View menu", "blockDataviewBoardColumnSettings": "Column settings", @@ -730,9 +732,12 @@ "popupSettingsPersonalSidebar": "Automatically show and hide sidebar", "popupSettingsPersonalSidebarMode": "Sidebar mode", "popupSettingsPersonalRelativeDates": "Display relative dates", + "popupSettingsPersonalDateFormat": "Date format", "popupSettingsPersonalSectionLanguage": "Language & Spelling", "popupSettingsPersonalSectionEditor": "Editor Personalisation", "popupSettingsPersonalSectionApp": "App Appearance", + "popupSettingsPersonalSectionDateTime": "Date & Time", + "popupSettingsPersonalTimeFormat": "Time format", "popupSettingsColorMode": "Color mode", "popupSettingsColorModeButtonLight": "Light", @@ -2217,6 +2222,9 @@ "participantPermissions2": "Owner", "participantPermissions3": "No access", + "relationMentions": "Mentioned in", + "relationCreator": "Created by", + "spaceStatus0": "Active", "spaceStatus1": "Loading", "spaceStatus2": "Ok", @@ -2245,7 +2253,6 @@ "networkMode2Title": "Self-hosted", "networkMode2Text": "Back up to your self-hosted network", - "formulaNone": "Calculate", "formulaCount": "Count", "formulaPercentage": "Percentage", "formulaMath": "Math", @@ -2277,4 +2284,5 @@ "formulaCheckboxNotEmptyShort": "Checked", "formulaCheckboxPercentEmpty": "Percentage unchecked", "formulaCheckboxPercentNotEmpty": "Percentage checked" + } diff --git a/src/json/theme.ts b/src/json/theme.ts index 220bb858a0..24fb6933c6 100644 --- a/src/json/theme.ts +++ b/src/json/theme.ts @@ -60,6 +60,11 @@ export default { text: '#b6b6b6', bg: '#f2f2f2' }, + + progress: { + bg: '#ebebeb', + fg: '#ffd15b', + } }, dark: { @@ -109,6 +114,11 @@ export default { text: '#9a9a9a', bg: '#b6b6b6' }, + + progress: { + bg: '#292929', + fg: '#ffd15b', + } } }; \ No newline at end of file diff --git a/src/scss/block/dataview/view/calendar.scss b/src/scss/block/dataview/view/calendar.scss index 4207e150db..01811679d8 100644 --- a/src/scss/block/dataview/view/calendar.scss +++ b/src/scss/block/dataview/view/calendar.scss @@ -30,7 +30,10 @@ .day.active { .number { padding: 0px; color: var(--color-text-inversion); } .number { - .inner { background-color: var(--color-system-accent-100); border-radius: 12px; padding: 0px 8px; align-self: flex-end; min-width: 24px; text-align: center; } + .inner { + background-color: var(--color-system-accent-100); border-radius: 12px; padding: 0px 8px; align-self: flex-end; min-width: 24px; text-align: center; + transition: $transitionAllCommon; + } } } diff --git a/src/scss/block/dataview/view/grid.scss b/src/scss/block/dataview/view/grid.scss index 99ff5807b5..5eb04df647 100644 --- a/src/scss/block/dataview/view/grid.scss +++ b/src/scss/block/dataview/view/grid.scss @@ -54,7 +54,7 @@ .cellFoot { height: 48px; @include text-common; color: var(--color-text-primary); } .cellFoot { .flex { justify-content: flex-end; } - .result { display: flex; flex-direction: row; align-items: center; gap: 0px 2px; max-width: 100%; } + .result { display: flex; flex-direction: row; align-items: center; gap: 0px 4px; max-width: 100%; } .name { width: auto !important; color: var(--color-text-secondary); } .cellContent { height: 48px !important; } diff --git a/src/scss/component/editor.scss b/src/scss/component/editor.scss index 65980c0335..f8e3a47978 100644 --- a/src/scss/component/editor.scss +++ b/src/scss/component/editor.scss @@ -232,10 +232,6 @@ .block.blockDataview { padding: 0px; } .editorControls { height: 52px; width: 100%; margin-bottom: 8px; padding: 0px 14px; } - - .headSimple { - .side.right { display: none; } - } } .block.blockCover { @@ -262,6 +258,12 @@ &.withIconAndCover { .editorControls { display: none; } } + + .blocks { + .headSimple { + .side.right { display: none; } + } + } } .editorWrapper.isSet, diff --git a/src/scss/component/headSimple.scss b/src/scss/component/headSimple.scss index cc9b3f7379..3c93afa09e 100644 --- a/src/scss/component/headSimple.scss +++ b/src/scss/component/headSimple.scss @@ -12,13 +12,13 @@ .editableWrap { flex-grow: 1; } .editableWrap { - .editable { z-index: 1; position: relative; word-break: break-word; cursor: text; } + .editable { z-index: 1; position: relative; word-break: break-word; cursor: text; min-height: 32px; } } > .descr { @include text-paragraph; } } - .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 { text-align: right; display: flex; flex-direction: row; gap: 0px 16px; align-items: center; justify-content: flex-end; } .side.right { .button { white-space: nowrap; } } diff --git a/src/scss/form/button.scss b/src/scss/form/button.scss index 6f10fde155..cd78128967 100644 --- a/src/scss/form/button.scss +++ b/src/scss/form/button.scss @@ -37,8 +37,9 @@ .button.dark:not(.disabled).hover { background: rgba(0,0,0,0.4); } .button.blank { background: none; border: solid 1px var(--color-shape-primary); font-weight: 400; } -.button.blank:not(.disabled):hover, -.button.blank:not(.disabled).hover { background: var(--color-shape-highlight-medium); } +.button.blank:not(.disabled) { + &:hover, &.hover, &.active { background: var(--color-shape-highlight-medium); } +} .button.c36 { @include text-common; height: 36px; border-radius: 6px; padding: 0px 12px; } .button.c32 { @include text-small; height: 32px; border-radius: 6px; padding: 0px 10px; } diff --git a/src/scss/list/object.scss b/src/scss/list/object.scss index 638d956bf0..2e2f489aaa 100644 --- a/src/scss/list/object.scss +++ b/src/scss/list/object.scss @@ -1,28 +1,28 @@ @import "~scss/_mixins"; .listObject { - .table { display: grid; border-color: var(--color-shape-secondary); border-style: solid; border-top-width: 1px; margin: 0px 0px 10px 0px; } + .table { display: grid; margin: 0px 0px 10px 0px; } .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-control-active); } .row.isHead { .cell { - text-align: left; padding: 14px 0px 14px 14px; white-space: nowrap; font-weight: 400; line-height: 20px; position: relative; + text-align: left; padding: 9px 0px 9px 14px; white-space: nowrap; font-weight: 400; line-height: 20px; position: relative; @include text-overflow-nw; } .cell { .name { 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); + @include text-overflow-nw; } .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; } - } + + .icon.sortArrow { width: 20px; height: 20px; margin: 0px; background-image: url('~img/icon/sortArrow.svg'); } + .icon.sortArrow.c1 { transform: rotateZ(180deg); } } .row { border-bottom: 1px solid var(--color-shape-secondary); } diff --git a/src/scss/menu/dataview/option.scss b/src/scss/menu/dataview/option.scss index 11db72a202..0b4061872b 100644 --- a/src/scss/menu/dataview/option.scss +++ b/src/scss/menu/dataview/option.scss @@ -3,7 +3,7 @@ .menus { .menu.menuDataviewOptionList { width: var(--menu-width-value);; } .menu.menuDataviewOptionList { - .content { overflow: visible; transition: none; padding: 0px; max-height: unset; } + .content { overflow: hidden; transition: none; padding: 0px; max-height: unset; } .content { .wrap { height: 100%; display: flex; flex-direction: column; } .wrap.noFilter { diff --git a/src/scss/page/common.scss b/src/scss/page/common.scss index ac0b832ca6..02431c278d 100644 --- a/src/scss/page/common.scss +++ b/src/scss/page/common.scss @@ -14,4 +14,5 @@ @import "./main/membership"; @import "./main/onboarding"; @import "./main/chat"; -@import "./main/void"; \ No newline at end of file +@import "./main/void"; +@import "./main/date"; \ No newline at end of file diff --git a/src/scss/page/main/date.scss b/src/scss/page/main/date.scss new file mode 100644 index 0000000000..91995c6aa7 --- /dev/null +++ b/src/scss/page/main/date.scss @@ -0,0 +1,28 @@ +@import "~scss/_mixins"; + +.pageMainDate { + .wrapper { width: 704px; margin: 0px auto; padding: 40px 0px 80px 0px; user-select: none; } + + .headSimple { align-items: center; height: 32px; } + .headSimple { + .side.right { gap: 0px; } + .side.right { + .icon { width: 24px !important; height: 24px !important; } + .icon.calendar { background-image: url('~img/icon/relation/date.svg'); } + .icon.arrow { background-image: url('~img/arrow/dateSelectLight.svg'); } + .icon.arrow.left { transform: rotateZ(180deg); } + } + } + + .categories { + display: flex; flex-direction: row; gap: 8px; margin: 0px 0px 12px 0px; align-items: center; justify-content: flex-start; flex-wrap: wrap; + } + .categories { + .icon.mention { width: 20px; height: 20px; margin: 0px 6px 0px 0px; background-image: url('~img/icon/mention.svg'); } + .separator { content: ''; background-color: var(--color-shape-secondary); width: 1px; height: 24px; } + } + + .cell.c-type { + .iconObject { display: none; } + } +} \ No newline at end of file diff --git a/src/scss/theme/dark/common.scss b/src/scss/theme/dark/common.scss index 0a179eceb0..4e42fcda5c 100644 --- a/src/scss/theme/dark/common.scss +++ b/src/scss/theme/dark/common.scss @@ -227,7 +227,7 @@ html.themeDark { /* Progress */ .progress { - .inner { background: var(--color-bg-secondary); } + .inner { background: var(--color-bg-secondary); box-shadow: 0px 4px 16px rgb(0 0 0 / 20%), 0px 0px 0px 1px var(--color-shape-primary) inset; } } .tooltip { color: var(--color-text-primary); } diff --git a/src/ts/component/block/chat.tsx b/src/ts/component/block/chat.tsx index 83a1e3403b..32128fb068 100644 --- a/src/ts/component/block/chat.tsx +++ b/src/ts/component/block/chat.tsx @@ -47,6 +47,7 @@ const BlockChat = observer(class BlockChat extends React.Component { - let date = U.Date.dayString(item.createdAt); - if (!date) { - date = U.Date.dateWithFormat(I.DateFormat.MonthAbbrAfterDay, item.createdAt); - }; + const day = showRelativeDates ? U.Date.dayString(item.createdAt) : null; + const date = day ? day : U.Date.dateWithFormat(S.Common.dateFormat, item.createdAt); return (
@@ -383,8 +382,8 @@ const BlockChat = observer(class BlockChat extends React.Component { - if (c1.time > c2.time) return 1; - if (c1.time < c2.time) return -1; + if (c1.createdAt > c2.createdAt) return 1; + if (c1.createdAt < c2.createdAt) return -1; return 0; }); diff --git a/src/ts/component/block/dataview/head.tsx b/src/ts/component/block/dataview/head.tsx index 063efcf21a..4314e7d033 100644 --- a/src/ts/component/block/dataview/head.tsx +++ b/src/ts/component/block/dataview/head.tsx @@ -315,7 +315,7 @@ const Head = observer(class Head extends React.Component checkInput (isEmpty: boolean) { if (this.ref) { - $(this.ref.node).toggleClass('isEmpty', isEmpty) + $(this.ref.node).toggleClass('isEmpty', isEmpty); }; }; diff --git a/src/ts/component/block/dataview/view/board/card.tsx b/src/ts/component/block/dataview/view/board/card.tsx index ece35c6ecb..407efb01c9 100644 --- a/src/ts/component/block/dataview/view/board/card.tsx +++ b/src/ts/component/block/dataview/view/board/card.tsx @@ -22,7 +22,7 @@ const Card = observer(class Card extends React.Component { const relations = getVisibleRelations(); const idPrefix = getIdPrefix(); const subId = S.Record.getGroupSubId(rootId, block.id, groupId); - const record = S.Detail.get(subId, id); + const record = S.Detail.get(subId, id, relations.map(it => it.relationKey)); const cn = [ 'card', U.Data.layoutClass(record.id, record.layout) ]; const { done } = record; const cover = getCoverObject(id); @@ -42,6 +42,7 @@ const Card = observer(class Card extends React.Component {
{relations.map((relation: any, i: number) => { const id = Relation.cellId(idPrefix, relation.relationKey, record.id); + return ( {data.map((item, i) => { - const { d, m, y } = item; const cn = []; - const current = [ d, m, y ].join('-'); + const current = [ item.d, item.m, item.y ].join('-'); if (m != item.m) { cn.push('other'); }; - if ((today.d == d) && (today.m == m) && (today.y == y)) { + if ((today.d == item.d) && (today.m == item.m) && (today.y == item.y)) { cn.push('active'); }; if (i < 7) { @@ -239,12 +238,11 @@ const ViewCalendar = observer(class ViewCalendar extends React.Component { + C.ObjectCreate(details, flags, templateId, type?.uniqueKey, S.Common.space, (message: any) => { if (message.error.code) { return; }; diff --git a/src/ts/component/block/dataview/view/calendar/item.tsx b/src/ts/component/block/dataview/view/calendar/item.tsx index aa55ce09f9..e42b334c00 100644 --- a/src/ts/component/block/dataview/view/calendar/item.tsx +++ b/src/ts/component/block/dataview/view/calendar/item.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { observer } from 'mobx-react'; import { IconObject, ObjectName } from 'Component'; -import { I, S, U, translate, Preview } from 'Lib'; +import { I, S, U, C, translate, Preview } from 'Lib'; interface Props extends I.ViewComponent { d: number; @@ -21,6 +21,7 @@ const Item = observer(class Item extends React.Component { super(props); this.onOpen = this.onOpen.bind(this); + this.onOpenDate = this.onOpenDate.bind(this); this.onMore = this.onMore.bind(this); this.onContext = this.onContext.bind(this); this.canCreate = this.canCreate.bind(this); @@ -73,7 +74,7 @@ const Item = observer(class Item extends React.Component { onContextMenu={this.onContext} onDoubleClick={this.onDoubleClick} > -
+
{d}
@@ -128,16 +129,14 @@ const Item = observer(class Item extends React.Component { onContext () { const node = $(this.node); - const options = []; + const options = [ + { id: 'open', icon: 'expand', name: translate('commonOpenObject') } + ] as I.Option[]; if (this.canCreate()) { options.push({ id: 'add', name: translate('commonNewObject') }); }; - if (!options.length) { - return; - }; - S.Menu.open('select', { element: node, vertical: I.MenuDirection.Bottom, @@ -150,9 +149,10 @@ const Item = observer(class Item extends React.Component { options, noVirtualisation: true, onSelect: (e: any, item: any) => { - if (item.id == 'add') { - this.onCreate(); - } + switch (item.id) { + case 'open': this.onOpenDate(); break; + case 'add': this.onCreate(); break; + }; }, } }); @@ -173,6 +173,12 @@ const Item = observer(class Item extends React.Component { onCreate(details); }; + onOpenDate () { + const { d, m, y } = this.props; + + U.Object.openDateByTimestamp(U.Date.timestamp(y, m, d, 12, 0, 0), 'config'); + }; + canCreate (): boolean { const { getView, isAllowedObject } = this.props; const view = getView(); diff --git a/src/ts/component/block/dataview/view/grid/foot/cell.tsx b/src/ts/component/block/dataview/view/grid/foot/cell.tsx index 7a25e3af96..2b5ea09cde 100644 --- a/src/ts/component/block/dataview/view/grid/foot/cell.tsx +++ b/src/ts/component/block/dataview/view/grid/foot/cell.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { observer } from 'mobx-react'; -import { Select } from 'Component'; -import { I, S, C, J, keyboard, Relation, Dataview, analytics, translate } from 'Lib'; +import { Icon } from 'Component'; +import { I, S, C, U, keyboard, Relation, Dataview, analytics, translate } from 'Lib'; interface Props extends I.ViewComponent, I.ViewRelation { rootId?: string; @@ -17,7 +17,6 @@ const FootCell = observer(class FootCell extends React.Component { node = null; menuContext = null; - refSelect = null; state = { isEditing: false, @@ -34,6 +33,7 @@ const FootCell = observer(class FootCell extends React.Component { this.onChange = this.onChange.bind(this); this.onMouseEnter = this.onMouseEnter.bind(this); this.onMouseLeave = this.onMouseLeave.bind(this); + this.onSelect = this.onSelect.bind(this); }; render () { @@ -43,27 +43,24 @@ const FootCell = observer(class FootCell extends React.Component { const view = getView(); if (!relation || !view) { - return null; + return
; }; // Subscriptions const viewRelation = view.getRelation(relationKey); if (!viewRelation) { - return null; + return
; }; const cn = [ 'cellFoot', `cell-key-${relationKey}` ]; - const sections = this.getSections(); const option = Relation.formulaByType(relation.format).find(it => it.id == String(viewRelation.formulaType)); + const name = option.short || option.name; + const subId = S.Record.getSubId(rootId, block.id); + const records = S.Record.getRecords(subId, [ relationKey ], true); - if (viewRelation.formulaType != I.FormulaType.None) { - const subId = S.Record.getSubId(rootId, block.id); - const records = S.Record.getRecords(subId, [ relationKey ], true); - - records.forEach(record => { - const value = record[relationKey]; - }); - }; + records.forEach(record => { + const value = record[relationKey]; + }); return (
{
{isEditing || (result === null) ? ( - ({ ...it, id: String(it.id) }))} + onChange={v => S.Common.dateFormatSet(v)} + arrowClassName="black" + menuParam={{ horizontal: I.MenuDirection.Right }} + /> +
+ +
+