Rebase (#6088)
Signed-off-by: Alexander Platov <alexander.platov@hardcoreeng.com>
@ -259,7 +259,7 @@ export function createModel (builder: Builder): void {
|
||||
core.space.Model,
|
||||
{
|
||||
label: calendar.string.Calendar,
|
||||
icon: calendar.icon.Calendar,
|
||||
icon: calendar.icon.CalendarView,
|
||||
component: calendar.component.CalendarView
|
||||
},
|
||||
calendar.viewlet.Calendar
|
||||
|
@ -181,6 +181,7 @@ export function createModel (builder: Builder): void {
|
||||
query: {
|
||||
[documents.mixin.DocumentTemplate]: { $exists: false }
|
||||
},
|
||||
icon: documents.icon.Library,
|
||||
title: documents.string.Documents,
|
||||
config: [
|
||||
['effective', documents.string.Effective, {}],
|
||||
|
@ -533,6 +533,7 @@ function defineApplication (builder: Builder): void {
|
||||
component: workbench.component.SpecialView,
|
||||
componentProps: {
|
||||
_class: document.class.Teamspace,
|
||||
icon: view.icon.List,
|
||||
label: document.string.Teamspaces
|
||||
},
|
||||
position: 'top'
|
||||
|
@ -657,7 +657,7 @@ function defineApplication (builder: Builder): void {
|
||||
core.space.Model,
|
||||
{
|
||||
label: drive.string.Drive,
|
||||
icon: drive.icon.Drive,
|
||||
icon: drive.icon.DriveApplication,
|
||||
alias: driveId,
|
||||
hidden: false,
|
||||
locationResolver: drive.resolver.Location,
|
||||
@ -667,7 +667,7 @@ function defineApplication (builder: Builder): void {
|
||||
id: 'browser',
|
||||
accessLevel: AccountRole.User,
|
||||
label: drive.string.Drives,
|
||||
icon: view.icon.List,
|
||||
icon: drive.icon.Drives,
|
||||
component: workbench.component.SpecialView,
|
||||
componentProps: {
|
||||
_class: drive.class.Drive,
|
||||
|
@ -117,7 +117,7 @@ export function createModel (builder: Builder): void {
|
||||
accessLevel: AccountRole.User,
|
||||
componentProps: {
|
||||
_class: lead.mixin.Customer,
|
||||
icon: lead.icon.Lead,
|
||||
icon: contact.icon.Person,
|
||||
label: lead.string.Customers
|
||||
},
|
||||
position: 'top'
|
||||
@ -125,12 +125,13 @@ export function createModel (builder: Builder): void {
|
||||
{
|
||||
id: 'funnels',
|
||||
component: workbench.component.SpecialView,
|
||||
icon: view.icon.List,
|
||||
icon: lead.icon.Funnels,
|
||||
label: lead.string.Funnels,
|
||||
position: 'bottom',
|
||||
accessLevel: AccountRole.User,
|
||||
componentProps: {
|
||||
_class: lead.class.Funnel,
|
||||
icon: lead.icon.Funnels,
|
||||
label: lead.string.Funnels,
|
||||
createComponent: lead.component.CreateFunnel,
|
||||
createLabel: lead.string.CreateFunnel
|
||||
|
@ -141,7 +141,6 @@ export function createModel (builder: Builder): void {
|
||||
alias: loveId,
|
||||
hidden: false,
|
||||
position: 'top',
|
||||
modern: true,
|
||||
component: love.component.Main
|
||||
},
|
||||
love.app.Love
|
||||
|
@ -455,6 +455,7 @@ function defineApplication (builder: Builder): void {
|
||||
component: workbench.component.SpecialView,
|
||||
componentProps: {
|
||||
_class: products.class.Product,
|
||||
icon: products.icon.Product,
|
||||
label: products.string.Products
|
||||
},
|
||||
position: 'top'
|
||||
@ -466,6 +467,7 @@ function defineApplication (builder: Builder): void {
|
||||
component: workbench.component.SpecialView,
|
||||
componentProps: {
|
||||
_class: products.class.ProductVersion,
|
||||
icon: products.icon.ProductVersion,
|
||||
label: products.string.ProductVersions
|
||||
},
|
||||
position: 'top'
|
||||
|
@ -226,6 +226,7 @@ export function createModel (builder: Builder): void {
|
||||
position: 'event',
|
||||
componentProps: {
|
||||
labelTasks: recruit.string.Applications,
|
||||
icon: recruit.icon.AssignedToMe,
|
||||
_class: recruit.class.Applicant,
|
||||
config: [
|
||||
['assigned', view.string.Assigned, {}],
|
||||
|
@ -349,8 +349,7 @@ export function createModel (builder: Builder): void {
|
||||
icon: setting.icon.Setting,
|
||||
alias: settingId,
|
||||
hidden: true,
|
||||
component: setting.component.Settings,
|
||||
modern: true
|
||||
component: setting.component.Settings
|
||||
},
|
||||
setting.ids.SettingApp
|
||||
)
|
||||
|
@ -197,7 +197,6 @@ export function createModel (builder: Builder): void {
|
||||
alias: timeId,
|
||||
hidden: false,
|
||||
position: 'top',
|
||||
modern: true,
|
||||
component: time.component.Me
|
||||
},
|
||||
time.app.Me
|
||||
|
@ -324,6 +324,7 @@ function defineApplication (
|
||||
icon: tracker.icon.MyIssues,
|
||||
component: tracker.component.MyIssues,
|
||||
componentProps: {
|
||||
icon: tracker.icon.MyIssues,
|
||||
config: [
|
||||
['assigned', view.string.Assigned, {}],
|
||||
['active', tracker.string.Active, {}],
|
||||
@ -341,6 +342,7 @@ function defineApplication (
|
||||
component: tracker.component.Issues,
|
||||
componentProps: {
|
||||
space: undefined,
|
||||
icon: tracker.icon.Issues,
|
||||
title: tracker.string.AllIssues,
|
||||
config: [
|
||||
['all', tracker.string.All, {}],
|
||||
@ -360,6 +362,7 @@ function defineApplication (
|
||||
spaceClass: tracker.class.Project,
|
||||
componentProps: {
|
||||
_class: tracker.class.Project,
|
||||
icon: view.icon.List,
|
||||
label: tracker.string.AllProjects
|
||||
}
|
||||
}
|
||||
@ -380,6 +383,7 @@ function defineApplication (
|
||||
icon: tracker.icon.Issues,
|
||||
component: tracker.component.Issues,
|
||||
componentProps: {
|
||||
icon: tracker.icon.Issues,
|
||||
title: tracker.string.Issues,
|
||||
config: [
|
||||
['all', tracker.string.All, {}],
|
||||
|
@ -45,9 +45,14 @@
|
||||
export let withoutContentScroll: boolean = false
|
||||
export let customAside: ButtonItem[] | undefined = undefined
|
||||
export let selectedAside: string | boolean = customAside ? customAside[0].id : isAside
|
||||
export let kind: 'default' | 'modern' = 'default'
|
||||
export let printHeader = true
|
||||
export let printAside = false
|
||||
export let printHeader: boolean = true
|
||||
export let printAside: boolean = false
|
||||
export let adaptive: 'default' | 'freezeActions' | 'doubleRow' | 'disabled' = 'disabled'
|
||||
export let hideBefore: boolean = false
|
||||
export let hideSearch: boolean = true
|
||||
export let hideActions: boolean = false
|
||||
export let hideExtra: boolean = false
|
||||
export let overflowExtra: boolean = false
|
||||
|
||||
export function getAside (): string | boolean {
|
||||
return panel.getAside()
|
||||
@ -115,13 +120,18 @@
|
||||
on:close
|
||||
{allowClose}
|
||||
{embedded}
|
||||
{kind}
|
||||
{floatAside}
|
||||
bind:useMaxWidth
|
||||
{isFullSize}
|
||||
{customAside}
|
||||
{printHeader}
|
||||
{printAside}
|
||||
{adaptive}
|
||||
{hideBefore}
|
||||
{hideSearch}
|
||||
{hideActions}
|
||||
{hideExtra}
|
||||
{overflowExtra}
|
||||
bind:selectedAside
|
||||
on:select={(result) => {
|
||||
selectedAside = result.detail
|
||||
@ -144,7 +154,6 @@
|
||||
<svelte:fragment slot="utils">
|
||||
{#if isUtils && $$slots.utils}
|
||||
<slot name="utils" />
|
||||
<div class="buttons-divider max-h-7 h-7 mx-2 no-print" />
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
|
||||
@ -196,6 +205,10 @@
|
||||
<slot name="post-utils" />
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="extra">
|
||||
<slot name="extra" />
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="page-header">
|
||||
<slot name="page-header" />
|
||||
</svelte:fragment>
|
||||
|
@ -31,7 +31,6 @@
|
||||
import SpaceInfo from './SpaceInfo.svelte'
|
||||
|
||||
export let _classes: Ref<Class<Space>>[] = []
|
||||
export let allowDeselect: boolean = false
|
||||
export let titleDeselect: IntlString | undefined = undefined
|
||||
export let placeholder: IntlString = presentation.string.Search
|
||||
export let placeholderParam: any | undefined = undefined
|
||||
@ -100,26 +99,21 @@
|
||||
<div class="box">
|
||||
{#each shownSpaces as space}
|
||||
<button
|
||||
class="menu-item"
|
||||
class="menu-item justify-between"
|
||||
on:click={() => {
|
||||
checkSelected(space)
|
||||
}}
|
||||
>
|
||||
<div class="check pointer-events-none">
|
||||
<CheckBox checked={isSelected(space)} kind={'primary'} />
|
||||
</div>
|
||||
<SpaceInfo size={'medium'} value={space} {iconWithEmoji} {defaultIcon} />
|
||||
{#if allowDeselect && space._id === selected}
|
||||
<div class="check pointer-events-none">
|
||||
{#if titleDeselect}
|
||||
<div class="clear-mins" use:tooltip={{ label: titleDeselect ?? presentation.string.Deselect }}>
|
||||
<CheckBox checked circle kind={'primary'} />
|
||||
</div>
|
||||
{:else}
|
||||
<CheckBox checked circle kind={'primary'} />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="check ml-0 pointer-events-none">
|
||||
{#if titleDeselect}
|
||||
<div class="clear-mins" use:tooltip={{ label: titleDeselect ?? presentation.string.Deselect }}>
|
||||
<CheckBox checked={isSelected(space)} kind={'primary'} />
|
||||
</div>
|
||||
{:else}
|
||||
<CheckBox checked={isSelected(space)} kind={'primary'} />
|
||||
{/if}
|
||||
</div>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
|
@ -189,7 +189,7 @@ input.search {
|
||||
.inline-flex { display: inline-flex; }
|
||||
.flex-grow { flex-grow: 1; }
|
||||
.flex-no-shrink { flex-shrink: 0; }
|
||||
.flex-shrink { flex-shrink: 1; }
|
||||
.flex-shrink { flex-shrink: 1 !important; }
|
||||
.flex-wrap { flex-wrap: wrap !important; }
|
||||
.flex-nowrap { flex-wrap: nowrap !important; }
|
||||
.flex-baseline {
|
||||
@ -270,7 +270,7 @@ input.search {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
.justify-between { justify-content: space-between; }
|
||||
.justify-between { justify-content: space-between !important; }
|
||||
.justify-start { justify-content: flex-start; }
|
||||
.justify-end { justify-content: flex-end !important; }
|
||||
.justify-center { justify-content: center; }
|
||||
@ -309,6 +309,7 @@ input.search {
|
||||
.icon {
|
||||
color: var(--theme-dark-color);
|
||||
|
||||
&.primary { color: var(--button-primary-BackgroundColor); }
|
||||
&.circle {
|
||||
padding: .25rem;
|
||||
background-color: var(--avatar-bg-color);
|
||||
@ -345,7 +346,11 @@ input.search {
|
||||
margin-left: .75rem;
|
||||
}
|
||||
&:hover {
|
||||
.icon { color: var(--theme-caption-color); }
|
||||
.icon {
|
||||
color: var(--theme-caption-color);
|
||||
|
||||
&.primary { color: var(--button-primary-hover-BackgroundColor); }
|
||||
}
|
||||
.label {
|
||||
color: var(--theme-caption-color);
|
||||
|
||||
@ -483,6 +488,7 @@ input.search {
|
||||
}
|
||||
|
||||
/* Margins & Paddings */
|
||||
.ml-0 { margin-left: 0 !important; }
|
||||
.ml-0-5 { margin-left: .125rem; }
|
||||
.ml-1 { margin-left: .25rem; }
|
||||
.ml-1-5 { margin-left: .375rem; }
|
||||
@ -508,6 +514,7 @@ input.search {
|
||||
.mr-8 { margin-right: 2rem; }
|
||||
.mr-10 { margin-right: 2.5rem; }
|
||||
.mr-32 { margin-right: 8rem }
|
||||
.mt--1 { margin-top: -.25rem; }
|
||||
.mt-0-5 { margin-top: .125rem; }
|
||||
.mt-1 { margin-top: .25rem; }
|
||||
.mt-2 { margin-top: .5rem; }
|
||||
@ -731,6 +738,7 @@ input.search {
|
||||
.min-h-9 { min-height: 2.25rem; }
|
||||
.min-h-11 { min-height: 2.75rem; }
|
||||
.min-h-12 { min-height: 3rem; }
|
||||
.min-h-13 { min-height: 3.25rem; }
|
||||
.min-h-16 { min-height: 4rem; }
|
||||
.min-h-30 { min-height: 7.5rem; }
|
||||
.min-h-60 { min-height: 15rem; }
|
||||
@ -958,6 +966,7 @@ a.no-line {
|
||||
&.bordered { border-color: var(--theme-button-border); }
|
||||
}
|
||||
|
||||
.overflow-hidden { overflow: hidden; }
|
||||
.overflow-x-auto { overflow-x: auto; }
|
||||
.overflow-y-auto { overflow-y: auto; }
|
||||
.overflow-x-auto,
|
||||
|
@ -53,6 +53,7 @@
|
||||
--global-popover-hover-BackgroundColor: #1F2737;
|
||||
--global-popover-BorderColor: #A5BDFF1A;
|
||||
--global-primary-LinkColor: #4D7FF5;
|
||||
--global-primary-IconColor: #ffffff;
|
||||
--global-primary-TextColor: #FFFFFF;
|
||||
--global-secondary-TextColor: #C1C9D6;
|
||||
--global-tertiary-TextColor: #8E99AF;
|
||||
@ -66,6 +67,7 @@
|
||||
--global-higlight-Color: #F76E53;
|
||||
--global-accent-SkyText: #B9D1F5;
|
||||
--global-accent-BackgroundColor: #204DC8;
|
||||
--global-on-nuance-TextColor: #041d7d;
|
||||
|
||||
--global-no-priority-PriorityColor: #8E99AF;
|
||||
--global-low-PriorityColor: #6493FF;
|
||||
@ -147,6 +149,7 @@
|
||||
--global-popover-hover-BackgroundColor: #1F2737;
|
||||
--global-popover-BorderColor: #A5BDFF26;
|
||||
--global-primary-LinkColor: #3566E2;
|
||||
--global-primary-IconColor: #0f121a;
|
||||
--global-primary-TextColor: #0F121A;
|
||||
--global-secondary-TextColor: #5A667E;
|
||||
--global-tertiary-TextColor: #7B879E;
|
||||
@ -160,6 +163,7 @@
|
||||
--global-higlight-Color: #F76E53;
|
||||
--global-accent-SkyText:#B9D1F5;
|
||||
--global-accent-BackgroundColor: #3566E2;
|
||||
--global-on-nuance-TextColor: #2553cf;
|
||||
|
||||
--global-no-priority-PriorityColor: #7B879E;
|
||||
--global-low-PriorityColor: #3566E2;
|
||||
|
@ -84,7 +84,7 @@
|
||||
|
||||
&:hover .btn-icon { color: var(--theme-caption-color); }
|
||||
&:not(.no-focus):focus {
|
||||
&:not(.sh-filter) { box-shadow: 0 0 0 2px var(--primary-button-outline); }
|
||||
&:not(.sh-filter, .regular) { box-shadow: 0 0 0 2px var(--primary-button-outline); }
|
||||
&.sh-filter { border-color: var(--primary-button-outline); }
|
||||
}
|
||||
|
||||
@ -109,7 +109,8 @@
|
||||
&.pressed:hover { background-color: var(--theme-button-pressed); }
|
||||
&:focus {
|
||||
background-color: var(--theme-button-focused);
|
||||
border-color: var(--theme-button-focused-border);
|
||||
outline: 2px solid var(--global-focus-BorderColor);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
&:disabled { background-color: var(--theme-button-disabled); }
|
||||
&.selected {
|
||||
|
@ -25,12 +25,16 @@
|
||||
.font-bold-14,
|
||||
.paragraph-regular-14,
|
||||
.heading-medium-16,
|
||||
.heading-bold-16,
|
||||
.heading-ui-H2,
|
||||
.heading-medium-20,
|
||||
.heading-bold-20 {
|
||||
font-family: var(--font-family);
|
||||
font-style: normal;
|
||||
color: var(--global-primary-TextColor);
|
||||
|
||||
&:not(.secondary, .tertiary) { color: var(--global-primary-TextColor); }
|
||||
&.secondary { color: var(--global-secondary-TextColor); }
|
||||
&.tertiary { color: var(--global-tertiary-TextColor); }
|
||||
&:not(.line-height-auto) { line-height: 1rem; }
|
||||
}
|
||||
.font-regular-11,
|
||||
@ -63,15 +67,24 @@
|
||||
.heading-medium-20 {
|
||||
font-weight: 500;
|
||||
}
|
||||
.heading-ui-H2 {
|
||||
font-weight: 600;
|
||||
}
|
||||
.font-bold-12,
|
||||
.font-bold-14,
|
||||
.heading-bold-16,
|
||||
.heading-bold-20 {
|
||||
font-weight: 700;
|
||||
}
|
||||
.heading-medium-16 {
|
||||
.heading-medium-16,
|
||||
.heading-bold-16 {
|
||||
font-size: 1rem;
|
||||
line-height: 1.125rem;
|
||||
}
|
||||
.heading-ui-H2 {
|
||||
font-size: 1.125rem;
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
.heading-medium-20,
|
||||
.heading-bold-20 {
|
||||
font-size: 1.25rem;
|
||||
@ -143,13 +156,8 @@
|
||||
filter: drop-shadow(2px 0 1px rgba(0, 0, 0, .2));
|
||||
z-index: 450;
|
||||
|
||||
&.portrait {
|
||||
left: 0;
|
||||
}
|
||||
&.landscape {
|
||||
.modern-app & { left: var(--app-panel-width); }
|
||||
:not(.modern-app) & { left: calc(var(--app-panel-width) + 1px); }
|
||||
}
|
||||
&.portrait { left: 0; }
|
||||
&.landscape { left: var(--app-panel-width); }
|
||||
}
|
||||
}
|
||||
.antiPanel-component {
|
||||
|
@ -31,6 +31,14 @@
|
||||
overflow: hidden;
|
||||
background-color: var(--theme-comp-header-color); // var(--global-surface-02-BackgroundColor);
|
||||
}
|
||||
&.beforeAside {
|
||||
border-right: none;
|
||||
border-radius: var(--small-focus-BorderRadius) 0 0 var(--small-focus-BorderRadius);
|
||||
}
|
||||
&.aside {
|
||||
border-left: none;
|
||||
border-radius: 0 var(--small-focus-BorderRadius) var(--small-focus-BorderRadius) 0;
|
||||
}
|
||||
}
|
||||
.hulyComponent-content,
|
||||
.hulyComponent-content__container,
|
||||
@ -44,8 +52,9 @@
|
||||
min-height: 0;
|
||||
}
|
||||
.hulyComponent-content {
|
||||
flex-shrink: 0;
|
||||
|
||||
&:not(.noShrink) {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
&:not(.withoutMaxWidth) {
|
||||
max-width: 64rem;
|
||||
}
|
||||
@ -308,15 +317,45 @@
|
||||
.hulyHeader-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: var(--spacing-1_5) var(--spacing-2);
|
||||
width: 100%;
|
||||
height: var(--spacing-6_5);
|
||||
min-width: 0;
|
||||
min-height: var(--spacing-6_5);
|
||||
|
||||
&:not(.clearPadding) { padding: var(--spacing-1_5) var(--spacing-2); }
|
||||
&.clearPadding {
|
||||
padding: 0 var(--spacing-2);
|
||||
|
||||
& > .hulyHeader-row {
|
||||
padding: 0;
|
||||
min-height: var(--spacing-6_5);
|
||||
}
|
||||
}
|
||||
&:not(.hideSeparator) {
|
||||
border-bottom: 1px solid var(--theme-divider-color); // var(--global-surface-02-BorderColor);
|
||||
}
|
||||
&.topIndent {
|
||||
margin-top: 1px;
|
||||
&.topIndent { margin-top: 1px; }
|
||||
.hulyHeader-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
padding: var(--spacing-1_5) 0;
|
||||
min-width: 0;
|
||||
|
||||
&:has(.extra.overflow) { padding: 0; }
|
||||
&:not(.noBorder):first-child {
|
||||
max-height: var(--spacing-6_5);
|
||||
border-bottom: 1px solid var(--theme-divider-color);
|
||||
}
|
||||
&:nth-child(2) { margin-top: -1px; }
|
||||
&.between { justify-content: space-between; }
|
||||
&.reverse { flex-direction: row-reverse; }
|
||||
&__divider {
|
||||
margin-top: -1px;
|
||||
width: 100%;
|
||||
min-height: 1px;
|
||||
max-height: 1px;
|
||||
background-color: var(--theme-divider-color);
|
||||
}
|
||||
}
|
||||
.hulyHeader-button {
|
||||
display: flex;
|
||||
@ -347,19 +386,38 @@
|
||||
.hulyHeader-titleGroup,
|
||||
.hulyHeader-buttonsGroup {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
.hulyHeader-titleGroup {
|
||||
flex-grow: 1;
|
||||
gap: var(--spacing-0_5);
|
||||
|
||||
&.withDescription { flex-direction: column; }
|
||||
&:not(.withDescription) {
|
||||
align-items: center;
|
||||
gap: var(--spacing-0_5);
|
||||
}
|
||||
}
|
||||
.hulyHeader-buttonsGroup {
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
gap: var(--spacing-1);
|
||||
margin-left: var(--spacing-2);
|
||||
|
||||
&.extra {
|
||||
flex-shrink: 1;
|
||||
margin-left: var(--spacing-2);
|
||||
|
||||
&.overflow {
|
||||
overflow-x: auto;
|
||||
margin: 0 -.25rem 0 1rem;
|
||||
padding: .25rem;
|
||||
}
|
||||
}
|
||||
&.before {
|
||||
gap: var(--spacing-0_5);
|
||||
|
||||
&.freezeBefore { min-width: var(--global-small-Size); }
|
||||
}
|
||||
&:not(.before) { gap: var(--spacing-1); }
|
||||
&__label {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -368,8 +426,21 @@
|
||||
color: var(--global-secondary-TextColor);
|
||||
}
|
||||
}
|
||||
.hulyHotKey-item {
|
||||
margin-right: .625rem;
|
||||
.hulyHotKey-item { margin-right: .625rem; }
|
||||
|
||||
&.doubleRow {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
flex-shrink: 0;
|
||||
padding: 0 var(--spacing-2);
|
||||
|
||||
.hulyHeader-row { min-height: var(--spacing-6_5); }
|
||||
.hulyHeader-buttonsGroup.search { flex-direction: row-reverse; }
|
||||
.hulyHeader-buttonsGroup.actions { margin-left: 1rem; }
|
||||
}
|
||||
&:not(.doubleRow) {
|
||||
.hulyHeader-buttonsGroup:not(.before) { margin-left: 1rem; }
|
||||
.hulyHeader-buttonsGroup.search + .hulyHeader-divider + .hulyHeader-buttonsGroup.actions { margin-left: 0; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -916,13 +987,13 @@
|
||||
min-width: 0;
|
||||
|
||||
.ac-header {
|
||||
padding: 0.5rem 2.25rem;
|
||||
padding: var(--spacing-1) var(--spacing-2);
|
||||
// height: 3.5rem;
|
||||
// min-height: 2.5rem;
|
||||
|
||||
&:not(.withoutBackground) { background-color: var(--theme-comp-header-color); }
|
||||
&.caption-height { min-height: 3.25rem; }
|
||||
&.search-start { padding-left: 1.75rem; }
|
||||
&.caption-height { min-height: 3.5rem; }
|
||||
&.search-start { padding-left: var(--spacing-3); }
|
||||
&.tabs-start { padding: 0 2.25rem; }
|
||||
&.short {
|
||||
display: flex;
|
||||
@ -1382,14 +1453,14 @@
|
||||
&::-webkit-scrollbar-thumb { background-color: var(--scrollbar-bar-color); }
|
||||
|
||||
&.mask-none { mask-image: none }
|
||||
&.mask-left { mask-image: linear-gradient(to right, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 1) 1rem); }
|
||||
&.mask-right { mask-image: linear-gradient(to left, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 1) 1rem); }
|
||||
&.mask-left { mask-image: linear-gradient(to right, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 1) 2rem); }
|
||||
&.mask-right { mask-image: linear-gradient(to left, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 1) 2rem); }
|
||||
&.mask-both {
|
||||
mask-image: linear-gradient(
|
||||
to right,
|
||||
rgba(0, 0, 0, 0) 0,
|
||||
rgba(0, 0, 0, 1) 1rem,
|
||||
rgba(0, 0, 0, 1) calc(100% - 1rem),
|
||||
rgba(0, 0, 0, 1) 2rem,
|
||||
rgba(0, 0, 0, 1) calc(100% - 2rem),
|
||||
rgba(0, 0, 0, 0) 100%
|
||||
);
|
||||
}
|
||||
|
@ -61,7 +61,7 @@
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
&.small { padding-bottom: .75rem; }
|
||||
&.small { padding-bottom: var(--spacing-1_5); }
|
||||
}
|
||||
|
||||
.hulyNavGroup-container {
|
||||
@ -291,8 +291,13 @@
|
||||
height: 100%;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
border-radius: var(--small-focus-BorderRadius);
|
||||
|
||||
&:not(.rowContent) { flex-direction: column; }
|
||||
.panel-instance & {
|
||||
background-color: var(--theme-panel-color);
|
||||
border: 1px solid var(--theme-divider-color);
|
||||
}
|
||||
|
||||
.popupPanel-title {
|
||||
display: flex;
|
||||
@ -300,7 +305,7 @@
|
||||
justify-content: stretch;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
min-height: 3.25rem;
|
||||
min-height: 3.5rem;
|
||||
background-color: var(--theme-comp-header-color);
|
||||
border-bottom: 1px solid var(--theme-divider-color);
|
||||
|
||||
@ -347,7 +352,7 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: var(--theme-panel-color);
|
||||
border: 1px solid var(--theme-divider-color);
|
||||
// border: 1px solid var(--theme-divider-color);
|
||||
border-top: none;
|
||||
border-left: none;
|
||||
|
||||
@ -555,15 +560,6 @@
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
&.modern {
|
||||
border: 1px solid transparent;
|
||||
border-radius: var(--small-focus-BorderRadius);
|
||||
|
||||
.popupPanel-title {
|
||||
min-height: 3.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
overflow: visible;
|
||||
}
|
||||
|
@ -223,16 +223,15 @@
|
||||
margin-right: .5rem;
|
||||
}
|
||||
.icon,
|
||||
.check {
|
||||
div.check {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
color: var(--theme-dark-color);
|
||||
}
|
||||
.check {
|
||||
div.check {
|
||||
flex-shrink: 0;
|
||||
margin-left: .5rem;
|
||||
|
||||
&.ml-3 { margin-left: .75rem; }
|
||||
&:not(.ml-0) { margin-left: .5rem; }
|
||||
}
|
||||
.color {
|
||||
width: .875rem;
|
||||
|
@ -15,24 +15,17 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher, ComponentType } from 'svelte'
|
||||
import type { Asset, IntlString } from '@hcengineering/platform'
|
||||
import { AnySvelteComponent } from '../types'
|
||||
import { AnySvelteComponent, BreadcrumbItem } from '../types'
|
||||
import ChevronRight from './icons/ChevronRight.svelte'
|
||||
import Label from './Label.svelte'
|
||||
import Breadcrumb from './Breadcrumb.svelte'
|
||||
|
||||
interface BreadcrumbItem {
|
||||
icon?: Asset | AnySvelteComponent | ComponentType
|
||||
iconProps?: any
|
||||
iconWidth?: string
|
||||
withoutIconBackground?: boolean
|
||||
label?: IntlString
|
||||
title?: string
|
||||
}
|
||||
|
||||
export let items: BreadcrumbItem[]
|
||||
export let afterLabel: IntlString | undefined = undefined
|
||||
export let size: 'large' | 'small' = 'large'
|
||||
export let selected: number | null = null
|
||||
export let currentOnly: boolean = false
|
||||
export let hideAfter: boolean = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
</script>
|
||||
@ -43,13 +36,13 @@
|
||||
<Breadcrumb
|
||||
{...item}
|
||||
{size}
|
||||
isCurrent={selected === i}
|
||||
isCurrent={selected === i || currentOnly}
|
||||
on:click={() => {
|
||||
if (selected !== i) dispatch('select', i)
|
||||
}}
|
||||
/>
|
||||
{/each}
|
||||
{#if afterLabel || $$slots.afterLabel}
|
||||
{#if (afterLabel || $$slots.afterLabel) && !hideAfter}
|
||||
<span class="hulyBreadcrumbs-afterLabel font-medium-12">
|
||||
{#if afterLabel}<Label label={afterLabel} />{/if}
|
||||
<slot name="afterLabel" />
|
||||
@ -65,6 +58,7 @@
|
||||
min-width: 0;
|
||||
|
||||
.hulyBreadcrumbs-afterLabel {
|
||||
max-width: 10rem;
|
||||
white-space: nowrap;
|
||||
word-break: break-all;
|
||||
text-overflow: ellipsis;
|
||||
|
@ -63,6 +63,7 @@
|
||||
export let shrink: number = 0
|
||||
export let accent: boolean = false
|
||||
export let noFocus: boolean = false
|
||||
export let noPrint: boolean = false
|
||||
export let adaptiveShrink: WidthType | null = null
|
||||
export let gap: 'medium' | 'large' = 'medium'
|
||||
export let stopPropagation: boolean = true
|
||||
@ -128,6 +129,7 @@
|
||||
class="antiButton {kind} {size} jf-{justify} sh-{shape ?? 'no-shape'} bs-{borderStyle} gap-{gap}"
|
||||
class:only-icon={iconOnly || adaptive}
|
||||
class:no-focus={noFocus}
|
||||
class:no-print={noPrint}
|
||||
class:accent
|
||||
class:highlight
|
||||
class:pressed
|
||||
|
@ -34,6 +34,7 @@
|
||||
export let loading: boolean = false
|
||||
export let pressed: boolean = false
|
||||
export let hasMenu: boolean = false
|
||||
export let noPrint: boolean = false
|
||||
export let autoFocus: boolean = false
|
||||
export let type: ButtonBaseType
|
||||
export let inheritColor: boolean = false
|
||||
@ -42,6 +43,7 @@
|
||||
export let element: HTMLButtonElement | undefined = undefined
|
||||
export let shape: 'rectangle' | 'round' = 'rectangle'
|
||||
export let id: string | undefined = undefined
|
||||
export let dataId: string | undefined = undefined
|
||||
|
||||
let actualIconSize: IconSize = 'small'
|
||||
|
||||
@ -97,7 +99,9 @@
|
||||
class:inheritFont
|
||||
class:menu={hasMenu}
|
||||
class:iconOnly
|
||||
class:no-print={noPrint}
|
||||
disabled={loading || disabled}
|
||||
data-id={dataId}
|
||||
use:tp={tooltip}
|
||||
on:click|stopPropagation|preventDefault
|
||||
on:keydown
|
||||
@ -120,8 +124,7 @@
|
||||
flex-shrink: 0;
|
||||
gap: var(--spacing-1);
|
||||
|
||||
border: 1px;
|
||||
border-style: solid;
|
||||
border: 1px solid transparent;
|
||||
|
||||
&:not(:disabled, .loading) {
|
||||
cursor: pointer;
|
||||
|
@ -26,13 +26,14 @@
|
||||
export let disabled: boolean = false
|
||||
export let pressed: boolean = false
|
||||
export let hasMenu: boolean = false
|
||||
export let noPrint: boolean = false
|
||||
export let loading: boolean = false
|
||||
export let inheritColor: boolean = false
|
||||
export let tooltip: LabelAndProps | undefined = undefined
|
||||
export let focusIndex = -1
|
||||
export let id: string | undefined = undefined
|
||||
|
||||
let element: ButtonBase | undefined
|
||||
export let dataId: string | undefined = undefined
|
||||
export let element: HTMLButtonElement | undefined = undefined
|
||||
|
||||
export function focus () {
|
||||
element?.focus()
|
||||
@ -40,7 +41,7 @@
|
||||
</script>
|
||||
|
||||
<ButtonBase
|
||||
bind:this={element}
|
||||
bind:element
|
||||
type={'type-button-icon'}
|
||||
{kind}
|
||||
{iconSize}
|
||||
@ -52,9 +53,11 @@
|
||||
{inheritColor}
|
||||
{pressed}
|
||||
{hasMenu}
|
||||
{noPrint}
|
||||
{tooltip}
|
||||
{focusIndex}
|
||||
{id}
|
||||
{dataId}
|
||||
on:click
|
||||
on:keydown
|
||||
/>
|
||||
|
@ -32,6 +32,7 @@
|
||||
export let loading: boolean = false
|
||||
export let inheritColor: boolean = false
|
||||
export let noSelection: boolean = false
|
||||
export let noPrint: boolean = false
|
||||
export let autoSelectionIfOne: boolean = false
|
||||
export let tooltip: LabelAndProps | undefined = undefined
|
||||
|
||||
@ -41,6 +42,7 @@
|
||||
export let element: HTMLButtonElement | undefined = undefined
|
||||
export let focusIndex = -1
|
||||
export let id: string | undefined = undefined
|
||||
export let dataId: string | undefined = undefined
|
||||
|
||||
let opened: boolean = false
|
||||
|
||||
@ -89,11 +91,13 @@
|
||||
{icon}
|
||||
{iconProps}
|
||||
{disabled}
|
||||
{noPrint}
|
||||
{loading}
|
||||
{inheritColor}
|
||||
pressed={opened}
|
||||
{focusIndex}
|
||||
{id}
|
||||
{dataId}
|
||||
{tooltip}
|
||||
on:click={openPopup}
|
||||
/>
|
||||
|
@ -67,6 +67,7 @@
|
||||
{kind}
|
||||
{justify}
|
||||
{disabled}
|
||||
pressed={opened}
|
||||
showTooltip={{ label, direction: labelDirection }}
|
||||
on:click={() => {
|
||||
if (!opened) {
|
||||
@ -98,7 +99,12 @@
|
||||
}
|
||||
}}
|
||||
>
|
||||
<span slot="content" class="overflow-label disabled" class:content-color={selectedItem === undefined}>
|
||||
<span
|
||||
slot="content"
|
||||
class="overflow-label disabled"
|
||||
class:mr-2={showDropdownIcon}
|
||||
class:content-color={selectedItem === undefined}
|
||||
>
|
||||
{#if $$slots.content}
|
||||
<slot name="content" />
|
||||
{:else if Array.isArray(selectedItem)}
|
||||
|
@ -13,46 +13,161 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { IconMaximize, IconMinimize, IconClose, ButtonIcon, deviceOptionsStore as deviceInfo } from '..'
|
||||
import { createEventDispatcher, onMount, onDestroy } from 'svelte'
|
||||
import {
|
||||
IconMaximize,
|
||||
IconMinimize,
|
||||
IconClose,
|
||||
ButtonIcon,
|
||||
deviceOptionsStore as deviceInfo,
|
||||
resizeObserver
|
||||
} from '..'
|
||||
|
||||
export let type: 'type-aside' | 'type-popup' | 'type-component' | 'type-panel' = 'type-component'
|
||||
export let noResize: boolean = false
|
||||
export let allowFullsize: boolean = false
|
||||
export let hideSeparator: boolean = false
|
||||
export let topIndent: boolean = false
|
||||
export let adaptive: 'default' | 'freezeActions' | 'doubleRow' | 'disabled' = 'default'
|
||||
export let hideBefore: boolean = false
|
||||
export let hideDescription: boolean = false
|
||||
export let hideSearch: boolean = false
|
||||
export let hideActions: boolean = false
|
||||
export let hideExtra: boolean = false
|
||||
export let overflowExtra: boolean = false
|
||||
export let noPrint: boolean = false
|
||||
export let freezeBefore: boolean = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
const closeButton: boolean = ['type-popup', 'type-aside'].some((v) => v === type)
|
||||
let doubleRow: boolean = false
|
||||
|
||||
onMount(() => {
|
||||
if (closeButton) window.addEventListener('keydown', _close)
|
||||
})
|
||||
onDestroy(() => {
|
||||
if (closeButton) window.removeEventListener('keydown', _close)
|
||||
})
|
||||
|
||||
function _close (ev: KeyboardEvent): void {
|
||||
if (closeButton && ev.key === 'Escape') {
|
||||
ev.preventDefault()
|
||||
ev.stopPropagation()
|
||||
dispatch('close')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="hulyHeader-container" class:topIndent={type === 'type-panel'} class:hideSeparator>
|
||||
{#if type === 'type-component'}
|
||||
{#if !noResize}
|
||||
<button
|
||||
class="hulyHeader-button"
|
||||
on:click={() => ($deviceInfo.navigator.visible = !$deviceInfo.navigator.visible)}
|
||||
>
|
||||
{#if $deviceInfo.navigator.visible}
|
||||
<IconMaximize size={'small'} />
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
use:resizeObserver={(element) => {
|
||||
if (!doubleRow && element.clientWidth <= 768) doubleRow = true
|
||||
else if (doubleRow && element.clientWidth > 768) doubleRow = false
|
||||
}}
|
||||
class="hulyHeader-container"
|
||||
class:doubleRow={adaptive === 'doubleRow' || (adaptive !== 'disabled' && doubleRow)}
|
||||
class:topIndent
|
||||
class:clearPadding={$$slots.description}
|
||||
class:hideSeparator
|
||||
class:no-print={noPrint}
|
||||
>
|
||||
{#if adaptive === 'doubleRow' || (adaptive !== 'disabled' && doubleRow)}
|
||||
<div class="hulyHeader-row">
|
||||
{#if allowFullsize}
|
||||
<ButtonIcon
|
||||
icon={$deviceInfo.navigator.visible ? IconMaximize : IconMinimize}
|
||||
kind={'tertiary'}
|
||||
size={'small'}
|
||||
noPrint
|
||||
on:click={() => ($deviceInfo.navigator.visible = !$deviceInfo.navigator.visible)}
|
||||
/>
|
||||
<div class="hulyHeader-divider no-print" />
|
||||
{/if}
|
||||
{#if $$slots.beforeTitle && !hideBefore}
|
||||
<div class="hulyHeader-buttonsGroup before mr-2 no-print" class:freezeBefore>
|
||||
<slot name="beforeTitle" {doubleRow} />
|
||||
</div>
|
||||
{/if}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div class="hulyHeader-titleGroup" class:withDescription={$$slots.description && !hideDescription} on:click>
|
||||
{#if $$slots.description && !hideDescription}
|
||||
<div class="hulyHeader-titleGroup"><slot /></div>
|
||||
<div class="hulyHeader-titleGroup"><slot name="description" /></div>
|
||||
{:else}
|
||||
<IconMinimize size={'small'} />
|
||||
<slot />
|
||||
{/if}
|
||||
</button>
|
||||
{/if}
|
||||
<slot name="beforeTitle" />
|
||||
{#if !noResize || $$slots.beforeTitle}
|
||||
<div class="hulyHeader-divider" />
|
||||
{/if}
|
||||
{/if}
|
||||
<div class="hulyHeader-titleGroup">
|
||||
<slot />
|
||||
</div>
|
||||
{#if $$slots.actions}
|
||||
<div class="hulyHeader-buttonsGroup">
|
||||
<slot name="actions" />
|
||||
</div>
|
||||
{#if $$slots.actions && !hideActions && (adaptive === 'freezeActions' || adaptive === 'doubleRow')}
|
||||
<div class="hulyHeader-buttonsGroup actions no-print">
|
||||
<slot name="actions" {doubleRow} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if closeButton}
|
||||
{#if type !== 'type-popup'}<div class="hulyHeader-divider no-print" />{/if}
|
||||
<div class="hulyHotKey-item no-print">Esc</div>
|
||||
<ButtonIcon icon={IconClose} kind={'tertiary'} size={'small'} noPrint on:click={() => dispatch('close')} />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{#if type === 'type-popup' || type === 'type-aside'}
|
||||
{#if type !== 'type-popup'}<div class="hulyHeader-divider" />{/if}
|
||||
<div class="hulyHotKey-item">Esc</div>
|
||||
<ButtonIcon icon={IconClose} kind={'tertiary'} size={'small'} on:click={() => dispatch('close')} />
|
||||
<!-- <div class="hulyHeader-row__divider" /> -->
|
||||
<div class="hulyHeader-row no-print" class:between={$$slots.search} class:reverse={!$$slots.search}>
|
||||
{#if $$slots.search}
|
||||
<div class="hulyHeader-buttonsGroup search">
|
||||
<slot name="search" {doubleRow} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if $$slots.actions && !hideActions && adaptive !== 'freezeActions' && adaptive !== 'doubleRow'}
|
||||
<div class="hulyHeader-buttonsGroup actions">
|
||||
<slot name="actions" {doubleRow} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if $$slots.extra && !hideExtra && adaptive === 'doubleRow'}
|
||||
<div class="hulyHeader-buttonsGroup extra" class:overflow={overflowExtra}>
|
||||
<slot name="extra" {doubleRow} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
{#if allowFullsize}
|
||||
<ButtonIcon
|
||||
icon={$deviceInfo.navigator.visible ? IconMaximize : IconMinimize}
|
||||
kind={'tertiary'}
|
||||
size={'small'}
|
||||
noPrint
|
||||
on:click={() => ($deviceInfo.navigator.visible = !$deviceInfo.navigator.visible)}
|
||||
/>
|
||||
<div class="hulyHeader-divider no-print" />
|
||||
{/if}
|
||||
{#if $$slots.beforeTitle && !hideBefore}
|
||||
<div class="hulyHeader-buttonsGroup before mr-2 no-print">
|
||||
<slot name="beforeTitle" {doubleRow} />
|
||||
</div>
|
||||
{/if}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div class="hulyHeader-titleGroup" class:withDescription={$$slots.description && !hideDescription} on:click>
|
||||
{#if $$slots.description && !hideDescription}
|
||||
<slot />
|
||||
<slot name="description" />
|
||||
{:else}
|
||||
<slot />
|
||||
{/if}
|
||||
</div>
|
||||
{#if $$slots.search && !hideSearch}
|
||||
<div class="hulyHeader-buttonsGroup search no-print">
|
||||
<slot name="search" {doubleRow} />
|
||||
</div>
|
||||
{#if $$slots.actions && !hideActions}<div class="hulyHeader-divider no-print" />{/if}
|
||||
{/if}
|
||||
{#if $$slots.actions && !hideActions}
|
||||
<div class="hulyHeader-buttonsGroup actions no-print">
|
||||
<slot name="actions" {doubleRow} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if closeButton}
|
||||
{#if type !== 'type-popup'}<div class="hulyHeader-divider no-print" />{/if}
|
||||
<div class="hulyHotKey-item no-print">Esc</div>
|
||||
<ButtonIcon icon={IconClose} kind={'tertiary'} size={'small'} noPrint on:click={() => dispatch('close')} />
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -31,7 +31,9 @@
|
||||
export let okLabel: IntlString = ui.string.Ok
|
||||
export let padding: string | undefined = undefined
|
||||
export let hidden: boolean = false
|
||||
export let noResize: boolean = false
|
||||
export let allowFullsize: boolean = false
|
||||
export let hideFooter: boolean = false
|
||||
export let adaptive: 'default' | 'freezeActions' | 'doubleRow' | 'disabled' = 'disabled'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@ -54,7 +56,14 @@
|
||||
<svelte:window on:keydown={onKeyDown} />
|
||||
|
||||
<div class="hulyModal-container {type}" class:hidden>
|
||||
<Header {type} {noResize} on:close={close}>
|
||||
<Header
|
||||
{type}
|
||||
{allowFullsize}
|
||||
{adaptive}
|
||||
on:close={close}
|
||||
hideBefore={!$$slots.beforeTitle}
|
||||
hideActions={!$$slots.actions}
|
||||
>
|
||||
<svelte:fragment slot="beforeTitle">
|
||||
<slot name="beforeTitle" />
|
||||
</svelte:fragment>
|
||||
@ -78,7 +87,7 @@
|
||||
</Scroller>
|
||||
</div>
|
||||
<slot name="afterContent" />
|
||||
{#if type !== 'type-component'}
|
||||
{#if type !== 'type-component' && !hideFooter}
|
||||
<div class="hulyModal-footer">
|
||||
<ButtonBase
|
||||
type={'type-button'}
|
||||
|
@ -1,9 +1,10 @@
|
||||
<script lang="ts" generics="T extends string">
|
||||
import TabList from './TabList.svelte'
|
||||
import Switcher from './Switcher.svelte'
|
||||
import { IModeSelector } from '../utils'
|
||||
|
||||
export let props: IModeSelector
|
||||
export let kind: 'separated' | 'separated-free' = 'separated'
|
||||
export let kind: 'nuance' | 'subtle' = 'nuance'
|
||||
export let onlyIcons: boolean = false
|
||||
export let expansion: 'stretch' | 'default' = 'default'
|
||||
export let padding: string | undefined = undefined
|
||||
|
||||
@ -19,15 +20,13 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="ac-header withoutBackground tabs-start full" style:padding>
|
||||
<TabList
|
||||
items={modeList}
|
||||
selected={props.mode}
|
||||
{kind}
|
||||
{expansion}
|
||||
adaptiveShrink="sm"
|
||||
on:select={(result) => {
|
||||
if (result.detail !== undefined && result.detail.action) result.detail.action()
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Switcher
|
||||
name={'modeSelector'}
|
||||
items={modeList}
|
||||
selected={props.mode}
|
||||
{kind}
|
||||
{onlyIcons}
|
||||
on:select={(result) => {
|
||||
if (result.detail !== undefined && result.detail.action) result.detail.action()
|
||||
}}
|
||||
/>
|
||||
|
@ -16,18 +16,24 @@
|
||||
export let size: ButtonBaseSize = 'large'
|
||||
export let shape: 'rectangle' | 'round' = 'rectangle'
|
||||
export let icon: Asset | AnySvelteComponent | ComponentType | undefined = undefined
|
||||
export let iconProps: any | undefined = undefined
|
||||
export let iconSize: IconSize | undefined = undefined
|
||||
export let disabled: boolean = false
|
||||
export let loading: boolean = false
|
||||
export let pressed: boolean = false
|
||||
export let hasMenu: boolean = false
|
||||
export let noPrint: boolean = false
|
||||
export let autoFocus: boolean = false
|
||||
export let inheritFont: boolean = false
|
||||
export let focusIndex = -1
|
||||
export let tooltip: LabelAndProps | undefined = undefined
|
||||
export let element: HTMLButtonElement | undefined = undefined
|
||||
export let id: string | undefined = undefined
|
||||
export let dataId: string | undefined = undefined
|
||||
</script>
|
||||
|
||||
<ButtonBase
|
||||
bind:element
|
||||
type={'type-button'}
|
||||
{title}
|
||||
{shape}
|
||||
@ -36,15 +42,19 @@
|
||||
{kind}
|
||||
{size}
|
||||
{icon}
|
||||
{iconProps}
|
||||
{iconSize}
|
||||
{loading}
|
||||
{disabled}
|
||||
{pressed}
|
||||
{hasMenu}
|
||||
{noPrint}
|
||||
{inheritFont}
|
||||
{focusIndex}
|
||||
{tooltip}
|
||||
{autoFocus}
|
||||
{id}
|
||||
{dataId}
|
||||
on:click
|
||||
>
|
||||
<slot />
|
||||
|
@ -213,6 +213,7 @@
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
text-overflow: ellipsis;
|
||||
color: var(--input-TextColor);
|
||||
caret-color: var(--global-focus-BorderColor);
|
||||
background-color: transparent;
|
||||
|
@ -256,7 +256,7 @@
|
||||
background-color: var(--global-ui-hover-highlight-BackgroundColor);
|
||||
}
|
||||
&.selected {
|
||||
cursor: auto;
|
||||
cursor: default;
|
||||
background-color: var(--global-ui-highlight-BackgroundColor);
|
||||
|
||||
// &:not(.type-anchor-link) .hulyNavItem-label:not(.description) {
|
||||
|
@ -23,7 +23,8 @@
|
||||
ButtonGroup,
|
||||
Scroller,
|
||||
panelSeparators,
|
||||
ButtonItem
|
||||
ButtonItem,
|
||||
Header
|
||||
} from '../../'
|
||||
import IconClose from './icons/Close.svelte'
|
||||
import IconDetails from './icons/Details.svelte'
|
||||
@ -44,9 +45,14 @@
|
||||
export let useMaxWidth: boolean | undefined = undefined
|
||||
export let customAside: ButtonItem[] | undefined = undefined
|
||||
export let selectedAside: string | boolean = customAside ? customAside[0].id : isAside
|
||||
export let kind: 'default' | 'modern' = 'default'
|
||||
export let printHeader = true
|
||||
export let printAside = false
|
||||
export let adaptive: 'default' | 'freezeActions' | 'doubleRow' | 'disabled' = 'default'
|
||||
export let hideBefore: boolean = false
|
||||
export let hideSearch: boolean = true
|
||||
export let hideActions: boolean = false
|
||||
export let hideExtra: boolean = false
|
||||
export let overflowExtra: boolean = false
|
||||
|
||||
export function getAside (): string | boolean {
|
||||
if (customAside) return selectedAside
|
||||
@ -147,7 +153,7 @@
|
||||
|
||||
<div
|
||||
bind:this={el}
|
||||
class="popupPanel panel {kind}"
|
||||
class="popupPanel panel"
|
||||
class:withPageHeader={$$slots['page-header'] !== undefined}
|
||||
class:withPageFooter={$$slots['page-footer'] !== undefined}
|
||||
class:embedded
|
||||
@ -156,48 +162,45 @@
|
||||
checkPanel()
|
||||
}}
|
||||
>
|
||||
<div class="popupPanel-title" class:no-print={!printHeader} class:indent={allowClose}>
|
||||
{#if allowClose}
|
||||
<div class="no-print">
|
||||
<Header
|
||||
type={'type-panel'}
|
||||
noPrint={!printHeader}
|
||||
{adaptive}
|
||||
{hideBefore}
|
||||
{hideSearch}
|
||||
{hideActions}
|
||||
{hideExtra}
|
||||
{overflowExtra}
|
||||
>
|
||||
<svelte:fragment slot="beforeTitle">
|
||||
{#if allowClose}
|
||||
<Button
|
||||
id={'btnPClose'}
|
||||
focusIndex={10001}
|
||||
icon={IconClose}
|
||||
iconProps={{ size: 'medium' }}
|
||||
kind={'icon'}
|
||||
noPrint
|
||||
on:click={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
/>
|
||||
<div class="antiHSpacer x2" />
|
||||
</div>
|
||||
{/if}
|
||||
<div class="popupPanel-title__content">
|
||||
{#if !withoutTitle}<slot name="title" />{/if}
|
||||
</div>
|
||||
<slot name="pre-utils" />
|
||||
<div class="flex-row-center flex-no-shrink ml-3 no-print">
|
||||
<slot name="utils" />
|
||||
{#if $$slots.aside && isAside}
|
||||
{#if customAside}
|
||||
<ButtonGroup
|
||||
items={customAside}
|
||||
props={{ kind: 'icon', iconProps: { size: 'medium' } }}
|
||||
bind:selected={selectedAside}
|
||||
on:select={handleSelectAside}
|
||||
/>
|
||||
{:else}
|
||||
<Button
|
||||
id={'btnPAside'}
|
||||
focusIndex={10008}
|
||||
icon={IconDetails}
|
||||
iconProps={{ size: 'medium', filled: asideShown }}
|
||||
kind={'icon'}
|
||||
selected={asideShown}
|
||||
on:click={handleAside}
|
||||
/>
|
||||
{#if $$slots.beforeTitle}
|
||||
<div class="hulyHeader-divider short no-print" />
|
||||
{/if}
|
||||
{/if}
|
||||
<slot name="beforeTitle" />
|
||||
</svelte:fragment>
|
||||
|
||||
{#if !withoutTitle}<slot name="title" />{/if}
|
||||
|
||||
<svelte:fragment slot="search">
|
||||
<slot name="search" />
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="actions">
|
||||
<slot name="actions" />
|
||||
<slot name="pre-utils" />
|
||||
<slot name="utils" />
|
||||
{#if useMaxWidth !== undefined}
|
||||
<Button
|
||||
focusIndex={10009}
|
||||
@ -224,9 +227,32 @@
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
<slot name="post-utils" />
|
||||
</div>
|
||||
{#if $$slots.aside && isAside}
|
||||
{#if customAside}
|
||||
<ButtonGroup
|
||||
items={customAside}
|
||||
props={{ kind: 'icon', iconProps: { size: 'medium' } }}
|
||||
bind:selected={selectedAside}
|
||||
on:select={handleSelectAside}
|
||||
/>
|
||||
{:else}
|
||||
<Button
|
||||
id={'btnPAside'}
|
||||
focusIndex={10008}
|
||||
icon={IconDetails}
|
||||
iconProps={{ size: 'medium', filled: asideShown }}
|
||||
kind={'icon'}
|
||||
selected={asideShown}
|
||||
on:click={handleAside}
|
||||
/>
|
||||
{/if}
|
||||
{/if}
|
||||
<slot name="post-utils" />
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="extra">
|
||||
<slot name="extra" />
|
||||
</svelte:fragment>
|
||||
</Header>
|
||||
<div class="popupPanel-body {$deviceInfo.isMobile ? 'mobile' : 'main'}" class:asideShown>
|
||||
{#if $deviceInfo.isMobile}
|
||||
<Scroller horizontal padding={'.5rem .75rem'}>
|
||||
|
@ -24,7 +24,6 @@
|
||||
import Spinner from './Spinner.svelte'
|
||||
|
||||
export let contentPanel: HTMLElement | undefined
|
||||
export let kind: 'default' | 'modern' = 'default'
|
||||
export let embedded: boolean = false
|
||||
export let readonly: boolean = false
|
||||
|
||||
@ -181,7 +180,6 @@
|
||||
_class={props._class}
|
||||
rightSection={props.rightSection}
|
||||
position={props.element}
|
||||
{kind}
|
||||
{readonly}
|
||||
{embedded}
|
||||
bind:popupOptions={options}
|
||||
|
@ -13,39 +13,77 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher, onDestroy } from 'svelte'
|
||||
import type { IntlString } from '@hcengineering/platform'
|
||||
import { translate } from '@hcengineering/platform'
|
||||
import { themeStore } from '@hcengineering/theme'
|
||||
import IconSearch from './icons/Search.svelte'
|
||||
import IconClose from './icons/Close.svelte'
|
||||
import plugin from '../plugin'
|
||||
|
||||
export let value: string | undefined = undefined
|
||||
export let placeholder: string
|
||||
export let placeholder: IntlString = plugin.string.Search
|
||||
export let placeholderParam: any | undefined = undefined
|
||||
export let collapsed: boolean = false
|
||||
|
||||
let input: HTMLInputElement
|
||||
let phTranslate: string = ''
|
||||
|
||||
$: void translate(placeholder, placeholderParam ?? {}, $themeStore.language).then((res) => {
|
||||
phTranslate = res
|
||||
})
|
||||
|
||||
$: _search = value
|
||||
const dispatch = createEventDispatcher()
|
||||
let timer: any
|
||||
|
||||
function restartTimer (): void {
|
||||
clearTimeout(timer)
|
||||
timer = setTimeout(() => {
|
||||
value = _search
|
||||
dispatch('change', _search)
|
||||
}, 500)
|
||||
}
|
||||
onDestroy(() => {
|
||||
clearTimeout(timer)
|
||||
})
|
||||
</script>
|
||||
|
||||
<label class="searchInput-wrapper" class:collapsed class:filled={value && value !== ''}>
|
||||
<div class="searchInput-icon">
|
||||
<div><IconSearch size={'small'} /></div>
|
||||
<IconSearch size={'small'} />
|
||||
</div>
|
||||
<input
|
||||
bind:this={input}
|
||||
type="text"
|
||||
class="font-regular-14"
|
||||
bind:value
|
||||
{placeholder}
|
||||
bind:value={_search}
|
||||
placeholder={phTranslate}
|
||||
autocomplete="off"
|
||||
spellcheck="false"
|
||||
on:change
|
||||
on:input
|
||||
on:change={() => {
|
||||
restartTimer()
|
||||
}}
|
||||
on:input={() => {
|
||||
restartTimer()
|
||||
}}
|
||||
on:keydown={(evt) => {
|
||||
if (evt.key === 'Enter') {
|
||||
clearTimeout(timer)
|
||||
value = _search
|
||||
dispatch('change', _search)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
class="searchInput-button"
|
||||
on:click={() => {
|
||||
value = ''
|
||||
dispatch('change', '')
|
||||
input.focus()
|
||||
}}
|
||||
>
|
||||
<div><IconClose size={'small'} /></div>
|
||||
<IconClose size={'small'} />
|
||||
</button>
|
||||
</label>
|
||||
|
||||
@ -56,11 +94,11 @@
|
||||
align-items: center;
|
||||
align-self: stretch;
|
||||
padding: 0 var(--spacing-0_5) 0 0;
|
||||
height: var(--spacing-4);
|
||||
min-width: var(--spacing-4);
|
||||
background-color: var(--input-BackgroundColor);
|
||||
height: var(--global-small-Size);
|
||||
min-width: var(--global-small-Size);
|
||||
background-color: var(--theme-button-default); // var(--input-BackgroundColor);
|
||||
border-radius: var(--small-BorderRadius);
|
||||
box-shadow: inset 0 0 0 1px var(--input-BorderColor);
|
||||
box-shadow: inset 0 0 0 1px var(--theme-button-border); // var(--input-BorderColor);
|
||||
transition: max-width 0.2s;
|
||||
cursor: text;
|
||||
|
||||
@ -75,15 +113,15 @@
|
||||
border: none;
|
||||
|
||||
div {
|
||||
width: var(--spacing-2);
|
||||
height: var(--spacing-2);
|
||||
width: var(--global-min-Size);
|
||||
height: var(--global-min-Size);
|
||||
}
|
||||
}
|
||||
.searchInput-icon {
|
||||
margin: 0 var(--spacing-0_5) 0 0;
|
||||
width: var(--spacing-4);
|
||||
height: var(--spacing-4);
|
||||
fill: var(--input-search-IconColor);
|
||||
width: var(--global-small-Size);
|
||||
height: var(--global-small-Size);
|
||||
color: var(--input-search-IconColor);
|
||||
border-radius: var(--small-BorderRadius);
|
||||
outline: none;
|
||||
cursor: text;
|
||||
@ -95,9 +133,9 @@
|
||||
}
|
||||
.searchInput-button {
|
||||
visibility: hidden;
|
||||
width: var(--spacing-3);
|
||||
height: var(--spacing-3);
|
||||
fill: var(--global-primary-TextColor);
|
||||
width: var(--global-extra-small-Size);
|
||||
height: var(--global-extra-small-Size);
|
||||
color: var(--global-primary-TextColor);
|
||||
border-radius: var(--extra-small-BorderRadius);
|
||||
cursor: pointer;
|
||||
|
||||
@ -108,10 +146,6 @@
|
||||
background-color: var(--button-tertiary-active-BackgroundColor);
|
||||
border-color: var(--button-menu-active-BorderColor);
|
||||
}
|
||||
&:focus {
|
||||
outline: 2px solid var(--global-focus-BorderColor);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
@ -128,7 +162,7 @@
|
||||
appearance: none;
|
||||
|
||||
&::placeholder {
|
||||
color: var(--input-PlaceholderColor);
|
||||
color: var(--theme-trans-color); // var(--input-PlaceholderColor);
|
||||
}
|
||||
&:not(:placeholder-shown) + .searchInput-button {
|
||||
visibility: visible;
|
||||
@ -139,25 +173,25 @@
|
||||
background-color: var(--input-hover-BackgroundColor);
|
||||
|
||||
input::placeholder {
|
||||
color: var(--input-hover-PlaceholderColor);
|
||||
color: var(--theme-darker-color); // var(--input-hover-PlaceholderColor);
|
||||
}
|
||||
}
|
||||
&:active,
|
||||
&:focus-within {
|
||||
padding: 0 var(--spacing-0_5) 0 0;
|
||||
max-width: 100%;
|
||||
max-width: 15rem;
|
||||
background-color: var(--input-BackgroundColor);
|
||||
outline: 2px solid var(--global-focus-BorderColor);
|
||||
outline-offset: 2px;
|
||||
|
||||
input::placeholder {
|
||||
color: var(--input-focus-PlaceholderColor);
|
||||
color: var(--theme-darker-color); // var(--input-focus-PlaceholderColor);
|
||||
}
|
||||
}
|
||||
|
||||
&.collapsed:not(:focus-within, :active, .filled) {
|
||||
padding: 0;
|
||||
max-width: var(--spacing-4);
|
||||
max-width: var(--global-small-Size);
|
||||
|
||||
.searchInput-icon {
|
||||
cursor: pointer;
|
||||
|
55
packages/ui/src/components/Switcher.svelte
Normal file
@ -0,0 +1,55 @@
|
||||
<script lang="ts">
|
||||
//
|
||||
// © 2023 Hardcore Engineering, Inc. All Rights Reserved.
|
||||
// Licensed under the Eclipse Public License v2.0 (SPDX: EPL-2.0).
|
||||
//
|
||||
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import type { TabItem } from '../types'
|
||||
import SwitcherBase from './SwitcherBase.svelte'
|
||||
|
||||
export let items: TabItem[]
|
||||
export let selected: string | number = ''
|
||||
export let kind: 'nuance' | 'subtle' = 'nuance'
|
||||
export let name: string
|
||||
export let onlyIcons: boolean = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
</script>
|
||||
|
||||
<div class="switcher-container {kind}">
|
||||
{#each items as item}
|
||||
<SwitcherBase
|
||||
id={item.id}
|
||||
{name}
|
||||
{kind}
|
||||
checked={selected === item.id}
|
||||
icon={item.icon}
|
||||
color={item.color}
|
||||
title={onlyIcons ? undefined : item.label}
|
||||
label={onlyIcons ? undefined : item.labelIntl}
|
||||
labelParams={onlyIcons ? undefined : item.labelParams}
|
||||
tooltip={item.tooltip ? { label: item.tooltip } : undefined}
|
||||
on:change={() => {
|
||||
dispatch('select', item)
|
||||
if (item.action !== undefined) item.action()
|
||||
}}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.switcher-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
flex-shrink: 0;
|
||||
min-width: 0;
|
||||
gap: var(--spacing-0_5);
|
||||
border-radius: var(--small-BorderRadius);
|
||||
|
||||
&.subtle {
|
||||
background-color: var(--selector-BackgroundColor);
|
||||
}
|
||||
}
|
||||
</style>
|
116
packages/ui/src/components/SwitcherBase.svelte
Normal file
@ -0,0 +1,116 @@
|
||||
<script lang="ts">
|
||||
//
|
||||
// © 2023 Hardcore Engineering, Inc. All Rights Reserved.
|
||||
// Licensed under the Eclipse Public License v2.0 (SPDX: EPL-2.0).
|
||||
//
|
||||
|
||||
import type { Asset, IntlString } from '@hcengineering/platform'
|
||||
import type { AnySvelteComponent, LabelAndProps } from '../types'
|
||||
import type { ComponentType } from 'svelte'
|
||||
import Icon from './Icon.svelte'
|
||||
import Label from './Label.svelte'
|
||||
import { tooltip as tp } from '..'
|
||||
|
||||
export let id: string | number
|
||||
export let icon: Asset | AnySvelteComponent | ComponentType | undefined = undefined
|
||||
export let color: string | undefined = undefined
|
||||
export let label: IntlString | undefined = undefined
|
||||
export let labelParams: Record<string, any> = {}
|
||||
export let title: string | undefined = undefined
|
||||
export let kind: 'nuance' | 'subtle' = 'nuance'
|
||||
export let name: string
|
||||
export let checked: boolean = false
|
||||
export let tooltip: LabelAndProps | undefined = undefined
|
||||
|
||||
$: woTitle = title === undefined && label === undefined
|
||||
</script>
|
||||
|
||||
<label use:tp={tooltip} class="switcher-element__wrapper" data-view={tooltip?.label} data-id={`tab-${id}`}>
|
||||
<input type="radio" class="switcher" {name} {checked} on:change />
|
||||
<div class="switcher-element {kind}" class:woTitle>
|
||||
{#if icon}<div class="icon"><Icon {icon} size={'small'} fill={color} /></div>{/if}
|
||||
{#if label}<span><Label {label} params={labelParams} /></span>{/if}
|
||||
{#if title}<span>{title}</span>{/if}
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<style lang="scss">
|
||||
.switcher-element,
|
||||
.switcher-element__wrapper {
|
||||
display: flex;
|
||||
min-width: var(--global-small-Size);
|
||||
min-height: var(--global-small-Size);
|
||||
}
|
||||
.switcher-element {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
flex-shrink: 0;
|
||||
gap: var(--spacing-0_75);
|
||||
border-radius: var(--small-BorderRadius);
|
||||
|
||||
&:not(.woTitle) {
|
||||
padding: 0 var(--spacing-1_5);
|
||||
}
|
||||
&.woTitle {
|
||||
padding: 0 var(--spacing-1);
|
||||
}
|
||||
.icon {
|
||||
width: var(--spacing-2);
|
||||
height: var(--spacing-2);
|
||||
color: var(--global-secondary-IconColor);
|
||||
}
|
||||
span {
|
||||
text-wrap: nowrap;
|
||||
color: var(--global-secondary-TextColor);
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
.switcher {
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
margin: -1px;
|
||||
padding: 0;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
border: 0;
|
||||
clip: rect(0 0 0 0);
|
||||
|
||||
&:checked + .switcher-element.nuance {
|
||||
background-color: var(--global-accent-BackgroundColor);
|
||||
|
||||
.icon {
|
||||
color: var(--global-on-nuance-TextColor);
|
||||
}
|
||||
span {
|
||||
color: var(--global-on-nuance-TextColor);
|
||||
}
|
||||
}
|
||||
&:checked + .switcher-element.subtle {
|
||||
background-color: var(--global-ui-active-BackgroundColor);
|
||||
|
||||
.icon {
|
||||
color: var(--global-primary-IconColor);
|
||||
}
|
||||
span {
|
||||
color: var(--global-primary-TextColor);
|
||||
}
|
||||
}
|
||||
&:focus + .switcher-element {
|
||||
box-shadow: 0 0 0 var(--spacing-0_25) var(--global-focus-inset-BorderColor);
|
||||
outline: var(--spacing-0_25) solid var(--global-focus-BorderColor);
|
||||
outline-offset: var(--spacing-0_25);
|
||||
}
|
||||
}
|
||||
.switcher-element__wrapper:hover .switcher-element {
|
||||
background-color: var(--selector-BackgroundColor);
|
||||
cursor: pointer;
|
||||
|
||||
.icon {
|
||||
color: var(--global-primary-IconColor);
|
||||
}
|
||||
span {
|
||||
color: var(--global-primary-TextColor);
|
||||
}
|
||||
}
|
||||
</style>
|
@ -21,7 +21,7 @@
|
||||
import DropdownLabelsIntl from './DropdownLabelsIntl.svelte'
|
||||
import { Scroller, checkAdaptiveMatching, deviceOptionsStore as deviceInfo } from '..'
|
||||
|
||||
export let selected: string | string[] = ''
|
||||
export let selected: string | number | Array<string | number> = ''
|
||||
export let multiselect: boolean = false
|
||||
export let items: TabItem[]
|
||||
export let kind: 'normal' | 'regular' | 'plain' | 'separated' | 'separated-free' = 'normal'
|
||||
@ -37,7 +37,7 @@
|
||||
if (multiselect && selected === '') selected = []
|
||||
if (selected === '') selected = items[0].id
|
||||
|
||||
const getSelected = (id: string, selected: string | string[]): boolean => {
|
||||
const getSelected = (id: string | number, selected: string | number | Array<string | number>): boolean => {
|
||||
let res: boolean = false
|
||||
if (multiselect && Array.isArray(selected)) res = selected.filter((it) => it === id).length > 0
|
||||
else if (selected === id) res = true
|
||||
|
@ -19,8 +19,8 @@
|
||||
const fill: string = 'currentColor'
|
||||
</script>
|
||||
|
||||
<svg class="svg-{size}" {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="1" y="3.5" width="14" height="1.5" />
|
||||
<rect x="2.5" y="7.5" width="11" height="1.5" />
|
||||
<rect x="4.5" y="11.5" width="7" height="1.5" />
|
||||
<svg class="svg-{size}" {fill} viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M29.9,4.1c-0.1-0.4-0.4-0.8-0.7-1.1c-0.3-0.3-0.7-0.5-1.1-0.7c-0.1,0-0.2-0.1-0.3-0.1H4.2c-0.1,0-0.2,0-0.3,0.1C3.5,2.5,3.1,2.7,2.8,3C2.5,3.3,2.3,3.7,2.1,4.1C2,4.5,2,5,2,5.4c0.1,0.4,0.2,0.8,0.5,1.2c0,0,0.1,0.1,0.1,0.1l8.8,9.7v6.9c0,0.3,0.1,0.6,0.4,0.8l7.3,5.4c0.2,0.1,0.4,0.2,0.6,0.2c0.2,0,0.3,0,0.4-0.1c0.3-0.2,0.6-0.5,0.6-0.9V16.4l8.8-9.7c0,0,0.1-0.1,0.1-0.1c0.2-0.4,0.4-0.8,0.5-1.2C30,5,30,4.5,29.9,4.1z M27.9,5.4l-9,9.9c-0.2,0.2-0.3,0.4-0.3,0.7v10.7l-5.3-3.9V16c0-0.2-0.1-0.5-0.3-0.7l-9-9.9C4.1,5.3,4,5.2,4,5.1C4,5,4,4.9,4,4.8c0-0.1,0.1-0.2,0.2-0.3c0.1-0.1,0.1-0.1,0.2-0.1h23.2c0.1,0,0.1,0.1,0.2,0.1c0.1,0.1,0.2,0.2,0.2,0.3C28,4.9,28,5,28,5.1C28,5.2,27.9,5.3,27.9,5.4z"
|
||||
/>
|
||||
</svg>
|
||||
|
@ -36,6 +36,7 @@ export type {
|
||||
ButtonItem,
|
||||
IconSize,
|
||||
TabItem,
|
||||
BreadcrumbItem,
|
||||
DeviceOptions,
|
||||
TSeparatedItem,
|
||||
SeparatedItem,
|
||||
@ -102,6 +103,9 @@ export { default as Row } from './components/Row.svelte'
|
||||
export { default as EditWithIcon } from './components/EditWithIcon.svelte'
|
||||
export { default as SearchEdit } from './components/SearchEdit.svelte'
|
||||
export { default as SearchPicker } from './components/SearchPicker.svelte'
|
||||
export { default as SearchInput } from './components/SearchInput.svelte'
|
||||
export { default as Switcher } from './components/Switcher.svelte'
|
||||
export { default as SwitcherBase } from './components/SwitcherBase.svelte'
|
||||
export { default as Chip } from './components/Chip.svelte'
|
||||
export { default as Loading } from './components/Loading.svelte'
|
||||
export { default as Spinner } from './components/Spinner.svelte'
|
||||
|
@ -115,7 +115,7 @@ export interface Tab extends TabBase {
|
||||
export type TabModel = Tab[]
|
||||
|
||||
export interface TabItem {
|
||||
id: string
|
||||
id: string | number
|
||||
label?: string
|
||||
labelIntl?: IntlString
|
||||
labelParams?: Record<string, any>
|
||||
@ -125,6 +125,15 @@ export interface TabItem {
|
||||
action?: () => void
|
||||
}
|
||||
|
||||
export interface BreadcrumbItem {
|
||||
icon?: Asset | AnySvelteComponent | ComponentType
|
||||
iconProps?: any
|
||||
iconWidth?: string
|
||||
withoutIconBackground?: boolean
|
||||
label?: IntlString
|
||||
title?: string
|
||||
}
|
||||
|
||||
export interface RadioItem {
|
||||
id?: string
|
||||
label?: string
|
||||
|
@ -174,7 +174,7 @@
|
||||
<MessageTimestamp date={message.createdOn ?? message.modifiedOn} shortTime />
|
||||
</span>
|
||||
{:else}
|
||||
<div class="min-w-6 mt-1 relative">
|
||||
<div class="min-w-6 mt-1 relative flex-no-shrink">
|
||||
{#if $$slots.icon}
|
||||
<slot name="icon" />
|
||||
{:else if person}
|
||||
|
@ -24,7 +24,7 @@
|
||||
"FileBrowserFilterIn": "In",
|
||||
"FileBrowserFilterDate": "Date",
|
||||
"FileBrowserFilterFileType": "File type",
|
||||
"FileBrowserSort": "Sort:",
|
||||
"FileBrowserSort": "Sort",
|
||||
"FileBrowserSortNewest": "Newest file",
|
||||
"FileBrowserSortOldest": "Oldest file",
|
||||
"FileBrowserSortAZ": "A to Z",
|
||||
|
@ -24,7 +24,7 @@
|
||||
"FileBrowserFilterIn": "En",
|
||||
"FileBrowserFilterDate": "Fecha",
|
||||
"FileBrowserFilterFileType": "Tipo de archivo",
|
||||
"FileBrowserSort": "Ordenar:",
|
||||
"FileBrowserSort": "Ordenar",
|
||||
"FileBrowserSortNewest": "Archivo más reciente",
|
||||
"FileBrowserSortOldest": "Archivo más antiguo",
|
||||
"FileBrowserSortAZ": "A a Z",
|
||||
|
@ -24,7 +24,7 @@
|
||||
"FileBrowserFilterIn": "Dans",
|
||||
"FileBrowserFilterDate": "Date",
|
||||
"FileBrowserFilterFileType": "Type de fichier",
|
||||
"FileBrowserSort": "Trier :",
|
||||
"FileBrowserSort": "Trier",
|
||||
"FileBrowserSortNewest": "Fichier le plus récent",
|
||||
"FileBrowserSortOldest": "Fichier le plus ancien",
|
||||
"FileBrowserSortAZ": "A à Z",
|
||||
|
@ -24,7 +24,7 @@
|
||||
"FileBrowserFilterIn": "Em",
|
||||
"FileBrowserFilterDate": "Data",
|
||||
"FileBrowserFilterFileType": "Tipo de ficheiro",
|
||||
"FileBrowserSort": "Ordenar:",
|
||||
"FileBrowserSort": "Ordenar",
|
||||
"FileBrowserSortNewest": "Ficheiro mais recente",
|
||||
"FileBrowserSortOldest": "Ficheiro mais antigo",
|
||||
"FileBrowserSortAZ": "A a Z",
|
||||
|
@ -24,7 +24,7 @@
|
||||
"FileBrowserFilterIn": "В",
|
||||
"FileBrowserFilterDate": "Дата",
|
||||
"FileBrowserFilterFileType": "Тип файла",
|
||||
"FileBrowserSort": "Сортировка:",
|
||||
"FileBrowserSort": "Сортировка",
|
||||
"FileBrowserSortNewest": "Самый новый файл",
|
||||
"FileBrowserSortOldest": "Самый старый файл",
|
||||
"FileBrowserSortAZ": "От А до Я",
|
||||
|
@ -24,7 +24,7 @@
|
||||
"FileBrowserFilterIn": "在",
|
||||
"FileBrowserFilterDate": "日期",
|
||||
"FileBrowserFilterFileType": "文件类型",
|
||||
"FileBrowserSort": "排序:",
|
||||
"FileBrowserSort": "排序",
|
||||
"FileBrowserSortNewest": "最新文件",
|
||||
"FileBrowserSortOldest": "最旧文件",
|
||||
"FileBrowserSortAZ": "A 到 Z",
|
||||
|
@ -75,9 +75,10 @@
|
||||
.attachmentRow {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
margin: 0.5rem 1.5rem;
|
||||
padding: 0.5rem;
|
||||
border: 1px solid var(--divider-color);
|
||||
border: 1px solid var(--theme-divider-color);
|
||||
border-radius: 0.5rem;
|
||||
|
||||
.eAttachmentRowActions {
|
||||
|
@ -121,12 +121,7 @@
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="ac-header full divide search-start">
|
||||
<div class="ac-header-full small-gap">
|
||||
<SearchEdit bind:value={search} on:change={() => {}} />
|
||||
<!-- <ActionIcon icon={IconMoreH} size={'small'} /> -->
|
||||
<div class="buttons-divider" />
|
||||
</div>
|
||||
<div class="hulyHeader-container background-comp-header-color">
|
||||
<FileBrowserFilters
|
||||
{requestedSpaceClasses}
|
||||
{spaceId}
|
||||
@ -136,13 +131,13 @@
|
||||
bind:selectedFileTypeId
|
||||
/>
|
||||
</div>
|
||||
<div class="hulyHeader-container justify-between">
|
||||
<span class="caption-color ml-4">
|
||||
<Label label={attachment.string.FileBrowserFileCounter} params={{ results: attachments?.length ?? 0 }} />
|
||||
</span>
|
||||
<FileBrowserSortMenu bind:selectedSort />
|
||||
</div>
|
||||
<div class="group">
|
||||
<div class="groupHeader">
|
||||
<div class="eGroupHeaderCount">
|
||||
<Label label={attachment.string.FileBrowserFileCounter} params={{ results: attachments?.length ?? 0 }} />
|
||||
</div>
|
||||
<FileBrowserSortMenu bind:selectedSort />
|
||||
</div>
|
||||
{#if isLoading}
|
||||
<div class="flex-grow">
|
||||
<Loading />
|
||||
@ -168,15 +163,4 @@
|
||||
padding: 1rem 0 1rem 0.5rem;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.groupHeader {
|
||||
margin: 0 1.5rem 0.75rem 1.5rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.eGroupHeaderCount {
|
||||
font-size: 0.75rem;
|
||||
color: var(--caption-color);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -44,7 +44,7 @@
|
||||
<SpaceMultiBoxList
|
||||
_classes={requestedSpaceClasses}
|
||||
label={attachment.string.FileBrowserFilterIn}
|
||||
selectedItems={spaceId ? [spaceId] : []}
|
||||
selectedItems={selectedSpaces}
|
||||
kind={'ghost'}
|
||||
size={'medium'}
|
||||
on:update={(evt) => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import { Label, Menu, showPopup } from '@hcengineering/ui'
|
||||
import { Label, Menu, showPopup, ModernButton, IconOptions } from '@hcengineering/ui'
|
||||
import { FileBrowserSortMode } from '..'
|
||||
import attachment from '../plugin'
|
||||
|
||||
@ -71,15 +71,12 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div class="sortMenu" on:click={(event) => showSortMenu(event)}>
|
||||
<Label label={attachment.string.FileBrowserSort} />
|
||||
<Label label={sortModeToString(selectedSort)} />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.sortMenu {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
<ModernButton
|
||||
icon={IconOptions}
|
||||
iconSize={'small'}
|
||||
label={sortModeToString(selectedSort)}
|
||||
kind={'tertiary'}
|
||||
size={'small'}
|
||||
tooltip={{ label: attachment.string.FileBrowserSort }}
|
||||
on:click={(event) => showSortMenu(event)}
|
||||
/>
|
||||
|
@ -2,6 +2,9 @@
|
||||
<symbol id="calendar" viewBox="0 0 32 32">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M28 24.0044C28 26.2136 26.2091 28 24 28H8C5.79086 28 4 26.2091 4 24V8C4 5.79086 5.79086 4 8 4H10V3C10 2.44772 10.4477 2 11 2C11.5523 2 12 2.44772 12 3V4H19.9995V3C19.9995 2.44772 20.4472 2 20.9995 2C21.5518 2 21.9995 2.44772 21.9995 3V4H24C26.2091 4 28 5.79086 28 8C28 11.5569 28 19.2641 28 24.0044ZM19.9995 6V7C19.9995 7.55228 20.4472 8 20.9995 8C21.5518 8 21.9995 7.55228 21.9995 7V6H24C25.1046 6 26 6.89543 26 8V12H6V8C6 6.89543 6.89543 6 8 6H10V7C10 7.55228 10.4477 8 11 8C11.5523 8 12 7.55228 12 7V6H19.9995ZM6 14V24C6 25.1046 6.89543 26 8 26H24C25.1046 26 26 25.1046 26 24V14H6Z" />
|
||||
</symbol>
|
||||
<symbol id="calendarView" viewBox="0 0 32 32">
|
||||
<path d="M24.7,4.9h-1.9V3c0-0.6-0.4-1-1-1s-1,0.4-1,1v1.9h-9.6V3c0-0.6-0.4-1-1-1s-1,0.4-1,1v1.9H7.3c-2.1,0-3.9,1.7-3.9,3.9v17.3c0,2.1,1.7,3.9,3.9,3.9h17.3c2.1,0,3.9-1.7,3.9-3.9V8.8C28.6,6.6,26.8,4.9,24.7,4.9z M7.3,6.9h1.9v1.9c0,0.6,0.4,1,1,1s1-0.4,1-1V6.9h9.6v1.9c0,0.6,0.4,1,1,1s1-0.4,1-1V6.9h1.9c1,0,1.9,0.8,1.9,1.9v4.8H5.4V8.8C5.4,7.7,6.3,6.9,7.3,6.9z M24.7,28H7.3c-1,0-1.9-0.8-1.9-1.9V15.6h21.1v10.6C26.6,27.2,25.7,28,24.7,28z" />
|
||||
</symbol>
|
||||
<symbol id="location" viewBox="0 0 16 16">
|
||||
<path d="M8,4.6c-1.5,0-2.6,1.2-2.6,2.6S6.5,9.9,8,9.9s2.6-1.2,2.6-2.6S9.5,4.6,8,4.6z M8,8.9c-0.9,0-1.6-0.7-1.6-1.6 c0-0.9,0.7-1.6,1.6-1.6s1.6,0.7,1.6,1.6C9.6,8.2,8.9,8.9,8,8.9z"/>
|
||||
<path d="M8,1.8c-3,0-5.5,2.5-5.5,5.5c0,1.9,0.9,3.4,2,4.5c1.1,1.1,2.3,1.8,2.9,2.1c0.4,0.2,0.9,0.2,1.3,0c0.6-0.3,1.8-1,2.9-2.1 c1.1-1.1,2-2.6,2-4.5C13.5,4.3,11,1.8,8,1.8z M10.8,11.1c-1,1-2.1,1.7-2.6,2c-0.1,0.1-0.2,0.1-0.3,0c-0.6-0.3-1.7-1-2.6-2 c-1-1-1.7-2.3-1.7-3.8c0-2.5,2-4.5,4.5-4.5s4.5,2,4.5,4.5C12.5,8.8,11.7,10.1,10.8,11.1z"/>
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@ -19,6 +19,7 @@ import { loadMetadata } from '@hcengineering/platform'
|
||||
const icons = require('../assets/icons.svg') as string // eslint-disable-line
|
||||
loadMetadata(calendar.icon, {
|
||||
Calendar: `${icons}#calendar`,
|
||||
CalendarView: `${icons}#calendarView`,
|
||||
Reminder: `${icons}#reminder`,
|
||||
Notifications: `${icons}#notifications`,
|
||||
Location: `${icons}#location`,
|
||||
|
@ -15,8 +15,18 @@
|
||||
<script lang="ts">
|
||||
import { Event } from '@hcengineering/calendar'
|
||||
import { Class, DocumentQuery, Ref, Space, WithLookup } from '@hcengineering/core'
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import { AnyComponent, Button, Component, IconAdd, Label, Loading, showPopup } from '@hcengineering/ui'
|
||||
import { IntlString, Asset } from '@hcengineering/platform'
|
||||
import {
|
||||
AnyComponent,
|
||||
Button,
|
||||
Component,
|
||||
IconAdd,
|
||||
Label,
|
||||
Loading,
|
||||
showPopup,
|
||||
Header,
|
||||
Breadcrumb
|
||||
} from '@hcengineering/ui'
|
||||
import { Viewlet, ViewletPreference } from '@hcengineering/view'
|
||||
import { ViewletSelector, getViewOptions, viewOptionStore } from '@hcengineering/view-resources'
|
||||
import calendar from '../plugin'
|
||||
@ -26,7 +36,7 @@
|
||||
export let space: Ref<Space> | undefined = undefined
|
||||
export let query: DocumentQuery<Event> = {}
|
||||
|
||||
// export let viewIcon: Asset = calendar.icon.Calendar
|
||||
export let viewIcon: Asset = calendar.icon.Calendar
|
||||
export let viewLabel: IntlString = calendar.string.Events
|
||||
|
||||
export let createComponent: AnyComponent | undefined = calendar.component.CreateEvent
|
||||
@ -58,17 +68,19 @@
|
||||
$: viewOptions = getViewOptions(viewlet, $viewOptionStore)
|
||||
</script>
|
||||
|
||||
<div class="ac-header full divide">
|
||||
<div class="ac-header__wrap-title mr-3">
|
||||
<span class="ac-header__title"><Label label={viewLabel} /></span>
|
||||
</div>
|
||||
|
||||
<div class="ac-header-full medium-gap mb-1">
|
||||
<Header adaptive={'disabled'}>
|
||||
<svelte:fragment slot="beforeTitle">
|
||||
<ViewletSelector bind:viewlet bind:loading bind:preference bind:viewlets viewletQuery={{ attachTo: _class }} />
|
||||
</svelte:fragment>
|
||||
|
||||
<Breadcrumb icon={viewIcon} label={viewLabel} size={'large'} isCurrent />
|
||||
|
||||
<svelte:fragment slot="actions">
|
||||
<Button icon={IconAdd} label={createLabel} kind={'primary'} on:click={showCreateDialog} />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-col w-full h-full background-comp-header-color">
|
||||
</svelte:fragment>
|
||||
</Header>
|
||||
|
||||
<div class="flex-col w-full h-full">
|
||||
{#if viewlet?.$lookup?.descriptor?.component}
|
||||
{#if loading}
|
||||
<Loading />
|
||||
|
@ -149,6 +149,7 @@ const calendarPlugin = plugin(calendarId, {
|
||||
},
|
||||
icon: {
|
||||
Calendar: '' as Asset,
|
||||
CalendarView: '' as Asset,
|
||||
Location: '' as Asset,
|
||||
Reminder: '' as Asset,
|
||||
Notifications: '' as Asset,
|
||||
|
@ -2,22 +2,34 @@
|
||||
<symbol id="chunter" viewBox="0 0 32 32">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M16 6C9.20948 6 4 10.6272 4 16C4 18.1619 4.82539 20.1782 6.25857 21.8353C6.48585 22.0981 6.56044 22.46 6.45559 22.7913C6.11025 23.8822 5.59859 24.9049 4.96437 25.8562C6.36749 25.6496 7.72455 25.2236 8.98685 24.5982C9.26684 24.4595 9.59558 24.4596 9.87546 24.5986C11.6632 25.4861 13.7558 26 16 26C22.7905 26 28 21.3728 28 16C28 10.6272 22.7905 6 16 6ZM2 16C2 9.2225 8.43112 4 16 4C23.5689 4 30 9.2225 30 16C30 22.7775 23.5689 28 16 28C13.6319 28 11.3944 27.4963 9.43078 26.6016C7.4311 27.5144 5.24057 28 3 28C2.63121 28 2.29235 27.797 2.11833 27.4719C1.94431 27.1467 1.96338 26.7522 2.16795 26.4453L3.37487 24.6349C3.78033 24.0267 4.11535 23.3749 4.37375 22.692C2.88402 20.7925 2 18.4911 2 16Z" />
|
||||
</symbol>
|
||||
<symbol id="hashtag" viewBox="0 0 24 24">
|
||||
<path d="M21.5,8.2h-5.3l0.6-5.2c0-0.4-0.3-0.8-0.7-0.8c-0.4,0-0.8,0.3-0.8,0.7l-0.6,5.3h-4.5l0.6-5.2c0-0.4-0.3-0.8-0.7-0.8 c-0.4,0-0.8,0.3-0.8,0.7L8.7,8.2H3.5C3.1,8.2,2.8,8.6,2.8,9s0.3,0.8,0.8,0.8h5L8,14.2H2.5c-0.4,0-0.8,0.3-0.8,0.8s0.3,0.8,0.8,0.8 h5.3l-0.6,5.2c0,0.4,0.3,0.8,0.7,0.8c0,0,0.1,0,0.1,0c0.4,0,0.7-0.3,0.7-0.7l0.6-5.3h4.5l-0.6,5.2c0,0.4,0.3,0.8,0.7,0.8 c0,0,0.1,0,0.1,0c0.4,0,0.7-0.3,0.7-0.7l0.6-5.3h5.2c0.4,0,0.8-0.3,0.8-0.8s-0.3-0.8-0.8-0.8h-5L16,9.8h5.5c0.4,0,0.8-0.3,0.8-0.8 S21.9,8.2,21.5,8.2z M14,14.2H9.5L10,9.8h4.5L14,14.2z" />
|
||||
<symbol id="hashtag" viewBox="0 0 32 32">
|
||||
<path d="M27.4,19.9h-6.4l1.9-7.8h4.5c0.6,0,1-0.4,1-1s-0.4-1-1-1h-4l1.7-6.9c0.1-0.5-0.2-1.1-0.7-1.2c-0.5-0.1-1.1,0.2-1.2,0.7l-1.8,7.4h-7.7l1.7-6.9c0.1-0.5-0.2-1.1-0.7-1.2c-0.5-0.1-1.1,0.2-1.2,0.7l-1.8,7.4H4.6c-0.6,0-1,0.4-1,1s0.4,1,1,1h6.4l-1.9,7.8H4.6c-0.6,0-1,0.4-1,1s0.4,1,1,1h4l-1.7,6.9c-0.1,0.5,0.2,1.1,0.7,1.2c0.1,0,0.2,0,0.2,0c0.4,0,0.9-0.3,1-0.8l1.8-7.4h7.7l-1.7,6.9c-0.1,0.5,0.2,1.1,0.7,1.2c0.1,0,0.2,0,0.2,0c0.4,0,0.9-0.3,1-0.8l1.8-7.4h6.9c0.6,0,1-0.4,1-1S27.9,19.9,27.4,19.9z M11.2,19.9l1.9-7.8h7.7l-1.9,7.8H11.2z" />
|
||||
</symbol>
|
||||
<symbol id="lock" viewBox="0 0 16 16">
|
||||
<path d="M12,7.1h-0.7V5.4c0-1.8-1.5-3.3-3.3-3.3c-1.8,0-3.3,1.5-3.3,3.3v1.7H4c-0.8,0-1.5,0.7-1.5,1.5v4.1c0,0.8,0.7,1.5,1.5,1.5h8 c0.8,0,1.5-0.7,1.5-1.5V8.6C13.5,7.8,12.8,7.1,12,7.1z M5.7,5.4c0-1.2,1-2.3,2.3-2.3s2.3,1,2.3,2.3v1.7H5.7V5.4z M12.5,12.7 c0,0.3-0.2,0.5-0.5,0.5H4c-0.3,0-0.5-0.2-0.5-0.5V8.6c0-0.3,0.2-0.5,0.5-0.5h8c0.3,0,0.5,0.2,0.5,0.5V12.7z"/>
|
||||
</symbol>
|
||||
<symbol id="thread" viewBox="0 0 32 32">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M16 6C9.20948 6 4 10.6272 4 16C4 18.1619 4.82539 20.1782 6.25857 21.8353C6.48585 22.0981 6.56044 22.46 6.45559 22.7913C6.11025 23.8822 5.59859 24.9049 4.96437 25.8562C6.36749 25.6496 7.72455 25.2236 8.98685 24.5982C9.26684 24.4595 9.59558 24.4596 9.87546 24.5986C11.6632 25.4861 13.7558 26 16 26C22.7905 26 28 21.3728 28 16C28 10.6272 22.7905 6 16 6ZM2 16C2 9.2225 8.43112 4 16 4C23.5689 4 30 9.2225 30 16C30 22.7775 23.5689 28 16 28C13.6319 28 11.3944 27.4963 9.43078 26.6016C7.4311 27.5144 5.24057 28 3 28C2.63121 28 2.29235 27.797 2.11833 27.4719C1.94431 27.1467 1.96338 26.7522 2.16795 26.4453L3.37487 24.6349C3.78033 24.0267 4.11535 23.3749 4.37375 22.692C2.88402 20.7925 2 18.4911 2 16Z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M27.4,25.4L27.4,25.4c0.2,0,0.4,0,0.6-0.1c0.2-0.1,0.3-0.2,0.5-0.3c0.1-0.1,0.2-0.3,0.3-0.5C29,24.2,29,24,29,23.9v-0.1c0-0.1,0-0.2-0.1-0.4l-1-3.5c0,0,0-0.1,0.1-0.1c0,0,0-0.1,0.1-0.1l0,0c1.2-1.8,1.9-4,1.9-6.2c0-3-1.2-5.8-3.3-7.9C24.4,3.3,21.4,2,18.1,2c-2.7,0-5.4,0.9-7.5,2.6c-2.1,1.7-3.5,4-4.1,6.5c-0.2,0.8-0.3,1.6-0.3,2.4c0,1.5,0.3,3,0.9,4.4c0.6,1.4,1.4,2.7,2.5,3.7c2.2,2.2,5.2,3.4,8.3,3.4c1.2,0,2.8-0.4,3.2-0.5c0.8-0.2,1.6-0.5,1.7-0.5c0.1,0,0.2,0,0.2,0c0.1,0,0.2,0,0.2,0l0,0l3.5,1.3C27.1,25.3,27.2,25.3,27.4,25.4L27.4,25.4z M26.7,23l-2.7-1h0c-0.6-0.2-1.3-0.3-1.9,0c0,0,0,0,0,0c-0.2,0.1-0.8,0.3-1.5,0.5C19.9,22.8,18.7,23,18,23c-5.3,0-9.7-4.3-9.7-9.6c0-0.6,0.1-1.3,0.2-1.9c0.9-4.4,5-7.5,9.7-7.5c2.7,0,5.3,1,7.1,2.9C27,8.7,28,11,28,13.4c0,1.8-0.5,3.6-1.5,5.1c-0.1,0.1-0.1,0.2-0.2,0.3l0,0c-0.3,0.6-0.4,1.1-0.3,1.5L26.7,23z" />
|
||||
<path d="M3.6,29.7C3.8,29.9,4.2,30,4.5,30h0c0.2,0,0.4,0,0.6-0.1l3.5-1.4l0,0c1.4,0.5,2.8,0.8,4.2,0.8h0c1.9,0,3.8-0.5,5.5-1.5c0.1-0.1,0.2-0.2,0.3-0.3c0.1-0.1,0.1-0.2,0.2-0.4s0-0.3,0-0.4c0-0.1-0.1-0.3-0.1-0.4c-0.1-0.1-0.2-0.2-0.3-0.3c-0.1-0.1-0.2-0.1-0.4-0.2c-0.1,0-0.3,0-0.4,0c-0.1,0-0.3,0.1-0.4,0.1c-1.4,0.8-2.9,1.2-4.5,1.2h0c-1.1,0-2.3-0.2-3.4-0.7c-0.5-0.2-1-0.2-1.5,0l-2.7,1c0.3-1.3,0.5-2.8,0.6-2.9c0.1-0.5-0.1-0.9-0.3-1.3l0,0c-0.8-1.2-1.3-2.7-1.4-4.2c-0.1-1.5,0.3-3,1-4.3c0.1-0.2,0.2-0.5,0.1-0.8C5,14,4.9,13.8,4.6,13.6c-0.2-0.1-0.5-0.2-0.8-0.1c-0.3,0.1-0.5,0.2-0.6,0.5c-0.9,1.6-1.3,3.5-1.3,5.4c0.1,1.9,0.7,3.7,1.7,5.2v0c-0.1,0.5-0.3,1.7-0.5,2.7C3.1,27.7,3.1,28,3,28.2C3,28.5,3,28.8,3.1,29C3.2,29.3,3.3,29.5,3.6,29.7L3.6,29.7z" />
|
||||
</symbol>
|
||||
<symbol id="channelbrowser" viewBox="0 0 24 24">
|
||||
<path d="M12.4,20.2H8.6c-4.3,0-5.9-1.6-5.9-5.8V8.7c0-4.4,1.5-6,5.9-6h5.7c4.4,0,6,1.6,6,6v3.7c0,0.4,0.3,0.7,0.8,0.7 s0.8-0.3,0.8-0.7V8.7c0-5.2-2.2-7.5-7.5-7.5H8.6c-5.2,0-7.4,2.2-7.4,7.5v5.7c0,5.1,2.3,7.3,7.4,7.3h3.8c0.4,0,0.7-0.3,0.7-0.8 S12.8,20.2,12.4,20.2z" />
|
||||
<path d="M22.2,21.4l-1-1c0,0,0,0-0.1,0c0.4-0.6,0.7-1.4,0.7-2.2c0-2.2-1.7-3.9-3.9-3.9s-4,1.7-4,3.9c0,2.1,1.8,4,4,4 c0.8,0,1.6-0.2,2.2-0.7c0,0,0,0,0,0.1l1,1c0.1,0.1,0.3,0.2,0.5,0.2s0.4-0.1,0.5-0.2C22.5,22.1,22.5,21.7,22.2,21.4z M17.9,20.5 c-1.3,0-2.5-1.2-2.5-2.5c0-1.4,1.1-2.4,2.5-2.4s2.4,1.1,2.4,2.4S19.3,20.5,17.9,20.5z" />
|
||||
<path d="M16.3,9.5c0.4,0,0.8-0.3,0.8-0.8S16.7,8,16.3,8h-2.9l0.3-2.9c0-0.4-0.3-0.8-0.7-0.8c-0.4,0-0.8,0.3-0.8,0.7 l-0.3,3H9.7L10,5.1c0-0.4-0.3-0.8-0.7-0.8C9,4.2,8.6,4.5,8.6,4.9L8.2,8H5.3C4.9,8,4.5,8.3,4.5,8.7s0.3,0.8,0.8,0.8h2.8l-0.2,2.1 H4.7c-0.4,0-0.8,0.3-0.8,0.8S4.3,13,4.7,13h3l-0.3,2.9c0,0.4,0.3,0.8,0.7,0.8c0,0,0.1,0,0.1,0c0.4,0,0.7-0.3,0.7-0.7l0.3-3h2.2 l-0.3,2.9c0,0.4,0.3,0.8,0.7,0.8c0,0,0.1,0,0.1,0c0.4,0,0.7-0.3,0.7-0.7l0.3-3h2.8c0.4,0,0.8-0.3,0.8-0.8s-0.3-0.8-0.8-0.8H13 l0.2-2.1H16.3z M11.5,11.5H9.3l0.2-2.1h2.2L11.5,11.5z" />
|
||||
<symbol id="channelbrowser" viewBox="0 0 32 32">
|
||||
<path d="M27.4,10.1h-4l1.7-6.9c0.1-0.5-0.2-1.1-0.7-1.2c-0.5-0.1-1.1,0.2-1.2,0.7l-1.8,7.4h-7.7l1.7-6.9c0.1-0.5-0.2-1.1-0.7-1.2c-0.5-0.1-1.1,0.2-1.2,0.7l-1.8,7.4H4.6c-0.6,0-1,0.4-1,1s0.4,1,1,1h6.4l-1.9,7.8H4.6c-0.6,0-1,0.4-1,1s0.4,1,1,1h4l-1.7,6.9c-0.1,0.5,0.2,1.1,0.7,1.2c0.1,0,0.2,0,0.2,0c0.4,0,0.9-0.3,1-0.8l1.8-7.4h4.6c0.6,0,1-0.4,1-1s-0.4-1-1-1h-4.1l1.9-7.8h7.7l-0.9,3.6c-0.1,0.5,0.2,1.1,0.7,1.2c0.1,0,0.2,0,0.2,0c0.4,0,0.9-0.3,1-0.8l1-4.1h4.5c0.6,0,1-0.4,1-1S27.9,10.1,27.4,10.1z" />
|
||||
<path d="M29.7,28.3l-2-2c0.6-0.8,0.9-1.9,0.9-3c0-2.9-2.4-5.3-5.3-5.3S18,20.4,18,23.3s2.4,5.3,5.3,5.3c1.1,0,2.1-0.3,3-0.9l2,2c0.2,0.2,0.5,0.3,0.7,0.3s0.5-0.1,0.7-0.3C30.1,29.3,30.1,28.7,29.7,28.3z M20,23.3c0-1.8,1.5-3.3,3.3-3.3s3.3,1.5,3.3,3.3s-1.5,3.3-3.3,3.3S20,25.1,20,23.3z" />
|
||||
</symbol>
|
||||
<symbol id="chunterbrowser" viewBox="0 0 32 32">
|
||||
<path d="M16,2C9.8,2,3.4,3.8,3.4,7.3V16v8.7C3.4,28.2,9.8,30,16,30c0.6,0,1-0.4,1-1s-0.4-1-1-1c-6.4,0-10.6-2-10.6-3.3V19c2.4,1.5,6.5,2.3,10.6,2.3c0.6,0,1-0.4,1-1s-0.4-1-1-1c-6.4,0-10.6-2-10.6-3.3v-5.7c2.4,1.5,6.5,2.3,10.6,2.3s8.2-0.8,10.6-2.3v4.9c0,0.6,0.4,1,1,1s1-0.4,1-1V7.3C28.6,3.8,22.2,2,16,2z M16,10.7c-6.4,0-10.6-2-10.6-3.3S9.6,4,16,4c6.4,0,10.6,2,10.6,3.3S22.4,10.7,16,10.7z" />
|
||||
<path d="M29.7,28.3l-2-2c0.6-0.8,0.9-1.9,0.9-3c0-2.9-2.4-5.3-5.3-5.3c-2.9,0-5.3,2.4-5.3,5.3c0,2.9,2.4,5.3,5.3,5.3c1.1,0,2.1-0.3,3-0.9l2,2c0.2,0.2,0.5,0.3,0.7,0.3s0.5-0.1,0.7-0.3C30.1,29.3,30.1,28.7,29.7,28.3z M20,23.3c0-1.8,1.5-3.3,3.3-3.3s3.3,1.5,3.3,3.3s-1.5,3.3-3.3,3.3S20,25.1,20,23.3z" />
|
||||
</symbol>
|
||||
<symbol id="copy" viewBox="0 0 12 14">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3 2C3 0.89543 3.89543 0 5 0H10C11.1046 0 12 0.895431 12 2V9C12 10.1046 11.1046 11 10 11H5C3.89543 11 3 10.1046 3 9V2ZM5 1C4.44772 1 4 1.44772 4 2V9C4 9.55228 4.44772 10 5 10H10C10.5523 10 11 9.55229 11 9V2C11 1.44772 10.5523 1 10 1H5Z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M2 4C1.44772 4 1 4.44772 1 5V12C1 12.5523 1.44772 13 2 13H7C7.55228 13 8 12.5523 8 12V11H9V12C9 13.1046 8.10457 14 7 14H2C0.895431 14 0 13.1046 0 12V5C0 3.89543 0.895431 3 2 3H3V4H2Z" />
|
||||
</symbol>
|
||||
<symbol id="messages" viewBox="0 0 32 32">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M27.4,25.4L27.4,25.4c0.2,0,0.4,0,0.6-0.1c0.2-0.1,0.3-0.2,0.5-0.3c0.1-0.1,0.2-0.3,0.3-0.5C29,24.2,29,24,29,23.9v-0.1c0-0.1,0-0.2-0.1-0.4l-1-3.5c0,0,0-0.1,0.1-0.1c0,0,0-0.1,0.1-0.1l0,0c1.2-1.8,1.9-4,1.9-6.2c0-3-1.2-5.8-3.3-7.9C24.4,3.3,21.4,2,18.1,2c-2.7,0-5.4,0.9-7.5,2.6c-2.1,1.7-3.5,4-4.1,6.5c-0.2,0.8-0.3,1.6-0.3,2.4c0,1.5,0.3,3,0.9,4.4c0.6,1.4,1.4,2.7,2.5,3.7c2.2,2.2,5.2,3.4,8.3,3.4c1.2,0,2.8-0.4,3.2-0.5c0.8-0.2,1.6-0.5,1.7-0.5c0.1,0,0.2,0,0.2,0c0.1,0,0.2,0,0.2,0l0,0l3.5,1.3C27.1,25.3,27.2,25.3,27.4,25.4L27.4,25.4z M26.7,23l-2.7-1h0c-0.6-0.2-1.3-0.3-1.9,0c0,0,0,0,0,0c-0.2,0.1-0.8,0.3-1.5,0.5C19.9,22.8,18.7,23,18,23c-5.3,0-9.7-4.3-9.7-9.6c0-0.6,0.1-1.3,0.2-1.9c0.9-4.4,5-7.5,9.7-7.5c2.7,0,5.3,1,7.1,2.9C27,8.7,28,11,28,13.4c0,1.8-0.5,3.6-1.5,5.1c-0.1,0.1-0.1,0.2-0.2,0.3l0,0c-0.3,0.6-0.4,1.1-0.3,1.5L26.7,23z" />
|
||||
<path d="M3.6,29.7C3.8,29.9,4.2,30,4.5,30h0c0.2,0,0.4,0,0.6-0.1l3.5-1.4l0,0c1.4,0.5,2.8,0.8,4.2,0.8h0c1.9,0,3.8-0.5,5.5-1.5c0.1-0.1,0.2-0.2,0.3-0.3c0.1-0.1,0.1-0.2,0.2-0.4s0-0.3,0-0.4c0-0.1-0.1-0.3-0.1-0.4c-0.1-0.1-0.2-0.2-0.3-0.3c-0.1-0.1-0.2-0.1-0.4-0.2c-0.1,0-0.3,0-0.4,0c-0.1,0-0.3,0.1-0.4,0.1c-1.4,0.8-2.9,1.2-4.5,1.2h0c-1.1,0-2.3-0.2-3.4-0.7c-0.5-0.2-1-0.2-1.5,0l-2.7,1c0.3-1.3,0.5-2.8,0.6-2.9c0.1-0.5-0.1-0.9-0.3-1.3l0,0c-0.8-1.2-1.3-2.7-1.4-4.2c-0.1-1.5,0.3-3,1-4.3c0.1-0.2,0.2-0.5,0.1-0.8C5,14,4.9,13.8,4.6,13.6c-0.2-0.1-0.5-0.2-0.8-0.1c-0.3,0.1-0.5,0.2-0.6,0.5c-0.9,1.6-1.3,3.5-1.3,5.4c0.1,1.9,0.7,3.7,1.7,5.2v0c-0.1,0.5-0.3,1.7-0.5,2.7C3.1,27.7,3.1,28,3,28.2C3,28.5,3,28.8,3.1,29C3.2,29.3,3.3,29.5,3.6,29.7L3.6,29.7z" />
|
||||
</symbol>
|
||||
<symbol id="bookmarks" viewBox="0 0 32 32">
|
||||
<path d="M18.2,7.4H8.4c-2.5,0-4.6,2.1-4.6,4.6v17c0,0.4,0.2,0.7,0.5,0.9c0.3,0.2,0.7,0.1,1-0.1l7.9-5.8l7.9,5.8c0.2,0.1,0.4,0.2,0.6,0.2c0.2,0,0.3,0,0.5-0.1c0.3-0.2,0.5-0.5,0.5-0.9V12C22.8,9.4,20.8,7.4,18.2,7.4z M20.8,27l-6.9-5.1c-0.4-0.3-0.8-0.3-1.2,0L5.8,27V12c0-1.4,1.2-2.6,2.6-2.6h9.9c1.4,0,2.6,1.2,2.6,2.6V27z" />
|
||||
<path d="M23.6,2h-9.9c-0.8,0-1.5,0.2-2.2,0.6c-0.5,0.3-0.7,0.9-0.4,1.4c0.3,0.5,0.9,0.7,1.4,0.4C12.9,4.1,13.3,4,13.8,4h9.9c1.4,0,2.6,1.2,2.6,2.6v17c0,0.6,0.4,1,1,1s1-0.4,1-1v-17C28.2,4.1,26.1,2,23.6,2z" />
|
||||
</symbol>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 7.8 KiB |
@ -23,5 +23,8 @@ loadMetadata(chunter.icon, {
|
||||
Thread: `${icons}#thread`,
|
||||
Lock: `${icons}#lock`,
|
||||
ChannelBrowser: `${icons}#channelbrowser`,
|
||||
Copy: `${icons}#copy`
|
||||
ChunterBrowser: `${icons}#chunterbrowser`,
|
||||
Copy: `${icons}#copy`,
|
||||
Messages: `${icons}#messages`,
|
||||
Bookmarks: `${icons}#bookmarks`
|
||||
})
|
||||
|
@ -28,10 +28,10 @@
|
||||
export let _id: Ref<Doc>
|
||||
export let _class: Ref<Class<Doc>>
|
||||
export let object: Doc | undefined
|
||||
export let allowClose = false
|
||||
export let canOpen = false
|
||||
export let withAside = false
|
||||
export let isAsideShown = false
|
||||
export let allowClose: boolean = false
|
||||
export let canOpen: boolean = false
|
||||
export let withAside: boolean = false
|
||||
export let isAsideShown: boolean = false
|
||||
export let filters: Ref<ActivityMessagesFilter>[] = []
|
||||
|
||||
const client = getClient()
|
||||
@ -60,30 +60,23 @@
|
||||
hierarchy.isDerived(_class, chunter.class.DirectMessage) || hierarchy.isDerived(_class, contact.class.Person)
|
||||
</script>
|
||||
|
||||
<div class="ac-header divide full caption-height">
|
||||
<Header
|
||||
bind:filters
|
||||
{object}
|
||||
icon={getObjectIcon(_class)}
|
||||
iconProps={{ value: object, showStatus: true }}
|
||||
label={title}
|
||||
intlLabel={chunter.string.Channel}
|
||||
{description}
|
||||
titleKind={isPerson ? 'default' : 'breadcrumbs'}
|
||||
withFilters={!hierarchy.isDerived(_class, chunter.class.ChunterSpace)}
|
||||
{allowClose}
|
||||
{canOpen}
|
||||
{withAside}
|
||||
{isAsideShown}
|
||||
on:aside-toggled
|
||||
on:close
|
||||
>
|
||||
<PinnedMessages {_id} {_class} on:select />
|
||||
</Header>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.ac-header {
|
||||
padding: 0.5rem 1rem;
|
||||
}
|
||||
</style>
|
||||
<Header
|
||||
bind:filters
|
||||
{object}
|
||||
icon={getObjectIcon(_class)}
|
||||
iconProps={{ value: object, showStatus: true }}
|
||||
label={title}
|
||||
intlLabel={chunter.string.Channel}
|
||||
{description}
|
||||
titleKind={isPerson ? 'default' : 'breadcrumbs'}
|
||||
withFilters={!hierarchy.isDerived(_class, chunter.class.ChunterSpace)}
|
||||
{allowClose}
|
||||
{canOpen}
|
||||
{withAside}
|
||||
{isAsideShown}
|
||||
hideBefore
|
||||
on:aside-toggled
|
||||
on:close
|
||||
>
|
||||
<PinnedMessages {_id} {_class} on:select />
|
||||
</Header>
|
||||
|
@ -16,6 +16,7 @@
|
||||
import { Button, eventToHTMLElement, IconFilter, showPopup } from '@hcengineering/ui'
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import activity, { ActivityMessagesFilter } from '@hcengineering/activity'
|
||||
import view from '@hcengineering/view-resources/src/plugin'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { ActivityMessagesFilterPopup } from '@hcengineering/activity-resources'
|
||||
|
||||
@ -41,4 +42,11 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<Button icon={IconFilter} iconProps={{ size: 'small' }} kind="icon" on:click={handleClick} />
|
||||
<Button
|
||||
icon={IconFilter}
|
||||
kind={'regular'}
|
||||
size={'medium'}
|
||||
pressed={selectedFilters[0] !== activity.ids.AllFilter}
|
||||
showTooltip={{ label: view.string.Filter }}
|
||||
on:click={handleClick}
|
||||
/>
|
||||
|
@ -37,7 +37,5 @@
|
||||
</script>
|
||||
|
||||
{#if object}
|
||||
<div class="antiComponent">
|
||||
<ChannelView {object} {context} embedded allowClose on:close />
|
||||
</div>
|
||||
<ChannelView {object} {context} on:close />
|
||||
{/if}
|
||||
|
@ -771,7 +771,7 @@
|
||||
}
|
||||
|
||||
.ref-input {
|
||||
margin: 1.25rem 1rem;
|
||||
margin: 1.25rem 1rem 1rem;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
|
@ -40,8 +40,7 @@
|
||||
|
||||
export let object: Doc
|
||||
export let context: DocNotifyContext | undefined
|
||||
export let allowClose = false
|
||||
export let embedded = false
|
||||
export let embedded: boolean = false
|
||||
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
@ -94,15 +93,15 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="popupPanel panel" class:embedded>
|
||||
<div class="popupPanel panel">
|
||||
<ChannelHeader
|
||||
_id={object._id}
|
||||
_class={object._class}
|
||||
{object}
|
||||
{allowClose}
|
||||
{withAside}
|
||||
bind:filters
|
||||
canOpen={isDocChat}
|
||||
allowClose={embedded}
|
||||
{isAsideShown}
|
||||
on:close
|
||||
on:select={handleMessageSelect}
|
||||
|
@ -19,10 +19,10 @@
|
||||
Breadcrumbs,
|
||||
Button,
|
||||
Icon,
|
||||
IconClose,
|
||||
IconDetails,
|
||||
Label,
|
||||
SearchEdit
|
||||
SearchInput,
|
||||
Header
|
||||
} from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import view from '@hcengineering/view'
|
||||
@ -41,102 +41,116 @@
|
||||
export let label: string | undefined = undefined
|
||||
export let intlLabel: IntlString | undefined = undefined
|
||||
export let description: string | undefined = undefined
|
||||
export let allowClose = false
|
||||
export let canOpen = false
|
||||
export let withAside = false
|
||||
export let isAsideShown = false
|
||||
export let allowClose: boolean = false
|
||||
export let allowFullsize: boolean = false
|
||||
export let canOpen: boolean = false
|
||||
export let withAside: boolean = false
|
||||
export let isAsideShown: boolean = false
|
||||
export let titleKind: 'default' | 'breadcrumbs' = 'default'
|
||||
export let withFilters = false
|
||||
export let withFilters: boolean = false
|
||||
export let filters: Ref<ActivityMessagesFilter>[] = []
|
||||
export let adaptive: 'default' | 'freezeActions' | 'doubleRow' | 'disabled' = 'default'
|
||||
export let hideBefore: boolean = false
|
||||
export let hideActions: boolean = false
|
||||
|
||||
const client = getClient()
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let searchValue: string = ''
|
||||
export let searchValue: string = ''
|
||||
userSearch.subscribe((v) => (searchValue = v))
|
||||
</script>
|
||||
|
||||
<div class="header ac-header__wrap-title flex-grow">
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div class="ac-header__wrap-title" on:click>
|
||||
{#if allowClose}
|
||||
<Button
|
||||
focusIndex={10001}
|
||||
icon={IconClose}
|
||||
iconProps={{ size: 'medium' }}
|
||||
kind={'icon'}
|
||||
on:click={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
/>
|
||||
<div class="antiHSpacer x2" />
|
||||
{/if}
|
||||
<Header
|
||||
{allowFullsize}
|
||||
type={allowClose ? 'type-aside' : 'type-component'}
|
||||
hideBefore={$$slots.default === undefined || hideBefore}
|
||||
hideActions={!((canOpen && object) || withAside || $$slots.actions) || hideActions}
|
||||
hideDescription={!description}
|
||||
adaptive={adaptive !== 'default' ? adaptive : withFilters ? 'freezeActions' : 'disabled'}
|
||||
on:click
|
||||
on:close
|
||||
>
|
||||
<svelte:fragment slot="beforeTitle">
|
||||
<slot />
|
||||
{#if titleKind === 'breadcrumbs'}
|
||||
<Breadcrumbs
|
||||
items={[
|
||||
{
|
||||
icon,
|
||||
iconProps,
|
||||
title: label,
|
||||
label: label ? undefined : intlLabel
|
||||
}
|
||||
]}
|
||||
/>
|
||||
{:else}
|
||||
</svelte:fragment>
|
||||
|
||||
{#if titleKind === 'breadcrumbs'}
|
||||
<Breadcrumbs
|
||||
items={[
|
||||
{
|
||||
icon,
|
||||
iconProps,
|
||||
title: label,
|
||||
label: label ? undefined : intlLabel
|
||||
}
|
||||
]}
|
||||
currentOnly
|
||||
/>
|
||||
{:else}
|
||||
<div class="hulyHeader-titleGroup">
|
||||
{#if icon}
|
||||
<div class="ac-header__icon pl-2">
|
||||
<div class="content-color mr-2 pl-2">
|
||||
<Icon {icon} size={'small'} {iconProps} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if label}
|
||||
<span class="title overflow-label heading-medium-16 mr-2">{label}</span>
|
||||
<span class="secondary-textColor overflow-label heading-medium-16 mr-2">{label}</span>
|
||||
{:else if intlLabel}
|
||||
<div class="title overflow-label mr-2">
|
||||
<div class="secondary-textColor overflow-label mr-2">
|
||||
<Label label={intlLabel} />
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
{#if description}
|
||||
<div class="ac-header__description over-underline" style="flex: 1" title={description}>{description}</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{#if withFilters}
|
||||
<ChannelMessagesFilter bind:selectedFilters={filters} />
|
||||
{/if}
|
||||
{#if canOpen && object}
|
||||
<Button
|
||||
icon={view.icon.Open}
|
||||
iconProps={{ size: 'small' }}
|
||||
kind={'icon'}
|
||||
on:click={() => {
|
||||
if (object) {
|
||||
openDoc(client.getHierarchy(), object)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
<SearchEdit
|
||||
value={searchValue}
|
||||
on:change={(ev) => {
|
||||
userSearch.set(ev.detail)
|
||||
|
||||
if (ev.detail !== '') {
|
||||
navigateToSpecial('chunterBrowser')
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{#if withAside}
|
||||
<Button
|
||||
icon={IconDetails}
|
||||
iconProps={{ size: 'medium', filled: isAsideShown }}
|
||||
kind={'icon'}
|
||||
selected={isAsideShown}
|
||||
on:click={() => dispatch('aside-toggled')}
|
||||
/>
|
||||
{/if}
|
||||
<svelte:fragment slot="description">
|
||||
{#if description}
|
||||
<div class="overflow-label content-dark-color text-sm pl-2 mt--1" title={description}>{description}</div>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="search" let:doubleRow>
|
||||
<SearchInput
|
||||
collapsed
|
||||
bind:value={searchValue}
|
||||
on:change={(ev) => {
|
||||
userSearch.set(ev.detail)
|
||||
|
||||
if (ev.detail !== '') {
|
||||
navigateToSpecial('chunterBrowser')
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{#if withFilters}
|
||||
<ChannelMessagesFilter bind:selectedFilters={filters} />
|
||||
{/if}
|
||||
<slot name="search" {doubleRow} />
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="actions" let:doubleRow>
|
||||
<slot name="actions" {doubleRow} />
|
||||
{#if canOpen && object}
|
||||
<Button
|
||||
icon={view.icon.Open}
|
||||
iconProps={{ size: 'small' }}
|
||||
kind={'icon'}
|
||||
on:click={() => {
|
||||
if (object) {
|
||||
openDoc(client.getHierarchy(), object)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
{#if withAside}
|
||||
<Button
|
||||
icon={IconDetails}
|
||||
iconProps={{ size: 'medium', filled: isAsideShown }}
|
||||
kind={'icon'}
|
||||
selected={isAsideShown}
|
||||
on:click={() => dispatch('aside-toggled')}
|
||||
/>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</Header>
|
||||
|
||||
<style lang="scss">
|
||||
.title {
|
||||
|
@ -63,8 +63,7 @@
|
||||
</script>
|
||||
|
||||
{#if count > 0}
|
||||
<div class="antiHSpacer x2" />
|
||||
<ModernButton size={'extra-small'} on:click={openMessagesPopup}>
|
||||
<ModernButton size={'small'} on:click={openMessagesPopup}>
|
||||
<Icon icon={view.icon.Pin} size={'x-small'} />
|
||||
<span class="text-sm"><Label label={chunter.string.PinnedCount} params={{ count }} /></span>
|
||||
</ModernButton>
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Doc, Ref, Class } from '@hcengineering/core'
|
||||
import { Doc, Ref, Class, Space } from '@hcengineering/core'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import {
|
||||
Component,
|
||||
@ -24,11 +24,12 @@
|
||||
Separator,
|
||||
Location,
|
||||
restoreLocation,
|
||||
deviceOptionsStore as deviceInfo
|
||||
deviceOptionsStore as deviceInfo,
|
||||
type AnyComponent
|
||||
} from '@hcengineering/ui'
|
||||
import { NavigatorModel, SpecialNavModel } from '@hcengineering/workbench'
|
||||
import { InboxNotificationsClientImpl } from '@hcengineering/notification-resources'
|
||||
import { onMount } from 'svelte'
|
||||
import { onMount, onDestroy } from 'svelte'
|
||||
import { chunterId } from '@hcengineering/chunter'
|
||||
import view, { decodeObjectURI } from '@hcengineering/view'
|
||||
import { parseLinkId, getObjectLinkId } from '@hcengineering/view-resources'
|
||||
@ -39,6 +40,10 @@
|
||||
import { SelectChannelEvent } from './types'
|
||||
import { openChannel } from '../../navigation'
|
||||
|
||||
export let currentSpace: Ref<Space> | undefined = undefined
|
||||
export let asideComponent: AnyComponent | undefined = undefined
|
||||
export let asideId: string | undefined = undefined
|
||||
|
||||
const notificationsClient = InboxNotificationsClientImpl.getClient()
|
||||
const contextByDocStore = notificationsClient.contextByDoc
|
||||
const objectQuery = createQuery()
|
||||
@ -56,6 +61,7 @@
|
||||
let currentSpecial: SpecialNavModel | undefined
|
||||
|
||||
let object: Doc | undefined = undefined
|
||||
let replacedPanel: HTMLElement
|
||||
|
||||
location.subscribe((loc) => {
|
||||
syncLocation(loc)
|
||||
@ -137,26 +143,40 @@
|
||||
|
||||
defineSeparators('chat', [
|
||||
{ minSize: 20, maxSize: 40, size: 30, float: 'navigator' },
|
||||
{ size: 'auto', minSize: 30, maxSize: 'auto', float: undefined }
|
||||
{ size: 'auto', minSize: 20, maxSize: 'auto' },
|
||||
{ size: 20, minSize: 20, maxSize: 50, float: 'aside' }
|
||||
])
|
||||
|
||||
onMount(() => {
|
||||
loadSavedAttachments()
|
||||
})
|
||||
$: $deviceInfo.replacedPanel = replacedPanel
|
||||
onDestroy(() => ($deviceInfo.replacedPanel = undefined))
|
||||
</script>
|
||||
|
||||
<div class="flex-row-top h-full">
|
||||
<div class="hulyPanels-container">
|
||||
{#if $deviceInfo.navigator.visible}
|
||||
<div class="antiPanel-navigator {$deviceInfo.navigator.direction === 'horizontal' ? 'portrait' : 'landscape'}">
|
||||
<div
|
||||
class="antiPanel-navigator {$deviceInfo.navigator.direction === 'horizontal'
|
||||
? 'portrait'
|
||||
: 'landscape'} border-left"
|
||||
>
|
||||
<div class="antiPanel-wrap__content hulyNavPanel-container">
|
||||
<ChatNavigator {object} {currentSpecial} on:select={handleChannelSelected} />
|
||||
</div>
|
||||
<Separator name="chat" float={$deviceInfo.navigator.float ? 'navigator' : true} index={0} />
|
||||
</div>
|
||||
<Separator name="chat" float={$deviceInfo.navigator.float} index={0} />
|
||||
<Separator
|
||||
name="chat"
|
||||
float={$deviceInfo.navigator.float}
|
||||
index={0}
|
||||
color={'transparent'}
|
||||
separatorSize={0}
|
||||
short
|
||||
/>
|
||||
{/if}
|
||||
|
||||
<div class="antiPanel-component filled w-full">
|
||||
<div bind:this={replacedPanel} class="hulyComponent" class:beforeAside={asideComponent !== undefined && asideId}>
|
||||
{#if currentSpecial}
|
||||
<Component
|
||||
is={currentSpecial.component}
|
||||
@ -177,4 +197,10 @@
|
||||
<ChannelView {object} {context} />
|
||||
{/if}
|
||||
</div>
|
||||
{#if asideComponent !== undefined && asideId}
|
||||
<Separator name={'chat'} index={1} color={'var(--theme-divider-color)'} separatorSize={1} />
|
||||
<div class="hulyComponent aside">
|
||||
<Component is={asideComponent} props={{ currentSpace, _id: asideId }} on:close />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -44,5 +44,5 @@
|
||||
{#if threadId}
|
||||
<ThreadView _id={threadId} on:close />
|
||||
{:else if object}
|
||||
<ChannelView {object} {context} allowClose embedded on:close />
|
||||
<ChannelView {object} {context} embedded on:close />
|
||||
{/if}
|
||||
|
@ -73,7 +73,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="hulyNavPanel-header withButton">
|
||||
<div class="hulyNavPanel-header" class:withButton={hasAccountRole(getCurrentAccount(), AccountRole.User)}>
|
||||
<span class="overflow-label">
|
||||
<Label label={chunter.string.Chat} />
|
||||
</span>
|
||||
|
@ -14,13 +14,16 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import attachment from '@hcengineering/attachment'
|
||||
import chunter from '@hcengineering/chunter'
|
||||
import { FileBrowser } from '@hcengineering/attachment-resources'
|
||||
import { AnySvelteComponent, Button, Scroller } from '@hcengineering/ui'
|
||||
import { Scroller, Switcher } from '@hcengineering/ui'
|
||||
import type { AnySvelteComponent } from '@hcengineering/ui'
|
||||
import workbench from '@hcengineering/workbench'
|
||||
import contact from '@hcengineering/contact-resources/src/plugin'
|
||||
import contact from '@hcengineering/contact'
|
||||
import contactPlg from '@hcengineering/contact-resources/src/plugin'
|
||||
import { EmployeeBrowser } from '@hcengineering/contact-resources'
|
||||
import MessagesBrowser from './MessagesBrowser.svelte'
|
||||
import { FilterButton } from '@hcengineering/view-resources'
|
||||
import { FilterBar, FilterButton } from '@hcengineering/view-resources'
|
||||
import { Class, Doc, Ref } from '@hcengineering/core'
|
||||
|
||||
import { userSearch } from '../../../index'
|
||||
@ -31,7 +34,9 @@
|
||||
let userSearch_: string = ''
|
||||
userSearch.subscribe((v) => (userSearch_ = v))
|
||||
|
||||
let searchType: SearchType = SearchType.Messages
|
||||
const saved = localStorage.getItem('chunter-browser-st')
|
||||
let searchType: SearchType = saved ? parseInt(saved, 10) : SearchType.Messages
|
||||
$: localStorage.setItem('chunter-browser-st', searchType.toString())
|
||||
|
||||
const components: {
|
||||
component: AnySvelteComponent
|
||||
@ -47,66 +52,71 @@
|
||||
requestedSpaceClasses: [plugin.class.Channel, plugin.class.DirectMessage]
|
||||
}
|
||||
},
|
||||
{ searchType: SearchType.Contacts, component: EmployeeBrowser, filterClass: contact.mixin.Employee }
|
||||
{ searchType: SearchType.Contacts, component: EmployeeBrowser, filterClass: contactPlg.mixin.Employee }
|
||||
]
|
||||
let searchValue: string = ''
|
||||
</script>
|
||||
|
||||
<div class="flex-col h-full">
|
||||
<div class="ac-header divide full caption-height" style="padding: 0.5rem 1rem">
|
||||
<Header icon={workbench.icon.Search} intlLabel={plugin.string.ChunterBrowser} titleKind="breadcrumbs" />
|
||||
</div>
|
||||
<div class="h-full browser">
|
||||
<div class="pb-16 component">
|
||||
<div class="h-full">
|
||||
{#if components[searchType].component}
|
||||
<Scroller>
|
||||
<svelte:component
|
||||
this={components[searchType].component}
|
||||
withHeader={false}
|
||||
bind:search={userSearch_}
|
||||
{...components[searchType].props}
|
||||
/>
|
||||
</Scroller>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-3 bar">
|
||||
<div class="w-32 flex-center"><FilterButton _class={components[searchType].filterClass} /></div>
|
||||
<div class="flex-center w-full mr-32 buttons">
|
||||
<div class="ml-1 p-1 btn">
|
||||
<Button
|
||||
label={plugin.string.Messages}
|
||||
selected={searchType === SearchType.Messages}
|
||||
kind="ghost"
|
||||
on:click={() => {
|
||||
searchType = SearchType.Messages
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="ml-1 p-1 btn">
|
||||
<Button
|
||||
label={attachment.string.Files}
|
||||
kind="ghost"
|
||||
selected={searchType === SearchType.Files}
|
||||
on:click={() => {
|
||||
searchType = SearchType.Files
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="ml-1 p-1 btn">
|
||||
<Button
|
||||
kind="ghost"
|
||||
label={contact.string.Contacts}
|
||||
selected={searchType === SearchType.Contacts}
|
||||
on:click={() => {
|
||||
searchType = SearchType.Contacts
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Header
|
||||
icon={plugin.icon.ChunterBrowser}
|
||||
intlLabel={plugin.string.ChunterBrowser}
|
||||
titleKind={'breadcrumbs'}
|
||||
bind:searchValue
|
||||
adaptive={'freezeActions'}
|
||||
>
|
||||
<svelte:fragment slot="search">
|
||||
<FilterButton _class={components[searchType].filterClass} />
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="actions">
|
||||
<Switcher
|
||||
name={'browser_group'}
|
||||
kind={'subtle'}
|
||||
selected={searchType}
|
||||
items={[
|
||||
{
|
||||
id: SearchType.Messages,
|
||||
icon: chunter.icon.Messages,
|
||||
labelIntl: plugin.string.Messages,
|
||||
tooltip: plugin.string.Messages
|
||||
},
|
||||
{
|
||||
id: SearchType.Files,
|
||||
icon: attachment.icon.FileBrowser,
|
||||
labelIntl: attachment.string.Files,
|
||||
tooltip: attachment.string.Files
|
||||
},
|
||||
{
|
||||
id: SearchType.Contacts,
|
||||
icon: contact.icon.Contacts,
|
||||
labelIntl: contactPlg.string.Contacts,
|
||||
tooltip: contactPlg.string.Contacts
|
||||
}
|
||||
]}
|
||||
on:select={(result) => {
|
||||
if (result !== undefined && result.detail.id !== undefined) searchType = result.detail.id
|
||||
}}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
</Header>
|
||||
{#if components[searchType].filterClass !== undefined}
|
||||
<FilterBar
|
||||
_class={components[searchType].filterClass}
|
||||
space={undefined}
|
||||
query={{ $search: searchValue }}
|
||||
hideSaveButtons
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if components[searchType].component}
|
||||
<Scroller>
|
||||
<svelte:component
|
||||
this={components[searchType].component}
|
||||
withHeader={false}
|
||||
search={userSearch_}
|
||||
{...components[searchType].props}
|
||||
/>
|
||||
</Scroller>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.browser {
|
||||
@ -114,7 +124,7 @@
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
flex-direction: column-reverse;
|
||||
background-color: var(--theme-popup-color);
|
||||
background-color: var(--theme-panel-color);
|
||||
}
|
||||
|
||||
.bar {
|
||||
|
@ -76,7 +76,7 @@
|
||||
on:change={(e) => (resultQuery = e.detail)}
|
||||
/>
|
||||
{#if messages.length > 0}
|
||||
<Scroller>
|
||||
<Scroller padding={'1rem 0'} bottomPadding={'1rem'}>
|
||||
{#each messages as message}
|
||||
<ActivityMessagePresenter
|
||||
value={message}
|
||||
|
@ -19,7 +19,7 @@
|
||||
import { personAccountByIdStore, personByIdStore } from '@hcengineering/contact-resources'
|
||||
import { getDisplayTime, IdMap, Ref, WithLookup } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { Icon, Label, Scroller } from '@hcengineering/ui'
|
||||
import { Label, Scroller } from '@hcengineering/ui'
|
||||
import activity, { ActivityMessage, SavedMessage } from '@hcengineering/activity'
|
||||
import { ActivityMessagePresenter, savedMessagesStore } from '@hcengineering/activity-resources'
|
||||
|
||||
@ -67,62 +67,54 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="ac-header full divide caption-height" style="padding: 0.5rem 1rem">
|
||||
<Header icon={activity.icon.Bookmark} intlLabel={chunter.string.Saved} titleKind="breadcrumbs" />
|
||||
</div>
|
||||
<Header icon={chunter.icon.Bookmarks} intlLabel={chunter.string.Saved} titleKind={'breadcrumbs'} />
|
||||
|
||||
<div class="body h-full w-full clear-mins">
|
||||
<Scroller padding={'.75rem .5rem'} bottomPadding={'.75rem'}>
|
||||
{#if savedMessages.length > 0 || savedAttachments.length > 0}
|
||||
{#each savedMessages as message}
|
||||
{#if message.$lookup?.attachedTo}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<Scroller padding={'.75rem .5rem'} bottomPadding={'.75rem'}>
|
||||
{#if savedMessages.length > 0 || savedAttachments.length > 0}
|
||||
{#each savedMessages as message}
|
||||
{#if message.$lookup?.attachedTo}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
|
||||
<ActivityMessagePresenter
|
||||
value={message.$lookup?.attachedTo}
|
||||
onClick={() => {
|
||||
handleMessageClicked(message.$lookup?.attachedTo)
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
{#each savedAttachments as attach}
|
||||
{#if attach.$lookup?.attachedTo}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="attachmentContainer flex-no-shrink clear-mins"
|
||||
on:click={() => openAttachment(attach.$lookup?.attachedTo)}
|
||||
>
|
||||
<AttachmentPreview value={attach.$lookup.attachedTo} isSaved={true} />
|
||||
<div class="label">
|
||||
<Label
|
||||
label={chunter.string.SharedBy}
|
||||
params={{
|
||||
name: getName(attach.$lookup.attachedTo, $personAccountByIdStore, $personByIdStore),
|
||||
time: getDisplayTime(attach.modifiedOn)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<ActivityMessagePresenter
|
||||
value={message.$lookup?.attachedTo}
|
||||
onClick={() => {
|
||||
handleMessageClicked(message.$lookup?.attachedTo)
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
{#each savedAttachments as attach}
|
||||
{#if attach.$lookup?.attachedTo}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="attachmentContainer flex-no-shrink clear-mins"
|
||||
on:click={() => openAttachment(attach.$lookup?.attachedTo)}
|
||||
>
|
||||
<AttachmentPreview value={attach.$lookup.attachedTo} isSaved={true} />
|
||||
<div class="label">
|
||||
<Label
|
||||
label={chunter.string.SharedBy}
|
||||
params={{
|
||||
name: getName(attach.$lookup.attachedTo, $personAccountByIdStore, $personByIdStore),
|
||||
time: getDisplayTime(attach.modifiedOn)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
{:else}
|
||||
<BlankView
|
||||
icon={activity.icon.Bookmark}
|
||||
header={chunter.string.EmptySavedHeader}
|
||||
label={chunter.string.EmptySavedText}
|
||||
/>
|
||||
{/if}
|
||||
</Scroller>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
{:else}
|
||||
<BlankView
|
||||
icon={activity.icon.Bookmark}
|
||||
header={chunter.string.EmptySavedHeader}
|
||||
label={chunter.string.EmptySavedText}
|
||||
/>
|
||||
{/if}
|
||||
</Scroller>
|
||||
|
||||
<style lang="scss">
|
||||
.body {
|
||||
background-color: var(--theme-panel-color);
|
||||
}
|
||||
|
||||
.attachmentContainer {
|
||||
cursor: pointer;
|
||||
padding: 2rem;
|
||||
|
@ -30,7 +30,6 @@ import { get, writable } from 'svelte/store'
|
||||
import view from '@hcengineering/view'
|
||||
import workbench, { type SpecialNavModel } from '@hcengineering/workbench'
|
||||
import attachment, { type SavedAttachments } from '@hcengineering/attachment'
|
||||
import activity from '@hcengineering/activity'
|
||||
import { InboxNotificationsClientImpl } from '@hcengineering/notification-resources'
|
||||
import { type Action, showPopup } from '@hcengineering/ui'
|
||||
import contact, { type PersonAccount } from '@hcengineering/contact'
|
||||
@ -84,24 +83,25 @@ export const chatSpecials: SpecialNavModel[] = [
|
||||
{
|
||||
id: 'saved',
|
||||
label: chunter.string.Saved,
|
||||
icon: activity.icon.Bookmark,
|
||||
icon: chunter.icon.Bookmarks,
|
||||
position: 'top',
|
||||
component: chunter.component.SavedMessages
|
||||
},
|
||||
{
|
||||
id: 'chunterBrowser',
|
||||
label: chunter.string.ChunterBrowser,
|
||||
icon: view.icon.Database,
|
||||
icon: chunter.icon.ChunterBrowser,
|
||||
component: chunter.component.ChunterBrowser,
|
||||
position: 'top'
|
||||
},
|
||||
{
|
||||
id: 'channels',
|
||||
label: chunter.string.Channels,
|
||||
icon: view.icon.List,
|
||||
icon: chunter.icon.ChannelBrowser,
|
||||
component: workbench.component.SpecialView,
|
||||
componentProps: {
|
||||
_class: chunter.class.Channel,
|
||||
icon: chunter.icon.ChannelBrowser,
|
||||
label: chunter.string.Channels,
|
||||
createLabel: chunter.string.CreateChannel,
|
||||
createComponent: chunter.component.CreateChannel
|
||||
|
@ -15,7 +15,7 @@
|
||||
<script lang="ts">
|
||||
import { Doc, Ref } from '@hcengineering/core'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { Breadcrumbs, IconClose, Label, location as locationStore } from '@hcengineering/ui'
|
||||
import { Breadcrumbs, IconClose, Label, location as locationStore, Header } from '@hcengineering/ui'
|
||||
import { createEventDispatcher, onDestroy } from 'svelte'
|
||||
import activity, { ActivityMessage, DisplayActivityMessage } from '@hcengineering/activity'
|
||||
import { getMessageFromLoc, messageInFocus } from '@hcengineering/activity-resources'
|
||||
@ -105,71 +105,41 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="popupPanel panel">
|
||||
{#if showHeader}
|
||||
<div class="ac-header divide full caption-height" style="padding: 0.5rem 1rem">
|
||||
<Breadcrumbs items={getBreadcrumbsItems(channel, message, channelName)} />
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="close"
|
||||
on:click={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
>
|
||||
<IconClose size="medium" />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{#if showHeader}
|
||||
<Header type={'type-aside'} adaptive={'disabled'} on:close>
|
||||
<Breadcrumbs items={getBreadcrumbsItems(channel, message, channelName)} currentOnly />
|
||||
</Header>
|
||||
{/if}
|
||||
|
||||
<div class="popupPanel-body">
|
||||
<div class="container">
|
||||
{#if message && dataProvider !== undefined}
|
||||
<ChannelScrollView
|
||||
bind:selectedMessageId
|
||||
embedded
|
||||
skipLabels
|
||||
object={message}
|
||||
objectId={message._id}
|
||||
objectClass={message._class}
|
||||
provider={dataProvider}
|
||||
>
|
||||
<svelte:fragment slot="header">
|
||||
<div class="mt-3">
|
||||
<ThreadParentMessage {message} />
|
||||
<div class="hulyComponent-content hulyComponent-content__container noShrink">
|
||||
{#if message && dataProvider !== undefined}
|
||||
<ChannelScrollView
|
||||
bind:selectedMessageId
|
||||
embedded
|
||||
skipLabels
|
||||
object={message}
|
||||
objectId={message._id}
|
||||
objectClass={message._class}
|
||||
provider={dataProvider}
|
||||
>
|
||||
<svelte:fragment slot="header">
|
||||
<div class="mt-3">
|
||||
<ThreadParentMessage {message} />
|
||||
</div>
|
||||
<div class="separator">
|
||||
{#if message.replies && message.replies > 0}
|
||||
<div class="label lower">
|
||||
<Label label={activity.string.RepliesCount} params={{ replies: message.replies }} />
|
||||
</div>
|
||||
<div class="separator">
|
||||
{#if message.replies && message.replies > 0}
|
||||
<div class="label lower">
|
||||
<Label label={activity.string.RepliesCount} params={{ replies: message.replies }} />
|
||||
</div>
|
||||
{/if}
|
||||
<div class="line" />
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</ChannelScrollView>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="line" />
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</ChannelScrollView>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.close {
|
||||
margin-left: 0.75rem;
|
||||
opacity: 0.4;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.separator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
@ -44,20 +44,10 @@
|
||||
)
|
||||
</script>
|
||||
|
||||
<div class="ac-header full divide caption-height" style="padding: 0.5rem 1rem">
|
||||
<Header icon={chunter.icon.Thread} intlLabel={chunter.string.Threads} titleKind="breadcrumbs" />
|
||||
</div>
|
||||
<Header icon={chunter.icon.Thread} intlLabel={chunter.string.Threads} titleKind={'breadcrumbs'} />
|
||||
|
||||
<div class="body h-full w-full">
|
||||
<Scroller padding="0.75rem 0.5rem">
|
||||
{#each threads as thread}
|
||||
<ActivityMessagePresenter value={thread} onClick={() => openMessageFromSpecial(thread)} withShowMore={false} />
|
||||
{/each}
|
||||
</Scroller>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.body {
|
||||
background-color: var(--theme-panel-color);
|
||||
}
|
||||
</style>
|
||||
<Scroller padding="0.75rem 0.5rem">
|
||||
{#each threads as thread}
|
||||
<ActivityMessagePresenter value={thread} onClick={() => openMessageFromSpecial(thread)} withShowMore={false} />
|
||||
{/each}
|
||||
</Scroller>
|
||||
|
@ -86,7 +86,10 @@ export default plugin(chunterId, {
|
||||
Thread: '' as Asset,
|
||||
Lock: '' as Asset,
|
||||
ChannelBrowser: '' as Asset,
|
||||
Copy: '' as Asset
|
||||
ChunterBrowser: '' as Asset,
|
||||
Copy: '' as Asset,
|
||||
Messages: '' as Asset,
|
||||
Bookmarks: '' as Asset
|
||||
},
|
||||
component: {
|
||||
DmHeader: '' as AnyComponent,
|
||||
|
@ -89,4 +89,10 @@
|
||||
<path d="M1 3C1 1.89543 1.89543 1 3 1H9C10.1046 1 11 1.89543 11 3V3.5H6C4.61929 3.5 3.5 4.61929 3.5 6V11H3C1.89543 11 1 10.1046 1 9V3Z" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 5C5.89543 5 5 5.89543 5 7V13C5 14.1046 5.89543 15 7 15H13C14.1046 15 15 14.1046 15 13V7C15 5.89543 14.1046 5 13 5H7ZM10 10C10.9665 10 11.5 9.2165 11.5 8.25C11.5 7.2835 10.9665 6.5 10 6.5C9.0335 6.5 8.5 7.2835 8.5 8.25C8.5 9.2165 9.0335 10 10 10ZM7 12.5616C7 11.5144 7.9841 10.746 9 11C9.47572 11.7136 10.5243 11.7136 11 11C12.0159 10.746 13 11.5144 13 12.5616V13.0101C13 13.2806 12.7806 13.5 12.5101 13.5H7.48995C7.21936 13.5 7 13.2806 7 13.0101V12.5616Z" />
|
||||
</symbol>
|
||||
<symbol id="contacts" viewBox="0 0 32 32">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.7,5.7c-1.4,0-2.7,0.5-3.5,1.5c-0.9,0.9-1.3,2.3-1.2,3.7c0.2,2.7,2.3,5.1,4.8,5.1c2.5,0,4.6-2.3,4.8-5.1C25.7,8,23.5,5.7,20.7,5.7z M18.5,8.5C18,9,17.7,9.8,17.7,10.8c0.1,2,1.6,3.3,2.9,3.3c1.3,0,2.8-1.3,2.9-3.3c0.1-1.9-1.1-3.2-2.9-3.2C19.8,7.6,19,7.9,18.5,8.5z" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.4,24.1c1.1-4.2,5.2-6.3,9.3-6.3c4,0,8.2,2,9.3,6.3c0.2,0.9-0.4,2.1-1.6,2.1H13C11.7,26.3,11.2,25.1,11.4,24.1z M13.3,24.4h14.8c-0.9-3-3.9-4.7-7.4-4.7C17.2,19.7,14.1,21.4,13.3,24.4z" />
|
||||
<path d="M9.6,16.2c-2.1,0-3.9-1.9-4-4.3c-0.1-1.2,0.3-2.3,1-3.1c0.8-0.8,1.8-1.2,3-1.2c1.2,0,2.2,0.4,3,1.3c0.8,0.8,1.1,1.9,1.1,3.1C13.5,14.3,11.7,16.2,9.6,16.2z M9.6,9.5C9,9.5,8.4,9.7,8,10.1c-0.4,0.4-0.6,1-0.5,1.7c0.1,1.4,1.1,2.5,2.2,2.5s2.1-1.2,2.2-2.5c0-0.7-0.2-1.3-0.6-1.7C10.9,9.7,10.3,9.5,9.6,9.5z" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M2,22.5c0.9-3.5,4.3-5.2,7.6-5.2c1.3,0,2.6,0.2,3.8,0.8c0.5,0.2,0.7,0.8,0.5,1.2c-0.2,0.5-0.8,0.7-1.2,0.5c-0.9-0.4-1.9-0.6-3.1-0.6c-2.6,0-4.9,1.2-5.7,3.4H10c0.5,0,0.9,0.4,0.9,0.9s-0.4,0.9-0.9,0.9H3.5C2.4,24.4,1.8,23.3,2,22.5L2,22.5z" />
|
||||
</symbol>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 21 KiB |
@ -41,6 +41,7 @@ loadMetadata(contact.icon, {
|
||||
Whatsapp: `${icons}#whatsapp`,
|
||||
Profile: `${icons}#profile`,
|
||||
KickUser: `${icons}#kickUser`,
|
||||
ComponentMembers: `${icons}#componentMembers`
|
||||
ComponentMembers: `${icons}#componentMembers`,
|
||||
Contacts: `${icons}#contacts`
|
||||
})
|
||||
addStringsLoader(contactId, async (lang: string) => await import(`../lang/${lang}.json`))
|
||||
|
@ -29,29 +29,23 @@
|
||||
$: updateEmployees(resultQuery)
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
<Scroller>
|
||||
<div>
|
||||
{#each employees as employee}
|
||||
<div class="fs-title item">
|
||||
<EmployeePresenter value={employee} avatarSize="medium" />
|
||||
</div>
|
||||
{/each}
|
||||
<Scroller padding={'var(--spacing-2)'}>
|
||||
{#each employees as employee}
|
||||
<div class="fs-title item">
|
||||
<EmployeePresenter value={employee} avatarSize="medium" />
|
||||
</div>
|
||||
</Scroller>
|
||||
</div>
|
||||
{/each}
|
||||
</Scroller>
|
||||
|
||||
<style lang="scss">
|
||||
.container {
|
||||
border-top: 1px solid var(--divider-color);
|
||||
}
|
||||
.item {
|
||||
color: var(--caption-color);
|
||||
padding: 0.5rem 2rem;
|
||||
color: var(--theme-caption-color);
|
||||
padding: 0.5rem 0.5rem;
|
||||
border-radius: var(--medium-BorderRadius);
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: var(--popup-bg-hover);
|
||||
background-color: var(--highlight-hover);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -78,7 +78,7 @@
|
||||
bind:loading
|
||||
viewletQuery={{ _id: contact.viewlet.TableMember }}
|
||||
/>
|
||||
<ViewletSettingButton kind={'ghost'} bind:viewlet />
|
||||
<ViewletSettingButton kind={'tertiary'} bind:viewlet />
|
||||
{#if !readonly}
|
||||
<Button id={contact.string.AddMember} icon={IconAdd} kind={'ghost'} on:click={createApp} />
|
||||
{/if}
|
||||
|
@ -41,6 +41,6 @@
|
||||
<Avatar person={value} {size} {icon} name={value.name} on:accent-color {showStatus} account={account?._id} />
|
||||
<div class="flex-col min-w-0 {size === 'tiny' || size === 'inline' ? 'ml-1' : 'ml-2'}" class:max-w-20={short}>
|
||||
{#if subtitle}<div class="content-dark-color text-sm">{subtitle}</div>{/if}
|
||||
<div class="label text-left">{getName(client.getHierarchy(), value)}</div>
|
||||
<div class="label text-left overflow-label">{getName(client.getHierarchy(), value)}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -265,7 +265,8 @@ export const contactPlugin = plugin(contactId, {
|
||||
Whatsapp: '' as Asset,
|
||||
ComponentMembers: '' as Asset,
|
||||
Profile: '' as Asset,
|
||||
KickUser: '' as Asset
|
||||
KickUser: '' as Asset,
|
||||
Contacts: '' as Asset
|
||||
},
|
||||
space: {
|
||||
Contacts: '' as Ref<Space>
|
||||
|
@ -47,43 +47,43 @@
|
||||
mode: 'browser'
|
||||
}}
|
||||
/>
|
||||
<div class="antiPanel-component">
|
||||
<ViewletPanelHeader
|
||||
viewletQuery={{
|
||||
attachTo: _class,
|
||||
descriptor: view.viewlet.Table
|
||||
}}
|
||||
bind:viewlet
|
||||
bind:loading
|
||||
bind:viewOptions
|
||||
bind:preference
|
||||
{_class}
|
||||
title={document.string.Categories}
|
||||
{query}
|
||||
bind:resultQuery
|
||||
>
|
||||
<div slot="header-tools">
|
||||
{#if canCreate}
|
||||
<Button
|
||||
icon={IconAdd}
|
||||
label={document.string.DocumentCategoryCreateLabel}
|
||||
size="small"
|
||||
kind="primary"
|
||||
on:click={showCreateDialog}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</ViewletPanelHeader>
|
||||
<ViewletPanelHeader
|
||||
viewletQuery={{
|
||||
attachTo: _class,
|
||||
descriptor: view.viewlet.Table
|
||||
}}
|
||||
bind:viewlet
|
||||
bind:loading
|
||||
bind:viewOptions
|
||||
bind:preference
|
||||
{_class}
|
||||
title={document.string.Categories}
|
||||
icon={documents.icon.Library}
|
||||
{query}
|
||||
bind:resultQuery
|
||||
hideActions={!canCreate}
|
||||
>
|
||||
<svelte:fragment slot="actions">
|
||||
{#if canCreate}
|
||||
<Button
|
||||
icon={IconAdd}
|
||||
label={document.string.DocumentCategoryCreateLabel}
|
||||
size="small"
|
||||
kind="primary"
|
||||
on:click={showCreateDialog}
|
||||
/>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</ViewletPanelHeader>
|
||||
|
||||
{#if loading}
|
||||
<Loading />
|
||||
{:else if viewlet && viewOptions}
|
||||
<TableBrowser
|
||||
{_class}
|
||||
config={preference?.config ?? viewlet.config}
|
||||
options={viewlet.options}
|
||||
query={resultQuery}
|
||||
showNotification
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
{#if loading}
|
||||
<Loading />
|
||||
{:else if viewlet && viewOptions}
|
||||
<TableBrowser
|
||||
{_class}
|
||||
config={preference?.config ?? viewlet.config}
|
||||
options={viewlet.options}
|
||||
query={resultQuery}
|
||||
showNotification
|
||||
/>
|
||||
{/if}
|
||||
|
@ -76,11 +76,13 @@
|
||||
bind:viewOptions
|
||||
bind:preference
|
||||
{_class}
|
||||
icon={documents.icon.Library}
|
||||
title={documents.string.DocumentTemplates}
|
||||
query={srcQuery}
|
||||
bind:resultQuery
|
||||
hideActions={!canAddTemplate}
|
||||
>
|
||||
<div slot="header-tools">
|
||||
<svelte:fragment slot="actions">
|
||||
{#if canAddTemplate}
|
||||
<Button
|
||||
icon={IconAdd}
|
||||
@ -90,7 +92,7 @@
|
||||
on:click={showCreateDialog}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</ViewletPanelHeader>
|
||||
|
||||
{#if loading}
|
||||
|
@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Document } from '@hcengineering/controlled-documents'
|
||||
import { Class, DocumentQuery, Ref, Space, WithLookup } from '@hcengineering/core'
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import type { IntlString, Asset } from '@hcengineering/platform'
|
||||
import { IModeSelector } from '@hcengineering/ui'
|
||||
import view, { Viewlet, ViewletPreference, ViewOptions } from '@hcengineering/view'
|
||||
import { ViewletPanelHeader } from '@hcengineering/view-resources'
|
||||
@ -12,6 +12,7 @@
|
||||
export let _class: Ref<Class<Document>> = document.class.Document
|
||||
export let query: DocumentQuery<Document> = {}
|
||||
export let title: IntlString
|
||||
export let icon: Asset | undefined = undefined
|
||||
export let space: Ref<Space> | undefined = undefined
|
||||
export let panelWidth: number = 0
|
||||
export let modeSelectorProps: IModeSelector | undefined = undefined
|
||||
@ -40,6 +41,8 @@
|
||||
bind:preference
|
||||
{_class}
|
||||
{title}
|
||||
{icon}
|
||||
adaptive={'doubleRow'}
|
||||
{modeSelectorProps}
|
||||
{query}
|
||||
bind:resultQuery
|
||||
|
@ -15,7 +15,7 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { Class, DocumentQuery, Ref, Space } from '@hcengineering/core'
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import type { IntlString, Asset } from '@hcengineering/platform'
|
||||
import { IModeSelector, resolvedLocationStore } from '@hcengineering/ui'
|
||||
import documents, { type Document, type DocumentSpace, DocumentState } from '@hcengineering/controlled-documents'
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
export let _class: Ref<Class<Document>> = document.class.Document
|
||||
export let query: DocumentQuery<Document> = {}
|
||||
export let title: IntlString
|
||||
export let icon: Asset | undefined = undefined
|
||||
export let space: Ref<Space> | undefined = undefined
|
||||
export let config: [string, IntlString, object][]
|
||||
export let panelWidth: number = 0
|
||||
@ -77,4 +78,4 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<Documents query={modifiedQuery} {_class} {title} {space} {panelWidth} {modeSelectorProps} />
|
||||
<Documents query={modifiedQuery} {_class} {icon} {title} {space} {panelWidth} {modeSelectorProps} />
|
||||
|
@ -273,11 +273,13 @@
|
||||
isSub={false}
|
||||
selectedAside={$activeRightPanelTab ?? false}
|
||||
withoutActivity
|
||||
contentClasses="m0 h-full flex-col"
|
||||
contentClasses="h-full flex-col"
|
||||
withoutContentScroll
|
||||
allowClose={withClose && !embedded}
|
||||
{embedded}
|
||||
printHeader={false}
|
||||
adaptive={'doubleRow'}
|
||||
overflowExtra
|
||||
on:close
|
||||
on:select={(ev) => rightPanelTabChanged(ev.detail)}
|
||||
>
|
||||
@ -312,8 +314,8 @@
|
||||
</button>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="pre-utils">
|
||||
<div class="flex flex-gap-2 no-print">
|
||||
<svelte:fragment slot="extra">
|
||||
<div class="flex flex-gap-1 no-print">
|
||||
{#if $isProjectEditable}
|
||||
{#if $isDocumentOwner && !$documentReviewIsActive && !$documentApprovalIsActive}
|
||||
{#if $canSendForReview}
|
||||
@ -377,7 +379,7 @@
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="post-utils">
|
||||
<div class="no-print">
|
||||
<div class="no-print ml-1">
|
||||
<Button
|
||||
icon={IconMoreV}
|
||||
iconProps={{ size: 'medium' }}
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
<DocumentsContainer
|
||||
query={resultQuery}
|
||||
icon={documents.icon.Document}
|
||||
title={documents.string.MyDocuments}
|
||||
{config}
|
||||
on:action={(event) => dispatch('action', event.detail)}
|
||||
|
@ -18,7 +18,7 @@
|
||||
import { rightPanelTabChanged } from '../../../stores/editors/document'
|
||||
</script>
|
||||
|
||||
<div class="header h-12 flex-between min-h-12 pl-4 pr-4 font-medium text-md bottom-divider">
|
||||
<div class="header flex-between min-h-13 pl-4 pr-4 font-medium text-md bottom-divider">
|
||||
<slot />
|
||||
<Button
|
||||
kind="ghost"
|
||||
|
@ -63,7 +63,6 @@
|
||||
export let _id: Ref<Document>
|
||||
export let readonly: boolean = false
|
||||
export let embedded: boolean = false
|
||||
export let kind: 'default' | 'modern' = 'default'
|
||||
|
||||
$: locked = doc?.lockedBy != null
|
||||
$: readonly = $restrictionStore.readonly || locked
|
||||
@ -240,7 +239,7 @@
|
||||
useMaxWidth={false}
|
||||
printHeader={false}
|
||||
{embedded}
|
||||
{kind}
|
||||
adaptive={'default'}
|
||||
bind:content
|
||||
bind:innerWidth
|
||||
floatAside={false}
|
||||
|
@ -1,6 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
|
||||
<symbol id="driveapplication" viewBox="0 0 32 32">
|
||||
<path d="M27.7,24.8h-8.3c-0.3-1.2-1.3-2.1-2.4-2.4v-1.8c0-0.6-0.4-1-1-1s-1,0.4-1,1v1.8c-1.2,0.3-2.1,1.3-2.4,2.4H4.3c-0.6,0-1,0.4-1,1s0.4,1,1,1h8.3c0.4,1.5,1.8,2.6,3.4,2.6s3-1.1,3.4-2.6h8.3c0.6,0,1-0.4,1-1S28.3,24.8,27.7,24.8z M16,27.3c-0.9,0-1.6-0.7-1.6-1.6s0.7-1.6,1.6-1.6s1.6,0.7,1.6,1.6S16.9,27.3,16,27.3z" />
|
||||
<path d="M9.1,21.6h1.7c0.6,0,1-0.4,1-1s-0.4-1-1-1H9.1c-2.8,0-5.1-2.2-5.1-4.8s2.3-4.8,5.1-4.8c0.5,0,0.9-0.3,1-0.8c0.4-1.9,2-3.5,4.1-4.2c2.1-0.6,4.5-0.2,6.2,1.1c1.6,1.3,2.4,3.3,1.9,5.2c-0.1,0.3,0,0.6,0.2,0.8c0.2,0.2,0.5,0.4,0.8,0.4h1.3c1.9,0,3.5,1.6,3.5,3.5s-1.6,3.5-3.5,3.5h-3.3c-0.6,0-1,0.4-1,1s0.4,1,1,1h3.3c3,0,5.5-2.5,5.5-5.5s-2.5-5.5-5.5-5.5h-0.2c0.1-2.3-0.9-4.5-2.8-6c-2.2-1.7-5.2-2.3-8-1.5C11,3.8,9.1,5.6,8.3,7.9C4.8,8.3,2,11.2,2,14.7C2,18.5,5.2,21.5,9.1,21.6z" />
|
||||
</symbol>
|
||||
<symbol id="drive" viewBox="0 0 32 32">
|
||||
<path d="M16 3C10.7021 3 5 4.252 5 7V25C5 27.748 10.7021 29 16 29C21.2979 29 27 27.748 27 25V7C27 4.252 21.2979 3 16 3ZM16 5C21.7976 5 24.7949 6.4341 24.9968 7C24.7949 7.5659 21.7976 9 16 9C10.1587 9 7.1606 7.5444 7 7.0176V7.0127C7.1606 6.4556 10.1587 5 16 5ZM7 9.4277C9.1279 10.4951 12.6426 11 16 11C19.3574 11 22.8721 10.4951 25 9.4277V12.9873C24.8394 13.5444 21.8413 15 16 15C10.1499 15 7.1509 13.54 7 13V9.4277ZM7 15.4277C9.1279 16.4951 12.6426 17 16 17C19.3574 17 22.8721 16.4951 25 15.4277V18.9873C24.8394 19.5444 21.8413 21 16 21C10.1499 21 7.1509 19.54 7 19V15.4277ZM16 27C10.1499 27 7.1509 25.54 7 25V21.4277C9.1279 22.4951 12.6426 23 16 23C19.3574 23 22.8721 22.4951 25 21.4277V24.9873C24.8394 25.5444 21.8413 27 16 27Z" fill="currentColor"/>
|
||||
<path d="M29.9,15.6C29.9,15.6,29.9,15.6,29.9,15.6l-4.5-9c-0.3-0.6-0.8-1.1-1.3-1.5c-0.6-0.4-1.2-0.5-1.9-0.5H9.8c-0.7,0-1.3,0.2-1.9,0.5C7.3,5.5,6.9,6,6.6,6.6l-4.5,9c0,0,0,0,0,0C2,15.7,2,15.8,2,16v7.8c0,1,0.4,1.9,1.1,2.5c0.7,0.7,1.6,1.1,2.5,1.1h20.8c1,0,1.9-0.4,2.5-1.1s1.1-1.6,1.1-2.5V16C30,15.8,30,15.7,29.9,15.6z M8.4,7.5C8.4,7.5,8.4,7.5,8.4,7.5C8.5,7.2,8.7,7,9,6.8c0.3-0.2,0.5-0.2,0.8-0.2h12.4c0.3,0,0.6,0.1,0.8,0.2c0.3,0.2,0.5,0.4,0.6,0.7l3.8,7.5H4.6L8.4,7.5z M27.5,24.9c-0.3,0.3-0.7,0.5-1.1,0.5H5.6c-0.4,0-0.8-0.2-1.1-0.5C4.2,24.6,4,24.2,4,23.8V17h24v6.8C28,24.2,27.8,24.6,27.5,24.9z" />
|
||||
<path d="M8.2,20.2L8.2,20.2c-0.6,0-1,0.4-1,1s0.5,1,1,1s1-0.4,1-1S8.8,20.2,8.2,20.2z" />
|
||||
<path d="M13.4,20.2L13.4,20.2c-0.6,0-1,0.4-1,1s0.5,1,1,1s1-0.4,1-1S14,20.2,13.4,20.2z" />
|
||||
</symbol>
|
||||
<symbol id="drives" viewBox="0 0 32 32">
|
||||
<path d="M30,11.7V8.8c0-2.9-2.4-5.3-5.3-5.3H7.3C4.4,3.4,2,5.8,2,8.8v2.9C2,13.5,2.9,15,4.2,16C2.9,17,2,18.5,2,20.3v2.9c0,2.9,2.4,5.3,5.3,5.3h17.3c2.9,0,5.3-2.4,5.3-5.3v-2.9c0-1.8-0.9-3.4-2.2-4.3C29.1,15,30,13.5,30,11.7z M28,20.3v2.9c0,1.8-1.5,3.3-3.3,3.3H7.3c-1.8,0-3.3-1.5-3.3-3.3v-2.9C4,18.5,5.5,17,7.3,17h17.3C26.5,17,28,18.5,28,20.3z M28,11.7c0,1.8-1.5,3.3-3.3,3.3H7.3C5.5,15,4,13.5,4,11.7V8.8c0-1.8,1.5-3.3,3.3-3.3h17.3c1.8,0,3.3,1.5,3.3,3.3V11.7z" />
|
||||
<path d="M8.8,9.2c-0.6,0-1,0.5-1,1s0.4,1,1,1s1-0.4,1-1v0C9.8,9.7,9.3,9.2,8.8,9.2z" />
|
||||
<path d="M8.8,22.8c0.6,0,1-0.4,1-1v0c0-0.6-0.4-1-1-1s-1,0.5-1,1S8.2,22.8,8.8,22.8z" />
|
||||
<path d="M23.2,9.2h-8.7c-0.6,0-1,0.4-1,1s0.4,1,1,1h8.7c0.6,0,1-0.4,1-1S23.8,9.2,23.2,9.2z" />
|
||||
<path d="M14.6,22.8h8.7c0.6,0,1-0.4,1-1s-0.4-1-1-1h-8.7c-0.6,0-1,0.4-1,1S14,22.8,14.6,22.8z" />
|
||||
</symbol>
|
||||
<symbol id="grid" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
@ -12,13 +25,15 @@
|
||||
<symbol id="folder" viewBox="0 0 32 32">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M2 9C2 6.23858 4.23858 4 7 4H10.6716C11.4672 4 12.2303 4.31607 12.7929 4.87868L15.6213 7.70711C15.8089 7.89464 16.0632 8 16.3284 8H25C27.7614 8 30 10.2386 30 13V23C30 25.7614 27.7614 28 25 28H7C4.23858 28 2 25.7614 2 23V9ZM7 6C5.34315 6 4 7.34315 4 9V23C4 24.6569 5.34315 26 7 26H25C26.6569 26 28 24.6569 28 23V13C28 11.3431 26.6569 10 25 10H16.3284C15.5328 10 14.7697 9.68393 14.2071 9.12132L11.3787 6.29289C11.1911 6.10536 10.9368 6 10.6716 6H7Z" fill="currentColor"/>
|
||||
</symbol>
|
||||
<symbol id="folder-open" viewBox="0 0 33 32">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M28 14V13C28 11.3431 26.6569 10 25 10H16.3284C15.5328 10 14.7697 9.68393 14.2071 9.12132L11.3787 6.29289C11.1911 6.10536 10.9368 6 10.6716 6H7C5.34315 6 4 7.34315 4 9V21L5.17111 16.9011C5.66174 15.1839 7.23128 14 9.01721 14H28Z" fill="currentColor" fill-opacity="0.1"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 4C4.23858 4 2 6.23858 2 9V23C2 25.7614 4.23858 28 7 28H26.9828C28.7687 28 30.3383 26.8161 30.8289 25.0989L32.5432 19.0989C33.147 16.9856 31.9391 14.8804 30 14.2152V13C30 10.2386 27.7614 8 25 8H16.3284C16.0632 8 15.8089 7.89464 15.6213 7.70711L12.7929 4.87868C12.2303 4.31607 11.4672 4 10.6716 4H7ZM28 14V13C28 11.3431 26.6569 10 25 10H16.3284C15.5328 10 14.7697 9.68393 14.2071 9.12132L11.3787 6.29289C11.1911 6.10536 10.9368 6 10.6716 6H7C5.34315 6 4 7.34315 4 9V21L5.17111 16.9011C5.66174 15.1839 7.23128 14 9.01721 14H28Z" fill="currentColor"/>
|
||||
<symbol id="folder-open" viewBox="0 0 32 32">
|
||||
<path opacity="0.5" d="M4.7,13.9v-5c0-1.8,1.5-3.3,3.3-3.3h3.3c1,0,2,0.5,2.6,1.2l1,1.3h9c1.8,0,3.3,1.5,3.3,3.3v2.5" />
|
||||
<path opacity="0.75" d="M5.5,13.9h21c1.6,0,2.8,1.6,2.4,3.1l-1.8,6.9c-0.4,1.5-1.7,2.5-3.2,2.5H8.1c-1.5,0-2.8-1-3.2-2.5l-1.8-6.9C2.7,15.5,3.9,13.9,5.5,13.9L5.5,13.9z" />
|
||||
<path d="M29.3,14.3c-0.3-0.4-0.6-0.7-1-0.9v-2c0-2.4-1.9-4.3-4.3-4.3h-8.5l-0.7-0.9c-0.8-1-2.1-1.6-3.4-1.6H8.1c-2.4,0-4.3,1.9-4.3,4.3v4.5c-0.4,0.2-0.7,0.5-1,0.9c-0.7,0.9-0.9,2-0.6,3L4,24.2c0.5,1.9,2.2,3.2,4.2,3.2h15.7c2,0,3.7-1.3,4.2-3.2l1.8-6.9C30.2,16.3,29.9,15.2,29.3,14.3z M8.1,6.6h3.3c0.7,0,1.4,0.3,1.8,0.9l1,1.3c0.2,0.2,0.5,0.4,0.8,0.4h9c1.3,0,2.3,1,2.3,2.3v1.5H5.7v-4C5.7,7.6,6.8,6.6,8.1,6.6z M27.9,16.8l-1.8,6.9c-0.3,1-1.2,1.7-2.3,1.7H8.1c-1.1,0-2-0.7-2.3-1.7l-1.8-6.9c-0.1-0.5,0-0.9,0.3-1.3c0.3-0.4,0.7-0.6,1.2-0.6h21c0.5,0,0.9,0.2,1.2,0.6C28,15.9,28.1,16.3,27.9,16.8z" />
|
||||
</symbol>
|
||||
<symbol id="folder-closed" viewBox="0 0 32 32">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M2 9C2 6.23858 4.23858 4 7 4H10.6716C11.4672 4 12.2303 4.31607 12.7929 4.87868L15.6213 7.70711C15.8089 7.89464 16.0632 8 16.3284 8H25C27.7614 8 30 10.2386 30 13V23C30 25.7614 27.7614 28 25 28H7C4.23858 28 2 25.7614 2 23V9ZM7 6C5.34315 6 4 7.34315 4 9V23C4 24.6569 5.34315 26 7 26H25C26.6569 26 28 24.6569 28 23V13C28 11.3431 26.6569 10 25 10H16.3284C15.5328 10 14.7697 9.68393 14.2071 9.12132L11.3787 6.29289C11.1911 6.10536 10.9368 6 10.6716 6H7Z" fill="currentColor"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 6C5.34315 6 4 7.34315 4 9V23C4 24.6569 5.34315 26 7 26H25C26.6569 26 28 24.6569 28 23V13C28 11.3431 26.6569 10 25 10H16.3284C15.5328 10 14.7697 9.68393 14.2071 9.12132L11.3787 6.29289C11.1911 6.10536 10.9368 6 10.6716 6H7Z" fill="currentColor" fill-opacity="0.1"/>
|
||||
<path opacity="0.5" d="M23.9,8.1h-9l-1-1.3c-0.6-0.8-1.6-1.2-2.6-1.2H8.1c-1.8,0-3.3,1.5-3.3,3.3v6.7c0-1.8,1.5-3.3,3.3-3.3h15.8c1.8,0,3.3,1.5,3.3,3.3v-4.2C27.3,9.6,25.8,8.1,23.9,8.1z" />
|
||||
<path opacity="0.75" d="M23.9,12.2H8.1c-1.8,0-3.3,1.5-3.3,3.3v7.5c0,1.8,1.5,3.3,3.3,3.3h15.8c1.8,0,3.3-1.5,3.3-3.3v-7.5C27.3,13.7,25.8,12.2,23.9,12.2z" />
|
||||
<path d="M23.9,7.1h-8.5l-0.7-0.9c-0.8-1-2.1-1.6-3.4-1.6H8.1c-2.4,0-4.3,1.9-4.3,4.3v6.7v7.5c0,2.4,1.9,4.3,4.3,4.3h15.8c2.4,0,4.3-1.9,4.3-4.3v-6.9v-0.6v-4.2C28.3,9,26.3,7.1,23.9,7.1z M8.1,6.6h3.3c0.7,0,1.4,0.3,1.8,0.9l1,1.3c0.2,0.2,0.5,0.4,0.8,0.4h9c1.3,0,2.3,1,2.3,2.3v0.5c-0.7-0.4-1.5-0.7-2.3-0.7H8.1c-0.9,0-1.7,0.3-2.3,0.7v-3C5.7,7.6,6.8,6.6,8.1,6.6z M26.3,23.1c0,1.3-1,2.3-2.3,2.3H8.1c-1.3,0-2.3-1-2.3-2.3v-7.5c0-1.3,1-2.3,2.3-2.3h15.8c1.3,0,2.3,1,2.3,2.3v0.6V23.1z" />
|
||||
</symbol>
|
||||
<symbol id="download" viewBox="0 0 24 24">
|
||||
<path d="M18.7,9.6C18.5,6,15.6,3.2,12,3.2C8.4,3.2,5.5,6,5.3,9.5c-2.3,0.7-4,2.9-4,5.5c0,3.2,2.6,5.8,5.8,5.8 c0.5,0,1.1-0.1,1.6-0.2C9,20.4,9.2,20,9.1,19.6S8.6,19,8.2,19.1c-0.4,0.1-0.8,0.2-1.2,0.2c-2.3,0-4.2-1.9-4.2-4.2 c0-2,1.4-3.7,3.3-4.1c0.2,0,0.3-0.1,0.4-0.2c0.2-0.1,0.4-0.4,0.4-0.6c0-2.9,2.4-5.2,5.2-5.2s5.2,2.4,5.2,5.2c0,0.1,0,0.1,0,0.2 c0,0.3,0.2,0.6,0.6,0.7c1.9,0.4,3.3,2.1,3.3,4.1c0,2.3-1.9,4.2-4.2,4.2c-0.4,0-0.8-0.1-1.2-0.2c-0.4-0.1-0.8,0.1-0.9,0.5 c-0.1,0.4,0.1,0.8,0.5,0.9c0.5,0.1,1,0.2,1.6,0.2c3.2,0,5.8-2.6,5.8-5.8C22.6,12.5,21,10.4,18.7,9.6z" />
|
||||
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 7.7 KiB |
@ -18,7 +18,9 @@ import drive from '@hcengineering/drive'
|
||||
|
||||
const icons = require('../assets/icons.svg') as string // eslint-disable-line
|
||||
loadMetadata(drive.icon, {
|
||||
DriveApplication: `${icons}#driveapplication`,
|
||||
Drive: `${icons}#drive`,
|
||||
Drives: `${icons}#drives`,
|
||||
Grid: `${icons}#grid`,
|
||||
File: `${icons}#file`,
|
||||
Folder: `${icons}#folder`,
|
||||
|
@ -16,16 +16,13 @@
|
||||
import { type Ref } from '@hcengineering/core'
|
||||
import drive, { type Drive } from '@hcengineering/drive'
|
||||
import { createQuery } from '@hcengineering/presentation'
|
||||
import { Panel, Scroller, Button, IconMoreH } from '@hcengineering/ui'
|
||||
import { DocAttributeBar, showMenu } from '@hcengineering/view-resources'
|
||||
import { showMenu } from '@hcengineering/view-resources'
|
||||
|
||||
import DrivePresenter from './DrivePresenter.svelte'
|
||||
import FolderBrowser from './FolderBrowser.svelte'
|
||||
|
||||
export let _id: Ref<Drive>
|
||||
export let readonly: boolean = false
|
||||
export let embedded: boolean = false
|
||||
export let kind: 'default' | 'modern' = 'default'
|
||||
|
||||
export function canClose (): boolean {
|
||||
return false
|
||||
@ -40,36 +37,15 @@
|
||||
</script>
|
||||
|
||||
{#if object}
|
||||
<Panel {embedded} allowClose={false} {kind} selectedAside={false}>
|
||||
<svelte:fragment slot="title">
|
||||
<div class="title">
|
||||
<DrivePresenter value={object} shouldShowAvatar={false} disabled noUnderline />
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="utils">
|
||||
<Button
|
||||
icon={IconMoreH}
|
||||
iconProps={{ size: 'medium' }}
|
||||
kind={'icon'}
|
||||
on:click={(ev) => {
|
||||
showMenu(ev, { object })
|
||||
}}
|
||||
/>
|
||||
<div class="buttons-divider max-h-7 h-7 mx-2 no-print" />
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="aside">
|
||||
<Scroller>
|
||||
<DocAttributeBar {object} {readonly} ignoreKeys={[]} />
|
||||
<div class="space-divider bottom" />
|
||||
</Scroller>
|
||||
</svelte:fragment>
|
||||
|
||||
<FolderBrowser
|
||||
space={object._id}
|
||||
parent={drive.ids.Root}
|
||||
on:contextmenu={(evt) => {
|
||||
showMenu(evt, { object })
|
||||
}}
|
||||
/>
|
||||
</Panel>
|
||||
<FolderBrowser
|
||||
space={object._id}
|
||||
parent={drive.ids.Root}
|
||||
{object}
|
||||
{embedded}
|
||||
{readonly}
|
||||
type={'drive'}
|
||||
on:contextmenu={(evt) => {
|
||||
showMenu(evt, { object })
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
|
@ -22,5 +22,5 @@
|
||||
</script>
|
||||
|
||||
{#if object}
|
||||
<FolderBrowser space={object.space} parent={object._id} {readonly} />
|
||||
<FolderBrowser space={object.space} parent={object._id} {readonly} type={'folder'} />
|
||||
{/if}
|
||||
|
@ -32,6 +32,6 @@
|
||||
|
||||
<div class="antiHSpacer x2" />
|
||||
<DocsNavigator elements={parents} />
|
||||
<div class="title">
|
||||
<div class="fs-title flex-row-center">
|
||||
<FilePresenter value={object} shouldShowAvatar={false} shouldShowVersion disabled noUnderline />
|
||||
</div>
|
||||
|
@ -33,7 +33,6 @@
|
||||
export let _id: Ref<DriveFile>
|
||||
export let readonly: boolean = false
|
||||
export let embedded: boolean = false
|
||||
export let kind: 'default' | 'modern' = 'default'
|
||||
|
||||
export function canClose (): boolean {
|
||||
return false
|
||||
@ -95,10 +94,10 @@
|
||||
<Panel
|
||||
{object}
|
||||
{embedded}
|
||||
{kind}
|
||||
allowClose={!embedded}
|
||||
isHeader={false}
|
||||
useMaxWidth={false}
|
||||
adaptive={'default'}
|
||||
on:open
|
||||
on:close
|
||||
on:update
|
||||
|
@ -15,24 +15,32 @@
|
||||
<script lang="ts">
|
||||
import { type Doc, type DocumentQuery, type Ref, type WithLookup } from '@hcengineering/core'
|
||||
import drive, { type Drive, type Folder } from '@hcengineering/drive'
|
||||
import { Scroller, SearchEdit } from '@hcengineering/ui'
|
||||
import { Scroller, SearchInput, Panel, Button, IconMoreH } from '@hcengineering/ui'
|
||||
import { Viewlet, ViewOptions } from '@hcengineering/view'
|
||||
import {
|
||||
FilterBar,
|
||||
FilterButton,
|
||||
ViewletContentView,
|
||||
ViewletSelector,
|
||||
ViewletSettingButton
|
||||
ViewletSettingButton,
|
||||
DocAttributeBar,
|
||||
showMenu
|
||||
} from '@hcengineering/view-resources'
|
||||
|
||||
import DrivePresenter from './DrivePresenter.svelte'
|
||||
import FolderHeader from './FolderHeader.svelte'
|
||||
import FileDropArea from './FileDropArea.svelte'
|
||||
|
||||
export let space: Ref<Drive>
|
||||
export let parent: Ref<Folder>
|
||||
export let object: Drive | Folder | undefined = undefined
|
||||
export let readonly: boolean = false
|
||||
export let embedded: boolean = false
|
||||
export let type: 'drive' | 'folder'
|
||||
|
||||
const _class = drive.class.Resource
|
||||
|
||||
$: object = type === 'drive' ? (object as Drive) : (object as Folder)
|
||||
$: query = { space, parent }
|
||||
|
||||
let viewlet: WithLookup<Viewlet> | undefined = undefined
|
||||
@ -48,26 +56,49 @@
|
||||
function updateSearchQuery (search: string): void {
|
||||
searchQuery = search === '' ? { ...query } : { ...query, $search: search }
|
||||
}
|
||||
|
||||
const getDrive = (obj: Drive | Folder): Drive => obj as Drive
|
||||
const getFolder = (obj: Drive | Folder): Folder => obj as Folder
|
||||
</script>
|
||||
|
||||
{#if space !== undefined}
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div class="antiComponent">
|
||||
<div class="ac-header full divide caption-height">
|
||||
<div class="ac-header-full small-gap">
|
||||
<SearchEdit bind:value={search} on:change={() => {}} />
|
||||
<div class="buttons-divider" />
|
||||
<FilterButton {_class} {space} />
|
||||
</div>
|
||||
<div class="ac-header-full medium-gap">
|
||||
<ViewletSettingButton bind:viewOptions bind:viewlet />
|
||||
<ViewletSelector bind:viewlet viewletQuery={{ attachTo: _class }} />
|
||||
</div>
|
||||
</div>
|
||||
{#if space !== undefined && object}
|
||||
<Panel {embedded} allowClose={false} selectedAside={false}>
|
||||
<svelte:fragment slot="beforeTitle">
|
||||
<ViewletSelector bind:viewlet viewletQuery={{ attachTo: _class }} />
|
||||
<ViewletSettingButton bind:viewOptions bind:viewlet />
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="title">
|
||||
{#if type === 'drive'}
|
||||
<DrivePresenter value={getDrive(object)} shouldShowAvatar={false} disabled noUnderline />
|
||||
{:else}
|
||||
<FolderHeader object={getFolder(object)} />
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="search">
|
||||
<SearchInput bind:value={search} collapsed />
|
||||
<FilterButton {_class} {space} />
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="utils">
|
||||
<Button
|
||||
icon={IconMoreH}
|
||||
iconProps={{ size: 'medium' }}
|
||||
kind={'icon'}
|
||||
on:click={(ev) => {
|
||||
showMenu(ev, { object })
|
||||
}}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="aside">
|
||||
<Scroller>
|
||||
<DocAttributeBar {object} {readonly} ignoreKeys={[]} />
|
||||
<div class="space-divider bottom" />
|
||||
</Scroller>
|
||||
</svelte:fragment>
|
||||
|
||||
{#if viewlet !== undefined && viewOptions}
|
||||
<FilterBar {_class} {space} query={searchQuery} {viewOptions} on:change={(e) => (resultQuery = e.detail)} />
|
||||
<div class="popupPanel rowContent" on:contextmenu>
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div class="popupPanel-body" on:contextmenu>
|
||||
{#if viewlet}
|
||||
<FileDropArea {space} {parent} canDrop={() => !readonly}>
|
||||
<Scroller horizontal={true}>
|
||||
@ -77,5 +108,5 @@
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</Panel>
|
||||
{/if}
|
||||
|
@ -16,16 +16,13 @@
|
||||
import { type Ref } from '@hcengineering/core'
|
||||
import drive, { type Folder } from '@hcengineering/drive'
|
||||
import { createQuery } from '@hcengineering/presentation'
|
||||
import { Panel, Button, Scroller, IconMoreH } from '@hcengineering/ui'
|
||||
import { DocAttributeBar, showMenu } from '@hcengineering/view-resources'
|
||||
import { showMenu } from '@hcengineering/view-resources'
|
||||
|
||||
import FolderHeader from './FolderHeader.svelte'
|
||||
import FolderBrowser from './FolderBrowser.svelte'
|
||||
|
||||
export let _id: Ref<Folder>
|
||||
export let readonly: boolean = false
|
||||
export let embedded: boolean = false
|
||||
export let kind: 'default' | 'modern' = 'default'
|
||||
|
||||
export function canClose (): boolean {
|
||||
return false
|
||||
@ -40,35 +37,15 @@
|
||||
</script>
|
||||
|
||||
{#if object}
|
||||
<Panel {embedded} allowClose={false} {kind} selectedAside={false}>
|
||||
<svelte:fragment slot="title">
|
||||
<FolderHeader {object} />
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="utils">
|
||||
<Button
|
||||
icon={IconMoreH}
|
||||
iconProps={{ size: 'medium' }}
|
||||
kind={'icon'}
|
||||
on:click={(ev) => {
|
||||
showMenu(ev, { object })
|
||||
}}
|
||||
/>
|
||||
<div class="buttons-divider max-h-7 h-7 mx-2 no-print" />
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="aside">
|
||||
<Scroller>
|
||||
<DocAttributeBar {object} {readonly} ignoreKeys={[]} />
|
||||
<div class="space-divider bottom" />
|
||||
</Scroller>
|
||||
</svelte:fragment>
|
||||
|
||||
<FolderBrowser
|
||||
space={object.space}
|
||||
parent={object._id}
|
||||
{readonly}
|
||||
on:contextmenu={(evt) => {
|
||||
showMenu(evt, { object })
|
||||
}}
|
||||
/>
|
||||
</Panel>
|
||||
<FolderBrowser
|
||||
space={object.space}
|
||||
parent={object._id}
|
||||
{object}
|
||||
{embedded}
|
||||
{readonly}
|
||||
type={'folder'}
|
||||
on:contextmenu={(evt) => {
|
||||
showMenu(evt, { object })
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
|
@ -42,7 +42,7 @@
|
||||
</script>
|
||||
|
||||
{#if isFolder}
|
||||
<Icon icon={IconFolderThumbnail} size={'full'} fill={'var(--theme-trans-color)'} />
|
||||
<Icon icon={IconFolderThumbnail} size={'full'} fill={'var(--global-no-priority-PriorityColor)'} />
|
||||
{:else if previewRef != null && isImage && !isError}
|
||||
{#await getBlobRef(undefined, previewRef, object.name, sizeToWidth(size)) then blobSrc}
|
||||
<img
|
||||
|
@ -39,7 +39,9 @@ export const drivePlugin = plugin(driveId, {
|
||||
DefaultDriveTypeData: '' as Ref<Mixin<Drive>>
|
||||
},
|
||||
icon: {
|
||||
DriveApplication: '' as Asset,
|
||||
Drive: '' as Asset,
|
||||
Drives: '' as Asset,
|
||||
Grid: '' as Asset,
|
||||
File: '' as Asset,
|
||||
Folder: '' as Asset,
|
||||
|
@ -13,6 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { onDestroy } from 'svelte'
|
||||
import { CalendarMode } from '@hcengineering/calendar-resources'
|
||||
import calendar from '@hcengineering/calendar-resources/src/plugin'
|
||||
import { Employee, PersonAccount } from '@hcengineering/contact'
|
||||
@ -20,25 +21,32 @@
|
||||
import { DocumentQuery, Ref, getCurrentAccount } from '@hcengineering/core'
|
||||
import { Department, Staff } from '@hcengineering/hr'
|
||||
import { createQuery } from '@hcengineering/presentation'
|
||||
import type { TabItem } from '@hcengineering/ui'
|
||||
import { getEmbeddedLabel } from '@hcengineering/platform'
|
||||
import type { TabItem, DropdownIntlItem } from '@hcengineering/ui'
|
||||
import {
|
||||
Button,
|
||||
ModernButton,
|
||||
ButtonIcon,
|
||||
IconBack,
|
||||
IconForward,
|
||||
Label,
|
||||
SearchEdit,
|
||||
SearchInput,
|
||||
Separator,
|
||||
TabList,
|
||||
Header,
|
||||
Breadcrumb,
|
||||
Switcher,
|
||||
defineSeparators,
|
||||
workbenchSeparators,
|
||||
deviceOptionsStore as deviceInfo
|
||||
deviceOptionsStore as deviceInfo,
|
||||
tableToCSV,
|
||||
showPopup
|
||||
} from '@hcengineering/ui'
|
||||
import view from '@hcengineering/view'
|
||||
import view, { Viewlet, ViewletPreference } from '@hcengineering/view'
|
||||
import { ViewletSelector, ViewletSettingButton } from '@hcengineering/view-resources'
|
||||
|
||||
import hr from '../plugin'
|
||||
|
||||
import ScheduleView from './ScheduleView.svelte'
|
||||
import Sidebar from './sidebar/Sidebar.svelte'
|
||||
import ExportPopup from './schedule/ExportPopup.svelte'
|
||||
|
||||
const accountEmployee = $employeeByIdStore.get((getCurrentAccount() as PersonAccount).person as Ref<Employee>)
|
||||
let accountStaff: Staff | undefined
|
||||
@ -122,10 +130,60 @@
|
||||
{ id: 'stats', icon: view.icon.Table }
|
||||
]
|
||||
|
||||
let viewlet: Viewlet | undefined
|
||||
let preference: ViewletPreference | undefined
|
||||
let loading = false
|
||||
|
||||
function exportTable (evt: Event) {
|
||||
interface ExportPopupItem extends DropdownIntlItem {
|
||||
separator: ',' | ';'
|
||||
}
|
||||
const items: ExportPopupItem[] = [
|
||||
{
|
||||
id: '0',
|
||||
label: getEmbeddedLabel(', (csv)'),
|
||||
separator: ','
|
||||
},
|
||||
{
|
||||
id: '1',
|
||||
label: getEmbeddedLabel('; (MS Excel)'),
|
||||
separator: ';'
|
||||
}
|
||||
]
|
||||
showPopup(
|
||||
ExportPopup,
|
||||
{
|
||||
items
|
||||
},
|
||||
evt.target as HTMLElement,
|
||||
(res) => {
|
||||
if (res != null) {
|
||||
const filename = 'exportStaff' + new Date().toLocaleDateString() + '.csv'
|
||||
const link = document.createElement('a')
|
||||
link.style.display = 'none'
|
||||
link.setAttribute('target', '_blank')
|
||||
link.setAttribute(
|
||||
'href',
|
||||
'data:text/csv;charset=utf-8,%EF%BB%BF' +
|
||||
encodeURIComponent(tableToCSV('exportableData', items[res].separator))
|
||||
)
|
||||
link.setAttribute('download', filename)
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
let replacedPanel: HTMLElement
|
||||
$: $deviceInfo.replacedPanel = replacedPanel
|
||||
onDestroy(() => ($deviceInfo.replacedPanel = undefined))
|
||||
|
||||
defineSeparators('workbench', workbenchSeparators)
|
||||
</script>
|
||||
|
||||
<div class="flex h-full clear-mins">
|
||||
<div class="hulyPanels-container">
|
||||
{#if $deviceInfo.navigator.visible}
|
||||
<Sidebar
|
||||
{department}
|
||||
@ -140,68 +198,90 @@
|
||||
float={$deviceInfo.navigator.float}
|
||||
disabledWhen={['panel-aside']}
|
||||
index={0}
|
||||
color={'var(--theme-navpanel-border)'}
|
||||
color={'transparent'}
|
||||
separatorSize={0}
|
||||
short
|
||||
/>
|
||||
{/if}
|
||||
|
||||
<div class="antiPanel-component filled">
|
||||
<div class="ac-header full divide caption-height">
|
||||
<div class="ac-header__wrap-title mr-3">
|
||||
<span class="ac-header__title"><Label label={hr.string.Schedule} /></span>
|
||||
</div>
|
||||
|
||||
<div class="ac-header-full medium-gap mb-1">
|
||||
<div class="hulyComponent" bind:this={replacedPanel}>
|
||||
<Header
|
||||
adaptive={'disabled'}
|
||||
hideBefore={mode === CalendarMode.Year}
|
||||
hideActions={!(mode === CalendarMode.Month && display === 'stats')}
|
||||
>
|
||||
<svelte:fragment slot="beforeTitle">
|
||||
{#if mode === CalendarMode.Month}
|
||||
<TabList
|
||||
<Switcher
|
||||
name={'schedule-mode-view'}
|
||||
items={viewslist}
|
||||
multiselect={false}
|
||||
kind={'subtle'}
|
||||
selected={display}
|
||||
on:select={(result) => {
|
||||
if (result.detail !== undefined) display = result.detail.id
|
||||
}}
|
||||
/>
|
||||
{#if display === 'stats'}
|
||||
<ViewletSelector
|
||||
hidden
|
||||
bind:viewlet
|
||||
bind:preference
|
||||
bind:loading
|
||||
viewletQuery={{ _id: hr.viewlet.StaffStats }}
|
||||
/>
|
||||
<ViewletSettingButton bind:viewlet />
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ac-header full divide search-start">
|
||||
<div class="ac-header-full small-gap">
|
||||
<SearchEdit
|
||||
</svelte:fragment>
|
||||
|
||||
<Breadcrumb icon={hr.icon.HR} label={hr.string.Schedule} size={'large'} isCurrent />
|
||||
|
||||
<svelte:fragment slot="search">
|
||||
<SearchInput
|
||||
bind:value={search}
|
||||
collapsed
|
||||
on:change={() => {
|
||||
updateResultQuery(search)
|
||||
}}
|
||||
/>
|
||||
<!-- <ActionIcon icon={IconMoreH} size={'small'} /> -->
|
||||
</div>
|
||||
<div class="ac-header-full medium-gap">
|
||||
<!-- <ViewletSettingButton bind:viewOptions {viewlet} /> -->
|
||||
<!-- <ActionIcon icon={IconMoreH} size={'small'} /> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="ac-header full divide">
|
||||
<div class="ac-header-full small-gap">
|
||||
<Button
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="actions">
|
||||
{#if mode === CalendarMode.Month && display === 'stats'}
|
||||
<ModernButton
|
||||
label={hr.string.Export}
|
||||
size={'small'}
|
||||
on:click={(evt) => {
|
||||
exportTable(evt)
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</Header>
|
||||
<div class="hulyHeader-container clearPadding justify-between flex-gap-4">
|
||||
<div class="flex-row-center flex-gap-2">
|
||||
<ButtonIcon
|
||||
icon={IconBack}
|
||||
kind={'ghost'}
|
||||
kind={'tertiary'}
|
||||
size={'small'}
|
||||
on:click={() => {
|
||||
inc(-1)
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
<ModernButton
|
||||
label={calendar.string.Today}
|
||||
kind={'ghost'}
|
||||
on:click={() => {
|
||||
currentDate = new Date()
|
||||
}}
|
||||
kind={'tertiary'}
|
||||
size={'small'}
|
||||
on:click={() => (currentDate = new Date())}
|
||||
/>
|
||||
<Button
|
||||
<ButtonIcon
|
||||
icon={IconForward}
|
||||
kind={'ghost'}
|
||||
kind={'tertiary'}
|
||||
size={'small'}
|
||||
on:click={() => {
|
||||
inc(1)
|
||||
}}
|
||||
/>
|
||||
<div class="buttons-divider" />
|
||||
<div class="hulyHeader-divider short" />
|
||||
<div class="fs-title flex-row-center flex-grow firstLetter">
|
||||
{#if mode === CalendarMode.Month}
|
||||
<span class="mr-2 overflow-label">{getMonthName(currentDate)}</span>
|
||||
@ -209,12 +289,14 @@
|
||||
{currentDate.getFullYear()}
|
||||
</div>
|
||||
</div>
|
||||
<TabList
|
||||
<Switcher
|
||||
name={'calendar-mode-view'}
|
||||
selected={mode === CalendarMode.Month ? 'ModeMonth' : 'ModeYear'}
|
||||
kind={'subtle'}
|
||||
items={[
|
||||
{ id: 'ModeMonth', labelIntl: calendar.string.ModeMonth },
|
||||
{ id: 'ModeYear', labelIntl: calendar.string.ModeYear }
|
||||
]}
|
||||
multiselect={false}
|
||||
on:select={handleSelect}
|
||||
/>
|
||||
</div>
|
||||
@ -227,6 +309,9 @@
|
||||
{currentDate}
|
||||
{mode}
|
||||
{display}
|
||||
{preference}
|
||||
{viewlet}
|
||||
{loading}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|