diff --git a/dist/img/icon/default/archive.svg b/dist/img/icon/default/archive.svg new file mode 100644 index 0000000000..47b87c2730 --- /dev/null +++ b/dist/img/icon/default/archive.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/dist/img/icon/default/graph.svg b/dist/img/icon/default/graph.svg new file mode 100644 index 0000000000..2ace35aa60 --- /dev/null +++ b/dist/img/icon/default/graph.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/dist/img/icon/default/settings.svg b/dist/img/icon/default/settings.svg new file mode 100644 index 0000000000..0b166ad7a4 --- /dev/null +++ b/dist/img/icon/default/settings.svg @@ -0,0 +1,3 @@ + + + diff --git a/dist/js/tabs.js b/dist/js/tabs.js index f1c1b44c2c..ef1eff7db5 100644 --- a/dist/js/tabs.js +++ b/dist/js/tabs.js @@ -28,6 +28,15 @@ $(() => { const TOOLTIP_DELAY = 650; const TOOLTIP_DELAY_SHORT = 50; + const tooltipReset = () => { + window.clearTimeout(tooltipTimeout); + window.clearTimeout(tooltipHideTimeout); + if (tooltipVisible) { + tooltipVisible = false; + electron.Api(winId, 'tabHideTooltip'); + }; + }; + // Tab detach state let windowBounds = null; let draggedTabId = null; @@ -267,6 +276,7 @@ $(() => { tab.find('.icon.close').off('click').on('click', (e) => { e.stopPropagation(); + tooltipReset(); electron.Api(winId, 'removeTab', [ item.id, true ]); }); @@ -290,6 +300,8 @@ $(() => { isPinned: Boolean(item.data.isPinned), offsetLeft: offset.left, width: tab.outerWidth(), + objectName: item.data.title || '', + action: item.data.action || '', }; tooltipTimeout = window.setTimeout(() => { @@ -385,12 +397,7 @@ $(() => { draggedTabId = $(evt.item).attr('data-id'); // Hide tooltip on drag start - window.clearTimeout(tooltipTimeout); - window.clearTimeout(tooltipHideTimeout); - if (tooltipVisible) { - tooltipVisible = false; - electron.Api(winId, 'tabHideTooltip'); - }; + tooltipReset(); const item = $(evt.item); item.css('visibility', 'hidden'); @@ -486,12 +493,7 @@ $(() => { }; // Hide tooltip on tabs update - window.clearTimeout(tooltipTimeout); - window.clearTimeout(tooltipHideTimeout); - if (tooltipVisible) { - tooltipVisible = false; - electron.Api(winId, 'tabHideTooltip'); - }; + tooltipReset(); container.empty(); @@ -558,6 +560,7 @@ $(() => { electron.on('remove-tab', (e, id) => { if (isDragging) return; + tooltipReset(); container.find(`#tab-${id}`).remove(); resize(); setTimeout(() => initSortable(), 10); diff --git a/src/scss/component/preview/common.scss b/src/scss/component/preview/common.scss index 617baacb08..00c44244a9 100644 --- a/src/scss/component/preview/common.scss +++ b/src/scss/component/preview/common.scss @@ -26,6 +26,9 @@ } &.isTab { width: auto; } + &.isTab { + .content { border-radius: 16px; box-shadow: none; border: 1px solid var(--color-shape-secondary); } + } } .previewWrapper.passThrough { pointer-events: none; } diff --git a/src/scss/component/preview/tab.scss b/src/scss/component/preview/tab.scss index 2bf604acc3..d720481832 100644 --- a/src/scss/component/preview/tab.scss +++ b/src/scss/component/preview/tab.scss @@ -1,10 +1,26 @@ -.previewTab { padding: 4px 8px; display: flex; flex-direction: column; gap: 4px; } +.previewTab { + padding: 16px 32px 16px 16px; display: flex; flex-direction: column; gap: 12px; + min-width: 288px; max-width: 360px; +} .previewTab { .previewHeader, - .previewObject { display: flex; gap: 0px 6px; align-items: center; height: auto; } + .previewObject { display: flex; align-items: center; height: auto; flex-wrap: nowrap; } .previewHeader, .previewObject { .iconObject { flex-shrink: 0; } } + + .previewHeader { gap: 0px 6px; } + .previewHeader { + .iconObject { border-radius: 3px; } + } + + .previewObject { gap: 0px 12px; } + .previewObject { + .side.right { @include text-overflow-nw; } + .iconObject { flex-shrink: 0; border-radius: 8px !important; background-color: var(--color-shape-highlight-medium) !important; } + .name { font-weight: 500; @include text-overflow-nw; } + .type { @include text-small; color: var(--color-text-secondary); } + } } diff --git a/src/ts/component/preview/index.tsx b/src/ts/component/preview/index.tsx index 677a70b87f..c6048ca256 100644 --- a/src/ts/component/preview/index.tsx +++ b/src/ts/component/preview/index.tsx @@ -222,7 +222,7 @@ const PreviewIndex = observer(forwardRef(() => { }; case I.PreviewType.Tab: { - content = ; + content = ; break; }; }; diff --git a/src/ts/component/preview/tab.tsx b/src/ts/component/preview/tab.tsx index beb87a16f4..3760dee15f 100644 --- a/src/ts/component/preview/tab.tsx +++ b/src/ts/component/preview/tab.tsx @@ -1,11 +1,11 @@ import React, { forwardRef, useEffect, useRef, useState } from 'react'; import { observer } from 'mobx-react'; -import { ObjectName, IconObject } from 'Component'; -import { U, I } from 'Lib'; +import { ObjectName, IconObject, Label } from 'Component'; +import { U, I, translate, S } from 'Lib'; interface Props { spaceview?: any; - object?: any; + data?: any; position?: () => void; }; @@ -13,35 +13,75 @@ const PreviewTab = observer(forwardRef<{}, Props>((props, ref) => { const { spaceview = {}, - object, + data, position, } = props; - const [ dummy, setDummy ] = useState(0); - const objectRef = useRef(object); + const { object, name, action } = data; + const [ displayObject, setDisplayObject ] = useState(null); + const [ displayObjectType, setDisplayObjectType ] = useState(null); + const cancelRef = useRef(false); useEffect(() => { - if (!object?.id || (object?.layout == I.ObjectLayout.SpaceView)) { - objectRef.current = {}; - setDummy(dummy + 1); - return; + cancelRef.current = false; + setDisplayObject(null); + setDisplayObjectType(null); + load(); + + return () => { + cancelRef.current = true; }; + }, [ object?.id, action, spaceview.targetSpaceId ]); + + useEffect(position); - let cancelled = false; + const load = () => { + const isChat = (object?.layout == I.ObjectLayout.SpaceView) && (spaceview.isOneToOne || spaceview.isChat); - objectRef.current = object; + if (isChat) { + setDisplayObject({ layout: I.ObjectLayout.Chat, name: translate('commonMainChat') }); + } else + if (action && name) { + objectByAction(); + } else { + loadObject(); + }; + }; + + const objectByAction = () => { + const layouts = { + navigation: I.ObjectLayout.Navigation, + graph: I.ObjectLayout.Graph, + archive: I.ObjectLayout.Archive, + settings: I.ObjectLayout.Settings, + }; + if (layouts[action]) { + setDisplayObject({ layout: layouts[action], name }); + } else { + loadObject(); + }; + }; + + const loadObject = () => { + if (!object || !object.id) { + return; + }; U.Object.getById(object.id, { spaceId: spaceview.targetSpaceId }, (loaded: any) => { - if (loaded && !cancelled) { - objectRef.current = loaded; - setDummy(dummy + 1); + if (loaded && !cancelRef.current) { + setDisplayObject(loaded); + loadType(loaded.type) }; }); + }; - return () => { cancelled = true; }; - }, [ object?.id ]); - - useEffect(position); + const loadType = (id: string) => { + U.Object.getById(id, { spaceId: spaceview.targetSpaceId }, (loaded: any) => { + if (loaded && !cancelRef.current) { + setDisplayObjectType(loaded); + }; + }); + }; return (
@@ -49,10 +89,15 @@ const PreviewTab = observer(forwardRef<{}, Props>((props, ref) => {
- {objectRef.current && objectRef.current.name ? ( + {displayObject?.name ? (
- - +
+ +
+
+ + {displayObjectType ?
) : null} diff --git a/src/ts/interface/preview.ts b/src/ts/interface/preview.ts index 24642e7249..6bece30f42 100644 --- a/src/ts/interface/preview.ts +++ b/src/ts/interface/preview.ts @@ -39,7 +39,7 @@ export interface Preview { withPlural?: boolean; typeX?: I.MenuDirection.Left | I.MenuDirection.Center | I.MenuDirection.Right; noOffset?: boolean; - relatedObject?: any; + relatedData?: any; delay?: number; x?: number; y?: number; diff --git a/src/ts/lib/keyboard.ts b/src/ts/lib/keyboard.ts index ab45cef2ea..269842d086 100644 --- a/src/ts/lib/keyboard.ts +++ b/src/ts/lib/keyboard.ts @@ -1369,7 +1369,7 @@ class Keyboard { if (title) { U.Data.setWindowTitleText(title); - U.Data.setTabTitleText(title); + U.Data.setTabTitleText(title, action); } else { U.Data.setWindowTitle(rootId, rootId); U.Data.setTabTitle(rootId, rootId); diff --git a/src/ts/lib/util/common.ts b/src/ts/lib/util/common.ts index 75b8e986fa..3257f35409 100644 --- a/src/ts/lib/util/common.ts +++ b/src/ts/lib/util/common.ts @@ -1581,14 +1581,12 @@ class UtilCommon { tabTooltipShow (data: any) { const spaceview = U.Space.getSpaceviewBySpaceId(data.spaceId); - const x = data.isPinned ? data.offsetLeft : data.offsetLeft + 6; - if (!spaceview) { return; }; Preview.previewShow({ - rect: { x, y: 2, width: data.width, height: 0 }, + rect: { x: data.offsetLeft, y: 0, width: data.width, height: 0 }, classNameWrap: 'isTab', object: spaceview, target: spaceview.id, @@ -1598,7 +1596,11 @@ class UtilCommon { noAnimation: true, noOffset: true, typeX: I.MenuDirection.Left, - relatedObject: data.objectData ? { ...data.objectData, name: data.title } : null, + relatedData: { + action: data?.action, + name: data?.objectName, + object: data?.objectData, + }, delay: 0, type: I.PreviewType.Tab, }); diff --git a/src/ts/lib/util/data.ts b/src/ts/lib/util/data.ts index 90acdd45b3..79f1b231b9 100644 --- a/src/ts/lib/util/data.ts +++ b/src/ts/lib/util/data.ts @@ -866,8 +866,9 @@ class UtilData { /** * Sets the tab title text. * @param {string} text - The text to set as the tab title. + * @param {string} action - Optional layout of the current object, useful for tab tooltips. */ - setTabTitleText(text: string) { + setTabTitleText(text: string, action?: string) { const spaceview = U.Space.getSpaceview(); Renderer.send('updateTab', S.Common.tabId, { @@ -876,6 +877,7 @@ class UtilData { spaceIcon: U.Graph.imageSrc(spaceview) || U.Object.defaultIcon(spaceview?.layout, spaceview?.type, 100), spaceId: spaceview.targetSpaceId || '', layout: I.ObjectLayout.Page, + action, }); }; diff --git a/src/ts/lib/util/object.ts b/src/ts/lib/util/object.ts index 83b7b4766c..e0e14482b0 100644 --- a/src/ts/lib/util/object.ts +++ b/src/ts/lib/util/object.ts @@ -117,6 +117,7 @@ class UtilObject { uxType: spaceview?.uxType, objectData: { id: object.id, type: object.type, layout: object.layout }, route, + action: '', }; }; @@ -973,6 +974,10 @@ class UtilObject { case I.ObjectLayout.Date: id = 'date'; break; case I.ObjectLayout.Type: id = 'type'; break; case I.ObjectLayout.Bookmark: id = 'page'; break; + case I.ObjectLayout.Settings: id = 'settings'; break; + case I.ObjectLayout.Graph: id = 'graph'; break; + case I.ObjectLayout.Navigation: id = 'graph'; break; + case I.ObjectLayout.Archive: id = 'archive'; break; }; src = U.Common.updateSvg(require(`img/icon/default/${id}.svg`), { id, size, fill: J.Theme[theme].iconDefault }); };