mirror of
https://github.com/hcengineering/platform.git
synced 2025-01-03 08:57:14 +03:00
Update Settings layout (#4277)
Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
parent
09579fd2b0
commit
f4d6faf4f8
@ -565,7 +565,7 @@ export function createModel (builder: Builder): void {
|
|||||||
name: 'relations',
|
name: 'relations',
|
||||||
label: tracker.string.RelatedIssues,
|
label: tracker.string.RelatedIssues,
|
||||||
icon: tracker.icon.Relations,
|
icon: tracker.icon.Relations,
|
||||||
component: tracker.component.EditRelatedTargets,
|
component: tracker.component.SettingsRelatedTargets,
|
||||||
group: 'settings-editor',
|
group: 'settings-editor',
|
||||||
secured: false,
|
secured: false,
|
||||||
order: 4000
|
order: 4000
|
||||||
|
@ -59,6 +59,7 @@ export default mergeIds(trackerId, tracker, {
|
|||||||
MilestoneFilter: '' as AnyComponent,
|
MilestoneFilter: '' as AnyComponent,
|
||||||
EditRelatedTargets: '' as AnyComponent,
|
EditRelatedTargets: '' as AnyComponent,
|
||||||
EditRelatedTargetsPopup: '' as AnyComponent,
|
EditRelatedTargetsPopup: '' as AnyComponent,
|
||||||
|
SettingsRelatedTargets: '' as AnyComponent,
|
||||||
IssueSearchIcon: '' as AnyComponent,
|
IssueSearchIcon: '' as AnyComponent,
|
||||||
MembersArrayEditor: '' as AnyComponent
|
MembersArrayEditor: '' as AnyComponent
|
||||||
},
|
},
|
||||||
|
@ -83,6 +83,20 @@
|
|||||||
|
|
||||||
// New
|
// New
|
||||||
--global-accent-IconColor: #6796FF;
|
--global-accent-IconColor: #6796FF;
|
||||||
|
|
||||||
|
--button-accent-LabelColor: #fff;
|
||||||
|
--button-disabled-LabelColor: #8b97ad;
|
||||||
|
--button-accent-IconColor: #fff;
|
||||||
|
--button-disabled-IconColor: #8b97ad;
|
||||||
|
--button-primary-BackgroundColor: #3364e2;
|
||||||
|
--button-primary-BorderColor: #d1d5de1a;
|
||||||
|
--button-primary-hover-BackgroundColor: #6191fe;
|
||||||
|
--button-primary-active-BackgroundColor: #2553cf;
|
||||||
|
--button-primary-loading-LabelColor: #6191fe;
|
||||||
|
--button-negative-loading-LabelColor: #ff9187;
|
||||||
|
--button-negative-BorderColor: #d1d5de26;
|
||||||
|
--button-negative-hover-BackgroundColor: #e34748;
|
||||||
|
--button-negative-active-BackgroundColor: #c42a32;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dark Theme */
|
/* Dark Theme */
|
||||||
@ -317,12 +331,42 @@
|
|||||||
--global-ui-hover-BackgroundColor: #A5BDFF1A;
|
--global-ui-hover-BackgroundColor: #A5BDFF1A;
|
||||||
--global-ui-highlight-BackgroundColor: #A5BDFF0D;
|
--global-ui-highlight-BackgroundColor: #A5BDFF0D;
|
||||||
--global-ui-hover-highlight-BackgroundColor: #A5BDFF26;
|
--global-ui-hover-highlight-BackgroundColor: #A5BDFF26;
|
||||||
|
--global-surface-01-BackgroundColor: #131925;
|
||||||
--global-surface-01-BorderColor: #1F2737;
|
--global-surface-01-BorderColor: #1F2737;
|
||||||
--global-surface-02-BackgroundColor: #19202E;
|
--global-surface-02-BackgroundColor: #19202E;
|
||||||
|
--global-surface-02-BorderColor: #262F40;
|
||||||
|
--global-surface-03-hover-BackgroundColor: #19202E;
|
||||||
|
--global-primary-LinkColor: #4D7FF5;
|
||||||
--global-primary-TextColor: #FFFFFF;
|
--global-primary-TextColor: #FFFFFF;
|
||||||
--global-secondary-TextColor: #C1C9D6;
|
--global-secondary-TextColor: #C1C9D6;
|
||||||
--global-tertiary-TextColor: #8E99AF;
|
--global-tertiary-TextColor: #8E99AF;
|
||||||
--global-accent-TextColor: #4D7FF5;
|
--global-accent-TextColor: #4D7FF5;
|
||||||
|
/** Buttons **/
|
||||||
|
--button-subtle-LabelColor: #fff;
|
||||||
|
--button-subtle-IconColor: #fff;
|
||||||
|
--button-disabled-BackgroundColor: #d1d5de0d;
|
||||||
|
--button-primary-loading-LabelColor: #6191fe;
|
||||||
|
--button-secondary-BackgroundColor: #d1d5de0d;
|
||||||
|
--button-secondary-BorderColor: #d1d5de1a;
|
||||||
|
--button-secondary-hover-BackgroundColor: #d1d5de1a;
|
||||||
|
--button-secondary-active-BackgroundColor: #d1d5de26;
|
||||||
|
--button-negative-BackgroundColor: #e34748;
|
||||||
|
--button-tertiary-hover-BackgroundColor: #d1d5de1a;
|
||||||
|
--button-tertiary-active-BackgroundColor: #d1d5de26;
|
||||||
|
--button-menu-active-BorderColor: #d9dee6;
|
||||||
|
/** Editbox **/
|
||||||
|
--input-BackgroundColor: #a5bdff0d;
|
||||||
|
--input-hover-BackgroundColor: #a5bdff1a;
|
||||||
|
--input-BorderColor: #a5bdff0d;
|
||||||
|
--input-TextColor: #ffffff;
|
||||||
|
--input-LabelColor: #ffffff;
|
||||||
|
--input-filled-LabelColor: #8b97ad;
|
||||||
|
--input-PlaceholderColor: #8b97ad;
|
||||||
|
--input-hover-PlaceholderColor: #ffffff;
|
||||||
|
--input-focus-PlaceholderColor: #556178;
|
||||||
|
--input-HelperColor: #8b97ad;
|
||||||
|
--input-error-BorderColor: #fb6863;
|
||||||
|
--input-search-IconColor: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Light Theme */
|
/* Light Theme */
|
||||||
@ -557,10 +601,40 @@
|
|||||||
--global-ui-hover-BackgroundColor: #1530721A;
|
--global-ui-hover-BackgroundColor: #1530721A;
|
||||||
--global-ui-highlight-BackgroundColor: #A5BDFF26;
|
--global-ui-highlight-BackgroundColor: #A5BDFF26;
|
||||||
--global-ui-hover-highlight-BackgroundColor: #A5BDFF40;
|
--global-ui-hover-highlight-BackgroundColor: #A5BDFF40;
|
||||||
|
--global-surface-01-BackgroundColor: #F8F9FA;
|
||||||
--global-surface-01-BorderColor: #DDE1E9;
|
--global-surface-01-BorderColor: #DDE1E9;
|
||||||
--global-surface-02-BackgroundColor: #19202E;
|
--global-surface-02-BackgroundColor: #19202E;
|
||||||
|
--global-surface-02-BorderColor: #EBEEF2;
|
||||||
|
--global-surface-03-hover-BackgroundColor: #F8F9FA;
|
||||||
|
--global-primary-LinkColor: #3566E2;
|
||||||
--global-primary-TextColor: #0F121A;
|
--global-primary-TextColor: #0F121A;
|
||||||
--global-secondary-TextColor: #5A667E;
|
--global-secondary-TextColor: #5A667E;
|
||||||
--global-tertiary-TextColor: #7B879E;
|
--global-tertiary-TextColor: #7B879E;
|
||||||
--global-accent-TextColor: #3566E2;
|
--global-accent-TextColor: #3566E2;
|
||||||
|
/** Buttons **/
|
||||||
|
--button-subtle-LabelColor: #000;
|
||||||
|
--button-subtle-IconColor: #000;
|
||||||
|
--button-disabled-BackgroundColor: #1725470d;
|
||||||
|
--button-primary-loading-LabelColor: #95baff;
|
||||||
|
--button-secondary-BackgroundColor: #1725470d;
|
||||||
|
--button-secondary-BorderColor: #1725471a;
|
||||||
|
--button-secondary-hover-BackgroundColor: #1725471a;
|
||||||
|
--button-secondary-active-BackgroundColor: #17254726;
|
||||||
|
--button-negative-BackgroundColor: #ea4c4c;
|
||||||
|
--button-tertiary-hover-BackgroundColor: #1725471a;
|
||||||
|
--button-tertiary-active-BackgroundColor: #17254726;
|
||||||
|
--button-menu-active-BorderColor: #0f121a;
|
||||||
|
/** Editbox **/
|
||||||
|
--input-BackgroundColor: #1530720d;
|
||||||
|
--input-hover-BackgroundColor: #1530721a;
|
||||||
|
--input-BorderColor: #1530720d;
|
||||||
|
--input-TextColor: #0f121a;
|
||||||
|
--input-LabelColor: #0f121a;
|
||||||
|
--input-filled-LabelColor: #556178;
|
||||||
|
--input-PlaceholderColor: #556178;
|
||||||
|
--input-hover-PlaceholderColor: #0f121a;
|
||||||
|
--input-focus-PlaceholderColor: #8b97ad;
|
||||||
|
--input-HelperColor: #556178;
|
||||||
|
--input-error-BorderColor: #e34748;
|
||||||
|
--input-search-IconColor: #0f121a;
|
||||||
}
|
}
|
||||||
|
@ -574,6 +574,7 @@ input.search {
|
|||||||
.py-0-5 { padding: 0.125rem 0; }
|
.py-0-5 { padding: 0.125rem 0; }
|
||||||
.py-1 { padding: 0.25rem 0; }
|
.py-1 { padding: 0.25rem 0; }
|
||||||
.py-2 { padding: 0.5rem 0; }
|
.py-2 { padding: 0.5rem 0; }
|
||||||
|
.py-3 { padding: 0.75rem 0; }
|
||||||
.py-4 { padding: 1rem 0; }
|
.py-4 { padding: 1rem 0; }
|
||||||
.py-8 { padding: 2rem 0; }
|
.py-8 { padding: 2rem 0; }
|
||||||
.py-10 { padding: 2.5rem 0; }
|
.py-10 { padding: 2.5rem 0; }
|
||||||
|
59
packages/theme/styles/_vars.scss
Normal file
59
packages/theme/styles/_vars.scss
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
//
|
||||||
|
// Copyright © 2021 Anticrm Platform Contributors.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
* {
|
||||||
|
/** Space & Dimensions **/
|
||||||
|
|
||||||
|
--spacing-0_25: 0.125rem;
|
||||||
|
--spacing-0_5: 0.25rem;
|
||||||
|
--spacing-0_75: 0.375rem;
|
||||||
|
--spacing-1: 0.5rem;
|
||||||
|
--spacing-1_5: 0.75rem;
|
||||||
|
--spacing-1_75: 0.875rem;
|
||||||
|
--spacing-2: 1rem;
|
||||||
|
--spacing-2_5: 1.25rem;
|
||||||
|
--spacing-3: 1.5rem;
|
||||||
|
--spacing-3_5: 1.75rem;
|
||||||
|
--spacing-4: 2rem;
|
||||||
|
--spacing-4_5: 2.25rem;
|
||||||
|
--spacing-5: 2.5rem;
|
||||||
|
--spacing-6: 3rem;
|
||||||
|
--spacing-6_5: 3.5rem;
|
||||||
|
--spacing-7: 4rem;
|
||||||
|
--spacing-8: 5rem;
|
||||||
|
--spacing-9: 6rem;
|
||||||
|
--spacing-10: 7.5rem;
|
||||||
|
|
||||||
|
/** UI Elements Size **/
|
||||||
|
|
||||||
|
--global-min-Size: 1rem;
|
||||||
|
--global-extra-small-Size: 1.5rem;
|
||||||
|
--global-small-Size: 2rem;
|
||||||
|
--global-medium-Size: 2.5rem;
|
||||||
|
--global-large-Size: 3rem;
|
||||||
|
--global-extra-large-Size: 3.5rem;
|
||||||
|
--global-max-Size: 4rem;
|
||||||
|
|
||||||
|
/** Border Radius **/
|
||||||
|
|
||||||
|
--extra-small-BorderRadius: 0.25rem;
|
||||||
|
--extra-small-focus-BorderRadius: 0.375rem;
|
||||||
|
--small-BorderRadius: 0.375rem;
|
||||||
|
--small-focus-BorderRadius: 0.5rem;
|
||||||
|
--medium-BorderRadius: 0.5rem;
|
||||||
|
--medium-focus-BorderRadius: 0.625rem;
|
||||||
|
--large-BorderRadius: 1rem;
|
||||||
|
--large-focus-BorderRadius: 1.125rem;
|
||||||
|
}
|
@ -18,7 +18,9 @@
|
|||||||
.font-medium-12,
|
.font-medium-12,
|
||||||
.font-regular-14,
|
.font-regular-14,
|
||||||
.font-medium-14,
|
.font-medium-14,
|
||||||
.font-bold-14 {
|
.font-bold-14,
|
||||||
|
.paragraph-regular-14,
|
||||||
|
.heading-medium-16 {
|
||||||
font-family: var(--font-family);
|
font-family: var(--font-family);
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
line-height: 1rem;
|
line-height: 1rem;
|
||||||
@ -30,11 +32,13 @@
|
|||||||
}
|
}
|
||||||
.font-regular-14,
|
.font-regular-14,
|
||||||
.font-medium-14,
|
.font-medium-14,
|
||||||
.font-bold-14 {
|
.font-bold-14,
|
||||||
|
.paragraph-regular-14 {
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
}
|
}
|
||||||
.font-regular-12,
|
.font-regular-12,
|
||||||
.font-regular-14 {
|
.font-regular-14,
|
||||||
|
.paragraph-regular-14 {
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
.font-medium-12,
|
.font-medium-12,
|
||||||
@ -44,7 +48,15 @@
|
|||||||
.font-bold-14 {
|
.font-bold-14 {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
.heading-medium-16 {
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1.125rem;
|
||||||
|
}
|
||||||
|
.paragraph-regular-14 {
|
||||||
|
line-height: 1.25rem;
|
||||||
|
color: var(--global-tertiary-TextColor);
|
||||||
|
}
|
||||||
|
|
||||||
/* Panels */
|
/* Panels */
|
||||||
* {
|
* {
|
||||||
@ -83,7 +95,7 @@
|
|||||||
|
|
||||||
&.header { background-color: var(--theme-comp-header-color); }
|
&.header { background-color: var(--theme-comp-header-color); }
|
||||||
&.filled { background-color: var(--theme-bg-color); }
|
&.filled { background-color: var(--theme-bg-color); }
|
||||||
&.filledNav { background-color: var(--theme-navpanel-color); }
|
&.filledNav { background-color: var(--theme-navpanel-color) !important; }
|
||||||
&.border-left { border-left: 1px solid var(--theme-divider-color); }
|
&.border-left { border-left: 1px solid var(--theme-divider-color); }
|
||||||
&.border-right { border-right: 1px solid var(--theme-divider-color); }
|
&.border-right { border-right: 1px solid var(--theme-divider-color); }
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,74 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
/* Huly Component */
|
||||||
|
.hulyComponent {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-grow: 1;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 0;
|
||||||
|
min-width: 0;
|
||||||
|
background-color: var(--theme-panel-color); // var(--global-surface-02-BackgroundColor);
|
||||||
|
border: 1px solid var(--theme-divider-color); // var(--global-surface-02-BorderColor);
|
||||||
|
border-radius: var(--small-focus-BorderRadius);
|
||||||
|
}
|
||||||
|
.hulyComponent-content,
|
||||||
|
.hulyComponent-content__container,
|
||||||
|
.hulyComponent-content__column,
|
||||||
|
.hulyComponent-content__column.content,
|
||||||
|
.hulyComponent-content__navHeader {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
.hulyComponent-content {
|
||||||
|
flex-shrink: 0;
|
||||||
|
max-width: 64rem;
|
||||||
|
|
||||||
|
&__container {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
&:not(.columns) {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
&__column {
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
&.navigation .hulyNavItem-container,
|
||||||
|
.hulyNavItem-container {
|
||||||
|
margin: 0 0.75rem;
|
||||||
|
}
|
||||||
|
&.content {
|
||||||
|
overflow-y: auto;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: var(--spacing-3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&__navHeader {
|
||||||
|
flex-direction: column;
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding-bottom: var(--spacing-3);
|
||||||
|
border-bottom: 1px solid var(--theme-navpanel-divider);
|
||||||
|
|
||||||
|
&-menu {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: var(--spacing-2);
|
||||||
|
width: var(--global-extra-large-Size);
|
||||||
|
height: var(--global-extra-large-Size);
|
||||||
|
}
|
||||||
|
&-hint {
|
||||||
|
margin: var(--spacing-0_25) var(--spacing-3) 0 var(--spacing-2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Component */
|
/* Component */
|
||||||
.antiComponent {
|
.antiComponent {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@import "./_vars.scss";
|
||||||
@import "./_colors.scss";
|
@import "./_colors.scss";
|
||||||
@import "./_layouts.scss";
|
@import "./_layouts.scss";
|
||||||
@import "./common.scss";
|
@import "./common.scss";
|
||||||
|
85
packages/ui/src/components/Breadcrumb.svelte
Normal file
85
packages/ui/src/components/Breadcrumb.svelte
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
<!--
|
||||||
|
// Copyright © 2023 Hardcore Engineering Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import type { Asset, IntlString } from '@hcengineering/platform'
|
||||||
|
import { AnySvelteComponent } from '../types'
|
||||||
|
import { ComponentType } from 'svelte'
|
||||||
|
import Icon from './Icon.svelte'
|
||||||
|
import Label from './Label.svelte'
|
||||||
|
|
||||||
|
export let icon: Asset | AnySvelteComponent | ComponentType | undefined = undefined
|
||||||
|
export let label: IntlString | undefined = undefined
|
||||||
|
export let title: string | undefined = undefined
|
||||||
|
export let size: 'large' | 'small'
|
||||||
|
export let isCurrent: boolean = false
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button class="hulyBreadcrumb-container {size}" class:current={isCurrent} on:click>
|
||||||
|
{#if size === 'large' && icon}
|
||||||
|
<div class="hulyBreadcrumb-avatar">
|
||||||
|
<Icon {icon} size={'small'} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<span class="{size === 'large' ? 'heading-medium-16' : 'font-regular-14'} hulyBreadcrumb-label overflow-label">
|
||||||
|
{#if label}
|
||||||
|
<Label {label} />
|
||||||
|
{:else if title}
|
||||||
|
{title}
|
||||||
|
{/if}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.hulyBreadcrumb-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--spacing-0_75);
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 var(--spacing-1);
|
||||||
|
min-width: 0;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
|
||||||
|
.hulyBreadcrumb-avatar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: var(--spacing-0_5);
|
||||||
|
width: var(--global-extra-small-Size);
|
||||||
|
height: var(--global-extra-small-Size);
|
||||||
|
color: var(--global-secondary-TextColor);
|
||||||
|
background-color: var(--global-ui-BackgroundColor);
|
||||||
|
border-radius: var(--extra-small-BorderRadius);
|
||||||
|
}
|
||||||
|
.hulyBreadcrumb-label {
|
||||||
|
color: var(--global-secondary-TextColor);
|
||||||
|
}
|
||||||
|
&.current .hulyBreadcrumb-label {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
&:not(.current) {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
.hulyBreadcrumb-avatar {
|
||||||
|
background-color: var(--global-ui-hover-BackgroundColor);
|
||||||
|
}
|
||||||
|
.hulyBreadcrumb-label {
|
||||||
|
color: var(--global-primary-LinkColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
75
packages/ui/src/components/Breadcrumbs.svelte
Normal file
75
packages/ui/src/components/Breadcrumbs.svelte
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<!--
|
||||||
|
// Copyright © 2023 Hardcore Engineering Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher, ComponentType } from 'svelte'
|
||||||
|
import type { Asset, IntlString } from '@hcengineering/platform'
|
||||||
|
import { AnySvelteComponent } from '../types'
|
||||||
|
import ChevronRight from './icons/ChevronRight.svelte'
|
||||||
|
import Label from './Label.svelte'
|
||||||
|
import Breadcrumb from './Breadcrumb.svelte'
|
||||||
|
|
||||||
|
interface BreadcrumbItem {
|
||||||
|
icon?: Asset | AnySvelteComponent | ComponentType
|
||||||
|
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
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="hulyBreadcrumbs-container {size}">
|
||||||
|
{#each items as item, i}
|
||||||
|
{#if i !== 0}<ChevronRight size={'small'} />{/if}
|
||||||
|
<Breadcrumb
|
||||||
|
{...item}
|
||||||
|
{size}
|
||||||
|
isCurrent={selected === i}
|
||||||
|
on:click={() => {
|
||||||
|
if (selected !== i) dispatch('select', i)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/each}
|
||||||
|
{#if afterLabel}
|
||||||
|
<span class="hulyBreadcrumbs-afterLabel">
|
||||||
|
<Label label={afterLabel} />
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.hulyBreadcrumbs-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: var(--global-small-Size);
|
||||||
|
min-width: 0;
|
||||||
|
|
||||||
|
.hulyBreadcrumbs-afterLabel {
|
||||||
|
white-space: nowrap;
|
||||||
|
word-break: break-all;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: var(--spacing-0_25) var(--spacing-0_5);
|
||||||
|
text-transform: uppercase;
|
||||||
|
background-color: var(--global-ui-hover-BackgroundColor);
|
||||||
|
color: var(--global-secondary-TextColor);
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
304
packages/ui/src/components/ButtonBase.svelte
Normal file
304
packages/ui/src/components/ButtonBase.svelte
Normal file
@ -0,0 +1,304 @@
|
|||||||
|
<!--
|
||||||
|
// Copyright © 2023 Hardcore Engineering Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import type { Asset, IntlString } from '@hcengineering/platform'
|
||||||
|
import { AnySvelteComponent } from '../types'
|
||||||
|
import { ComponentType } from 'svelte'
|
||||||
|
import Spinner from './Spinner.svelte'
|
||||||
|
import Icon from './Icon.svelte'
|
||||||
|
import Label from './Label.svelte'
|
||||||
|
|
||||||
|
export let title: string | undefined = undefined
|
||||||
|
export let label: IntlString | undefined = undefined
|
||||||
|
export let icon: Asset | AnySvelteComponent | ComponentType | undefined = undefined
|
||||||
|
export let kind: 'primary' | 'secondary' | 'tertiary' | 'negative'
|
||||||
|
export let size: 'large' | 'medium' | 'small'
|
||||||
|
export let disabled: boolean = false
|
||||||
|
export let loading: boolean = false
|
||||||
|
export let pressed: boolean = false
|
||||||
|
export let hasMenu: boolean = false
|
||||||
|
export let type: 'type-button' | 'type-button-icon'
|
||||||
|
export let inheritColor: boolean = false
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="font-medium-14 {kind} {size} {type}"
|
||||||
|
class:loading
|
||||||
|
class:pressed
|
||||||
|
class:inheritColor
|
||||||
|
class:menu={hasMenu}
|
||||||
|
disabled={loading || disabled}
|
||||||
|
on:click
|
||||||
|
>
|
||||||
|
{#if loading}
|
||||||
|
<div class="icon animate"><Spinner size={'small'} /></div>
|
||||||
|
{:else if icon}<div class="icon"><Icon {icon} size={'small'} /></div>{/if}
|
||||||
|
{#if title}<span>{title}</span>{/if}
|
||||||
|
{#if label}<span><Label {label} /></span>{/if}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
button {
|
||||||
|
display: inline-flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
gap: var(--spacing-1);
|
||||||
|
|
||||||
|
border: 1px;
|
||||||
|
border-style: solid;
|
||||||
|
|
||||||
|
&:not(:disabled, .loading) {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: var(--spacing-2_5);
|
||||||
|
height: var(--spacing-2_5);
|
||||||
|
|
||||||
|
&.animate {
|
||||||
|
animation: rotate 2s linear infinite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: 2px solid var(--global-focus-BorderColor);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
&.type-button-icon {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
&.large {
|
||||||
|
height: var(--spacing-6);
|
||||||
|
border-radius: var(--medium-BorderRadius);
|
||||||
|
|
||||||
|
&.type-button {
|
||||||
|
padding: 0 var(--spacing-2);
|
||||||
|
}
|
||||||
|
&.type-button-icon {
|
||||||
|
width: var(--spacing-6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.medium {
|
||||||
|
height: var(--spacing-5);
|
||||||
|
border-radius: var(--medium-BorderRadius);
|
||||||
|
|
||||||
|
&.type-button {
|
||||||
|
padding: 0 var(--spacing-2);
|
||||||
|
}
|
||||||
|
&.type-button-icon {
|
||||||
|
width: var(--spacing-5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.small {
|
||||||
|
height: var(--spacing-4);
|
||||||
|
border-radius: var(--small-BorderRadius);
|
||||||
|
|
||||||
|
&.type-button {
|
||||||
|
padding: 0 var(--spacing-1_5);
|
||||||
|
}
|
||||||
|
&.type-button-icon {
|
||||||
|
width: var(--spacing-4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.type-button-icon .icon {
|
||||||
|
width: var(--spacing-2);
|
||||||
|
height: var(--spacing-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.primary {
|
||||||
|
border-color: var(--button-primary-BorderColor);
|
||||||
|
background-color: var(--button-primary-BackgroundColor);
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
fill: var(--button-accent-IconColor);
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
color: var(--button-accent-LabelColor);
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--button-primary-hover-BackgroundColor);
|
||||||
|
}
|
||||||
|
&:active,
|
||||||
|
&.pressed {
|
||||||
|
background-color: var(--button-primary-active-BackgroundColor);
|
||||||
|
}
|
||||||
|
&.menu:enabled:active,
|
||||||
|
&.pressed {
|
||||||
|
border-color: var(--button-menu-active-BorderColor);
|
||||||
|
}
|
||||||
|
&:disabled:not(.loading) {
|
||||||
|
background-color: var(--button-disabled-BackgroundColor);
|
||||||
|
border-color: transparent;
|
||||||
|
cursor: not-allowed;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
fill: var(--button-disabled-IconColor);
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
color: var(--button-disabled-LabelColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.loading {
|
||||||
|
background-color: var(--button-primary-active-BackgroundColor);
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: var(--button-primary-loading-LabelColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.secondary {
|
||||||
|
border-color: var(--button-secondary-BorderColor);
|
||||||
|
background-color: var(--button-secondary-BackgroundColor);
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
fill: var(--button-subtle-IconColor);
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
color: var(--button-subtle-LabelColor);
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--button-secondary-hover-BackgroundColor);
|
||||||
|
}
|
||||||
|
&:active,
|
||||||
|
&.pressed {
|
||||||
|
background-color: var(--button-secondary-active-BackgroundColor);
|
||||||
|
}
|
||||||
|
&.menu:enabled:active,
|
||||||
|
&.pressed {
|
||||||
|
border-color: var(--button-menu-active-BorderColor);
|
||||||
|
}
|
||||||
|
&:disabled:not(.loading) {
|
||||||
|
background-color: var(--button-disabled-BackgroundColor);
|
||||||
|
border-color: transparent;
|
||||||
|
cursor: not-allowed;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
fill: var(--button-disabled-IconColor);
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
color: var(--button-disabled-LabelColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.loading {
|
||||||
|
background-color: var(--button-secondary-active-BackgroundColor);
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: var(--button-disabled-LabelColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.tertiary {
|
||||||
|
border-color: transparent;
|
||||||
|
background-color: transparent;
|
||||||
|
|
||||||
|
&:not(.inheritColor) .icon {
|
||||||
|
fill: var(--button-subtle-IconColor);
|
||||||
|
}
|
||||||
|
&.inheritColor {
|
||||||
|
color: inherit;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
color: var(--button-subtle-LabelColor);
|
||||||
|
}
|
||||||
|
&:hover:enabled {
|
||||||
|
background-color: var(--button-tertiary-hover-BackgroundColor);
|
||||||
|
}
|
||||||
|
&:active:enabled,
|
||||||
|
&.pressed:enabled {
|
||||||
|
background-color: var(--button-tertiary-active-BackgroundColor);
|
||||||
|
}
|
||||||
|
&.menu:active:enabled,
|
||||||
|
&.pressed:enabled {
|
||||||
|
border-color: var(--button-menu-active-BorderColor);
|
||||||
|
}
|
||||||
|
&:disabled:not(.loading) {
|
||||||
|
border-color: transparent;
|
||||||
|
cursor: not-allowed;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
fill: var(--button-disabled-IconColor);
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
color: var(--button-disabled-LabelColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.loading {
|
||||||
|
background-color: var(--button-tertiary-active-BackgroundColor);
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: var(--button-disabled-LabelColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.negative {
|
||||||
|
border-color: var(--button-negative-BorderColor);
|
||||||
|
background-color: var(--button-negative-BackgroundColor);
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
fill: var(--button-accent-IconColor);
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
color: var(--button-accent-LabelColor);
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--button-negative-hover-BackgroundColor);
|
||||||
|
}
|
||||||
|
&:active,
|
||||||
|
&.pressed {
|
||||||
|
background-color: var(--button-negative-active-BackgroundColor);
|
||||||
|
}
|
||||||
|
&.menu:enabled:active,
|
||||||
|
&.pressed {
|
||||||
|
border-color: var(--button-menu-active-BorderColor);
|
||||||
|
}
|
||||||
|
&:disabled:not(.loading) {
|
||||||
|
background-color: var(--button-disabled-BackgroundColor);
|
||||||
|
border-color: transparent;
|
||||||
|
cursor: not-allowed;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
fill: var(--button-disabled-IconColor);
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
color: var(--button-disabled-LabelColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.loading {
|
||||||
|
background-color: var(--button-negative-active-BackgroundColor);
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: var(--button-negative-loading-LabelColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rotate {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(359deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
29
packages/ui/src/components/ButtonIcon.svelte
Normal file
29
packages/ui/src/components/ButtonIcon.svelte
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<!--
|
||||||
|
// Copyright © 2023 Hardcore Engineering Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import type { Asset } from '@hcengineering/platform'
|
||||||
|
import { AnySvelteComponent } from '../types'
|
||||||
|
import { ComponentType } from 'svelte'
|
||||||
|
import ButtonBase from './ButtonBase.svelte'
|
||||||
|
|
||||||
|
export let kind: 'primary' | 'secondary' | 'tertiary' | 'negative' = 'secondary'
|
||||||
|
export let size: 'large' | 'medium' | 'small' = 'large'
|
||||||
|
export let icon: Asset | AnySvelteComponent | ComponentType
|
||||||
|
export let disabled: boolean = false
|
||||||
|
export let loading: boolean = false
|
||||||
|
export let inheritColor: boolean = false
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ButtonBase type={'type-button-icon'} {kind} {size} {icon} {disabled} {loading} {inheritColor} on:click />
|
52
packages/ui/src/components/Fold.svelte
Normal file
52
packages/ui/src/components/Fold.svelte
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<!--
|
||||||
|
// Copyright © 2023 Hardcore Engineering Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
export let isOpen: boolean
|
||||||
|
export let empty: boolean = false
|
||||||
|
export let level: number = 1
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="hulyFold-container" class:opened={isOpen && !empty} style:margin-left={`${(level - 1) * 1.5}rem`}>
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
{#if empty}
|
||||||
|
<path
|
||||||
|
d="M8 8.99988C8.55228 8.99988 9 8.55216 9 7.99988C9 7.44759 8.55228 6.99988 8 6.99988C7.44772 6.99988 7 7.44759 7 7.99988C7 8.55216 7.44772 8.99988 8 8.99988Z"
|
||||||
|
/>
|
||||||
|
{:else}
|
||||||
|
<path d="M11 8L5.99995 3L5.29285 3.70711L9.58574 8L5.29285 12.2929L5.99995 13L11 8Z" />
|
||||||
|
{/if}
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.hulyFold-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: 0.25rem;
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 1.5rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
color: var(--button-disabled-IconColor);
|
||||||
|
transform-origin: center;
|
||||||
|
transform: rotate(0deg);
|
||||||
|
transition: transform 0.15s ease-in-out;
|
||||||
|
|
||||||
|
&.opened {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
89
packages/ui/src/components/Header.svelte
Normal file
89
packages/ui/src/components/Header.svelte
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
<!--
|
||||||
|
// Copyright © 2023 Hardcore Engineering Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher } from 'svelte'
|
||||||
|
import { IconMaximize, IconMinimize } from '..'
|
||||||
|
|
||||||
|
export let minimize: boolean = false
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="hulyHeader-container">
|
||||||
|
<button class="hulyHeader-button" on:click={() => dispatch('resize', minimize)}>
|
||||||
|
{#if minimize}
|
||||||
|
<IconMinimize size={'small'} />
|
||||||
|
{:else}
|
||||||
|
<IconMaximize size={'small'} />
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
<div class="hulyHeader-divider" />
|
||||||
|
<div class="hulyHeader-titleGroup">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
{#if $$slots.actions}
|
||||||
|
<div class="hulyHeader-buttonsGroup">
|
||||||
|
<slot name="actions" />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.hulyHeader-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: var(--spacing-1_5) var(--spacing-2);
|
||||||
|
width: 100%;
|
||||||
|
height: var(--spacing-6_5);
|
||||||
|
border-bottom: 1px solid var(--theme-divider-color); // var(--global-surface-02-BorderColor);
|
||||||
|
|
||||||
|
.hulyHeader-button {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 1.5rem;
|
||||||
|
color: var(--button-disabled-IconColor);
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--button-subtle-LabelColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.hulyHeader-divider {
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin: 0 var(--spacing-2);
|
||||||
|
width: 1px;
|
||||||
|
height: var(--spacing-4);
|
||||||
|
background-color: var(--theme-divider-color); // var(--global-surface-02-BorderColor);
|
||||||
|
}
|
||||||
|
.hulyHeader-titleGroup,
|
||||||
|
.hulyHeader-buttonsGroup {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.hulyHeader-titleGroup {
|
||||||
|
flex-grow: 1;
|
||||||
|
gap: var(--spacing-0_5);
|
||||||
|
}
|
||||||
|
.hulyHeader-buttonsGroup {
|
||||||
|
gap: var(--spacing-1);
|
||||||
|
margin-left: var(--spacing-2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
189
packages/ui/src/components/ModernEditbox.svelte
Normal file
189
packages/ui/src/components/ModernEditbox.svelte
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
<!--
|
||||||
|
// Copyright © 2023 Hardcore Engineering Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
export let label: string
|
||||||
|
export let value: string | undefined = undefined
|
||||||
|
export let kind: 'default' | 'ghost' = 'default'
|
||||||
|
export let size: 'small' | 'large' = 'small'
|
||||||
|
export let disabled: boolean = false
|
||||||
|
export let error: boolean = false
|
||||||
|
export let password: boolean = false
|
||||||
|
export let limit: number = 0
|
||||||
|
|
||||||
|
$: labeled = kind === 'default' && size === 'large'
|
||||||
|
$: placeholder = labeled ? ' ' : label
|
||||||
|
$: maxlength = limit === 0 ? null : limit
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<label class="editbox-wrapper {kind} {size}" class:error class:disabled>
|
||||||
|
{#if password}
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
class="font-regular-14"
|
||||||
|
class:labeled
|
||||||
|
bind:value
|
||||||
|
autocomplete="off"
|
||||||
|
{placeholder}
|
||||||
|
spellcheck="false"
|
||||||
|
{disabled}
|
||||||
|
{maxlength}
|
||||||
|
on:blur
|
||||||
|
on:change
|
||||||
|
on:keyup
|
||||||
|
on:input
|
||||||
|
/>
|
||||||
|
{:else}
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="font-regular-14"
|
||||||
|
class:labeled
|
||||||
|
bind:value
|
||||||
|
autocomplete="off"
|
||||||
|
{placeholder}
|
||||||
|
spellcheck="false"
|
||||||
|
{disabled}
|
||||||
|
{maxlength}
|
||||||
|
on:blur
|
||||||
|
on:change
|
||||||
|
on:keyup
|
||||||
|
on:input
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
{#if labeled}<div class="font-regular-14 label">{label}</div>{/if}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.editbox-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 0;
|
||||||
|
border-radius: var(--medium-BorderRadius);
|
||||||
|
|
||||||
|
&.default {
|
||||||
|
background-color: var(--input-BackgroundColor);
|
||||||
|
box-shadow: inset 0 0 0 1px var(--input-BorderColor);
|
||||||
|
|
||||||
|
&.small {
|
||||||
|
padding: var(--spacing-1) var(--spacing-1_5);
|
||||||
|
height: var(--spacing-4);
|
||||||
|
}
|
||||||
|
&.large {
|
||||||
|
position: relative;
|
||||||
|
padding: 0 var(--spacing-2);
|
||||||
|
height: var(--spacing-6_5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.ghost {
|
||||||
|
&.small {
|
||||||
|
padding: var(--spacing-1_5) var(--spacing-2);
|
||||||
|
height: var(--spacing-5);
|
||||||
|
}
|
||||||
|
&.large {
|
||||||
|
padding: var(--spacing-1) var(--spacing-2);
|
||||||
|
height: var(--spacing-6);
|
||||||
|
|
||||||
|
input {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.error {
|
||||||
|
box-shadow: inset 0 0 0 1px var(--input-error-BorderColor);
|
||||||
|
}
|
||||||
|
&:not(.disabled) {
|
||||||
|
cursor: text;
|
||||||
|
|
||||||
|
&.default {
|
||||||
|
input::placeholder {
|
||||||
|
color: var(--input-LabelColor);
|
||||||
|
}
|
||||||
|
&:active,
|
||||||
|
&:focus-within {
|
||||||
|
background-color: var(--input-BackgroundColor);
|
||||||
|
outline: 2px solid var(--global-focus-BorderColor);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--input-hover-BackgroundColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.ghost input::placeholder {
|
||||||
|
color: var(--input-PlaceholderColor);
|
||||||
|
}
|
||||||
|
&:hover input:not(:focus)::placeholder {
|
||||||
|
color: var(--input-hover-PlaceholderColor);
|
||||||
|
}
|
||||||
|
input:focus::placeholder {
|
||||||
|
color: var(--input-focus-PlaceholderColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.disabled {
|
||||||
|
&,
|
||||||
|
input {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
input::placeholder {
|
||||||
|
color: var(--input-PlaceholderColor);
|
||||||
|
}
|
||||||
|
&.default {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
&.ghost {
|
||||||
|
box-shadow: inset 0 0 0 1px var(--input-BorderColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
color: var(--input-TextColor);
|
||||||
|
caret-color: var(--global-focus-BorderColor);
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
appearance: none;
|
||||||
|
|
||||||
|
&.labeled {
|
||||||
|
height: 100%;
|
||||||
|
padding-top: var(--spacing-3_5);
|
||||||
|
padding-bottom: var(--spacing-1_5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 100%;
|
||||||
|
padding: var(--spacing-2_5) var(--spacing-2);
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: var(--input-LabelColor);
|
||||||
|
transition:
|
||||||
|
padding-top 0.2s,
|
||||||
|
font-size 0.2s;
|
||||||
|
pointer-events: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
input:focus + .label,
|
||||||
|
input:not(:placeholder-shown) + .label {
|
||||||
|
padding-top: var(--spacing-1_5);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: var(--input-filled-LabelColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -14,20 +14,25 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { IntlString } from '@hcengineering/platform'
|
import type { IntlString } from '@hcengineering/platform'
|
||||||
import type { AnyComponent } from '@hcengineering/ui'
|
import type { AnyComponent } from '..'
|
||||||
import { Label, Component } from '@hcengineering/ui'
|
import { Label, Component } from '..'
|
||||||
|
|
||||||
export let label: IntlString
|
export let label: IntlString
|
||||||
export let categoryName: string
|
export let categoryName: string
|
||||||
export let selected: boolean = false
|
export let selected: boolean = false
|
||||||
export let tools: AnyComponent | undefined = undefined
|
export let tools: AnyComponent | undefined = undefined
|
||||||
export let collapsed: boolean = false
|
export let collapsed: boolean = false
|
||||||
|
export let second: boolean = false
|
||||||
|
|
||||||
$: id = `navGroup-${categoryName}`
|
$: id = `navGroup-${categoryName}`
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="hulyAccordionItem-container">
|
<div class="hulyAccordionItem-container" class:collapsed class:second>
|
||||||
<button class="hulyAccordionItem-header" class:selected on:click={() => (collapsed = !collapsed)}>
|
<button
|
||||||
|
class="hulyAccordionItem-header"
|
||||||
|
class:selected={selected || !collapsed}
|
||||||
|
on:click={() => (collapsed = !collapsed)}
|
||||||
|
>
|
||||||
<div class="hulyAccordionItem-header__label font-medium-12">
|
<div class="hulyAccordionItem-header__label font-medium-12">
|
||||||
<Label {label} />
|
<Label {label} />
|
||||||
</div>
|
</div>
|
||||||
@ -53,9 +58,13 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
border-top: 1px solid var(--theme-navpanel-divider);
|
|
||||||
// border-bottom: 1px solid var(--theme-navpanel-divider); // var(--global-surface-01-BorderColor);
|
|
||||||
|
|
||||||
|
&:not(.second) {
|
||||||
|
border-top: 1px solid var(--theme-navpanel-divider);
|
||||||
|
}
|
||||||
|
&.second.collapsed {
|
||||||
|
border-bottom: 1px solid var(--theme-navpanel-divider); // var(--global-surface-01-BorderColor);
|
||||||
|
}
|
||||||
.hulyAccordionItem-header {
|
.hulyAccordionItem-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
// Copyright © 2021 Anticrm Platform Contributors.
|
// Copyright © 2021, 2023 Anticrm Platform Contributors.
|
||||||
//
|
//
|
||||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License. You may
|
// you may not use this file except in compliance with the License. You may
|
||||||
@ -14,7 +14,7 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Asset, IntlString } from '@hcengineering/platform'
|
import type { Asset, IntlString } from '@hcengineering/platform'
|
||||||
import { Icon, Label, IconOpenedArrow } from '@hcengineering/ui'
|
import { Icon, Label, IconOpenedArrow, Fold } from '..'
|
||||||
|
|
||||||
export let icon: Asset | undefined = undefined
|
export let icon: Asset | undefined = undefined
|
||||||
export let label: IntlString | undefined = undefined
|
export let label: IntlString | undefined = undefined
|
||||||
@ -23,13 +23,22 @@
|
|||||||
export let count: number | null = null
|
export let count: number | null = null
|
||||||
export let selected: boolean = false
|
export let selected: boolean = false
|
||||||
export let isFold: boolean = false
|
export let isFold: boolean = false
|
||||||
|
export let isOpen: boolean = false
|
||||||
|
export let empty: boolean = false
|
||||||
|
export let level: number = 1
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="hulyNavItem-container {type} {type === 'type-anchor-link' ? 'font-regular-12' : 'font-regular-14'}"
|
class="hulyNavItem-container {type} {type === 'type-anchor-link' ? 'font-regular-12' : 'font-regular-14'}"
|
||||||
|
class:fold={isFold}
|
||||||
class:selected
|
class:selected
|
||||||
on:click|stopPropagation
|
on:click|stopPropagation
|
||||||
|
on:contextmenu|preventDefault|stopPropagation
|
||||||
>
|
>
|
||||||
|
{#if isFold}
|
||||||
|
<Fold {isOpen} {empty} {level} />
|
||||||
|
{/if}
|
||||||
|
{#if icon || (type === 'type-tag' && color)}
|
||||||
<div class="hulyNavItem-icon">
|
<div class="hulyNavItem-icon">
|
||||||
{#if type !== 'type-tag' && icon}
|
{#if type !== 'type-tag' && icon}
|
||||||
<Icon {icon} size={'small'} />
|
<Icon {icon} size={'small'} />
|
||||||
@ -37,6 +46,7 @@
|
|||||||
<div style:background-color={color} class="hulyNavItem-icon__tag" />
|
<div style:background-color={color} class="hulyNavItem-icon__tag" />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
<span class="hulyNavItem-label" style:color={type === 'type-tag' && selected ? color : null}>
|
<span class="hulyNavItem-label" style:color={type === 'type-tag' && selected ? color : null}>
|
||||||
{#if label}<Label {label} />{/if}
|
{#if label}<Label {label} />{/if}
|
||||||
</span>
|
</span>
|
||||||
@ -78,8 +88,12 @@
|
|||||||
}
|
}
|
||||||
&.right {
|
&.right {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
|
margin-left: 0.5rem;
|
||||||
color: var(--global-accent-IconColor);
|
color: var(--global-accent-IconColor);
|
||||||
}
|
}
|
||||||
|
&:not(.right) {
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.hulyNavItem-label {
|
.hulyNavItem-label {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
@ -91,6 +105,7 @@
|
|||||||
color: var(--global-primary-TextColor);
|
color: var(--global-primary-TextColor);
|
||||||
}
|
}
|
||||||
.hulyNavItem-count {
|
.hulyNavItem-count {
|
||||||
|
margin-left: 0.5rem;
|
||||||
color: var(--global-tertiary-TextColor);
|
color: var(--global-tertiary-TextColor);
|
||||||
}
|
}
|
||||||
&:not(.selected):hover {
|
&:not(.selected):hover {
|
||||||
@ -109,12 +124,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.type-link {
|
&.type-link {
|
||||||
gap: 0.5rem;
|
|
||||||
padding: 0 0.625rem;
|
padding: 0 0.625rem;
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
|
&:not(.fold) {
|
||||||
padding: 0 0.375rem 0 0.625rem;
|
padding: 0 0.375rem 0 0.625rem;
|
||||||
|
}
|
||||||
|
&.fold {
|
||||||
|
padding: 0 0.375rem 0 0.25rem;
|
||||||
|
}
|
||||||
.hulyNavItem-icon {
|
.hulyNavItem-icon {
|
||||||
color: var(--global-accent-TextColor);
|
color: var(--global-accent-TextColor);
|
||||||
}
|
}
|
||||||
@ -128,7 +146,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.type-tag {
|
&.type-tag {
|
||||||
gap: 0.5rem;
|
|
||||||
padding: 0 0.625rem;
|
padding: 0 0.625rem;
|
||||||
|
|
||||||
.hulyNavItem-label {
|
.hulyNavItem-label {
|
||||||
@ -136,7 +153,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.type-object {
|
&.type-object {
|
||||||
gap: 0.375rem;
|
|
||||||
padding: 0 0.625rem 0 0.25rem;
|
padding: 0 0.625rem 0 0.25rem;
|
||||||
|
|
||||||
.hulyNavItem-icon {
|
.hulyNavItem-icon {
|
||||||
@ -144,6 +160,10 @@
|
|||||||
height: 1.5rem;
|
height: 1.5rem;
|
||||||
background-color: var(--global-ui-BackgroundColor);
|
background-color: var(--global-ui-BackgroundColor);
|
||||||
border-radius: 0.25rem;
|
border-radius: 0.25rem;
|
||||||
|
|
||||||
|
&:not(.right) {
|
||||||
|
margin-right: 0.375rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.hulyNavItem-label {
|
.hulyNavItem-label {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
@ -153,7 +173,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.type-anchor-link {
|
&.type-anchor-link {
|
||||||
gap: 0.5rem;
|
|
||||||
padding: 0 0.75rem 0 0.625rem;
|
padding: 0 0.75rem 0 0.625rem;
|
||||||
min-height: 1.75rem;
|
min-height: 1.75rem;
|
||||||
|
|
||||||
@ -169,5 +188,12 @@
|
|||||||
color: var(--global-primary-TextColor);
|
color: var(--global-primary-TextColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&.fold {
|
||||||
|
padding-left: 0.25rem;
|
||||||
|
|
||||||
|
:global(.hulyFold-container) {
|
||||||
|
margin-right: 0.375rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
22
packages/ui/src/components/icons/ChevronRight.svelte
Normal file
22
packages/ui/src/components/icons/ChevronRight.svelte
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<!--
|
||||||
|
// Copyright © 2023 Hardcore Engineering Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
export let size: 'small' | 'medium' | 'large'
|
||||||
|
const fill: string = 'currentColor'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svg class="svg-{size}" {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M11.0001 8L6.00008 3L5.29297 3.70711L9.58586 8L5.29297 12.2929L6.00008 13L11.0001 8Z" />
|
||||||
|
</svg>
|
31
packages/ui/src/components/icons/Description.svelte
Normal file
31
packages/ui/src/components/icons/Description.svelte
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<!--
|
||||||
|
// Copyright © 2023 Hardcore Engineering Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import { IconSize } from '../../types'
|
||||||
|
export let size: IconSize
|
||||||
|
const fill: string = 'currentColor'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svg class="svg-{size}" {fill} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||||
|
<path
|
||||||
|
d="M2 4.5C2 4.22386 2.22386 4 2.5 4H13.5C13.7761 4 14 4.22386 14 4.5C14 4.77614 13.7761 5 13.5 5H2.5C2.22386 5 2 4.77614 2 4.5Z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M2 8C2 7.72386 2.22386 7.5 2.5 7.5H9.5C9.77614 7.5 10 7.72386 10 8C10 8.27614 9.77614 8.5 9.5 8.5H2.5C2.22386 8.5 2 8.27614 2 8Z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M2 11.5C2 11.2239 2.22386 11 2.5 11H11.5C11.7761 11 12 11.2239 12 11.5C12 11.7761 11.7761 12 11.5 12H2.5C2.22386 12 2 11.7761 2 11.5Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
23
packages/ui/src/components/icons/Maximize.svelte
Normal file
23
packages/ui/src/components/icons/Maximize.svelte
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<!--
|
||||||
|
// Copyright © 2023 Hardcore Engineering Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import { IconSize } from '../../types'
|
||||||
|
export let size: IconSize
|
||||||
|
const fill: string = 'currentColor'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svg class="svg-{size}" {fill} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||||
|
<path d="M7 3V2H2V7H3V3.707L12.293 13H9V14H14V9H13V12.293L3.707 3H7Z" />
|
||||||
|
</svg>
|
28
packages/ui/src/components/icons/Minimize.svelte
Normal file
28
packages/ui/src/components/icons/Minimize.svelte
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<!--
|
||||||
|
// Copyright © 2023 Hardcore Engineering Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import { IconSize } from '../../types'
|
||||||
|
export let size: IconSize
|
||||||
|
const fill: string = 'currentColor'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svg class="svg-{size}" {fill} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||||
|
<path
|
||||||
|
d="M14.1464 1.14645C14.3417 0.951184 14.6583 0.951184 14.8535 1.14645C15.0477 1.34063 15.0488 1.6548 14.8567 1.85031L10.707 5.99999H14V6.99999H8.99996V1.99999H9.99996V5.29299L14.1464 1.14645Z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M1.99996 8.99999V9.99999H5.29296L1.14645 14.1464C0.951184 14.3417 0.951184 14.6583 1.14645 14.8535C1.34171 15.0488 1.65829 15.0488 1.85355 14.8535L5.99996 10.707V14H6.99996V8.99999H1.99996Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
@ -3,37 +3,27 @@
|
|||||||
const fill: string = 'currentColor'
|
const fill: string = 'currentColor'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svg class="svg-{size}" {fill} viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
<svg class="svg-{size}" {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path
|
<path
|
||||||
d="M13 9.99988C13 10.5522 13.4477 10.9999 14 10.9999C14.5523 10.9999 15 10.5522 15 9.99988C15 9.44759 14.5523 8.99988 14 8.99988C13.4477 8.99988 13 9.44759 13 9.99988Z"
|
d="M9 5.99988C9 6.55216 9.44772 6.99988 10 6.99988C10.5523 6.99988 11 6.55216 11 5.99988C11 5.44759 10.5523 4.99988 10 4.99988C9.44772 4.99988 9 5.44759 9 5.99988Z"
|
||||||
fill="#8B97AD"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M13 13.9999C13 14.5522 13.4477 14.9999 14 14.9999C14.5523 14.9999 15 14.5522 15 13.9999C15 13.4476 14.5523 12.9999 14 12.9999C13.4477 12.9999 13 13.4476 13 13.9999Z"
|
|
||||||
fill="#8B97AD"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M14 18.9999C13.4477 18.9999 13 18.5522 13 17.9999C13 17.4476 13.4477 16.9999 14 16.9999C14.5523 16.9999 15 17.4476 15 17.9999C15 18.5522 14.5523 18.9999 14 18.9999Z"
|
|
||||||
fill="#8B97AD"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M13 6C13 6.55228 13.4477 7 14 7C14.5523 7 15 6.55228 15 6C15 5.44772 14.5523 5 14 5C13.4477 5 13 5.44772 13 6Z"
|
|
||||||
fill="#8B97AD"
|
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d="M9 9.99988C9 10.5522 9.44772 10.9999 10 10.9999C10.5523 10.9999 11 10.5522 11 9.99988C11 9.44759 10.5523 8.99988 10 8.99988C9.44772 8.99988 9 9.44759 9 9.99988Z"
|
d="M9 9.99988C9 10.5522 9.44772 10.9999 10 10.9999C10.5523 10.9999 11 10.5522 11 9.99988C11 9.44759 10.5523 8.99988 10 8.99988C9.44772 8.99988 9 9.44759 9 9.99988Z"
|
||||||
fill="#8B97AD"
|
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d="M9 13.9999C9 14.5522 9.44772 14.9999 10 14.9999C10.5523 14.9999 11 14.5522 11 13.9999C11 13.4476 10.5523 12.9999 10 12.9999C9.44772 12.9999 9 13.4476 9 13.9999Z"
|
d="M10 14.9999C9.44772 14.9999 9 14.5522 9 13.9999C9 13.4476 9.44772 12.9999 10 12.9999C10.5523 12.9999 11 13.4476 11 13.9999C11 14.5522 10.5523 14.9999 10 14.9999Z"
|
||||||
fill="#8B97AD"
|
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d="M10 18.9999C9.44772 18.9999 9 18.5522 9 17.9999C9 17.4476 9.44772 16.9999 10 16.9999C10.5523 16.9999 11 17.4476 11 17.9999C11 18.5522 10.5523 18.9999 10 18.9999Z"
|
d="M9 2C9 2.55228 9.44772 3 10 3C10.5523 3 11 2.55228 11 2C11 1.44772 10.5523 1 10 1C9.44772 1 9 1.44772 9 2Z"
|
||||||
fill="#8B97AD"
|
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d="M9 6C9 6.55228 9.44772 7 10 7C10.5523 7 11 6.55228 11 6C11 5.44772 10.5523 5 10 5C9.44772 5 9 5.44772 9 6Z"
|
d="M5 5.99988C5 6.55216 5.44772 6.99988 6 6.99988C6.55229 6.99988 7 6.55216 7 5.99988C7 5.44759 6.55229 4.99988 6 4.99988C5.44772 4.99988 5 5.44759 5 5.99988Z"
|
||||||
fill="#8B97AD"
|
|
||||||
/>
|
/>
|
||||||
|
<path
|
||||||
|
d="M5 9.99988C5 10.5522 5.44772 10.9999 6 10.9999C6.55228 10.9999 7 10.5522 7 9.99988C7 9.44759 6.55229 8.99988 6 8.99988C5.44772 8.99988 5 9.44759 5 9.99988Z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M6 14.9999C5.44772 14.9999 5 14.5522 5 13.9999C5 13.4476 5.44772 12.9999 6 12.9999C6.55228 12.9999 7 13.4476 7 13.9999C7 14.5522 6.55228 14.9999 6 14.9999Z"
|
||||||
|
/>
|
||||||
|
<path d="M5 2C5 2.55228 5.44772 3 6 3C6.55229 3 7 2.55228 7 2C7 1.44772 6.55229 1 6 1C5.44772 1 5 1.44772 5 2Z" />
|
||||||
</svg>
|
</svg>
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
// Copyright © 2023 Hardcore Engineering Inc.
|
||||||
// Copyright © 2021 Hardcore Engineering Inc.
|
|
||||||
//
|
//
|
||||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License. You may
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
@ -211,7 +211,7 @@
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 150%;
|
line-height: 150%;
|
||||||
background-color: var(--theme-statusbar-color);
|
background-color: var(--theme-statusbar-color);
|
||||||
border-bottom: 1px solid var(--theme-navpanel-divider);
|
// border-bottom: 1px solid var(--theme-navpanel-divider);
|
||||||
|
|
||||||
.history-box {
|
.history-box {
|
||||||
-webkit-app-region: no-drag;
|
-webkit-app-region: no-drag;
|
||||||
|
@ -123,6 +123,14 @@ export { default as Chevron } from './components/Chevron.svelte'
|
|||||||
export { default as Timeline } from './components/Timeline.svelte'
|
export { default as Timeline } from './components/Timeline.svelte'
|
||||||
export { default as TimeShiftPresenter } from './components/TimeShiftPresenter.svelte'
|
export { default as TimeShiftPresenter } from './components/TimeShiftPresenter.svelte'
|
||||||
export { default as Separator } from './components/Separator.svelte'
|
export { default as Separator } from './components/Separator.svelte'
|
||||||
|
export { default as Fold } from './components/Fold.svelte'
|
||||||
|
export { default as Header } from './components/Header.svelte'
|
||||||
|
export { default as Breadcrumb } from './components/Breadcrumb.svelte'
|
||||||
|
export { default as Breadcrumbs } from './components/Breadcrumbs.svelte'
|
||||||
|
export { default as ButtonIcon } from './components/ButtonIcon.svelte'
|
||||||
|
export { default as ModernEditbox } from './components/ModernEditbox.svelte'
|
||||||
|
export { default as NavItem } from './components/NavItem.svelte'
|
||||||
|
export { default as NavGroup } from './components/NavGroup.svelte'
|
||||||
|
|
||||||
export { default as IconAdd } from './components/icons/Add.svelte'
|
export { default as IconAdd } from './components/icons/Add.svelte'
|
||||||
export { default as IconCircleAdd } from './components/icons/CircleAdd.svelte'
|
export { default as IconCircleAdd } from './components/icons/CircleAdd.svelte'
|
||||||
@ -183,6 +191,11 @@ export { default as IconObjects } from './components/icons/Objects.svelte'
|
|||||||
export { default as IconUndo } from './components/icons/Undo.svelte'
|
export { default as IconUndo } from './components/icons/Undo.svelte'
|
||||||
export { default as IconRedo } from './components/icons/Redo.svelte'
|
export { default as IconRedo } from './components/icons/Redo.svelte'
|
||||||
export { default as IconOpenedArrow } from './components/icons/OpenedArrow.svelte'
|
export { default as IconOpenedArrow } from './components/icons/OpenedArrow.svelte'
|
||||||
|
export { default as IconMaximize } from './components/icons/Maximize.svelte'
|
||||||
|
export { default as IconMinimize } from './components/icons/Minimize.svelte'
|
||||||
|
export { default as IconChevronRight } from './components/icons/ChevronRight.svelte'
|
||||||
|
export { default as IconDescription } from './components/icons/Description.svelte'
|
||||||
|
export { default as IconSettings } from './components/icons/Settings.svelte'
|
||||||
|
|
||||||
export { default as PanelInstance } from './components/PanelInstance.svelte'
|
export { default as PanelInstance } from './components/PanelInstance.svelte'
|
||||||
export { default as Panel } from './components/Panel.svelte'
|
export { default as Panel } from './components/Panel.svelte'
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
<!--
|
|
||||||
// Copyright © 2023 Hardcore Engineering Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License. You may
|
|
||||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
//
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
-->
|
|
||||||
<script lang="ts">
|
|
||||||
import type { Asset, IntlString } from '@hcengineering/platform'
|
|
||||||
import { Icon, Label } from '@hcengineering/ui'
|
|
||||||
import { createEventDispatcher } from 'svelte'
|
|
||||||
|
|
||||||
export let icon: Asset | undefined = undefined
|
|
||||||
export let label: IntlString | undefined = undefined
|
|
||||||
export let selected: boolean = false
|
|
||||||
export let expandable = false
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
||||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
||||||
<div
|
|
||||||
class="antiNav-element"
|
|
||||||
class:selected
|
|
||||||
class:expandable
|
|
||||||
on:click|stopPropagation={() => {
|
|
||||||
dispatch('click')
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div class="an-element__icon">
|
|
||||||
{#if icon}
|
|
||||||
<Icon {icon} size={'small'} />
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
<span class="an-element__label">
|
|
||||||
{#if label}<Label {label} />{/if}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.expandable {
|
|
||||||
position: relative;
|
|
||||||
&::after {
|
|
||||||
content: '▶';
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
right: 0.5rem;
|
|
||||||
font-size: 0.375rem;
|
|
||||||
color: var(--dark-color);
|
|
||||||
transform: translateY(-50%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -106,8 +106,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex-grow vScroll w-full">
|
<div class="container">
|
||||||
<div class="container">
|
|
||||||
<Grid {column} columnGap={5} rowGap={1.5}>
|
<Grid {column} columnGap={5} rowGap={1.5}>
|
||||||
{#each types as type}
|
{#each types as type}
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
@ -131,12 +130,10 @@
|
|||||||
{/each}
|
{/each}
|
||||||
{/each}
|
{/each}
|
||||||
</Grid>
|
</Grid>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.container {
|
.container {
|
||||||
padding: 3rem;
|
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher, onDestroy } from 'svelte'
|
||||||
import { Ref } from '@hcengineering/core'
|
import { Ref } from '@hcengineering/core'
|
||||||
import type {
|
import type {
|
||||||
NotificationGroup,
|
NotificationGroup,
|
||||||
@ -22,12 +23,26 @@
|
|||||||
} from '@hcengineering/notification'
|
} from '@hcengineering/notification'
|
||||||
import { getResource } from '@hcengineering/platform'
|
import { getResource } from '@hcengineering/platform'
|
||||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||||
import { Location, Scroller, getCurrentResolvedLocation, navigate, resolvedLocationStore } from '@hcengineering/ui'
|
import {
|
||||||
import { onDestroy } from 'svelte'
|
Location,
|
||||||
|
Scroller,
|
||||||
|
getCurrentResolvedLocation,
|
||||||
|
navigate,
|
||||||
|
resolvedLocationStore,
|
||||||
|
Header,
|
||||||
|
Breadcrumb,
|
||||||
|
defineSeparators,
|
||||||
|
settingsSeparators,
|
||||||
|
Separator,
|
||||||
|
NavItem
|
||||||
|
} from '@hcengineering/ui'
|
||||||
import notification from '../plugin'
|
import notification from '../plugin'
|
||||||
import GroupElement from './GroupElement.svelte'
|
|
||||||
import NotificationGroupSetting from './NotificationGroupSetting.svelte'
|
import NotificationGroupSetting from './NotificationGroupSetting.svelte'
|
||||||
|
|
||||||
|
export let visibleNav: boolean = true
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
let groups: NotificationGroup[] = []
|
let groups: NotificationGroup[] = []
|
||||||
let preferencesGroups: NotificationPreferencesGroup[] = []
|
let preferencesGroups: NotificationPreferencesGroup[] = []
|
||||||
@ -73,14 +88,23 @@
|
|||||||
})(loc)
|
})(loc)
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
defineSeparators('notificationSettings', settingsSeparators)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex">
|
<div class="hulyComponent">
|
||||||
<div class="antiPanel-element ml-4 mt-2">
|
<Header minimize={!visibleNav} on:resize={(event) => dispatch('change', event.detail)}>
|
||||||
<div class="antiPanel-wrap__content">
|
<Breadcrumb
|
||||||
|
icon={notification.icon.Notifications}
|
||||||
|
label={notification.string.Notifications}
|
||||||
|
size={'large'}
|
||||||
|
isCurrent
|
||||||
|
/>
|
||||||
|
</Header>
|
||||||
|
<div class="hulyComponent-content__container columns">
|
||||||
|
<div class="hulyComponent-content__column navigation py-2">
|
||||||
<Scroller shrink>
|
<Scroller shrink>
|
||||||
{#each preferencesGroups as preferenceGroup}
|
{#each preferencesGroups as preferenceGroup}
|
||||||
<GroupElement
|
<NavItem
|
||||||
icon={preferenceGroup.icon}
|
icon={preferenceGroup.icon}
|
||||||
label={preferenceGroup.label}
|
label={preferenceGroup.label}
|
||||||
selected={preferenceGroup === currentPreferenceGroup}
|
selected={preferenceGroup === currentPreferenceGroup}
|
||||||
@ -94,10 +118,10 @@
|
|||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
{#if preferencesGroups.length > 0 && groups.length > 0}
|
{#if preferencesGroups.length > 0 && groups.length > 0}
|
||||||
<div class="antiNav-divider short line" />
|
<div class="antiNav-divider line" />
|
||||||
{/if}
|
{/if}
|
||||||
{#each groups as gr}
|
{#each groups as gr}
|
||||||
<GroupElement
|
<NavItem
|
||||||
icon={gr.icon}
|
icon={gr.icon}
|
||||||
label={gr.label}
|
label={gr.label}
|
||||||
selected={gr._id === group}
|
selected={gr._id === group}
|
||||||
@ -114,8 +138,10 @@
|
|||||||
<div class="antiNav-space" />
|
<div class="antiNav-space" />
|
||||||
</Scroller>
|
</Scroller>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<Separator name={'notificationSettings'} index={0} color={'var(--theme-divider-color)'} />
|
||||||
<div class="antiPanel-component filled">
|
<div class="hulyComponent-content__column content">
|
||||||
|
<div class="hulyComponent-content">
|
||||||
|
<Scroller>
|
||||||
{#if group}
|
{#if group}
|
||||||
<NotificationGroupSetting {group} {settings} />
|
<NotificationGroupSetting {group} {settings} />
|
||||||
{/if}
|
{/if}
|
||||||
@ -124,5 +150,8 @@
|
|||||||
<svelte:component this={presenter} />
|
<svelte:component this={presenter} />
|
||||||
{/await}
|
{/await}
|
||||||
{/if}
|
{/if}
|
||||||
|
</Scroller>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -31,6 +31,8 @@
|
|||||||
"IntegrationDisabledDescr": "Integration disabled",
|
"IntegrationDisabledDescr": "Integration disabled",
|
||||||
"IntegrationWith": "Integration with ",
|
"IntegrationWith": "Integration with ",
|
||||||
"ClassSetting": "Class setting",
|
"ClassSetting": "Class setting",
|
||||||
|
"ClassSettingHint": "A set or category of things having some property or attribute in common from others by kind, type, or quality.",
|
||||||
|
"ClassProperties": "Class properties",
|
||||||
"Classes": "Classes",
|
"Classes": "Classes",
|
||||||
"Attributes": "Attributes",
|
"Attributes": "Attributes",
|
||||||
"DeleteAttribute": "Delete attribute",
|
"DeleteAttribute": "Delete attribute",
|
||||||
|
@ -31,6 +31,8 @@
|
|||||||
"IntegrationDisabledDescr": "Интеграция отключена",
|
"IntegrationDisabledDescr": "Интеграция отключена",
|
||||||
"IntegrationWith": "Интеграция с ",
|
"IntegrationWith": "Интеграция с ",
|
||||||
"ClassSetting": "Настройки класса",
|
"ClassSetting": "Настройки класса",
|
||||||
|
"ClassSettingHint": "Набор или категория вещей, обладающих каким-либо свойством или атрибутом, отличающимся от других по виду, типу или качеству.",
|
||||||
|
"ClassProperties": "Свойства класса",
|
||||||
"Classes": "Классы",
|
"Classes": "Классы",
|
||||||
"Attributes": "Атрибуты",
|
"Attributes": "Атрибуты",
|
||||||
"DeleteAttribute": "Удалить атрибут",
|
"DeleteAttribute": "Удалить атрибут",
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
Action,
|
Action,
|
||||||
ActionIcon,
|
ActionIcon,
|
||||||
AnySvelteComponent,
|
AnySvelteComponent,
|
||||||
CircleButton,
|
ButtonIcon,
|
||||||
Icon,
|
Icon,
|
||||||
IconAdd,
|
IconAdd,
|
||||||
IconDelete,
|
IconDelete,
|
||||||
@ -41,7 +41,8 @@
|
|||||||
Label,
|
Label,
|
||||||
Menu,
|
Menu,
|
||||||
getEventPositionElement,
|
getEventPositionElement,
|
||||||
showPopup
|
showPopup,
|
||||||
|
IconSettings
|
||||||
} from '@hcengineering/ui'
|
} from '@hcengineering/ui'
|
||||||
import { getContextActions } from '@hcengineering/view-resources'
|
import { getContextActions } from '@hcengineering/view-resources'
|
||||||
import settings from '../plugin'
|
import settings from '../plugin'
|
||||||
@ -53,7 +54,6 @@
|
|||||||
export let ofClass: Ref<Class<Doc>> | undefined = undefined
|
export let ofClass: Ref<Class<Doc>> | undefined = undefined
|
||||||
export let useOfClassAttributes = true
|
export let useOfClassAttributes = true
|
||||||
export let showTitle = true
|
export let showTitle = true
|
||||||
export let showCreate = true
|
|
||||||
|
|
||||||
export let attributeMapper:
|
export let attributeMapper:
|
||||||
| {
|
| {
|
||||||
@ -69,6 +69,7 @@
|
|||||||
const classQuery = createQuery()
|
const classQuery = createQuery()
|
||||||
|
|
||||||
let clazz: Class<Doc> | undefined
|
let clazz: Class<Doc> | undefined
|
||||||
|
let hovered: number | null = null
|
||||||
|
|
||||||
$: classQuery.query(core.class.Class, { _id: _class }, (res) => {
|
$: classQuery.query(core.class.Class, { _id: _class }, (res) => {
|
||||||
clazz = res.shift()
|
clazz = res.shift()
|
||||||
@ -120,7 +121,8 @@
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function showMenu (ev: MouseEvent, attribute: AnyAttribute): Promise<void> {
|
async function showMenu (ev: MouseEvent, attribute: AnyAttribute, row: number): Promise<void> {
|
||||||
|
hovered = row
|
||||||
const exist = (await client.findOne(attribute.attributeOf, { [attribute.name]: { $exists: true } })) !== undefined
|
const exist = (await client.findOne(attribute.attributeOf, { [attribute.name]: { $exists: true } })) !== undefined
|
||||||
|
|
||||||
const actions: Action[] = [
|
const actions: Action[] = [
|
||||||
@ -152,7 +154,9 @@
|
|||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
showPopup(Menu, { actions }, getEventPositionElement(ev))
|
showPopup(Menu, { actions }, getEventPositionElement(ev), () => {
|
||||||
|
hovered = null
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAttrType (type: Type<any>): IntlString | undefined {
|
function getAttrType (type: Type<any>): IntlString | undefined {
|
||||||
@ -179,72 +183,60 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if showTitle}
|
{#if showTitle}
|
||||||
<div class="flex-row-center fs-title mb-3">
|
|
||||||
{#if clazz?.icon}
|
|
||||||
<div class="mr-2 flex">
|
|
||||||
<Icon icon={clazz.icon} size={'medium'} />
|
|
||||||
{#if clazz.kind === ClassifierKind.MIXIN && hierarchy.hasMixin(clazz, settings.mixin.UserMixin)}
|
|
||||||
<Icon icon={IconAdd} size={'x-small'} />
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{#if clazz}
|
{#if clazz}
|
||||||
|
<div class="flex-row-center flex-no-shrink mb-6">
|
||||||
|
<div class="hulyInput-body">
|
||||||
<Label label={clazz.label} />
|
<Label label={clazz.label} />
|
||||||
|
</div>
|
||||||
{#if clazz.kind === ClassifierKind.MIXIN && hierarchy.hasMixin(clazz, settings.mixin.UserMixin)}
|
{#if clazz.kind === ClassifierKind.MIXIN && hierarchy.hasMixin(clazz, settings.mixin.UserMixin)}
|
||||||
<div class="ml-2">
|
<div class="ml-2">
|
||||||
<ActionIcon icon={IconEdit} size="small" action={editLabel} />
|
<ActionIcon icon={IconEdit} size="small" action={editLabel} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
{#if showCreate}
|
<div class="hulyTableAttr-container">
|
||||||
<div class="flex-between trans-title mb-3">
|
<div class="hulyTableAttr-header font-medium-12">
|
||||||
<Label label={settings.string.Attributes} />
|
<IconSettings size={'small'} />
|
||||||
<CircleButton icon={IconAdd} size="medium" on:click={createAttribute} />
|
<span><Label label={settings.string.ClassProperties} /></span>
|
||||||
|
<ButtonIcon kind={'primary'} icon={IconAdd} size={'small'} on:click={createAttribute} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{#if attributes.length}
|
||||||
{#each attributes as attr, i}
|
<div class="hulyTableAttr-content">
|
||||||
|
{#each attributes as attr, i}
|
||||||
{@const attrType = getAttrType(attr.type)}
|
{@const attrType = getAttrType(attr.type)}
|
||||||
<tr
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||||
class="antiTable-body__row"
|
<div
|
||||||
|
class="hulyTableAttr-content__row"
|
||||||
|
class:hovered={hovered === i}
|
||||||
on:contextmenu={(ev) => {
|
on:contextmenu={(ev) => {
|
||||||
ev.preventDefault()
|
ev.preventDefault()
|
||||||
void showMenu(ev, attr)
|
void showMenu(ev, attr, i)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<td>
|
|
||||||
{#if i === 0 && clazz?.label !== undefined}
|
|
||||||
<div class="trans-title">
|
|
||||||
<Label label={clazz.label} />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="antiTable-cells__firstCell whitespace-nowrap flex-row-center">
|
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||||
<div id="context-menu" on:click={(ev) => showMenu(ev, attr)}>
|
<div class="hulyTableAttr-content__row-dragMenu" on:click={(ev) => showMenu(ev, attr, i)}>
|
||||||
<div class="p-1">
|
<IconMoreV2 size={'small'} />
|
||||||
<IconMoreV2 size={'medium'} />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
{#if attr.icon !== undefined}
|
|
||||||
<div class="p-1">
|
|
||||||
<Icon icon={attr.icon} size={'small'} />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{#if attr.isCustom}
|
{#if attr.isCustom}
|
||||||
<div class="trans-title p-1">
|
<div class="hulyTableAttr-content__row-chip font-medium-12">
|
||||||
<Label label={settings.string.Custom} />
|
<Label label={settings.string.Custom} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div class:accent={!attr.hidden}>
|
{#if attr.icon !== undefined}
|
||||||
|
<div class="hulyTableAttr-content__row-icon">
|
||||||
|
<Icon icon={attr.icon} size={'small'} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<div class="hulyTableAttr-content__row-label font-regular-14" class:accent={!attr.hidden}>
|
||||||
<Label label={attr.label} />
|
<Label label={attr.label} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{#if attributeMapper}
|
||||||
</td>
|
<svelte:component this={attributeMapper.component} {...attributeMapper.props} attribute={attr} />
|
||||||
<td class="select-text whitespace-nowrap trans-title text-xs text-right" style:padding-right={'1rem !important'}>
|
{/if}
|
||||||
|
<div class="hulyTableAttr-content__row-type font-medium-12">
|
||||||
<Label label={attr.type.label} />
|
<Label label={attr.type.label} />
|
||||||
{#if attrType !== undefined}
|
{#if attrType !== undefined}
|
||||||
: <Label label={attrType} />
|
: <Label label={attrType} />
|
||||||
@ -256,27 +248,111 @@
|
|||||||
{/if}
|
{/if}
|
||||||
{/await}
|
{/await}
|
||||||
{/if}
|
{/if}
|
||||||
</td>
|
|
||||||
{#if attributeMapper}
|
|
||||||
<td>
|
|
||||||
<svelte:component this={attributeMapper.component} {...attributeMapper.props} attribute={attr} />
|
|
||||||
</td>
|
|
||||||
{/if}
|
|
||||||
</tr>
|
|
||||||
{/each}
|
|
||||||
{#if attributes.length === 0}
|
|
||||||
<tr class="antiTable-body__row">
|
|
||||||
<td>
|
|
||||||
<div class="trans-title">
|
|
||||||
{#if clazz}
|
|
||||||
<Label label={clazz.label} />
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</div>
|
||||||
<td class="select-text whitespace-nowrap"> </td>
|
{/each}
|
||||||
<td> </td>
|
</div>
|
||||||
{#if attributeMapper}
|
|
||||||
<td> </td>
|
|
||||||
{/if}
|
{/if}
|
||||||
</tr>
|
</div>
|
||||||
{/if}
|
|
||||||
|
<style lang="scss">
|
||||||
|
.hulyInput-body {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: var(--spacing-1) var(--spacing-2);
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
line-height: 2rem;
|
||||||
|
color: var(--input-TextColor);
|
||||||
|
}
|
||||||
|
.hulyTableAttr-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
align-self: stretch;
|
||||||
|
background-color: var(--theme-table-row-color);
|
||||||
|
border: 1px solid var(--theme-divider-color);
|
||||||
|
border-radius: var(--large-BorderRadius);
|
||||||
|
|
||||||
|
.hulyTableAttr-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
align-self: stretch;
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: var(--spacing-2) var(--spacing-2) var(--spacing-2) var(--spacing-2_5);
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--global-secondary-TextColor);
|
||||||
|
|
||||||
|
span {
|
||||||
|
flex-grow: 1;
|
||||||
|
margin-left: var(--spacing-1_5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.hulyTableAttr-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
align-self: stretch;
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: var(--spacing-1);
|
||||||
|
border-top: 1px solid var(--theme-divider-color);
|
||||||
|
|
||||||
|
&__row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
align-self: stretch;
|
||||||
|
gap: var(--spacing-1);
|
||||||
|
padding: var(--spacing-1) var(--spacing-2) var(--spacing-1) var(--spacing-1);
|
||||||
|
border-radius: var(--small-BorderRadius);
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&.hovered,
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--theme-table-header-color); // var(--global-surface-03-hover-BackgroundColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-dragMenu {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: var(--global-extra-small-Size);
|
||||||
|
height: var(--global-extra-small-Size);
|
||||||
|
border-radius: var(--extra-small-BorderRadius);
|
||||||
|
}
|
||||||
|
&-chip {
|
||||||
|
padding: var(--spacing-0_25) var(--spacing-0_5);
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--global-tertiary-TextColor);
|
||||||
|
background-color: var(--global-ui-BackgroundColor);
|
||||||
|
border-radius: var(--extra-small-BorderRadius);
|
||||||
|
}
|
||||||
|
&-icon {
|
||||||
|
width: var(--global-min-Size);
|
||||||
|
height: var(--global-min-Size);
|
||||||
|
color: var(--global-primary-TextColor);
|
||||||
|
}
|
||||||
|
&-label {
|
||||||
|
white-space: nowrap;
|
||||||
|
word-break: break-all;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-grow: 1;
|
||||||
|
min-width: 0;
|
||||||
|
color: var(--global-primary-TextColor);
|
||||||
|
|
||||||
|
&.accent {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-type {
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--global-secondary-TextColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -0,0 +1,282 @@
|
|||||||
|
<!--
|
||||||
|
// Copyright © 2022 Hardcore Engineering Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License. You may
|
||||||
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import core, {
|
||||||
|
AnyAttribute,
|
||||||
|
ArrOf,
|
||||||
|
AttachedDoc,
|
||||||
|
Class,
|
||||||
|
ClassifierKind,
|
||||||
|
Collection,
|
||||||
|
Doc,
|
||||||
|
EnumOf,
|
||||||
|
Ref,
|
||||||
|
RefTo,
|
||||||
|
Type
|
||||||
|
} from '@hcengineering/core'
|
||||||
|
import { IntlString, getResource } from '@hcengineering/platform'
|
||||||
|
import presentation, { MessageBox, createQuery, getClient } from '@hcengineering/presentation'
|
||||||
|
import {
|
||||||
|
Action,
|
||||||
|
ActionIcon,
|
||||||
|
AnySvelteComponent,
|
||||||
|
CircleButton,
|
||||||
|
Icon,
|
||||||
|
IconAdd,
|
||||||
|
IconDelete,
|
||||||
|
IconEdit,
|
||||||
|
IconMoreV2,
|
||||||
|
Label,
|
||||||
|
Menu,
|
||||||
|
getEventPositionElement,
|
||||||
|
showPopup
|
||||||
|
} from '@hcengineering/ui'
|
||||||
|
import { getContextActions } from '@hcengineering/view-resources'
|
||||||
|
import settings from '../plugin'
|
||||||
|
import CreateAttribute from './CreateAttribute.svelte'
|
||||||
|
import EditAttribute from './EditAttribute.svelte'
|
||||||
|
import EditClassLabel from './EditClassLabel.svelte'
|
||||||
|
|
||||||
|
export let _class: Ref<Class<Doc>>
|
||||||
|
export let ofClass: Ref<Class<Doc>> | undefined = undefined
|
||||||
|
export let useOfClassAttributes = true
|
||||||
|
export let showTitle = true
|
||||||
|
export let showCreate = true
|
||||||
|
|
||||||
|
export let attributeMapper:
|
||||||
|
| {
|
||||||
|
component: AnySvelteComponent
|
||||||
|
label: IntlString
|
||||||
|
props: Record<string, any>
|
||||||
|
}
|
||||||
|
| undefined = undefined
|
||||||
|
|
||||||
|
const client = getClient()
|
||||||
|
const hierarchy = client.getHierarchy()
|
||||||
|
|
||||||
|
const classQuery = createQuery()
|
||||||
|
|
||||||
|
let clazz: Class<Doc> | undefined
|
||||||
|
|
||||||
|
$: classQuery.query(core.class.Class, { _id: _class }, (res) => {
|
||||||
|
clazz = res.shift()
|
||||||
|
})
|
||||||
|
$: attributes = getCustomAttributes(_class)
|
||||||
|
|
||||||
|
function getCustomAttributes (_class: Ref<Class<Doc>>): AnyAttribute[] {
|
||||||
|
const cl = hierarchy.getClass(_class)
|
||||||
|
const attributes = Array.from(
|
||||||
|
hierarchy
|
||||||
|
.getAllAttributes(_class, _class === ofClass && useOfClassAttributes ? core.class.Doc : cl.extends)
|
||||||
|
.values()
|
||||||
|
)
|
||||||
|
return attributes
|
||||||
|
}
|
||||||
|
|
||||||
|
const attrQuery = createQuery()
|
||||||
|
|
||||||
|
$: attrQuery.query(core.class.Attribute, { attributeOf: _class }, () => {
|
||||||
|
attributes = getCustomAttributes(_class)
|
||||||
|
})
|
||||||
|
|
||||||
|
function update (): void {
|
||||||
|
attributes = getCustomAttributes(_class)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createAttribute (): void {
|
||||||
|
showPopup(CreateAttribute, { _class }, 'top', update)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function editAttribute (attribute: AnyAttribute, exist: boolean): Promise<void> {
|
||||||
|
showPopup(EditAttribute, { attribute, exist }, 'top', update)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function removeAttribute (attribute: AnyAttribute, exist: boolean): Promise<void> {
|
||||||
|
showPopup(
|
||||||
|
MessageBox,
|
||||||
|
{
|
||||||
|
label: settings.string.DeleteAttribute,
|
||||||
|
message: exist ? settings.string.DeleteAttributeExistConfirm : settings.string.DeleteAttributeConfirm
|
||||||
|
},
|
||||||
|
'top',
|
||||||
|
async (result) => {
|
||||||
|
if (result != null) {
|
||||||
|
await client.remove(attribute)
|
||||||
|
update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function showMenu (ev: MouseEvent, attribute: AnyAttribute): Promise<void> {
|
||||||
|
const exist = (await client.findOne(attribute.attributeOf, { [attribute.name]: { $exists: true } })) !== undefined
|
||||||
|
|
||||||
|
const actions: Action[] = [
|
||||||
|
{
|
||||||
|
label: presentation.string.Edit,
|
||||||
|
icon: IconEdit,
|
||||||
|
action: async () => {
|
||||||
|
await editAttribute(attribute, exist)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
if (attribute.isCustom === true) {
|
||||||
|
actions.push({
|
||||||
|
label: presentation.string.Remove,
|
||||||
|
icon: IconDelete,
|
||||||
|
action: async () => {
|
||||||
|
await removeAttribute(attribute, exist)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const extra = await getContextActions(client, attribute, { mode: 'context' })
|
||||||
|
actions.push(
|
||||||
|
...extra.map((it) => ({
|
||||||
|
label: it.label,
|
||||||
|
icon: it.icon,
|
||||||
|
action: async (_: any, evt: Event) => {
|
||||||
|
const r = await getResource(it.action)
|
||||||
|
await r(attribute, evt, it.actionProps)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
showPopup(Menu, { actions }, getEventPositionElement(ev))
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAttrType (type: Type<any>): IntlString | undefined {
|
||||||
|
switch (type._class) {
|
||||||
|
case core.class.RefTo:
|
||||||
|
return client.getHierarchy().getClass((type as RefTo<Doc>).to).label
|
||||||
|
case core.class.Collection:
|
||||||
|
return client.getHierarchy().getClass((type as Collection<AttachedDoc>).of).label
|
||||||
|
case core.class.ArrOf:
|
||||||
|
return (type as ArrOf<Doc>).of.label
|
||||||
|
default:
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getEnumName (type: Type<any>): Promise<string | undefined> {
|
||||||
|
const ref = (type as EnumOf).of
|
||||||
|
const res = await client.findOne(core.class.Enum, { _id: ref })
|
||||||
|
return res?.name
|
||||||
|
}
|
||||||
|
function editLabel (evt: MouseEvent): void {
|
||||||
|
showPopup(EditClassLabel, { clazz }, getEventPositionElement(evt))
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if showTitle}
|
||||||
|
<div class="flex-row-center fs-title mb-3">
|
||||||
|
{#if clazz?.icon}
|
||||||
|
<div class="mr-2 flex">
|
||||||
|
<Icon icon={clazz.icon} size={'medium'} />
|
||||||
|
{#if clazz.kind === ClassifierKind.MIXIN && hierarchy.hasMixin(clazz, settings.mixin.UserMixin)}
|
||||||
|
<Icon icon={IconAdd} size={'x-small'} />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#if clazz}
|
||||||
|
<Label label={clazz.label} />
|
||||||
|
{#if clazz.kind === ClassifierKind.MIXIN && hierarchy.hasMixin(clazz, settings.mixin.UserMixin)}
|
||||||
|
<div class="ml-2">
|
||||||
|
<ActionIcon icon={IconEdit} size="small" action={editLabel} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#if showCreate}
|
||||||
|
<div class="flex-between trans-title mb-3">
|
||||||
|
<Label label={settings.string.Attributes} />
|
||||||
|
<CircleButton icon={IconAdd} size="medium" on:click={createAttribute} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#each attributes as attr, i}
|
||||||
|
{@const attrType = getAttrType(attr.type)}
|
||||||
|
<tr
|
||||||
|
class="antiTable-body__row"
|
||||||
|
on:contextmenu={(ev) => {
|
||||||
|
ev.preventDefault()
|
||||||
|
void showMenu(ev, attr)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<td>
|
||||||
|
{#if i === 0 && clazz?.label !== undefined}
|
||||||
|
<div class="trans-title">
|
||||||
|
<Label label={clazz.label} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="antiTable-cells__firstCell whitespace-nowrap flex-row-center">
|
||||||
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||||
|
<div id="context-menu" on:click={(ev) => showMenu(ev, attr)}>
|
||||||
|
<div class="p-1">
|
||||||
|
<IconMoreV2 size={'medium'} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{#if attr.icon !== undefined}
|
||||||
|
<div class="p-1">
|
||||||
|
<Icon icon={attr.icon} size={'small'} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#if attr.isCustom}
|
||||||
|
<div class="trans-title p-1">
|
||||||
|
<Label label={settings.string.Custom} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<div class:accent={!attr.hidden}>
|
||||||
|
<Label label={attr.label} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="select-text whitespace-nowrap trans-title text-xs text-right" style:padding-right={'1rem !important'}>
|
||||||
|
<Label label={attr.type.label} />
|
||||||
|
{#if attrType !== undefined}
|
||||||
|
: <Label label={attrType} />
|
||||||
|
{/if}
|
||||||
|
{#if attr.type._class === core.class.EnumOf}
|
||||||
|
{#await getEnumName(attr.type) then name}
|
||||||
|
{#if name}
|
||||||
|
: {name}
|
||||||
|
{/if}
|
||||||
|
{/await}
|
||||||
|
{/if}
|
||||||
|
</td>
|
||||||
|
{#if attributeMapper}
|
||||||
|
<td>
|
||||||
|
<svelte:component this={attributeMapper.component} {...attributeMapper.props} attribute={attr} />
|
||||||
|
</td>
|
||||||
|
{/if}
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
{#if attributes.length === 0}
|
||||||
|
<tr class="antiTable-body__row">
|
||||||
|
<td>
|
||||||
|
<div class="trans-title">
|
||||||
|
{#if clazz}
|
||||||
|
<Label label={clazz.label} />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="select-text whitespace-nowrap"> </td>
|
||||||
|
<td> </td>
|
||||||
|
{#if attributeMapper}
|
||||||
|
<td> </td>
|
||||||
|
{/if}
|
||||||
|
</tr>
|
||||||
|
{/if}
|
@ -15,15 +15,15 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Class, ClassifierKind, Doc, Ref } from '@hcengineering/core'
|
import { Class, ClassifierKind, Doc, Ref } from '@hcengineering/core'
|
||||||
import { getClient } from '@hcengineering/presentation'
|
import { getClient } from '@hcengineering/presentation'
|
||||||
import { Icon, IconAdd, getEventPositionElement, showPopup } from '@hcengineering/ui'
|
import { getEventPositionElement, showPopup, NavItem } from '@hcengineering/ui'
|
||||||
import { ContextMenu } from '@hcengineering/view-resources'
|
import { ContextMenu } from '@hcengineering/view-resources'
|
||||||
import ObjectPresenter from '@hcengineering/view-resources/src/components/ObjectPresenter.svelte'
|
|
||||||
import { createEventDispatcher } from 'svelte'
|
import { createEventDispatcher } from 'svelte'
|
||||||
import settings from '../plugin'
|
import settings from '../plugin'
|
||||||
|
|
||||||
export let classes: Ref<Class<Doc>>[] = ['contact:class:Contact' as Ref<Class<Doc>>]
|
export let classes: Ref<Class<Doc>>[] = ['contact:class:Contact' as Ref<Class<Doc>>]
|
||||||
export let _class: Ref<Class<Doc>> | undefined
|
export let _class: Ref<Class<Doc>> | undefined
|
||||||
export let ofClass: Ref<Class<Doc>> | undefined
|
export let ofClass: Ref<Class<Doc>> | undefined
|
||||||
|
export let level: number = 1
|
||||||
|
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
@ -58,35 +58,20 @@
|
|||||||
{#each classes as cl}
|
{#each classes as cl}
|
||||||
{@const clazz = client.getHierarchy().getClass(cl)}
|
{@const clazz = client.getHierarchy().getClass(cl)}
|
||||||
{@const desc = getDescendants(cl)}
|
{@const desc = getDescendants(cl)}
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
<NavItem
|
||||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
label={clazz.label}
|
||||||
<div
|
isFold
|
||||||
class="ac-column__list-item"
|
empty
|
||||||
class:ac-column__list-selected={cl === _class}
|
{level}
|
||||||
|
selected={cl === _class}
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
dispatch('select', cl)
|
dispatch('select', cl)
|
||||||
}}
|
}}
|
||||||
on:contextmenu|preventDefault|stopPropagation={(evt) => {
|
on:contextmenu={(evt) => {
|
||||||
showContextMenu(evt, clazz)
|
showContextMenu(evt, clazz)
|
||||||
}}
|
}}
|
||||||
>
|
/>
|
||||||
<div class="flex-row-center">
|
|
||||||
{#if clazz.icon}
|
|
||||||
<div class="mr-1 flex">
|
|
||||||
<Icon icon={clazz.icon} size={'medium'} />
|
|
||||||
{#if clazz.kind === ClassifierKind.MIXIN && client.getHierarchy().hasMixin(clazz, settings.mixin.UserMixin)}
|
|
||||||
<Icon icon={IconAdd} size={'x-small'} fill={'var(--theme-dark-color)'} />
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
<span class="overflow-label caption-color">
|
|
||||||
<ObjectPresenter _class={clazz._class} objectId={clazz._id} value={clazz} />
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{#if desc.length}
|
{#if desc.length}
|
||||||
<div class="ml-8 mt-3 mb-3">
|
<svelte:self classes={desc} {_class} level={level + 1} on:select />
|
||||||
<svelte:self classes={desc} {_class} on:select />
|
|
||||||
</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
|
@ -13,10 +13,25 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher } from 'svelte'
|
||||||
import core, { Class, Doc, Obj, Ref } from '@hcengineering/core'
|
import core, { Class, Doc, Obj, Ref } from '@hcengineering/core'
|
||||||
import { IntlString } from '@hcengineering/platform'
|
import { IntlString } from '@hcengineering/platform'
|
||||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||||
import { AnySvelteComponent, Icon, Label, getLocation, navigate } from '@hcengineering/ui'
|
import {
|
||||||
|
AnySvelteComponent,
|
||||||
|
Scroller,
|
||||||
|
ButtonIcon,
|
||||||
|
IconDescription,
|
||||||
|
Label,
|
||||||
|
getLocation,
|
||||||
|
navigate,
|
||||||
|
Header,
|
||||||
|
Breadcrumb,
|
||||||
|
defineSeparators,
|
||||||
|
settingsSeparators,
|
||||||
|
Separator,
|
||||||
|
NavGroup
|
||||||
|
} from '@hcengineering/ui'
|
||||||
import setting from '../plugin'
|
import setting from '../plugin'
|
||||||
import { filterDescendants } from '../utils'
|
import { filterDescendants } from '../utils'
|
||||||
import ClassAttributes from './ClassAttributes.svelte'
|
import ClassAttributes from './ClassAttributes.svelte'
|
||||||
@ -32,6 +47,9 @@
|
|||||||
| undefined = undefined
|
| undefined = undefined
|
||||||
export let withoutHeader = false
|
export let withoutHeader = false
|
||||||
export let useOfClassAttributes = true
|
export let useOfClassAttributes = true
|
||||||
|
export let visibleNav: boolean = true
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
const loc = getLocation()
|
const loc = getLocation()
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
@ -80,18 +98,27 @@
|
|||||||
$: if (ofClass !== undefined && _class !== undefined && !client.getHierarchy().isDerived(_class, ofClass)) {
|
$: if (ofClass !== undefined && _class !== undefined && !client.getHierarchy().isDerived(_class, ofClass)) {
|
||||||
_class = ofClass
|
_class = ofClass
|
||||||
}
|
}
|
||||||
|
defineSeparators('workspaceSettings', settingsSeparators)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="antiComponent">
|
<div class="hulyComponent">
|
||||||
{#if !withoutHeader}
|
{#if !withoutHeader}
|
||||||
<div class="ac-header short divide">
|
<Header minimize={!visibleNav} on:resize={(event) => dispatch('change', event.detail)}>
|
||||||
<div class="ac-header__icon"><Icon icon={setting.icon.Clazz} size={'medium'} /></div>
|
<Breadcrumb icon={setting.icon.Clazz} label={setting.string.ClassSetting} size={'large'} isCurrent />
|
||||||
<div class="ac-header__title"><Label label={setting.string.ClassSetting} /></div>
|
</Header>
|
||||||
</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
<div class="ac-body columns hScroll">
|
<div class="hulyComponent-content__container columns">
|
||||||
<div class="ac-column">
|
<div class="hulyComponent-content__column">
|
||||||
<div class="overflow-y-auto">
|
<div class="hulyComponent-content__navHeader">
|
||||||
|
<div class="hulyComponent-content__navHeader-menu">
|
||||||
|
<ButtonIcon kind={'tertiary'} icon={IconDescription} size={'small'} inheritColor />
|
||||||
|
</div>
|
||||||
|
<div class="hulyComponent-content__navHeader-hint paragraph-regular-14">
|
||||||
|
<Label label={setting.string.ClassSettingHint} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Scroller>
|
||||||
|
<NavGroup label={setting.string.Classes} selected={_class !== undefined} categoryName={'classes'} second>
|
||||||
<ClassHierarchy
|
<ClassHierarchy
|
||||||
{classes}
|
{classes}
|
||||||
{_class}
|
{_class}
|
||||||
@ -100,16 +127,18 @@
|
|||||||
_class = e.detail
|
_class = e.detail
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</NavGroup>
|
||||||
|
</Scroller>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<Separator name={'workspaceSettings'} index={0} color={'var(--theme-divider-color)'} />
|
||||||
<div class="ac-column max">
|
<div class="hulyComponent-content__column content">
|
||||||
|
<div class="hulyComponent-content">
|
||||||
{#if _class !== undefined}
|
{#if _class !== undefined}
|
||||||
<table class="antiTable">
|
<Scroller>
|
||||||
<tbody>
|
|
||||||
<ClassAttributes {_class} {ofClass} {attributeMapper} {useOfClassAttributes} />
|
<ClassAttributes {_class} {ofClass} {attributeMapper} {useOfClassAttributes} />
|
||||||
</tbody>
|
</Scroller>
|
||||||
</table>
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -13,11 +13,16 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher } from 'svelte'
|
||||||
import { PluginConfiguration } from '@hcengineering/core'
|
import { PluginConfiguration } from '@hcengineering/core'
|
||||||
import { configurationStore, getClient } from '@hcengineering/presentation'
|
import { configurationStore, getClient } from '@hcengineering/presentation'
|
||||||
import { Button, Icon, IconInfo, Label, Scroller } from '@hcengineering/ui'
|
import { Button, Icon, IconInfo, Label, Header, Breadcrumb } from '@hcengineering/ui'
|
||||||
import setting from '../plugin'
|
import setting from '../plugin'
|
||||||
|
|
||||||
|
export let visibleNav: boolean = true
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
|
|
||||||
async function change (config: PluginConfiguration, value: boolean): Promise<void> {
|
async function change (config: PluginConfiguration, value: boolean): Promise<void> {
|
||||||
@ -27,13 +32,12 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="antiComponent">
|
<div class="hulyComponent">
|
||||||
<div class="ac-header short divide">
|
<Header minimize={!visibleNav} on:resize={(event) => dispatch('change', event.detail)}>
|
||||||
<div class="ac-header__icon"><Icon icon={setting.icon.Setting} size={'medium'} /></div>
|
<Breadcrumb icon={setting.icon.Setting} label={setting.string.Configuration} size={'large'} isCurrent />
|
||||||
<div class="ac-header__title"><Label label={setting.string.Configuration} /></div>
|
</Header>
|
||||||
</div>
|
<div class="hulyComponent-content__column content">
|
||||||
<Scroller>
|
<div class="flex-row-center flex-wrap gap-around-4">
|
||||||
<div class="flex-row-center flex-wrap p-1 gap-around-4">
|
|
||||||
{#each $configurationStore.list as config}
|
{#each $configurationStore.list as config}
|
||||||
{#if config.label}
|
{#if config.label}
|
||||||
<div class="cardBox flex-col clear-mins" class:enabled={config.enabled ?? true}>
|
<div class="cardBox flex-col clear-mins" class:enabled={config.enabled ?? true}>
|
||||||
@ -66,7 +70,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</Scroller>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@ -13,26 +13,36 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher } from 'svelte'
|
||||||
import core, { Enum } from '@hcengineering/core'
|
import core, { Enum } from '@hcengineering/core'
|
||||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||||
import {
|
import {
|
||||||
CircleButton,
|
CircleButton,
|
||||||
EditBox,
|
EditBox,
|
||||||
Icon,
|
|
||||||
eventToHTMLElement,
|
eventToHTMLElement,
|
||||||
IconAdd,
|
IconAdd,
|
||||||
IconMoreH,
|
IconMoreH,
|
||||||
Label,
|
Label,
|
||||||
showPopup
|
showPopup,
|
||||||
|
Header,
|
||||||
|
Breadcrumb,
|
||||||
|
defineSeparators,
|
||||||
|
settingsSeparators,
|
||||||
|
Separator
|
||||||
} from '@hcengineering/ui'
|
} from '@hcengineering/ui'
|
||||||
import { ContextMenu } from '@hcengineering/view-resources'
|
import { ContextMenu } from '@hcengineering/view-resources'
|
||||||
import setting from '../plugin'
|
import setting from '../plugin'
|
||||||
import EnumValues from './EnumValues.svelte'
|
import EnumValues from './EnumValues.svelte'
|
||||||
|
|
||||||
|
export let visibleNav: boolean = true
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
const query = createQuery()
|
const query = createQuery()
|
||||||
|
|
||||||
let enums: Enum[] = []
|
let enums: Enum[] = []
|
||||||
let selected: Enum | undefined
|
let selected: Enum | undefined
|
||||||
|
let hovered: number | null = null
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
|
|
||||||
query.query(core.class.Enum, {}, (res) => {
|
query.query(core.class.Enum, {}, (res) => {
|
||||||
@ -51,25 +61,26 @@
|
|||||||
name: value.name
|
name: value.name
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
defineSeparators('workspaceSettings', settingsSeparators)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="antiComponent">
|
<div class="hulyComponent">
|
||||||
<div class="ac-header short divide">
|
<Header minimize={!visibleNav} on:resize={(event) => dispatch('change', event.detail)}>
|
||||||
<div class="ac-header__icon"><Icon icon={setting.icon.Enums} size={'medium'} /></div>
|
<Breadcrumb icon={setting.icon.Enums} label={setting.string.Enums} size={'large'} isCurrent />
|
||||||
<div class="ac-header__title"><Label label={setting.string.Enums} /></div>
|
</Header>
|
||||||
</div>
|
<div class="hulyComponent-content__container columns">
|
||||||
<div class="ac-body columns hScroll">
|
<div class="hulyComponent-content__column">
|
||||||
<div class="ac-column">
|
<div class="flex-between trans-title m-3">
|
||||||
<div class="flex-between trans-title mb-3">
|
|
||||||
<Label label={setting.string.Enums} />
|
<Label label={setting.string.Enums} />
|
||||||
<CircleButton icon={IconAdd} size="medium" on:click={create} />
|
<CircleButton icon={IconAdd} size="medium" on:click={create} />
|
||||||
</div>
|
</div>
|
||||||
<div class="overflow-y-auto">
|
<div class="overflow-y-auto">
|
||||||
{#each enums as value}
|
{#each enums as value, i}
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||||
<div
|
<div
|
||||||
class="ac-column__list-item"
|
class="enum__list-item"
|
||||||
|
class:hovered={hovered === i}
|
||||||
class:selected={selected === value}
|
class:selected={selected === value}
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
selected = value
|
selected = value
|
||||||
@ -79,7 +90,10 @@
|
|||||||
<div
|
<div
|
||||||
class="hover-trans"
|
class="hover-trans"
|
||||||
on:click|stopPropagation={(ev) => {
|
on:click|stopPropagation={(ev) => {
|
||||||
showPopup(ContextMenu, { object: value }, eventToHTMLElement(ev), () => {})
|
hovered = i
|
||||||
|
showPopup(ContextMenu, { object: value }, eventToHTMLElement(ev), () => {
|
||||||
|
hovered = null
|
||||||
|
})
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<IconMoreH size={'medium'} />
|
<IconMoreH size={'medium'} />
|
||||||
@ -88,10 +102,37 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ac-column max">
|
<Separator name={'workspaceSettings'} index={0} color={'var(--theme-divider-color)'} />
|
||||||
|
<div class="hulyComponent-content__column content">
|
||||||
|
<div class="hulyComponent-content">
|
||||||
{#if selected !== undefined}
|
{#if selected !== undefined}
|
||||||
<EnumValues value={selected} />
|
<EnumValues value={selected} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.enum__list-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 2.5rem;
|
||||||
|
margin: 0 0.75rem;
|
||||||
|
padding: 0 1.25rem;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&.hovered,
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--theme-button-hovered);
|
||||||
|
}
|
||||||
|
&.selected {
|
||||||
|
background-color: var(--theme-button-default);
|
||||||
|
border-color: var(--theme-button-border);
|
||||||
|
cursor: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -13,13 +13,18 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher } from 'svelte'
|
||||||
import { Ref, getCurrentAccount } from '@hcengineering/core'
|
import { Ref, getCurrentAccount } from '@hcengineering/core'
|
||||||
import { createQuery } from '@hcengineering/presentation'
|
import { createQuery } from '@hcengineering/presentation'
|
||||||
import type { Integration, IntegrationType } from '@hcengineering/setting'
|
import type { Integration, IntegrationType } from '@hcengineering/setting'
|
||||||
import setting from '@hcengineering/setting'
|
import setting from '@hcengineering/setting'
|
||||||
import { Icon, Label } from '@hcengineering/ui'
|
import { Header, Breadcrumb } from '@hcengineering/ui'
|
||||||
import PluginCard from './PluginCard.svelte'
|
import PluginCard from './PluginCard.svelte'
|
||||||
|
|
||||||
|
export let visibleNav: boolean = true
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
const accountId = getCurrentAccount()._id
|
const accountId = getCurrentAccount()._id
|
||||||
const typeQuery = createQuery()
|
const typeQuery = createQuery()
|
||||||
const integrationQuery = createQuery()
|
const integrationQuery = createQuery()
|
||||||
@ -39,11 +44,10 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="antiComponent">
|
<div class="hulyComponent">
|
||||||
<div class="ac-header short divide">
|
<Header minimize={!visibleNav} on:resize={(event) => dispatch('change', event.detail)}>
|
||||||
<div class="ac-header__icon"><Icon icon={setting.icon.Integrations} size={'medium'} /></div>
|
<Breadcrumb icon={setting.icon.Integrations} label={setting.string.Integrations} size={'large'} isCurrent />
|
||||||
<div class="ac-header__title"><Label label={setting.string.Integrations} /></div>
|
</Header>
|
||||||
</div>
|
|
||||||
<div class="ac-body__cards-container">
|
<div class="ac-body__cards-container">
|
||||||
{#each integrationTypes as integrationType (integrationType._id)}
|
{#each integrationTypes as integrationType (integrationType._id)}
|
||||||
{#if integrationType.allowMultiple}
|
{#if integrationType.allowMultiple}
|
||||||
|
@ -13,10 +13,15 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher } from 'svelte'
|
||||||
import login from '@hcengineering/login'
|
import login from '@hcengineering/login'
|
||||||
import presentation, { createQuery, getClient } from '@hcengineering/presentation'
|
import presentation, { createQuery, getClient } from '@hcengineering/presentation'
|
||||||
import setting, { InviteSettings } from '@hcengineering/setting'
|
import setting, { InviteSettings } from '@hcengineering/setting'
|
||||||
import { Button, EditBox, MiniToggle } from '@hcengineering/ui'
|
import { Button, EditBox, MiniToggle, Header, Breadcrumb } from '@hcengineering/ui'
|
||||||
|
|
||||||
|
export let visibleNav: boolean = true
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
let expTime: number = 48
|
let expTime: number = 48
|
||||||
@ -55,7 +60,11 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="form">
|
<div class="hulyComponent">
|
||||||
|
<Header minimize={!visibleNav} on:resize={(event) => dispatch('change', event.detail)}>
|
||||||
|
<Breadcrumb icon={setting.icon.InviteSettings} label={setting.string.InviteSettings} size={'large'} isCurrent />
|
||||||
|
</Header>
|
||||||
|
<div class="form">
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
<EditBox label={login.string.LinkValidHours} format={'number'} bind:value={expTime} />
|
<EditBox label={login.string.LinkValidHours} format={'number'} bind:value={expTime} />
|
||||||
</div>
|
</div>
|
||||||
@ -73,6 +82,7 @@
|
|||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
<Button label={presentation.string.Save} size={'medium'} kind={'primary'} on:click={() => setInviteSettings()} />
|
<Button label={presentation.string.Save} size={'medium'} kind={'primary'} on:click={() => setInviteSettings()} />
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@ -13,13 +13,18 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher } from 'svelte'
|
||||||
import contact, { PersonAccount } from '@hcengineering/contact'
|
import contact, { PersonAccount } from '@hcengineering/contact'
|
||||||
import { EmployeePresenter, personByIdStore } from '@hcengineering/contact-resources'
|
import { EmployeePresenter, personByIdStore } from '@hcengineering/contact-resources'
|
||||||
import { AccountRole, SortingOrder, getCurrentAccount } from '@hcengineering/core'
|
import { AccountRole, SortingOrder, getCurrentAccount } from '@hcengineering/core'
|
||||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
import presentation, { createQuery, getClient } from '@hcengineering/presentation'
|
||||||
import { DropdownIntlItem, DropdownLabelsIntl, EditBox, Icon, Label } from '@hcengineering/ui'
|
import { DropdownIntlItem, DropdownLabelsIntl, EditBox, Header, Breadcrumb } from '@hcengineering/ui'
|
||||||
import setting from '../plugin'
|
import setting from '../plugin'
|
||||||
|
|
||||||
|
export let visibleNav: boolean = true
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
|
|
||||||
const query = createQuery()
|
const query = createQuery()
|
||||||
@ -54,14 +59,13 @@
|
|||||||
let search = ''
|
let search = ''
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="antiComponent">
|
<div class="hulyComponent">
|
||||||
<div class="ac-header short divide">
|
<Header minimize={!visibleNav} on:resize={(event) => dispatch('change', event.detail)}>
|
||||||
<div class="ac-header__icon"><Icon icon={setting.icon.Password} size={'medium'} /></div>
|
<Breadcrumb icon={setting.icon.Owners} label={setting.string.Owners} size={'large'} isCurrent />
|
||||||
<div class="ac-header__title"><Label label={setting.string.Owners} /></div>
|
<EditBox kind={'search-style'} focusIndex={1} bind:value={search} placeholder={presentation.string.Search} />
|
||||||
<EditBox kind={'search-style'} focusIndex={1} bind:value={search} />
|
</Header>
|
||||||
</div>
|
<div class="hulyComponent-content__column content">
|
||||||
<div class="ac-body columns">
|
<div class="hulyComponent-content">
|
||||||
<div class="ac-column max">
|
|
||||||
{#each accounts as account (account._id)}
|
{#each accounts as account (account._id)}
|
||||||
{@const employee = $personByIdStore.get(account.person)}
|
{@const employee = $personByIdStore.get(account.person)}
|
||||||
{#if employee?.name?.includes(search)}
|
{#if employee?.name?.includes(search)}
|
||||||
|
@ -13,14 +13,19 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher } from 'svelte'
|
||||||
import setting from '@hcengineering/setting'
|
import setting from '@hcengineering/setting'
|
||||||
import presentation from '@hcengineering/presentation'
|
import presentation from '@hcengineering/presentation'
|
||||||
import { Button, EditBox, Icon, Label } from '@hcengineering/ui'
|
import { Button, EditBox, Icon, Label, Header, Breadcrumb } from '@hcengineering/ui'
|
||||||
import login from '@hcengineering/login'
|
import login from '@hcengineering/login'
|
||||||
import Error from './icons/Error.svelte'
|
import Error from './icons/Error.svelte'
|
||||||
import plugin from '../plugin'
|
import plugin from '../plugin'
|
||||||
import { getResource } from '@hcengineering/platform'
|
import { getResource } from '@hcengineering/platform'
|
||||||
|
|
||||||
|
export let visibleNav: boolean = true
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
let oldPassword: string = ''
|
let oldPassword: string = ''
|
||||||
let password: string = ''
|
let password: string = ''
|
||||||
let password2: string = ''
|
let password2: string = ''
|
||||||
@ -54,11 +59,10 @@
|
|||||||
$: updateSaved(oldPassword, password, password2)
|
$: updateSaved(oldPassword, password, password2)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="antiComponent">
|
<div class="hulyComponent">
|
||||||
<div class="ac-header short divide">
|
<Header minimize={!visibleNav} on:resize={(event) => dispatch('change', event.detail)}>
|
||||||
<div class="ac-header__icon"><Icon icon={setting.icon.Password} size={'medium'} /></div>
|
<Breadcrumb icon={setting.icon.Password} label={setting.string.ChangePassword} size={'large'} isCurrent />
|
||||||
<div class="ac-header__title"><Label label={setting.string.ChangePassword} /></div>
|
</Header>
|
||||||
</div>
|
|
||||||
<div class="flex-row-stretch flex-grow p-10">
|
<div class="flex-row-stretch flex-grow p-10">
|
||||||
<div class="flex-grow flex-col">
|
<div class="flex-grow flex-col">
|
||||||
{#if error}
|
{#if error}
|
||||||
|
@ -13,16 +13,20 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher, onDestroy } from 'svelte'
|
||||||
import contact, { Employee, PersonAccount, combineName, getFirstName, getLastName } from '@hcengineering/contact'
|
import contact, { Employee, PersonAccount, combineName, getFirstName, getLastName } from '@hcengineering/contact'
|
||||||
import { ChannelsEditor, EditableAvatar, employeeByIdStore } from '@hcengineering/contact-resources'
|
import { ChannelsEditor, EditableAvatar, employeeByIdStore } from '@hcengineering/contact-resources'
|
||||||
import { Ref, getCurrentAccount } from '@hcengineering/core'
|
import { Ref, getCurrentAccount } from '@hcengineering/core'
|
||||||
import login from '@hcengineering/login'
|
import login from '@hcengineering/login'
|
||||||
import { getResource } from '@hcengineering/platform'
|
import { getResource } from '@hcengineering/platform'
|
||||||
import { AttributeEditor, getClient, MessageBox } from '@hcengineering/presentation'
|
import { AttributeEditor, getClient, MessageBox } from '@hcengineering/presentation'
|
||||||
import { Button, createFocusManager, EditBox, FocusHandler, Icon, Label, showPopup } from '@hcengineering/ui'
|
import { Button, createFocusManager, EditBox, FocusHandler, showPopup, Header, Breadcrumb } from '@hcengineering/ui'
|
||||||
import { onDestroy } from 'svelte'
|
|
||||||
import setting from '../plugin'
|
import setting from '../plugin'
|
||||||
|
|
||||||
|
export let visibleNav: boolean = true
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
|
|
||||||
let avatarEditor: EditableAvatar
|
let avatarEditor: EditableAvatar
|
||||||
@ -84,11 +88,10 @@
|
|||||||
|
|
||||||
<FocusHandler {manager} />
|
<FocusHandler {manager} />
|
||||||
|
|
||||||
<div class="antiComponent">
|
<div class="hulyComponent">
|
||||||
<div class="ac-header short divide">
|
<Header minimize={!visibleNav} on:resize={(event) => dispatch('change', event.detail)}>
|
||||||
<div class="ac-header__icon"><Icon icon={setting.icon.AccountSettings} size={'medium'} /></div>
|
<Breadcrumb icon={setting.icon.AccountSettings} label={setting.string.AccountSettings} size={'large'} isCurrent />
|
||||||
<div class="ac-header__title"><Label label={setting.string.AccountSettings} /></div>
|
</Header>
|
||||||
</div>
|
|
||||||
<div class="ac-body p-10">
|
<div class="ac-body p-10">
|
||||||
{#if employee}
|
{#if employee}
|
||||||
<div class="flex flex-grow w-full">
|
<div class="flex flex-grow w-full">
|
||||||
|
@ -31,12 +31,12 @@
|
|||||||
resolvedLocationStore,
|
resolvedLocationStore,
|
||||||
setMetadataLocalStorage,
|
setMetadataLocalStorage,
|
||||||
showPopup,
|
showPopup,
|
||||||
Label
|
Label,
|
||||||
|
NavItem,
|
||||||
|
NavGroup
|
||||||
} from '@hcengineering/ui'
|
} from '@hcengineering/ui'
|
||||||
import { NavFooter } from '@hcengineering/workbench-resources'
|
import { NavFooter } from '@hcengineering/workbench-resources'
|
||||||
import { onDestroy } from 'svelte'
|
import { onDestroy } from 'svelte'
|
||||||
import NavItem from './NavItem.svelte'
|
|
||||||
import NavGroup from './NavGroup.svelte'
|
|
||||||
|
|
||||||
export let visibleNav: boolean = true
|
export let visibleNav: boolean = true
|
||||||
export let navFloat: boolean = false
|
export let navFloat: boolean = false
|
||||||
@ -105,9 +105,12 @@
|
|||||||
defineSeparators('setting', settingsSeparators)
|
defineSeparators('setting', settingsSeparators)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex h-full clear-mins">
|
<div class="hulyPanels-container">
|
||||||
{#if visibleNav}
|
{#if visibleNav}
|
||||||
<div class="antiPanel-navigator {appsDirection === 'horizontal' ? 'portrait' : 'landscape'}">
|
<div
|
||||||
|
class="antiPanel-navigator {appsDirection === 'horizontal' ? 'portrait' : 'landscape'} border-left"
|
||||||
|
class:border-right={category?.component === undefined}
|
||||||
|
>
|
||||||
<div class="antiPanel-wrap__content hulyNavPanel-container">
|
<div class="antiPanel-wrap__content hulyNavPanel-container">
|
||||||
<div class="hulyNavPanel-header">
|
<div class="hulyNavPanel-header">
|
||||||
<Label label={setting.string.Settings} />
|
<Label label={setting.string.Settings} />
|
||||||
@ -157,29 +160,40 @@
|
|||||||
<NavItem icon={setting.icon.Signout} label={setting.string.Signout} on:click={signOut} />
|
<NavItem icon={setting.icon.Signout} label={setting.string.Signout} on:click={signOut} />
|
||||||
</NavFooter>
|
</NavFooter>
|
||||||
</div>
|
</div>
|
||||||
<Separator
|
<Separator name={'setting'} float={navFloat ? 'navigator' : true} index={0} color={'transparent'} />
|
||||||
name={'setting'}
|
|
||||||
float={navFloat ? 'navigator' : true}
|
|
||||||
index={0}
|
|
||||||
color={'var(--theme-navpanel-border)'}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<Separator name={'setting'} float={navFloat} index={0} color={'var(--theme-navpanel-border)'} />
|
<Separator name={'setting'} float={navFloat} index={0} color={'transparent'} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="antiPanel-component filled">
|
<div class="antiPanel-component filledNav">
|
||||||
{#if category}
|
{#if category}
|
||||||
<Component
|
<Component
|
||||||
is={category.component}
|
is={category.component}
|
||||||
props={{
|
props={{
|
||||||
|
kind: 'content',
|
||||||
visibleNav
|
visibleNav
|
||||||
}}
|
}}
|
||||||
|
on:change={(event) => (visibleNav = event.detail)}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
.hulyPanels-container {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
min-height: 0;
|
||||||
|
background-color: var(--theme-navpanel-color); // var(--global-surface-01-BackgroundColor);
|
||||||
|
|
||||||
|
// .antiPanel-navigator {
|
||||||
|
// background-color: transparent;
|
||||||
|
// }
|
||||||
|
.antiPanel-component {
|
||||||
|
border-radius: var(--small-focus-BorderRadius);
|
||||||
|
}
|
||||||
|
}
|
||||||
.hulyNavPanel-container :global(.hulyNavItem-container),
|
.hulyNavPanel-container :global(.hulyNavItem-container),
|
||||||
.hulyNavPanel-container :global(.hulyTaskNavLink-container) {
|
.hulyNavPanel-container :global(.hulyTaskNavLink-container) {
|
||||||
margin: 0 0.75rem;
|
margin: 0 0.75rem;
|
||||||
|
@ -17,12 +17,19 @@
|
|||||||
import { AccountRole, getCurrentAccount } from '@hcengineering/core'
|
import { AccountRole, getCurrentAccount } from '@hcengineering/core'
|
||||||
import { createQuery } from '@hcengineering/presentation'
|
import { createQuery } from '@hcengineering/presentation'
|
||||||
import setting, { SettingsCategory } from '@hcengineering/setting'
|
import setting, { SettingsCategory } from '@hcengineering/setting'
|
||||||
import { Component, Location, getCurrentResolvedLocation, navigate, resolvedLocationStore } from '@hcengineering/ui'
|
import {
|
||||||
|
Component,
|
||||||
|
Location,
|
||||||
|
getCurrentResolvedLocation,
|
||||||
|
navigate,
|
||||||
|
resolvedLocationStore,
|
||||||
|
NavItem
|
||||||
|
} from '@hcengineering/ui'
|
||||||
import { onDestroy } from 'svelte'
|
import { onDestroy } from 'svelte'
|
||||||
import NavItem from './NavItem.svelte'
|
|
||||||
|
|
||||||
export let kind: 'navigation' | undefined
|
export let kind: 'navigation' | 'content' | undefined
|
||||||
export let categoryName: string
|
export let categoryName: string
|
||||||
|
export let visibleNav: boolean = true
|
||||||
|
|
||||||
let category: SettingsCategory | undefined
|
let category: SettingsCategory | undefined
|
||||||
let categoryId: string = ''
|
let categoryId: string = ''
|
||||||
@ -81,6 +88,8 @@
|
|||||||
<Component is={category.extraComponents?.navigation} props={{ kind: 'navigation', categoryName: categoryId }} />
|
<Component is={category.extraComponents?.navigation} props={{ kind: 'navigation', categoryName: categoryId }} />
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
|
{:else if kind === 'content' && !category}
|
||||||
|
<div class="hulyComponent" />
|
||||||
{:else if category}
|
{:else if category}
|
||||||
<Component is={category.component} props={{ kind: 'content' }} />
|
<Component is={category.component} props={{ kind: 'content', visibleNav }} on:change />
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -47,8 +47,9 @@ import setting from './plugin'
|
|||||||
import IntegrationPanel from './components/IntegrationPanel.svelte'
|
import IntegrationPanel from './components/IntegrationPanel.svelte'
|
||||||
import { getOwnerFirstName, getOwnerLastName, getOwnerPosition, getValue, filterDescendants } from './utils'
|
import { getOwnerFirstName, getOwnerLastName, getOwnerPosition, getValue, filterDescendants } from './utils'
|
||||||
import ClassAttributes from './components/ClassAttributes.svelte'
|
import ClassAttributes from './components/ClassAttributes.svelte'
|
||||||
|
import ClassAttributesList from './components/ClassAttributesList.svelte'
|
||||||
|
|
||||||
export { ClassSetting, filterDescendants, ClassAttributes }
|
export { ClassSetting, filterDescendants, ClassAttributes, ClassAttributesList }
|
||||||
|
|
||||||
async function DeleteMixin (object: Mixin<Class<Doc>>): Promise<void> {
|
async function DeleteMixin (object: Mixin<Class<Doc>>): Promise<void> {
|
||||||
const docs = await getClient().findAll(object._id, {}, { limit: 1 })
|
const docs = await getClient().findAll(object._id, {}, { limit: 1 })
|
||||||
|
@ -66,7 +66,6 @@ export default mergeIds(settingId, setting, {
|
|||||||
ShowAttribute: '' as IntlString,
|
ShowAttribute: '' as IntlString,
|
||||||
Visibility: '' as IntlString,
|
Visibility: '' as IntlString,
|
||||||
Hidden: '' as IntlString,
|
Hidden: '' as IntlString,
|
||||||
InviteSettings: '' as IntlString,
|
|
||||||
DefaultValue: '' as IntlString,
|
DefaultValue: '' as IntlString,
|
||||||
SelectAValue: '' as IntlString,
|
SelectAValue: '' as IntlString,
|
||||||
DateOnly: '' as IntlString,
|
DateOnly: '' as IntlString,
|
||||||
@ -77,6 +76,8 @@ export default mergeIds(settingId, setting, {
|
|||||||
ConfigurationDisabled: '' as IntlString,
|
ConfigurationDisabled: '' as IntlString,
|
||||||
ConfigDisable: '' as IntlString,
|
ConfigDisable: '' as IntlString,
|
||||||
ConfigEnable: '' as IntlString,
|
ConfigEnable: '' as IntlString,
|
||||||
ConfigBeta: '' as IntlString
|
ConfigBeta: '' as IntlString,
|
||||||
|
ClassSettingHint: '' as IntlString,
|
||||||
|
ClassProperties: '' as IntlString
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -168,7 +168,8 @@ export default plugin(settingId, {
|
|||||||
ClassSetting: '' as IntlString,
|
ClassSetting: '' as IntlString,
|
||||||
Classes: '' as IntlString,
|
Classes: '' as IntlString,
|
||||||
Owners: '' as IntlString,
|
Owners: '' as IntlString,
|
||||||
Configure: '' as IntlString
|
Configure: '' as IntlString,
|
||||||
|
InviteSettings: '' as IntlString
|
||||||
},
|
},
|
||||||
icon: {
|
icon: {
|
||||||
AccountSettings: '' as Asset,
|
AccountSettings: '' as Asset,
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
import { typeStore } from '../../'
|
import { typeStore } from '../../'
|
||||||
import ProjectEditor from './ProjectEditor.svelte'
|
import ProjectEditor from './ProjectEditor.svelte'
|
||||||
|
|
||||||
|
export let visibleNav: boolean = true
|
||||||
|
|
||||||
let type: WithLookup<ProjectType> | undefined
|
let type: WithLookup<ProjectType> | undefined
|
||||||
let typeId: Ref<ProjectType> | undefined
|
let typeId: Ref<ProjectType> | undefined
|
||||||
|
|
||||||
@ -36,8 +38,8 @@
|
|||||||
$: type = typeId !== undefined ? $typeStore.get(typeId) : undefined
|
$: type = typeId !== undefined ? $typeStore.get(typeId) : undefined
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="p-1 w-full h-full">
|
<div class="hulyComponent">
|
||||||
{#if type !== undefined}
|
{#if type !== undefined}
|
||||||
<ProjectEditor {type} descriptor={type.$lookup?.descriptor} />
|
<ProjectEditor {type} descriptor={type.$lookup?.descriptor} {visibleNav} on:change />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher, onDestroy } from 'svelte'
|
||||||
import { ComponentExtensions, createQuery, getClient } from '@hcengineering/presentation'
|
import { ComponentExtensions, createQuery, getClient } from '@hcengineering/presentation'
|
||||||
import task, { Project, ProjectType, ProjectTypeDescriptor, Task, TaskType } from '@hcengineering/task'
|
import task, { Project, ProjectType, ProjectTypeDescriptor, Task, TaskType } from '@hcengineering/task'
|
||||||
|
|
||||||
@ -21,6 +22,7 @@
|
|||||||
import { getEmbeddedLabel } from '@hcengineering/platform'
|
import { getEmbeddedLabel } from '@hcengineering/platform'
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
|
ButtonIcon,
|
||||||
Component,
|
Component,
|
||||||
EditBox,
|
EditBox,
|
||||||
Icon,
|
Icon,
|
||||||
@ -31,15 +33,15 @@
|
|||||||
IconMoreV,
|
IconMoreV,
|
||||||
Label,
|
Label,
|
||||||
Location,
|
Location,
|
||||||
Scroller,
|
|
||||||
eventToHTMLElement,
|
eventToHTMLElement,
|
||||||
getCurrentResolvedLocation,
|
getCurrentResolvedLocation,
|
||||||
navigate,
|
navigate,
|
||||||
resolvedLocationStore,
|
resolvedLocationStore,
|
||||||
showPopup
|
showPopup,
|
||||||
|
Header,
|
||||||
|
Breadcrumbs
|
||||||
} from '@hcengineering/ui'
|
} from '@hcengineering/ui'
|
||||||
import { ContextMenu } from '@hcengineering/view-resources'
|
import { ContextMenu } from '@hcengineering/view-resources'
|
||||||
import { onDestroy } from 'svelte'
|
|
||||||
import plugin from '../../plugin'
|
import plugin from '../../plugin'
|
||||||
import CreateTaskType from '../taskTypes/CreateTaskType.svelte'
|
import CreateTaskType from '../taskTypes/CreateTaskType.svelte'
|
||||||
import TaskTypeEditor from '../taskTypes/TaskTypeEditor.svelte'
|
import TaskTypeEditor from '../taskTypes/TaskTypeEditor.svelte'
|
||||||
@ -49,6 +51,9 @@
|
|||||||
|
|
||||||
export let type: ProjectType
|
export let type: ProjectType
|
||||||
export let descriptor: ProjectTypeDescriptor | undefined
|
export let descriptor: ProjectTypeDescriptor | undefined
|
||||||
|
export let visibleNav: boolean = true
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
const query = createQuery()
|
const query = createQuery()
|
||||||
@ -141,54 +146,49 @@
|
|||||||
selectedTaskTypeId = id as Ref<TaskType>
|
selectedTaskTypeId = id as Ref<TaskType>
|
||||||
navigate(loc)
|
navigate(loc)
|
||||||
}
|
}
|
||||||
|
$: items =
|
||||||
|
selectedTaskType !== undefined
|
||||||
|
? [{ label: plugin.string.ProjectType }, { title: selectedTaskType.name }]
|
||||||
|
: [{ label: plugin.string.ProjectType }]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="h-full flex-col w-full">
|
{#if type !== undefined && descriptor !== undefined}
|
||||||
{#if type !== undefined && descriptor !== undefined}
|
<Header minimize={!visibleNav} on:resize={(event) => dispatch('change', event.detail)}>
|
||||||
<div class="p-2 bottom-divider flex-row-center">
|
<ButtonIcon
|
||||||
<div class="button-group flex-row-center right-divider pr-2">
|
|
||||||
<Button
|
|
||||||
icon={IconDelete}
|
|
||||||
kind={'regular'}
|
|
||||||
on:click={(ev) => {
|
|
||||||
// Ask for delete
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
icon={IconCopy}
|
icon={IconCopy}
|
||||||
kind={'regular'}
|
size={'small'}
|
||||||
|
kind={'secondary'}
|
||||||
on:click={(ev) => {
|
on:click={(ev) => {
|
||||||
// Do copy of type
|
// Do copy of type
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Button
|
<ButtonIcon
|
||||||
|
icon={IconDelete}
|
||||||
|
size={'small'}
|
||||||
|
kind={'secondary'}
|
||||||
|
on:click={(ev) => {
|
||||||
|
// Ask for delete
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<ButtonIcon
|
||||||
icon={IconMoreV}
|
icon={IconMoreV}
|
||||||
kind={'regular'}
|
size={'small'}
|
||||||
|
kind={'secondary'}
|
||||||
on:click={(ev) => {
|
on:click={(ev) => {
|
||||||
showPopup(ContextMenu, { object: type }, eventToHTMLElement(ev), () => {})
|
showPopup(ContextMenu, { object: type }, eventToHTMLElement(ev), () => {})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
<Breadcrumbs
|
||||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
{items}
|
||||||
<div class="fs-title ml-2 flex-row-center">
|
size={'large'}
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
selected={selectedTaskType !== undefined ? 1 : 0}
|
||||||
<div
|
on:select={(event) => {
|
||||||
class="hover-trans"
|
if (event.detail === 0) selectTaskType(undefined)
|
||||||
on:click={() => {
|
|
||||||
selectTaskType(undefined)
|
|
||||||
}}
|
}}
|
||||||
>
|
/>
|
||||||
<Label label={plugin.string.ProjectType} />
|
</Header>
|
||||||
</div>
|
<div class="hulyComponent-content__column content">
|
||||||
{#if selectedTaskType !== undefined}
|
<div class="hulyComponent-content">
|
||||||
<span class="p-1">/</span>
|
|
||||||
{selectedTaskType.name}
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="h-full flex-row-top w-full justify-center">
|
|
||||||
<div class="h-full editorBox flex-col">
|
|
||||||
<Scroller padding={'0 1rem'} noStretch shrink>
|
|
||||||
{#if selectedTaskType === undefined}
|
{#if selectedTaskType === undefined}
|
||||||
<!-- <div class="flex-col">Navigation</div> -->
|
<!-- <div class="flex-col">Navigation</div> -->
|
||||||
<div class="flex-grow h-full">
|
<div class="flex-grow h-full">
|
||||||
@ -295,19 +295,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<TaskTypeEditor
|
<TaskTypeEditor taskType={selectedTaskType} projectType={type} {taskTypes} {taskTypeCounter} {statusCounter} />
|
||||||
taskType={selectedTaskType}
|
|
||||||
projectType={type}
|
|
||||||
{taskTypes}
|
|
||||||
{taskTypeCounter}
|
|
||||||
{statusCounter}
|
|
||||||
/>
|
|
||||||
{/if}
|
{/if}
|
||||||
</Scroller>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.row {
|
.row {
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import core, { Class, Doc, Obj, Ref } from '@hcengineering/core'
|
import core, { Class, Doc, Obj, Ref } from '@hcengineering/core'
|
||||||
import { getClient } from '@hcengineering/presentation'
|
import { getClient } from '@hcengineering/presentation'
|
||||||
import { ClassAttributes } from '@hcengineering/setting-resources'
|
import { ClassAttributesList } from '@hcengineering/setting-resources'
|
||||||
import { Button, Icon, IconAdd } from '@hcengineering/ui'
|
import { Button, Icon, IconAdd } from '@hcengineering/ui'
|
||||||
import { ObjectPresenter } from '@hcengineering/view-resources'
|
import { ObjectPresenter } from '@hcengineering/view-resources'
|
||||||
|
|
||||||
@ -41,7 +41,7 @@
|
|||||||
})
|
})
|
||||||
$: clazz = client.getHierarchy().getClass(_class)
|
$: clazz = client.getHierarchy().getClass(_class)
|
||||||
|
|
||||||
let mainAttributes: ClassAttributes
|
let mainAttributes: ClassAttributesList
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex flex-between mb-4">
|
<div class="flex flex-between mb-4">
|
||||||
@ -60,7 +60,7 @@
|
|||||||
<div class="ml-2 mr-2">
|
<div class="ml-2 mr-2">
|
||||||
<table class="antiTable mx-2">
|
<table class="antiTable mx-2">
|
||||||
<tbody>
|
<tbody>
|
||||||
<ClassAttributes
|
<ClassAttributesList
|
||||||
bind:this={mainAttributes}
|
bind:this={mainAttributes}
|
||||||
{_class}
|
{_class}
|
||||||
{ofClass}
|
{ofClass}
|
||||||
@ -69,7 +69,7 @@
|
|||||||
showCreate={false}
|
showCreate={false}
|
||||||
/>
|
/>
|
||||||
{#each classes as clazz2}
|
{#each classes as clazz2}
|
||||||
<ClassAttributes
|
<ClassAttributesList
|
||||||
_class={clazz2._id}
|
_class={clazz2._id}
|
||||||
{ofClass}
|
{ofClass}
|
||||||
useOfClassAttributes={false}
|
useOfClassAttributes={false}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher } from 'svelte'
|
||||||
import core, { Data, Ref } from '@hcengineering/core'
|
import core, { Data, Ref } from '@hcengineering/core'
|
||||||
import { getEmbeddedLabel, getResource } from '@hcengineering/platform'
|
import { getEmbeddedLabel, getResource } from '@hcengineering/platform'
|
||||||
import { createQuery, getClient, MessageViewer, SpaceSelector } from '@hcengineering/presentation'
|
import { createQuery, getClient, MessageViewer, SpaceSelector } from '@hcengineering/presentation'
|
||||||
@ -9,17 +10,25 @@
|
|||||||
Button,
|
Button,
|
||||||
EditBox,
|
EditBox,
|
||||||
eventToHTMLElement,
|
eventToHTMLElement,
|
||||||
Icon,
|
|
||||||
IconAdd,
|
IconAdd,
|
||||||
IconEdit,
|
IconEdit,
|
||||||
Label,
|
Label,
|
||||||
showPopup
|
showPopup,
|
||||||
|
Header,
|
||||||
|
Breadcrumb,
|
||||||
|
Separator,
|
||||||
|
defineSeparators,
|
||||||
|
settingsSeparators
|
||||||
} from '@hcengineering/ui'
|
} from '@hcengineering/ui'
|
||||||
import { getActions as getContributedActions, TreeItem, TreeNode } from '@hcengineering/view-resources'
|
import { getActions as getContributedActions, TreeItem, TreeNode } from '@hcengineering/view-resources'
|
||||||
import templatesPlugin from '../plugin'
|
import templatesPlugin from '../plugin'
|
||||||
import CreateTemplateCategory from './CreateTemplateCategory.svelte'
|
import CreateTemplateCategory from './CreateTemplateCategory.svelte'
|
||||||
import FieldPopup from './FieldPopup.svelte'
|
import FieldPopup from './FieldPopup.svelte'
|
||||||
|
|
||||||
|
export let visibleNav: boolean = true
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
const query = createQuery()
|
const query = createQuery()
|
||||||
const spaceQ = createQuery()
|
const spaceQ = createQuery()
|
||||||
@ -138,17 +147,22 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
let space: Ref<TemplateCategory> | undefined = undefined
|
let space: Ref<TemplateCategory> | undefined = undefined
|
||||||
|
defineSeparators('workspaceSettings', settingsSeparators)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="antiComponent">
|
<div class="hulyComponent">
|
||||||
<div class="ac-header short divide">
|
<Header minimize={!visibleNav} on:resize={(event) => dispatch('change', event.detail)}>
|
||||||
<div class="ac-header__icon"><Icon icon={templatesPlugin.icon.Templates} size={'medium'} /></div>
|
<Breadcrumb
|
||||||
<div class="ac-header__title"><Label label={templatesPlugin.string.Templates} /></div>
|
icon={templatesPlugin.icon.Templates}
|
||||||
</div>
|
label={templatesPlugin.string.Templates}
|
||||||
|
size={'large'}
|
||||||
|
isCurrent
|
||||||
|
/>
|
||||||
|
</Header>
|
||||||
|
|
||||||
<div class="ac-body columns clear-mins">
|
<div class="hulyComponent-content__container columns">
|
||||||
<div class="ac-column">
|
<div class="hulyComponent-content__column">
|
||||||
<div id="create-template" class="flex-between trans-title mb-3">
|
<div id="create-template" class="flex-between trans-title m-3">
|
||||||
<Button
|
<Button
|
||||||
icon={templatesPlugin.icon.Template}
|
icon={templatesPlugin.icon.Template}
|
||||||
label={templatesPlugin.string.CreateTemplate}
|
label={templatesPlugin.string.CreateTemplate}
|
||||||
@ -179,8 +193,9 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<Separator name={'workspaceSettings'} index={0} color={'var(--theme-divider-color)'} />
|
||||||
<div class="ac-column max template-container">
|
<div class="hulyComponent-content__column content">
|
||||||
|
<div class="hulyComponent-content">
|
||||||
{#if newTemplate}
|
{#if newTemplate}
|
||||||
<div class="flex-between mr-4">
|
<div class="flex-between mr-4">
|
||||||
<span class="trans-title mb-3">
|
<span class="trans-title mb-3">
|
||||||
@ -254,6 +269,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher } from 'svelte'
|
||||||
|
import { Space } from '@hcengineering/core'
|
||||||
|
import { Header, Breadcrumb } from '@hcengineering/ui'
|
||||||
|
import tracker from '../plugin'
|
||||||
|
import EditRelatedTargets from './EditRelatedTargets.svelte'
|
||||||
|
|
||||||
|
export let value: Space | undefined
|
||||||
|
export let visibleNav: boolean = true
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="hulyComponent">
|
||||||
|
<Header minimize={!visibleNav} on:resize={(event) => dispatch('change', event.detail)}>
|
||||||
|
<Breadcrumb icon={tracker.icon.Relations} label={tracker.string.RelatedIssues} size={'large'} isCurrent />
|
||||||
|
</Header>
|
||||||
|
<EditRelatedTargets {value} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.bordered {
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
background-color: var(--theme-comp-header-color);
|
||||||
|
border: 1px solid var(--theme-divider-color);
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
</style>
|
@ -44,6 +44,7 @@ import ProjectComponents from './components/components/ProjectComponents.svelte'
|
|||||||
import CreateIssue from './components/CreateIssue.svelte'
|
import CreateIssue from './components/CreateIssue.svelte'
|
||||||
import EditRelatedTargets from './components/EditRelatedTargets.svelte'
|
import EditRelatedTargets from './components/EditRelatedTargets.svelte'
|
||||||
import EditRelatedTargetsPopup from './components/EditRelatedTargetsPopup.svelte'
|
import EditRelatedTargetsPopup from './components/EditRelatedTargetsPopup.svelte'
|
||||||
|
import SettingsRelatedTargets from './components/SettingsRelatedTargets.svelte'
|
||||||
import Inbox from './components/inbox/Inbox.svelte'
|
import Inbox from './components/inbox/Inbox.svelte'
|
||||||
import AssigneeEditor from './components/issues/AssigneeEditor.svelte'
|
import AssigneeEditor from './components/issues/AssigneeEditor.svelte'
|
||||||
import DueDatePresenter from './components/issues/DueDatePresenter.svelte'
|
import DueDatePresenter from './components/issues/DueDatePresenter.svelte'
|
||||||
@ -506,6 +507,7 @@ export default async (): Promise<Resources> => ({
|
|||||||
ComponentFilterValuePresenter,
|
ComponentFilterValuePresenter,
|
||||||
EditRelatedTargets,
|
EditRelatedTargets,
|
||||||
EditRelatedTargetsPopup,
|
EditRelatedTargetsPopup,
|
||||||
|
SettingsRelatedTargets,
|
||||||
TimePresenter,
|
TimePresenter,
|
||||||
EstimationValueEditor,
|
EstimationValueEditor,
|
||||||
IssueStatusIcon,
|
IssueStatusIcon,
|
||||||
|
@ -53,7 +53,8 @@
|
|||||||
resolvedLocationStore,
|
resolvedLocationStore,
|
||||||
setResolvedLocation,
|
setResolvedLocation,
|
||||||
showPopup,
|
showPopup,
|
||||||
workbenchSeparators
|
workbenchSeparators,
|
||||||
|
IconSettings
|
||||||
} from '@hcengineering/ui'
|
} from '@hcengineering/ui'
|
||||||
import view from '@hcengineering/view'
|
import view from '@hcengineering/view'
|
||||||
import {
|
import {
|
||||||
@ -78,7 +79,6 @@
|
|||||||
import Navigator from './Navigator.svelte'
|
import Navigator from './Navigator.svelte'
|
||||||
import SelectWorkspaceMenu from './SelectWorkspaceMenu.svelte'
|
import SelectWorkspaceMenu from './SelectWorkspaceMenu.svelte'
|
||||||
import SpaceView from './SpaceView.svelte'
|
import SpaceView from './SpaceView.svelte'
|
||||||
import IconSettings from './icons/Settings.svelte'
|
|
||||||
import TopMenu from './icons/TopMenu.svelte'
|
import TopMenu from './icons/TopMenu.svelte'
|
||||||
|
|
||||||
let contentPanel: HTMLElement
|
let contentPanel: HTMLElement
|
||||||
@ -640,7 +640,11 @@
|
|||||||
/>
|
/>
|
||||||
</clipPath>
|
</clipPath>
|
||||||
</svg>
|
</svg>
|
||||||
<div class="workbench-container" style:flex-direction={appsDirection === 'horizontal' ? 'column-reverse' : 'row'}>
|
<div
|
||||||
|
class="workbench-container"
|
||||||
|
class:setting-app={currentApplication?.alias === 'setting'}
|
||||||
|
style:flex-direction={appsDirection === 'horizontal' ? 'column-reverse' : 'row'}
|
||||||
|
>
|
||||||
<div class="antiPanel-application {appsDirection}" class:lastDivider={!visibleNav}>
|
<div class="antiPanel-application {appsDirection}" class:lastDivider={!visibleNav}>
|
||||||
<div
|
<div
|
||||||
class="hamburger-container clear-mins"
|
class="hamburger-container clear-mins"
|
||||||
@ -750,7 +754,7 @@
|
|||||||
application: currentApplication?._id
|
application: currentApplication?._id
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div class="workbench-container">
|
<div class="workbench-container inner">
|
||||||
{#if currentApplication && navigatorModel && navigator && visibleNav}
|
{#if currentApplication && navigatorModel && navigator && visibleNav}
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||||
@ -879,6 +883,28 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
touch-action: none;
|
touch-action: none;
|
||||||
|
|
||||||
|
&:not(.setting-app, .inner) {
|
||||||
|
border-top: 1px solid var(--theme-navpanel-divider);
|
||||||
|
}
|
||||||
|
&.setting-app {
|
||||||
|
position: relative;
|
||||||
|
background-color: var(--theme-statusbar-color);
|
||||||
|
border-radius: var(--medium-BorderRadius);
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
content: '';
|
||||||
|
inset: 0;
|
||||||
|
border: 1px solid var(--theme-divider-color);
|
||||||
|
border-radius: var(--medium-BorderRadius);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.antiPanel-application {
|
||||||
|
border-radius: var(--medium-BorderRadius) 0 0 var(--medium-BorderRadius);
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.hamburger-container {
|
.hamburger-container {
|
||||||
|
Loading…
Reference in New Issue
Block a user