From bf80ba02e5f5d040a0914e4ae38928abd463a8ad Mon Sep 17 00:00:00 2001 From: Alexander Platov Date: Wed, 8 May 2024 06:42:44 +0300 Subject: [PATCH] Updated layout of the Chat navigator (#5537) Signed-off-by: Alexander Platov --- packages/theme/styles/_layouts.scss | 1 + packages/theme/styles/components.scss | 36 +-- packages/theme/styles/panel.scss | 8 + .../ui/src/components/EditWithIcon.svelte | 10 +- packages/ui/src/components/NavGroup.svelte | 33 ++- packages/ui/src/components/NavItem.svelte | 144 +++++++---- packages/ui/src/components/SearchEdit.svelte | 2 + .../src/components/chat/Chat.svelte | 2 +- .../chat/navigator/ChatNavItem.svelte | 8 +- .../chat/navigator/ChatNavSection.svelte | 35 ++- .../chat/navigator/ChatNavigator.svelte | 18 +- .../chat/navigator/ChatSectionHeader.svelte | 77 ------ .../chat/navigator/ChatSpecialElement.svelte | 29 +-- .../components/chat/navigator/NavItem.svelte | 237 +++++------------- .../src/components/NotifyMarker.svelte | 1 + tests/sanity/tests/model/chunter-page.ts | 2 +- 16 files changed, 273 insertions(+), 370 deletions(-) delete mode 100644 plugins/chunter-resources/src/components/chat/navigator/ChatSectionHeader.svelte diff --git a/packages/theme/styles/_layouts.scss b/packages/theme/styles/_layouts.scss index d3e43dd3a0..d02843b3b6 100644 --- a/packages/theme/styles/_layouts.scss +++ b/packages/theme/styles/_layouts.scss @@ -680,6 +680,7 @@ input.search { .w-min { width: min-content; } .w-max { width: max-content; } .w-full { width: 100%; } +.w-auto { width: auto !important; } .w-2 { width: .5rem; } .w-4 { width: 1rem; } .w-6 { width: 1.5rem; } diff --git a/packages/theme/styles/components.scss b/packages/theme/styles/components.scss index 2ddc75130e..ce873baedc 100644 --- a/packages/theme/styles/components.scss +++ b/packages/theme/styles/components.scss @@ -399,6 +399,17 @@ } } + &.small .hulyAccordionItem-header__chevron { + margin: 0 0.125rem; + width: 1.25rem; + height: 1.25rem; + border: 1px solid transparent; + } + &.medium .hulyAccordionItem-header__chevron { + margin-right: var(--spacing-0_75); + background-color: var(--global-ui-BackgroundColor); + border: 1px solid var(--global-subtle-ui-BorderColor); + } &.small, &.medium { padding: var(--spacing-1) var(--spacing-2); @@ -413,11 +424,6 @@ text-transform: uppercase; } - .hulyAccordionItem-header__chevron { - background-color: var(--global-ui-BackgroundColor); - border: 1px solid var(--global-subtle-ui-BorderColor); - } - &:hover { .hulyAccordionItem-header__label { color: var(--global-primary-TextColor); @@ -516,10 +522,10 @@ color: var(--global-secondary-TextColor); } } - &:hover .hulyAccordionItem-header__chevron { - color: var(--button-subtle-IconColor); - background-color: var(--global-ui-hover-BackgroundColor); - } + } + &:hover .hulyAccordionItem-header__chevron { + color: var(--button-subtle-IconColor); + background-color: var(--global-ui-hover-BackgroundColor); } &.isOpen { @@ -533,13 +539,11 @@ &.medium.bottomSpace + .hulyAccordionItem-content { padding-bottom: var(--spacing-2); } - &.large { - .hulyAccordionItem-header__chevron > * { - transform: rotate(90deg); - } - &.bottomSpace + .hulyAccordionItem-content { - padding-bottom: var(--spacing-2); - } + &.large.bottomSpace + .hulyAccordionItem-content { + padding-bottom: var(--spacing-2); + } + &:is(.small, .large) .hulyAccordionItem-header__chevron > * { + transform: rotate(90deg); } } } diff --git a/packages/theme/styles/panel.scss b/packages/theme/styles/panel.scss index 097d46c0ae..eb04ec1cdf 100644 --- a/packages/theme/styles/panel.scss +++ b/packages/theme/styles/panel.scss @@ -30,6 +30,14 @@ border-radius: var(--small-focus-BorderRadius); } } +.hulyNavPanel-container a.noUnderline { + display: inline-flex; + flex-shrink: 0; + min-width: 0; + min-height: 0; + + button.type-link { width: 100%; } +} .hulyNavPanel-container .hulyNavItem-container, .hulyNavPanel-container .hulyTaskNavLink-container { margin: 0 0.75rem; diff --git a/packages/ui/src/components/EditWithIcon.svelte b/packages/ui/src/components/EditWithIcon.svelte index 80594fbb26..95a2cf922d 100644 --- a/packages/ui/src/components/EditWithIcon.svelte +++ b/packages/ui/src/components/EditWithIcon.svelte @@ -29,6 +29,7 @@ export let placeholder: IntlString = plugin.string.EditBoxPlaceholder export let placeholderParam: any | undefined = undefined export let autoFocus: boolean = false + export let kind: 'ghost' | 'secondary' = 'ghost' export let size: 'small' | 'medium' | 'large' = 'medium' export let loading = false @@ -52,7 +53,7 @@
{ textHTML.focus() @@ -116,5 +117,12 @@ color: var(--theme-dark-color); } } + + &.secondary { + padding: var(--spacing-1); + background-color: var(--theme-button-default); + border: 1px solid var(--theme-button-border); + border-radius: var(--small-BorderRadius); + } } diff --git a/packages/ui/src/components/NavGroup.svelte b/packages/ui/src/components/NavGroup.svelte index ffcfb4134a..03364365e6 100644 --- a/packages/ui/src/components/NavGroup.svelte +++ b/packages/ui/src/components/NavGroup.svelte @@ -13,29 +13,56 @@ // limitations under the License. -->
- + {/if}
- + + + {#if label}
+ {#if isFold}
{/if} {#if tools || $$slots.tools}
{#if tools} diff --git a/packages/ui/src/components/NavItem.svelte b/packages/ui/src/components/NavItem.svelte index 8ec9a28e2d..9ced70118b 100644 --- a/packages/ui/src/components/NavItem.svelte +++ b/packages/ui/src/components/NavItem.svelte @@ -14,50 +14,74 @@ --> @@ -68,9 +92,10 @@ justify-content: stretch; align-items: center; padding: 0; - min-height: 2rem; + min-width: 0; + min-height: var(--global-small-Size); border: none; - border-radius: 0.375rem; + border-radius: var(--small-BorderRadius); outline: none; .hulyNavItem-icon { @@ -78,8 +103,8 @@ justify-content: center; align-items: center; flex-shrink: 0; - width: 1rem; - height: 1rem; + width: var(--global-min-Size); + height: var(--global-min-Size); color: var(--global-primary-TextColor); &__tag { @@ -90,11 +115,18 @@ } &.right { visibility: hidden; - margin-left: 0.5rem; + margin-left: var(--spacing-0_5); color: var(--global-accent-IconColor); } &:not(.right) { - margin-right: 0.5rem; + margin-right: var(--spacing-1); + } + &.withBackground { + width: var(--global-extra-small-Size); + height: var(--global-extra-small-Size); + background: var(--global-ui-BackgroundColor); + border: 1px solid var(--global-subtle-ui-BorderColor); + border-radius: var(--extra-small-BorderRadius); } } .hulyNavItem-label { @@ -105,19 +137,39 @@ text-align: left; min-width: 0; color: var(--global-primary-TextColor); + + &.description { + font-size: 0.875rem; + font-weight: 400; + } + } + .hulyNavItem-label + .hulyNavItem-label { + margin-left: var(--spacing-0_5); + } + .hulyNavItem-actions { + display: none; + align-items: center; + flex-shrink: 0; + min-width: 0; + min-height: 0; + gap: var(--spacing-0_25); } .hulyNavItem-count { - margin-left: 0.5rem; + margin-left: var(--spacing-1); color: var(--global-tertiary-TextColor); } - &:not(.selected):hover { + &:not(.selected) .hulyNavItem-count { + margin-right: var(--spacing-1); + } + &:not(.selected):hover, + &:not(.selected).showMenu { background-color: var(--global-ui-hover-highlight-BackgroundColor); } &.selected { cursor: auto; background-color: var(--global-ui-highlight-BackgroundColor); - &:not(.type-anchor-link) .hulyNavItem-label { + &:not(.type-anchor-link) .hulyNavItem-label:not(.description) { font-weight: 700; } .hulyNavItem-count { @@ -126,22 +178,19 @@ } &.type-link { - padding: 0 0.625rem; + padding: 0 var(--spacing-1_25); - .hulyNavItem-label { - flex-grow: 1; - } &.selected { &:not(.fold) { - padding: 0 0.375rem 0 0.625rem; + padding: 0 var(--spacing-0_75) 0 var(--spacing-1_25); } &.fold { - padding: 0 0.375rem 0 0.25rem; + padding: 0 var(--spacing-0_75) 0 var(--spacing-0_5); } .hulyNavItem-icon { color: var(--global-accent-TextColor); } - .hulyNavItem-label { + .hulyNavItem-label:not(.description) { color: var(--global-accent-TextColor); } .hulyNavItem-icon.right { @@ -150,34 +199,36 @@ } } &.type-tag { - padding: 0 0.625rem; - - .hulyNavItem-label { - flex-grow: 1; - } + padding: 0 var(--spacing-1_25); } &.type-object { - padding: 0 0.625rem 0 0.25rem; + padding: 0 var(--spacing-0_5) 0 var(--spacing-0_5); .hulyNavItem-icon { - width: 1.5rem; - height: 1.5rem; - background-color: var(--global-ui-BackgroundColor); - border-radius: 0.25rem; + width: var(--global-extra-small-Size); + height: var(--global-extra-small-Size); &:not(.right) { - margin-right: 0.375rem; + margin-right: var(--spacing-0_75); + background-color: var(--global-ui-BackgroundColor); + border-radius: var(--extra-small-BorderRadius); } } - .hulyNavItem-label { - flex-grow: 1; - } - &.selected .hulyNavItem-label { - color: var(--global-accent-TextColor); + &.selected { + .hulyNavItem-label:not(.description) { + color: var(--global-accent-TextColor); + } + .hulyNavItem-icon { + color: var(--global-accent-TextColor); + + &.right { + visibility: visible; + } + } } } &.type-anchor-link { - padding: 0 0.75rem 0 0.625rem; + padding: 0 var(--spacing-1_5) 0 var(--spacing-1_25); width: fit-content; min-height: 1.75rem; @@ -194,11 +245,16 @@ } } &.fold { - padding-left: 0.25rem; + padding-left: var(--spacing-0_5); :global(.hulyFold-container) { - margin-right: 0.375rem; + margin-right: var(--spacing-0_75); } } + + &:hover .hulyNavItem-actions, + &.showMenu .hulyNavItem-actions { + display: flex; + } } diff --git a/packages/ui/src/components/SearchEdit.svelte b/packages/ui/src/components/SearchEdit.svelte index 894d4dec3a..ea36004b07 100644 --- a/packages/ui/src/components/SearchEdit.svelte +++ b/packages/ui/src/components/SearchEdit.svelte @@ -6,6 +6,7 @@ export let value: string = '' export let width: string = '12rem' + export let kind: 'ghost' | 'secondary' = 'ghost' $: _search = value const dispatch = createEventDispatcher() @@ -27,6 +28,7 @@ icon={IconSearch} {width} placeholder={plugin.string.Search} + {kind} bind:value={_search} on:change={() => { restartTimer() diff --git a/plugins/chunter-resources/src/components/chat/Chat.svelte b/plugins/chunter-resources/src/components/chat/Chat.svelte index 86e5bd26c5..058ddb6842 100644 --- a/plugins/chunter-resources/src/components/chat/Chat.svelte +++ b/plugins/chunter-resources/src/components/chat/Chat.svelte @@ -133,7 +133,7 @@
{#if visibleNav}
-
+
diff --git a/plugins/chunter-resources/src/components/chat/navigator/ChatNavItem.svelte b/plugins/chunter-resources/src/components/chat/navigator/ChatNavItem.svelte index 06d1530093..2a153c4206 100644 --- a/plugins/chunter-resources/src/components/chat/navigator/ChatNavItem.svelte +++ b/plugins/chunter-resources/src/components/chat/navigator/ChatNavItem.svelte @@ -36,6 +36,7 @@ export let context: DocNotifyContext | undefined export let item: ChatNavItemModel export let isSelected = false + export let type: 'type-link' | 'type-tag' | 'type-anchor-link' | 'type-object' = 'type-link' const client = getClient() const hierarchy = client.getHierarchy() @@ -44,7 +45,7 @@ let notifications: InboxNotification[] = [] - let notificationsCount = 0 + let count: number | null = null let actions: Action[] = [] notificationClient.inboxNotificationsByContext.subscribe((res) => { @@ -60,7 +61,7 @@ }) $: void getNotificationsCount(context, notifications).then((res) => { - notificationsCount = res + count = res === 0 ? null : res }) $: void getChannelActions(context, item.object).then((res) => { @@ -121,10 +122,11 @@ iconSize={item.iconSize} {isSelected} iconProps={{ ...item.iconProps, value: item.object }} - {notificationsCount} + {count} title={item.title} description={item.description} {actions} + {type} on:click={() => { dispatch('select', { object: item.object }) }} diff --git a/plugins/chunter-resources/src/components/chat/navigator/ChatNavSection.svelte b/plugins/chunter-resources/src/components/chat/navigator/ChatNavSection.svelte index 8a8dc75111..6542b69a12 100644 --- a/plugins/chunter-resources/src/components/chat/navigator/ChatNavSection.svelte +++ b/plugins/chunter-resources/src/components/chat/navigator/ChatNavSection.svelte @@ -16,7 +16,7 @@ import { Doc, Ref } from '@hcengineering/core' import { DocNotifyContext } from '@hcengineering/notification' import { getClient } from '@hcengineering/presentation' - import ui, { Action, AnySvelteComponent, IconSize, ModernButton } from '@hcengineering/ui' + import ui, { Action, AnySvelteComponent, IconSize, ModernButton, NavGroup } from '@hcengineering/ui' import { getDocTitle } from '@hcengineering/view-resources' import contact from '@hcengineering/contact' import { getResource, translate } from '@hcengineering/platform' @@ -26,7 +26,6 @@ import chunter from '../../../plugin' import { ChatNavItemModel } from '../types' import { getObjectIcon, getChannelName } from '../../../utils' - import ChatSectionHeader from './ChatSectionHeader.svelte' import { navigatorStateStore, toggleSections } from '../utils' export let id: string @@ -134,19 +133,21 @@ {#if items.length > 0 && contexts.length > 0} -
- { - toggleSections(id) - }} - /> + { + toggleSections(id) + }} + > {#if !isCollapsed} {#each visibleItems as item (item.id)} {@const context = contexts.find(({ attachedTo }) => attachedTo === item.id)} - + {/each} {#if canShowMore}
@@ -166,18 +167,10 @@ {/if} {/if} -
+
{/if} diff --git a/plugins/chunter-resources/src/components/chat/navigator/ChatSectionHeader.svelte b/plugins/chunter-resources/src/components/chat/navigator/ChatSectionHeader.svelte deleted file mode 100644 index 1e60b570c6..0000000000 --- a/plugins/chunter-resources/src/components/chat/navigator/ChatSectionHeader.svelte +++ /dev/null @@ -1,77 +0,0 @@ - - - -
- dispatch('collapse')} - /> - - - -
- {header} -
-
- - diff --git a/plugins/chunter-resources/src/components/chat/navigator/ChatSpecialElement.svelte b/plugins/chunter-resources/src/components/chat/navigator/ChatSpecialElement.svelte index 99b86175bd..564dd5fab2 100644 --- a/plugins/chunter-resources/src/components/chat/navigator/ChatSpecialElement.svelte +++ b/plugins/chunter-resources/src/components/chat/navigator/ChatSpecialElement.svelte @@ -27,15 +27,16 @@ export let special: SpecialNavModel export let currentSpecial: SpecialNavModel | undefined = undefined + export let type: 'type-link' | 'type-tag' | 'type-anchor-link' | 'type-object' = 'type-link' const notificationsClient = InboxNotificationsClientImpl.getClient() const notificationsByContextStore = notificationsClient.inboxNotificationsByContext - let notificationsCount = 0 + let count: number | null = null let elementsCount = 0 $: void getNotificationsCount(special, $notificationsByContextStore).then((res) => { - notificationsCount = res + count = res === 0 ? null : res }) $: elementsCount = getElementsCount(special, $savedMessagesStore, $savedAttachmentsStore) @@ -65,17 +66,13 @@ } -
- -
+ diff --git a/plugins/chunter-resources/src/components/chat/navigator/NavItem.svelte b/plugins/chunter-resources/src/components/chat/navigator/NavItem.svelte index 1e98a4774c..8dbbb980a7 100644 --- a/plugins/chunter-resources/src/components/chat/navigator/NavItem.svelte +++ b/plugins/chunter-resources/src/components/chat/navigator/NavItem.svelte @@ -14,16 +14,15 @@ --> - - -
- {#if icon} -
- -
- {/if} - -
- 0} - class:selected={isSelected} - style="flex-shrink: 0" - > - {#if title} - {title} - {:else if intlTitle} - -
- -
- -
-
- {#each inlineActions as action} -
handleInlineActionClicked(ev, action)} - > - -
- {/each} - {#if menuActions.length > 0} -
- -
- {/if} - {#if elementsCount > 0} -
-
{elementsCount}
- {/if} - {#if notificationsCount > 0} -
- - {/if} - {#if isSelected} -
- - {/if} -
-
-
+ 0 ? elementsCount : null} + {type} + withBackground={withIconBackground} + showMenu={menuOpened} + on:click + on:contextmenu +> + + {#each inlineActions as action} + + {/each} + {#if menuActions.length > 0} + + {/if} + + + {#if count != null && count > 0} +
+ +
+ {/if} + + diff --git a/plugins/notification-resources/src/components/NotifyMarker.svelte b/plugins/notification-resources/src/components/NotifyMarker.svelte index 97a113d949..4aa0781f65 100644 --- a/plugins/notification-resources/src/components/NotifyMarker.svelte +++ b/plugins/notification-resources/src/components/NotifyMarker.svelte @@ -34,6 +34,7 @@ display: flex; align-items: center; justify-content: center; + flex-shrink: 0; border-radius: 50%; background-color: var(--global-higlight-Color); color: var(--global-on-accent-TextColor); diff --git a/tests/sanity/tests/model/chunter-page.ts b/tests/sanity/tests/model/chunter-page.ts index 19be7e346b..c5875590a1 100644 --- a/tests/sanity/tests/model/chunter-page.ts +++ b/tests/sanity/tests/model/chunter-page.ts @@ -7,7 +7,7 @@ export class ChunterPage { this.page = page } - readonly buttonChannelBrowser = (): Locator => this.page.locator('.header > button.type-button-icon') + readonly buttonChannelBrowser = (): Locator => this.page.locator('.hulyNavPanel-header > button.type-button-icon') readonly buttonNewChannelHeader = (): Locator => this.page.getByRole('button', { name: 'New channel' }) readonly inputNewChannelName = (): Locator => this.page.getByPlaceholder('New channel') readonly inputDescription = (): Locator => this.page.getByPlaceholder('Description (optional)')