Adaptive aSide in Settings (#7130)

Signed-off-by: Alexander Platov <alexander.platov@hardcoreeng.com>
This commit is contained in:
Alexander Platov 2024-11-08 08:43:06 +03:00 committed by GitHub
parent 97412400ff
commit ad54f56f4c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 127 additions and 27 deletions

View File

@ -38,7 +38,7 @@ import {
import templates from '@hcengineering/templates'
import setting from './plugin'
import workbench from '@hcengineering/model-workbench'
import workbench, { WidgetType } from '@hcengineering/model-workbench'
import { type AnyComponent } from '@hcengineering/ui/src/types'
export { settingId } from '@hcengineering/setting'
@ -133,6 +133,18 @@ export function createModel (builder: Builder): void {
TSpaceTypeCreator
)
builder.createDoc(
workbench.class.Widget,
core.space.Model,
{
label: setting.string.Settings,
type: WidgetType.Flexible,
icon: setting.icon.Setting,
component: setting.component.SettingsWidget
},
setting.ids.SettingsWidget
)
builder.mixin(setting.class.Integration, core.class.Class, notification.mixin.ClassCollaborators, {
fields: ['modifiedBy']
})

View File

@ -46,7 +46,8 @@ export default mergeIds(settingId, setting, {
InviteSetting: '' as AnyComponent,
ArrayEditor: '' as AnyComponent,
IntegrationPanel: '' as AnyComponent,
Configure: '' as AnyComponent
Configure: '' as AnyComponent,
SettingsWidget: '' as AnyComponent
},
category: {
Settings: '' as Ref<ActionCategory>

View File

@ -41,7 +41,8 @@ import workbench from './plugin'
export { workbenchId } from '@hcengineering/workbench'
export { workbenchOperation } from './migration'
export type { Application }
export type { Application, Widget }
export { WidgetType } from '@hcengineering/workbench'
@Model(workbench.class.Application, core.class.Doc, DOMAIN_MODEL)
@UX(workbench.string.Application)

View File

@ -62,6 +62,7 @@
gap: var(--spacing-4);
}
&__container {
justify-content: stretch;
height: 100%;
}
&__container:not(.columns),

View File

@ -282,4 +282,10 @@
}
}
}
&.short .hulyTableAttr-content.withTitle {
flex-direction: column;
align-items: stretch;
.hulyTableAttr-content__wrapper:empty { display: none; }
}
}

View File

@ -32,6 +32,7 @@
export let padding: string | undefined = undefined
export let hidden: boolean = false
export let allowFullsize: boolean = false
export let noTopIndent: boolean = false
export let hideFooter: boolean = false
export let adaptive: 'default' | 'freezeActions' | 'doubleRow' | 'disabled' = 'disabled'
export let showCancelButton: boolean = true
@ -56,7 +57,7 @@
<svelte:window on:keydown={onKeyDown} />
<div class="hulyModal-container {type}" class:hidden>
<div class="hulyModal-container {type}" class:hidden class:noTopIndent>
<Header
{type}
{allowFullsize}

View File

@ -164,6 +164,11 @@ export const settingsSeparators: DefSeparators = [
{ minSize: 19, size: 30, maxSize: 32, float: 'aside' }
]
export const twoPanelsSeparators: DefSeparators = [
{ minSize: 12.5, size: 17.5, maxSize: 22.5, float: 'navigator' },
null
]
export const mainSeparators: DefSeparators = [
{ minSize: 30, size: 'auto', maxSize: 'auto' },
{ minSize: 25, size: 30, maxSize: 80, float: 'sidebar' }

View File

@ -35,7 +35,7 @@
resolvedLocationStore,
Scroller,
Separator,
settingsSeparators
twoPanelsSeparators
} from '@hcengineering/ui'
import notification from '../../plugin'
@ -93,7 +93,7 @@
unsubscribeTypeSetting()
unsubscribeProviderSetting()
})
defineSeparators('notificationSettings', settingsSeparators)
defineSeparators('notificationSettings', twoPanelsSeparators)
</script>
<div class="hulyComponent">

View File

@ -26,7 +26,9 @@
getEventPositionElement,
showPopup,
IconSettings,
ModernButton
ModernButton,
resizeObserver,
deviceWidths
} from '@hcengineering/ui'
import { ObjectPresenter } from '@hcengineering/view-resources'
import settings from '../plugin'
@ -144,7 +146,13 @@
</div>
{/if}
{/if}
<div class="hulyTableAttr-container">
<div
class="hulyTableAttr-container"
use:resizeObserver={(el) => {
if (el.clientWidth < deviceWidths[0] && !el.classList.contains('short')) el.classList.add('short')
else if (el.clientWidth >= deviceWidths[0] && el.classList.contains('short')) el.classList.remove('short')
}}
>
<div class="hulyTableAttr-header font-medium-12" class:withButton={showHierarchy}>
{#if showHierarchy}
<ModernButton icon={IconSettings} kind={'secondary'} size={'small'} {disabled} hasMenu>

View File

@ -27,7 +27,7 @@
Header,
Breadcrumb,
defineSeparators,
settingsSeparators,
twoPanelsSeparators,
Separator,
NavGroup
} from '@hcengineering/ui'
@ -97,7 +97,7 @@
$: if (ofClass !== undefined && _class !== undefined && !client.getHierarchy().isDerived(_class, ofClass)) {
_class = ofClass
}
defineSeparators('workspaceSettings', settingsSeparators)
defineSeparators('workspaceSettings', twoPanelsSeparators)
</script>
<div class="hulyComponent">

View File

@ -35,6 +35,7 @@
export let attribute: AnyAttribute
export let exist: boolean
export let disabled: boolean = true
export let noTopIndent: boolean = false
let name: string
let type: Type<PropertyType> | undefined = attribute.type
@ -133,9 +134,8 @@
okLabel={presentation.string.Save}
okAction={save}
canSave={!(name === undefined || name.trim().length === 0) && !disabled}
onCancel={() => {
clearSettingsStore()
}}
onCancel={clearSettingsStore}
{noTopIndent}
>
<svelte:fragment slot="actions">
{#if !disabled}

View File

@ -27,7 +27,7 @@
Scroller,
Separator,
defineSeparators,
settingsSeparators,
twoPanelsSeparators,
showPopup
} from '@hcengineering/ui'
import { showMenu } from '@hcengineering/view-resources'
@ -51,7 +51,7 @@
showPopup(setting.component.EditEnum, { title: setting.string.CreateEnum }, 'top')
}
defineSeparators('workspaceSettings', settingsSeparators)
defineSeparators('workspaceSettings', twoPanelsSeparators)
</script>
<div class="hulyComponent">

View File

@ -17,7 +17,8 @@
import { AccountRole, getCurrentAccount, hasAccountRole } from '@hcengineering/core'
import login, { loginId } from '@hcengineering/login'
import { setMetadata } from '@hcengineering/platform'
import presentation, { closeClient, createQuery } from '@hcengineering/presentation'
import presentation, { closeClient, getClient, createQuery } from '@hcengineering/presentation'
import settingPlg from '../plugin'
import setting, { SettingsCategory, SettingsEvents } from '@hcengineering/setting'
import {
Component,
@ -35,13 +36,18 @@
settingsSeparators,
showPopup,
type AnyComponent,
deviceOptionsStore as deviceInfo
deviceOptionsStore as deviceInfo,
resizeObserver,
deviceWidths
} from '@hcengineering/ui'
import { NavFooter } from '@hcengineering/workbench-resources'
import { closeWidget, NavFooter, openWidget, minimizeSidebar } from '@hcengineering/workbench-resources'
import workbench from '@hcengineering/workbench'
import { ComponentType, onDestroy, onMount } from 'svelte'
import { clearSettingsStore, settingsStore, type SettingsStore } from '../store'
import { Analytics } from '@hcengineering/analytics'
const client = getClient()
let category: SettingsCategory | undefined
let categoryId: string = ''
@ -122,11 +128,26 @@
return ss.component === undefined ? null : ss.component
}
$: asideComponent = updatedStore($settingsStore)
let moveASide: boolean = false
const widget = client.getModel().findAllSync(workbench.class.Widget, { _id: settingPlg.ids.SettingsWidget })[0]
$: if (moveASide && asideComponent != null) {
openWidget(widget, { component: asideComponent, ...asideProps }, { active: true, openedByUser: true })
$deviceInfo.aside.visible = true
} else if ((moveASide && asideComponent == null) || (!moveASide && asideComponent != null)) {
closeWidget(widget._id)
minimizeSidebar()
}
defineSeparators('setting', settingsSeparators)
</script>
<div class="hulyPanels-container">
<div
class="hulyPanels-container"
use:resizeObserver={(el) => {
if (el.clientWidth < deviceWidths[2] && !moveASide) moveASide = true
else if (el.clientWidth >= deviceWidths[2] && moveASide) moveASide = false
}}
>
{#if $deviceInfo.navigator.visible}
<div
class="antiPanel-navigator {$deviceInfo.navigator.direction === 'horizontal'
@ -208,7 +229,7 @@
<Component is={category.component} props={{ kind: 'content' }} />
{/if}
</div>
{#if asideComponent != null}
{#if asideComponent != null && !moveASide}
<Separator name={'setting'} index={1} color={'transparent'} separatorSize={0} short />
<div class="hulySidePanel-container">
{#key asideProps}

View File

@ -0,0 +1,32 @@
<!--
// Copyright © 2024 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script lang="ts">
import { WidgetState } from '@hcengineering/workbench-resources'
import { type AnyComponent, Component } from '@hcengineering/ui'
import { ComponentType } from 'svelte'
export let widgetState: WidgetState | undefined
$: asideProps = widgetState?.data
$: asideComponent = asideProps?.component as AnyComponent | ComponentType
</script>
{#key asideProps}
{#if typeof asideComponent === 'string'}
<Component is={asideComponent} props={{ ...asideProps, noTopIndent: true }} />
{:else}
<svelte:component this={asideComponent} {...asideProps} noTopIndent />
{/if}
{/key}

View File

@ -58,6 +58,7 @@ import RefEditor from './components/typeEditors/RefEditor.svelte'
import RoleAssignmentEditor from './components/typeEditors/RoleAssignmentEditor.svelte'
import StringTypeEditor from './components/typeEditors/StringTypeEditor.svelte'
import WorkspaceSettings from './components/WorkspaceSettings.svelte'
import SettingsWidget from './components/SettingsWidget.svelte'
import setting from './plugin'
import { filterDescendants, getOwnerFirstName, getOwnerLastName, getOwnerPosition, getValue } from './utils'
@ -121,7 +122,8 @@ export default async (): Promise<Resources> => ({
SpaceTypePropertiesSectionEditor,
SpaceTypeRolesSectionEditor,
RoleEditor,
RoleAssignmentEditor
RoleAssignmentEditor,
SettingsWidget
},
actionImpl: {
DeleteMixin

View File

@ -13,12 +13,17 @@
// limitations under the License.
//
import { type Ref } from '@hcengineering/core'
import type { IntlString } from '@hcengineering/platform'
import { mergeIds } from '@hcengineering/platform'
import setting, { settingId } from '@hcengineering/setting'
import { type AnyComponent } from '@hcengineering/ui'
import { type Widget } from '@hcengineering/workbench'
export default mergeIds(settingId, setting, {
ids: {
SettingsWidget: '' as Ref<Widget>
},
component: {
EditEnum: '' as AnyComponent,
ManageSpaceTypes: '' as AnyComponent,

View File

@ -17,7 +17,7 @@
Breadcrumb,
Separator,
defineSeparators,
settingsSeparators,
twoPanelsSeparators,
Scroller
} from '@hcengineering/ui'
import { getActions as getContributedActions, TreeItem, TreeNode } from '@hcengineering/view-resources'
@ -147,7 +147,7 @@
}
let space: Ref<TemplateCategory> | undefined = undefined
defineSeparators('workspaceSettings', settingsSeparators)
defineSeparators('workspaceSettings', twoPanelsSeparators)
</script>
<div class="hulyComponent">

View File

@ -79,7 +79,7 @@
overflow: hidden;
flex-direction: row;
min-width: 25rem;
border-radius: var(--medium-BorderRadius);
border-radius: 0 var(--medium-BorderRadius) var(--medium-BorderRadius) 0;
&.mini:not(.float) {
width: 3.5rem !important;
@ -89,6 +89,9 @@
&.mini.float {
justify-content: flex-end;
}
&.float > :global(.sidebar-content) {
border-top: none;
}
}
@media (max-width: 1024px) {
.sidebar-container {

View File

@ -96,7 +96,7 @@
}
</script>
<div class="content">
<div class="sidebar-content">
{#if widget?.component}
<div class="component" use:resizeObserver={resize}>
{#if widget.headerLabel}
@ -145,7 +145,7 @@
<WidgetsBar {widgets} {preferences} selected={widgetId} />
<style lang="scss">
.content {
.sidebar-content {
display: flex;
flex-direction: column;

View File

@ -334,6 +334,8 @@ export function minimizeSidebar (closedByUser = false): void {
}
sidebarStore.set({ ...state, ...widgetsState, widget: undefined, variant: SidebarVariant.MINI })
const devInfo = get(deviceInfo)
if (devInfo.navigator.float && devInfo.aside.visible) deviceInfo.set({ ...devInfo, aside: { visible: false } })
}
export function updateTabData (widget: Ref<Widget>, tabId: string, data: Record<string, any>): void {

View File

@ -12,7 +12,7 @@ export class SidebarPage extends CommonPage {
}
sidebar = (): Locator => this.page.locator('#sidebar')
content = (): Locator => this.sidebar().locator('.content')
content = (): Locator => this.sidebar().locator('.sidebar-content')
contentHeaderByTitle = (title: string): Locator =>
this.content().locator(`.hulyHeader-titleGroup:has-text("${title}")`)