Updated Classes layout (#4314)

Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
Alexander Platov 2024-01-08 08:17:02 +03:00 committed by GitHub
parent c75939dcff
commit bf86948959
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 1061 additions and 355 deletions

View File

@ -80,23 +80,6 @@
--theme-clockface-sec-arrow: conic-gradient(at 50% -10px, rgba(255, 0, 0, 0), rgba(255, 0, 0, 0) 49%, #F47758 50%, rgba(255, 0, 0, 0) 51%, rgba(255, 0, 0, 0) 100%);
--theme-clockface-sec-holder: #F47758;
// New
--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 */
@ -325,48 +308,6 @@
--theme-clockface-min-arrow: conic-gradient(at 50% -10px, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0) 49%, #2F2F3A 50%, rgba(0, 0, 0, 0) 51%, rgba(0, 0, 0, 0) 100%);
--theme-clockface-arrows-holder: radial-gradient(at top center, #2F2F3A, #555555);
--theme-clockface-arrows-shadow: 0 0 1px white;
// New
--global-ui-BackgroundColor: #A5BDFF0D;
--global-ui-hover-BackgroundColor: #A5BDFF1A;
--global-ui-highlight-BackgroundColor: #A5BDFF0D;
--global-ui-hover-highlight-BackgroundColor: #A5BDFF26;
--global-surface-01-BackgroundColor: #131925;
--global-surface-01-BorderColor: #1F2737;
--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-secondary-TextColor: #C1C9D6;
--global-tertiary-TextColor: #8E99AF;
--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 */
@ -595,46 +536,4 @@
--theme-clockface-min-arrow: conic-gradient(at 50% -10px, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0) 49%, white 50%, rgba(255, 255, 255, 0) 51%, rgba(255, 255, 255, 0) 100%);
--theme-clockface-arrows-holder: radial-gradient(at top center, #eee, #aaa);
--theme-clockface-arrows-shadow: 0 0 1px black;
// New
--global-ui-BackgroundColor: #1530720D;
--global-ui-hover-BackgroundColor: #1530721A;
--global-ui-highlight-BackgroundColor: #A5BDFF26;
--global-ui-hover-highlight-BackgroundColor: #A5BDFF40;
--global-surface-01-BackgroundColor: #F8F9FA;
--global-surface-01-BorderColor: #DDE1E9;
--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-secondary-TextColor: #5A667E;
--global-tertiary-TextColor: #7B879E;
--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;
}

View File

@ -0,0 +1,137 @@
//
// 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.
//
/* Common Colors */
* {
--global-accent-IconColor: #6796FF;
--global-on-accent-TextColor: #FFFFFF;
--global-focus-inset-BorderColor: #0D121C;
--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 */
.theme-dark {
--global-ui-BackgroundColor: #A5BDFF0D;
--global-ui-hover-BackgroundColor: #A5BDFF1A;
--global-ui-highlight-BackgroundColor: #A5BDFF0D;
--global-ui-hover-highlight-BackgroundColor: #A5BDFF26;
--global-surface-01-BackgroundColor: #131925;
--global-surface-01-BorderColor: #1F2737;
--global-surface-02-BackgroundColor: #19202E;
--global-surface-02-BorderColor: #262F40;
--global-surface-03-hover-BackgroundColor: #19202E;
--global-subtle-ui-BorderColor: #A5BDFF0D;
--global-popover-BackgroundColor: #262F40;
--global-popover-hover-BackgroundColor: #1F2737;
--global-popover-BorderColor: #A5BDFF1A;
--global-primary-LinkColor: #4D7FF5;
--global-primary-TextColor: #FFFFFF;
--global-secondary-TextColor: #C1C9D6;
--global-tertiary-TextColor: #8E99AF;
--global-accent-TextColor: #4D7FF5;
--global-focus-BorderColor: #2A59D6;
/** 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 */
.theme-light {
--global-ui-BackgroundColor: #1530720D;
--global-ui-hover-BackgroundColor: #1530721A;
--global-ui-highlight-BackgroundColor: #A5BDFF26;
--global-ui-hover-highlight-BackgroundColor: #A5BDFF40;
--global-surface-01-BackgroundColor: #F8F9FA;
--global-surface-01-BorderColor: #DDE1E9;
--global-surface-02-BackgroundColor: #19202E;
--global-surface-02-BorderColor: #EBEEF2;
--global-surface-03-hover-BackgroundColor: #F8F9FA;
--global-subtle-ui-BorderColor: #1530720D;
--global-popover-BackgroundColor: #131925;
--global-popover-hover-BackgroundColor: #1F2737;
--global-popover-BorderColor: #A5BDFF26;
--global-primary-LinkColor: #3566E2;
--global-primary-TextColor: #0F121A;
--global-secondary-TextColor: #5A667E;
--global-tertiary-TextColor: #7B879E;
--global-accent-TextColor: #3566E2;
--global-focus-BorderColor: #204DC8;
/** 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;
}

View File

@ -81,6 +81,166 @@
}
}
/* Header */
.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);
}
.hulyHotKey-item {
margin-right: .625rem;
}
}
/* Modal */
.hulyModal-container,
.hulyModal-container .hulyModal-content,
.hulyModal-container .hulyModal-content__titleGroup,
.hulyModal-container .hulyModal-content__settingsSet,
.hulyModal-container .hulyModal-footer {
display: flex;
flex-direction: column;
width: 100%;
min-width: 0;
min-height: 0;
}
.hulyModal-container {
height: 100%;
border-top: 1px solid transparent;
.hulyModal-content {
padding: var(--spacing-2) var(--spacing-1_5) var(--spacing-6);
height: 100%;
&__titleGroup {
flex-shrink: 0;
padding: var(--spacing-2) var(--spacing-0_5) 0;
.hulyChip-item {
margin: 0 0 var(--spacing-0_75) var(--spacing-1_5);
}
}
&__settingsSet {
flex-shrink: 0;
padding: var(--spacing-4) var(--spacing-2_5) 0;
&-line {
display: flex;
justify-content: space-between;
align-items: center;
flex-shrink: 0;
padding: var(--spacing-1_5) 0;
width: 100%;
min-width: 0;
min-height: var(--global-max-Size);
border-bottom: 1px solid var(--global-subtle-ui-BorderColor);
&:first-child {
border-top: 1px solid var(--global-subtle-ui-BorderColor);
}
.label {
text-transform: uppercase;
font-weight: 500;
font-size: .75rem;
font-style: normal;
line-height: 1rem;
color: var(--global-secondary-TextColor);
}
}
}
}
.hulyModal-footer {
flex-direction: row-reverse;
flex-shrink: 0;
gap: var(--spacing-1);
padding: var(--spacing-2) var(--spacing-2_5);
border-top: 1px solid var(--theme-divider-color); // var(--global-surface-01-BorderColor);
}
&.type-aside .hulyHeader-container {
border-radius: 0 var(--small-focus-BorderRadius) 0 0;
.hulyHeader-titleGroup {
text-transform: uppercase;
font-family: var(--font-family);
font-weight: 500;
font-size: .75rem;
font-style: normal;
line-height: 1rem;
color: var(--global-secondary-TextColor);
}
.hulyHeader-buttonsGroup {
gap: var(--spacing-0_5);
}
}
}
.hulyChip-item {
padding: var(--spacing-0_25) var(--spacing-0_5);
width: fit-content;
text-transform: uppercase;
color: var(--global-tertiary-TextColor);
background-color: var(--global-ui-BackgroundColor);
border-radius: var(--extra-small-BorderRadius);
}
.hulyHotKey-item {
display: flex;
justify-content: center;
align-items: center;
padding: var(--spacing-0_25) var(--spacing-0_5);
height: var(--global-min-Size);
min-width: var(--global-min-Size);
text-align: center;
font-family: var(--font-family);
font-weight: 400;
font-size: .625rem;
font-style: normal;
line-height: normal;
color: var(--global-primary-TextColor);
background: var(--button-secondary-hover-BackgroundColor);
border-radius: var(--extra-small-BorderRadius);
}
/* Component */
.antiComponent {
display: flex;

View File

@ -15,6 +15,7 @@
@import "./_vars.scss";
@import "./_colors.scss";
@import "./_lumia-colors.scss";
@import "./_layouts.scss";
@import "./common.scss";
@import "./button.scss";

View File

@ -14,22 +14,25 @@
-->
<script lang="ts">
import { createEventDispatcher } from 'svelte'
import { IconMaximize, IconMinimize } from '..'
import { IconMaximize, IconMinimize, IconClose, ButtonIcon } from '..'
export let type: 'type-aside' | 'type-component' = 'type-component'
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" />
{#if type === 'type-component'}
<button class="hulyHeader-button" on:click={() => dispatch('resize', minimize)}>
{#if minimize}
<IconMinimize size={'small'} />
{:else}
<IconMaximize size={'small'} />
{/if}
</button>
<div class="hulyHeader-divider" />
{/if}
<div class="hulyHeader-titleGroup">
<slot />
</div>
@ -38,52 +41,9 @@
<slot name="actions" />
</div>
{/if}
{#if type === 'type-aside'}
<div class="hulyHeader-divider" />
<div class="hulyHotKey-item">Esc</div>
<ButtonIcon icon={IconClose} kind={'tertiary'} size={'small'} on:click={() => dispatch('close')} />
{/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>

View File

@ -0,0 +1,74 @@
<!--
// 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 { IntlString } from '@hcengineering/platform'
import Header from './Header.svelte'
import Label from './Label.svelte'
import ButtonIcon from './ButtonIcon.svelte'
import ButtonBase from './ButtonBase.svelte'
import Scroller from './Scroller.svelte'
import IconDelete from './icons/Delete.svelte'
import IconCopy from './icons/Copy.svelte'
import ui from '..'
export let type: 'type-aside' | 'type-component'
export let label: IntlString
export let labelProps: any | undefined = undefined
export let okAction: () => Promise<void> | void
export let onCancel: (() => void) | undefined = undefined
export let canSave: boolean = false
export let okLabel: IntlString = ui.string.Ok
const dispatch = createEventDispatcher()
function close (): void {
if (onCancel) onCancel()
else dispatch('close')
}
function onKeyDown (ev: KeyboardEvent) {
if (ev.key === 'Escape') close()
}
</script>
<svelte:window on:keydown={onKeyDown} />
<div class="hulyModal-container {type}">
<Header {type} on:close={close}>
<Label {label} params={labelProps} />
<svelte:fragment slot="actions">
<ButtonIcon icon={IconDelete} size={'small'} kind={'tertiary'} />
<ButtonIcon icon={IconCopy} size={'small'} kind={'tertiary'} />
</svelte:fragment>
</Header>
<div class="hulyModal-content">
<Scroller>
<slot />
</Scroller>
</div>
{#if type === 'type-aside'}
<div class="hulyModal-footer">
<ButtonBase
type={'type-button'}
kind={'primary'}
size={'large'}
label={okLabel}
on:click={okAction}
disabled={!canSave}
/>
<ButtonBase type={'type-button'} kind={'secondary'} size={'large'} label={ui.string.Cancel} on:click={onCancel} />
</div>
{/if}
</div>

View File

@ -13,7 +13,11 @@
// limitations under the License.
-->
<script lang="ts">
export let label: string
import { IntlString, translate } from '@hcengineering/platform'
import Label from './Label.svelte'
import { themeStore } from '..'
export let label: IntlString
export let value: string | undefined = undefined
export let kind: 'default' | 'ghost' = 'default'
export let size: 'small' | 'large' = 'small'
@ -22,9 +26,14 @@
export let password: boolean = false
export let limit: number = 0
$: labeled = kind === 'default' && size === 'large'
$: placeholder = labeled ? ' ' : label
$: maxlength = limit === 0 ? null : limit
let placeholderStr: string = ''
$: ph = translate(label, {}, $themeStore.language).then((r) => {
placeholderStr = r
})
$: labeled = kind === 'default' && size === 'large'
$: placeholder = labeled ? ' ' : placeholderStr
</script>
<label class="editbox-wrapper {kind} {size}" class:error class:disabled>
@ -61,7 +70,7 @@
on:input
/>
{/if}
{#if labeled}<div class="font-regular-14 label">{label}</div>{/if}
{#if labeled}<div class="font-regular-14 label"><Label {label} /></div>{/if}
</label>
<style lang="scss">

View File

@ -0,0 +1,170 @@
<!--
// 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 IconSearch from './icons/Search.svelte'
import IconClose from './icons/Close.svelte'
export let value: string | undefined = undefined
export let placeholder: string
export let collapsed: boolean = false
let input: HTMLInputElement
</script>
<label class="searchInput-wrapper" class:collapsed class:filled={value && value !== ''}>
<div class="searchInput-icon">
<div><IconSearch size={'small'} /></div>
</div>
<input
bind:this={input}
type="text"
class="font-regular-14"
bind:value
{placeholder}
autocomplete="off"
spellcheck="false"
on:change
on:input
/>
<button
class="searchInput-button"
on:click={() => {
value = ''
input.focus()
}}
>
<div><IconClose size={'small'} /></div>
</button>
</label>
<style lang="scss">
.searchInput-wrapper {
display: flex;
justify-content: stretch;
align-items: center;
align-self: stretch;
padding: 0 var(--spacing-0_5) 0 0;
height: var(--spacing-4);
min-width: var(--spacing-4);
background-color: var(--input-BackgroundColor);
border-radius: var(--small-BorderRadius);
box-shadow: inset 0 0 0 1px var(--input-BorderColor);
transition: max-width 0.2s;
cursor: text;
.searchInput-icon,
.searchInput-button {
display: flex;
justify-content: center;
align-items: center;
flex-shrink: 0;
padding: 0;
background-color: transparent;
border: none;
div {
width: var(--spacing-2);
height: var(--spacing-2);
}
}
.searchInput-icon {
margin: 0 var(--spacing-0_5) 0 0;
width: var(--spacing-4);
height: var(--spacing-4);
fill: var(--input-search-IconColor);
border-radius: var(--small-BorderRadius);
outline: none;
cursor: text;
&:active,
&:focus {
background-color: transparent;
}
}
.searchInput-button {
visibility: hidden;
width: var(--spacing-3);
height: var(--spacing-3);
fill: var(--global-primary-TextColor);
border-radius: var(--extra-small-BorderRadius);
cursor: pointer;
&:hover {
background-color: var(--button-tertiary-hover-BackgroundColor);
}
&:active {
background-color: var(--button-tertiary-active-BackgroundColor);
border-color: var(--button-menu-active-BorderColor);
}
&:focus {
outline: 2px solid var(--global-focus-BorderColor);
outline-offset: 2px;
}
}
input {
margin: 0;
margin-right: var(--spacing-1_5);
padding: 0;
width: 100%;
height: 100%;
color: var(--input-TextColor);
caret-color: var(--global-focus-BorderColor);
background-color: transparent;
border: none;
outline: none;
appearance: none;
&::placeholder {
color: var(--input-PlaceholderColor);
}
&:not(:placeholder-shown) + .searchInput-button {
visibility: visible;
}
}
&:hover {
background-color: var(--input-hover-BackgroundColor);
input::placeholder {
color: var(--input-hover-PlaceholderColor);
}
}
&:active,
&:focus-within {
padding: 0 var(--spacing-0_5) 0 0;
max-width: 100%;
background-color: var(--input-BackgroundColor);
outline: 2px solid var(--global-focus-BorderColor);
outline-offset: 2px;
input::placeholder {
color: var(--input-focus-PlaceholderColor);
}
}
&.collapsed:not(:focus-within, :active, .filled) {
padding: 0;
max-width: var(--spacing-4);
.searchInput-icon {
cursor: pointer;
}
input:not(:placeholder-shown) + .searchInput-button {
visibility: hidden;
}
}
}
</style>

View File

@ -3,8 +3,8 @@
export let fill: string = 'currentColor'
</script>
<svg class="svg-{size}" {fill} viewBox="0 0 32 32" 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
d="M6.29289 6.29338C5.90237 6.68391 5.90237 7.31707 6.29289 7.70759L14.5858 16.0005L6.29289 24.2934C5.90237 24.6839 5.90237 25.3171 6.29289 25.7076C6.68342 26.0981 7.31658 26.0981 7.70711 25.7076L16 17.4147L24.2929 25.7076C24.6834 26.0981 25.3166 26.0981 25.7071 25.7076C26.0976 25.3171 26.0976 24.6839 25.7071 24.2934L17.4142 16.0005L25.7071 7.70759C26.0976 7.31707 26.0976 6.68391 25.7071 6.29338C25.3166 5.90286 24.6834 5.90286 24.2929 6.29338L16 14.5863L7.70711 6.29338C7.31658 5.90286 6.68342 5.90286 6.29289 6.29338Z"
d="M3.14645 3.14645C2.95118 3.34171 2.95118 3.65829 3.14645 3.85355L7.29289 8L3.14645 12.1464C2.95118 12.3417 2.95118 12.6583 3.14645 12.8536C3.34171 13.0488 3.65829 13.0488 3.85355 12.8536L8 8.70711L12.1464 12.8536C12.3417 13.0488 12.6583 13.0488 12.8536 12.8536C13.0488 12.6583 13.0488 12.3417 12.8536 12.1464L8.70711 8L12.8536 3.85355C13.0488 3.65829 13.0488 3.34171 12.8536 3.14645C12.6583 2.95118 12.3417 2.95118 12.1464 3.14645L8 7.29289L3.85355 3.14645C3.65829 2.95118 3.34171 2.95118 3.14645 3.14645Z"
/>
</svg>

View File

@ -131,6 +131,7 @@ 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 Modal } from './components/Modal.svelte'
export { default as IconAdd } from './components/icons/Add.svelte'
export { default as IconCircleAdd } from './components/icons/CircleAdd.svelte'

View File

@ -160,7 +160,8 @@ export const workbenchSeparators: DefSeparators = [
export const settingsSeparators: DefSeparators = [
{ minSize: 12.5, size: 17.5, maxSize: 22.5, float: 'navigator' },
null
null,
{ minSize: 17, size: 30, maxSize: 32, float: 'aside' }
]
export const separatorsStore = writable<string[]>([])

View File

@ -42,13 +42,16 @@
Menu,
getEventPositionElement,
showPopup,
IconSettings
IconSettings,
IconOpenedArrow
} 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'
import { settingsStore, clearSettingsStore } from '../store'
import TypesPopup from './typeEditors/TypesPopup.svelte'
export let _class: Ref<Class<Doc>>
export let ofClass: Ref<Class<Doc>> | undefined = undefined
@ -70,6 +73,8 @@
let clazz: Class<Doc> | undefined
let hovered: number | null = null
let selected: number | null = null
let btnAdd: ButtonIcon
$: classQuery.query(core.class.Class, { _id: _class }, (res) => {
clazz = res.shift()
@ -96,8 +101,11 @@
attributes = getCustomAttributes(_class)
}
export function createAttribute (): void {
showPopup(CreateAttribute, { _class }, 'top', update)
export function createAttribute (ev: MouseEvent): void {
showPopup(TypesPopup, { _class }, getEventPositionElement(ev), (_id) => {
if (_id !== undefined) $settingsStore = { component: CreateAttribute, props: { _id, _class } }
})
// showPopup(CreateAttribute, { _class }, 'top', update)
}
export async function editAttribute (attribute: AnyAttribute, exist: boolean): Promise<void> {
@ -130,7 +138,7 @@
label: presentation.string.Edit,
icon: IconEdit,
action: async () => {
await editAttribute(attribute, exist)
await selectAttribute(attribute, row)
}
}
]
@ -180,6 +188,23 @@
function editLabel (evt: MouseEvent): void {
showPopup(EditClassLabel, { clazz }, getEventPositionElement(evt))
}
async function selectAttribute (attribute: AnyAttribute, n: number): Promise<void> {
if (selected === n) {
selected = null
clearSettingsStore()
return
}
selected = n
const exist = (await client.findOne(attribute.attributeOf, { [attribute.name]: { $exists: true } })) !== undefined
$settingsStore = { component: EditAttribute, props: { attribute, exist } }
}
settingsStore.subscribe((value) => {
if (value.component == null) selected = null
})
const classUpdated = (_clazz: Ref<Class<Doc>>): void => {
selected = null
}
$: classUpdated(_class)
</script>
{#if showTitle}
@ -200,28 +225,41 @@
<div class="hulyTableAttr-header font-medium-12">
<IconSettings size={'small'} />
<span><Label label={settings.string.ClassProperties} /></span>
<ButtonIcon kind={'primary'} icon={IconAdd} size={'small'} on:click={createAttribute} />
<ButtonIcon
bind:this={btnAdd}
kind={'primary'}
icon={IconAdd}
size={'small'}
on:click={(ev) => {
createAttribute(ev)
}}
/>
</div>
{#if attributes.length}
<div class="hulyTableAttr-content">
{#each attributes as attr, i}
{@const attrType = getAttrType(attr.type)}
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
class="hulyTableAttr-content__row"
class:hovered={hovered === i}
class:selected={selected === i}
on:contextmenu={(ev) => {
ev.preventDefault()
void showMenu(ev, attr, i)
}}
on:click={async () => {
void selectAttribute(attr, i)
}}
>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div class="hulyTableAttr-content__row-dragMenu" on:click={(ev) => showMenu(ev, attr, i)}>
<div class="hulyTableAttr-content__row-dragMenu" on:click|stopPropagation={(ev) => showMenu(ev, attr, i)}>
<IconMoreV2 size={'small'} />
</div>
{#if attr.isCustom}
<div class="hulyTableAttr-content__row-chip font-medium-12">
<div class="hulyChip-item font-medium-12">
<Label label={settings.string.Custom} />
</div>
{/if}
@ -249,6 +287,9 @@
{/await}
{/if}
</div>
<div class="hulyTableAttr-content__row-arrow">
<IconOpenedArrow size={'small'} />
</div>
</div>
{/each}
</div>
@ -307,11 +348,6 @@
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;
@ -321,13 +357,6 @@
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);
@ -352,6 +381,38 @@
text-transform: uppercase;
color: var(--global-secondary-TextColor);
}
&-arrow {
display: none;
flex-shrink: 0;
width: var(--global-min-Size);
height: var(--global-min-Size);
color: var(--global-primary-LinkColor);
}
&.hovered,
&:hover {
background-color: var(--theme-table-header-color); // var(--global-surface-03-hover-BackgroundColor);
}
&.selected {
background-color: var(--theme-table-header-color); // var(--global-surface-03-hover-BackgroundColor);
.hulyTableAttr-content__row-icon,
.hulyTableAttr-content__row-arrow,
.hulyTableAttr-content__row-label {
color: var(--global-primary-LinkColor);
}
.hulyTableAttr-content__row-type {
color: var(--global-primary-TextColor);
}
.hulyTableAttr-content__row-label {
font-weight: 700;
}
}
&.hovered .hulyTableAttr-content__row-arrow,
&:hover .hulyTableAttr-content__row-arrow,
&.selected .hulyTableAttr-content__row-arrow {
display: block;
}
}
}
}

View File

@ -36,6 +36,7 @@
import { filterDescendants } from '../utils'
import ClassAttributes from './ClassAttributes.svelte'
import ClassHierarchy from './ClassHierarchy.svelte'
import { clearSettingsStore } from '../store'
export let ofClass: Ref<Class<Obj>> | undefined = undefined
export let attributeMapper:
@ -125,6 +126,7 @@
{ofClass}
on:select={(e) => {
_class = e.detail
clearSettingsStore()
}}
/>
</NavGroup>

View File

@ -25,14 +25,16 @@
Type
} from '@hcengineering/core'
import { getEmbeddedLabel } from '@hcengineering/platform'
import { Card, getClient } from '@hcengineering/presentation'
import { AnyComponent, Component, DropdownLabelsIntl, EditBox, Label } from '@hcengineering/ui'
import presentation, { getClient } from '@hcengineering/presentation'
import { AnyComponent, Component, DropdownLabelsIntl, ModernEditbox, Label, Modal } from '@hcengineering/ui'
import { DropdownIntlItem } from '@hcengineering/ui/src/types'
import { createEventDispatcher } from 'svelte'
import setting from '../plugin'
import view from '@hcengineering/view'
import { clearSettingsStore } from '../store'
export let _id: Ref<Class<Type<PropertyType>>> | undefined = undefined
export let _class: Ref<Class<Doc>>
let name: string
let type: Type<PropertyType> | undefined
let index: IndexKind | undefined
@ -40,7 +42,6 @@
let is: AnyComponent | undefined
const client = getClient()
const hierarchy = client.getHierarchy()
const dispatch = createEventDispatcher()
async function save (): Promise<void> {
if (type === undefined) return
@ -57,7 +58,7 @@
data.index = index
}
await client.createDoc(core.class.Attribute, core.space.Model, data)
dispatch('close')
clearSettingsStore()
}
function getTypes (): DropdownIntlItem[] {
@ -95,44 +96,49 @@
index = e.detail?.index
defaultValue = e.detail?.defaultValue
}
$: clazz = client.getHierarchy().getClass(_class)
</script>
<Card
<Modal
label={setting.string.CreatingAttribute}
type={'type-aside'}
okLabel={presentation.string.Create}
okAction={save}
canSave={!(type === undefined || name === undefined || name.trim().length === 0)}
on:close={() => {
dispatch('close')
onCancel={() => {
clearSettingsStore()
}}
on:changeContent
>
<svelte:fragment slot="title">
<div class="flex-row-center">
<Label label={setting.string.CreatingAttribute} />
<div class="p-1">></div>
<Label label={clazz.label} />
<div class="hulyModal-content__titleGroup">
<div class="hulyChip-item font-medium-12">
<Label label={setting.string.Custom} />
</div>
</svelte:fragment>
<div class="mb-2"><EditBox bind:value={name} placeholder={core.string.Name} /></div>
<div class="flex-col mb-2">
<div class="flex-row-center flex-grow">
<Label label={setting.string.Type} />
<div class="ml-4">
<DropdownLabelsIntl
label={setting.string.Type}
{items}
width="8rem"
bind:selected={selectedType}
on:selected={handleSelection}
/>
</div>
<ModernEditbox bind:value={name} label={core.string.Name} size={'large'} kind={'ghost'} />
</div>
<div class="hulyModal-content__settingsSet">
<div class="hulyModal-content__settingsSet-line">
<span class="label">
<Label label={setting.string.Type} />
</span>
<DropdownLabelsIntl
label={setting.string.Type}
{items}
size={'large'}
width="8rem"
bind:selected={selectedType}
on:selected={handleSelection}
/>
</div>
{#if is}
<div class="flex mt-4">
<Component {is} on:change={handleChange} />
</div>
<Component
{is}
props={{
type,
defaultValue,
kind: 'regular',
size: 'large'
}}
on:change={handleChange}
/>
{/if}
</div>
</Card>
</Modal>

View File

@ -15,19 +15,20 @@
<script lang="ts">
import core, { AnyAttribute, Class, DocumentUpdate, IndexKind, PropertyType, Ref, Type } from '@hcengineering/core'
import { getEmbeddedLabel, translate } from '@hcengineering/platform'
import presentation, { Card, getClient } from '@hcengineering/presentation'
import presentation, { getClient } from '@hcengineering/presentation'
import setting from '../plugin'
import {
AnyComponent,
Component,
DropdownIntlItem,
DropdownLabelsIntl,
EditBox,
ModernEditbox,
Label,
themeStore
themeStore,
Modal
} from '@hcengineering/ui'
import view from '@hcengineering/view-resources/src/plugin'
import { createEventDispatcher } from 'svelte'
import { clearSettingsStore } from '../store'
export let attribute: AnyAttribute
export let exist: boolean
@ -39,7 +40,6 @@
const client = getClient()
const hierarchy = client.getHierarchy()
const dispatch = createEventDispatcher()
translate(attribute.label, {}, $themeStore.language).then((p) => (name = p))
@ -61,7 +61,7 @@
}
}
await client.updateDoc(attribute._class, attribute.space, attribute._id, update)
dispatch('close')
clearSettingsStore()
}
function getTypes (): DropdownIntlItem[] {
@ -101,46 +101,54 @@
}
</script>
<Card
<Modal
label={setting.string.EditAttribute}
type={'type-aside'}
okLabel={presentation.string.Save}
okAction={save}
canSave={!(name === undefined || name.trim().length === 0)}
on:close={() => {
dispatch('close')
onCancel={() => {
clearSettingsStore()
}}
on:changeContent
>
<div class="mb-2"><EditBox bind:value={name} placeholder={core.string.Name} /></div>
<div class="flex-col mb-2">
<div class="flex-row-center flex-grow">
<Label label={setting.string.Type} />
<div class="ml-4">
{#if exist}
<Label label={attribute.type.label} />
{:else}
<DropdownLabelsIntl
label={setting.string.Type}
{items}
width="8rem"
bind:selected={selectedType}
on:selected={handleSelect}
/>
{/if}
</div>
</div>
{#if is}
<div class="flex mt-4">
<Component
{is}
props={{
type,
defaultValue,
editable: !exist
}}
on:change={handleChange}
/>
<div class="hulyModal-content__titleGroup">
{#if attribute.isCustom}
<div class="hulyChip-item font-medium-12">
<Label label={setting.string.Custom} />
</div>
{/if}
<ModernEditbox bind:value={name} label={core.string.Name} size={'large'} kind={'ghost'} />
</div>
</Card>
<div class="hulyModal-content__settingsSet">
<div class="hulyModal-content__settingsSet-line">
<span class="label">
<Label label={setting.string.Type} />
</span>
{#if exist}
<Label label={attribute.type.label} />
{:else}
<DropdownLabelsIntl
label={setting.string.Type}
{items}
size={'large'}
width="8rem"
bind:selected={selectedType}
on:selected={handleSelect}
/>
{/if}
</div>
{#if is}
<Component
{is}
props={{
type,
defaultValue,
editable: !exist,
kind: 'regular',
size: 'large'
}}
on:change={handleChange}
/>
{/if}
</div>
</Modal>

View File

@ -36,7 +36,8 @@
NavGroup
} from '@hcengineering/ui'
import { NavFooter } from '@hcengineering/workbench-resources'
import { onDestroy } from 'svelte'
import { ComponentType, onDestroy } from 'svelte'
import { settingsStore, clearSettingsStore, type SettingsStore } from '../store'
export let visibleNav: boolean = true
export let navFloat: boolean = false
@ -47,6 +48,8 @@
let categories: SettingsCategory[] = []
const account = getCurrentAccount() as PersonAccount
let asideComponent: ComponentType | null = null
let asideProps: object | null = null
const settingsQuery = createQuery()
settingsQuery.query(
@ -72,6 +75,7 @@
return categories.find((x) => x.name === name)
}
function selectCategory (id: string): void {
clearSettingsStore()
const loc = getCurrentResolvedLocation()
if (loc.path[3] === id) {
loc.path.length = 3
@ -102,6 +106,12 @@
showPopup(login.component.InviteLink, {})
}
const updatedStore = (ss: SettingsStore): ComponentType | null => {
asideProps = ss.props ?? null
return ss.component ?? null
}
$: asideComponent = updatedStore($settingsStore)
defineSeparators('setting', settingsSeparators)
</script>
@ -165,7 +175,7 @@
<Separator name={'setting'} float={navFloat} index={0} color={'transparent'} />
{/if}
<div class="antiPanel-component filledNav">
<div class="antiPanel-component filledNav" style:flex-direction={'row'}>
{#if category}
<Component
is={category.component}
@ -177,15 +187,25 @@
/>
{/if}
</div>
{#if asideComponent != null}
<Separator name={'setting'} index={1} color={'transparent'} />
<div class="hulySidePanel-container">
{#key asideProps}
<svelte:component this={asideComponent} {...asideProps} />
{/key}
</div>
{/if}
</div>
<style lang="scss">
.hulyPanels-container {
display: flex;
width: 100%;
height: 100%;
min-width: 0;
min-height: 0;
background-color: var(--theme-navpanel-color); // var(--global-surface-01-BackgroundColor);
border-radius: 0 var(--small-focus-BorderRadius) var(--small-focus-BorderRadius) 0;
// .antiPanel-navigator {
// background-color: transparent;
@ -208,4 +228,13 @@
line-height: 1.5rem;
color: var(--global-primary-TextColor);
}
.hulySidePanel-container {
display: flex;
flex-direction: column;
width: 10rem;
height: 100%;
min-width: 0;
min-height: 0;
border-radius: 0 var(--small-focus-BorderRadius) var(--small-focus-BorderRadius) 0;
}
</style>

View File

@ -26,6 +26,7 @@
NavItem
} from '@hcengineering/ui'
import { onDestroy } from 'svelte'
import { clearSettingsStore } from '../store'
export let kind: 'navigation' | 'content' | undefined
export let categoryName: string
@ -62,6 +63,7 @@
)
function selectCategory (id: string): void {
clearSettingsStore()
const loc = getCurrentResolvedLocation()
loc.path[3] = categoryName
if (loc.path[4] === id) {

View File

@ -20,9 +20,12 @@
import view from '@hcengineering/view'
import { createEventDispatcher } from 'svelte'
import setting from '../../plugin'
import type { ButtonKind, ButtonSize } from '@hcengineering/ui'
export let type: ArrOf<Doc> | undefined
export let editable: boolean = true
export let kind: ButtonKind = 'regular'
export let size: ButtonSize = 'medium'
const dispatch = createEventDispatcher()
const client = getClient()
@ -56,34 +59,34 @@
}
</script>
<div class="flex-col">
<div class="flex-row-center flex-grow">
<div class="hulyModal-content__settingsSet-line">
<span class="label">
<Label label={setting.string.Type} />
<div class="ml-4">
{#if editable}
<DropdownLabelsIntl
label={core.string.Class}
items={types.map((p) => {
return { id: p._id, label: p.label }
})}
width="8rem"
bind:selected={refClass}
/>
{:else if selected}
<Label label={selected.label} />
{/if}
</div>
</div>
{#if selected}
<div class="flex mt-4">
<Component
is={getComponent(selected)}
props={{
type: type?.of,
editable
}}
on:change={handleChange}
/>
</div>
</span>
{#if editable}
<DropdownLabelsIntl
label={core.string.Class}
{kind}
{size}
items={types.map((p) => {
return { id: p._id, label: p.label }
})}
width="8rem"
bind:selected={refClass}
/>
{:else if selected}
<Label label={selected.label} />
{/if}
</div>
{#if selected}
<Component
is={getComponent(selected)}
props={{
type: type?.of,
editable,
kind,
size
}}
on:change={handleChange}
/>
{/if}

View File

@ -19,9 +19,12 @@
import { DropdownLabelsIntl, Label, DropdownIntlItem } from '@hcengineering/ui'
import { createEventDispatcher, onMount } from 'svelte'
import setting from '../../plugin'
import type { ButtonKind, ButtonSize } from '@hcengineering/ui'
export let type: DateType | undefined
export let editable: boolean = true
export let kind: ButtonKind = 'regular'
export let size: ButtonSize = 'medium'
const dispatch = createEventDispatcher()
const items: DropdownIntlItem[] = [
@ -49,22 +52,23 @@
})
</script>
<div class="flex-row-center">
<Label label={setting.string.DateMode} />
<div class="ml-2">
{#if editable}
<DropdownLabelsIntl
{selected}
{items}
size="medium"
label={setting.string.DateMode}
on:selected={(res) => {
selected = res.detail
dispatch('change', { type: TypeDate(res.detail._id) })
}}
/>
{:else}
<Label {label} />
{/if}
</div>
<div class="hulyModal-content__settingsSet-line">
<span class="label">
<Label label={setting.string.DateMode} />
</span>
{#if editable}
<DropdownLabelsIntl
{selected}
{items}
{kind}
{size}
label={setting.string.DateMode}
on:selected={(res) => {
selected = res.detail
dispatch('change', { type: TypeDate(res.detail._id) })
}}
/>
{:else}
<Label {label} />
{/if}
</div>

View File

@ -23,8 +23,8 @@
getFocusManager,
TooltipAlignment
} from '@hcengineering/ui'
import type { ButtonKind, ButtonSize } from '@hcengineering/ui'
import EnumPopup from './EnumPopup.svelte'
import core, { Ref, Class, DocumentQuery, Enum } from '@hcengineering/core'
import { ObjectCreate } from '@hcengineering/presentation'
@ -34,6 +34,8 @@
export let focus = false
export let create: ObjectCreate | undefined = undefined
export let labelDirection: TooltipAlignment | undefined = undefined
export let kind: ButtonKind = 'no-border'
export let size: ButtonSize = 'small'
const _class: Ref<Class<Enum>> = core.class.Enum
const query: DocumentQuery<Enum> = {}
@ -66,8 +68,8 @@
{focus}
{focusIndex}
icon={IconFolder}
size={'small'}
kind={'no-border'}
{size}
{kind}
showTooltip={{ label, direction: labelDirection }}
on:click={handleClick}
>

View File

@ -17,6 +17,7 @@
import { TypeEnum } from '@hcengineering/model'
import presentation, { getClient } from '@hcengineering/presentation'
import { Button, Label, showPopup } from '@hcengineering/ui'
import type { ButtonKind, ButtonSize } from '@hcengineering/ui'
import { EnumEditor } from '@hcengineering/view-resources'
import { createEventDispatcher } from 'svelte'
import setting from '../../plugin'
@ -26,6 +27,8 @@
export let editable: boolean = true
export let value: Enum | undefined
export let defaultValue: string | undefined
export let kind: ButtonKind = 'no-border'
export let size: ButtonSize = 'small'
const client = getClient()
const dispatch = createEventDispatcher()
@ -55,45 +58,45 @@
}
</script>
<div>
<div class="flex-row-center flex-grow">
<div class="hulyModal-content__settingsSet-line">
<span class="label">
<Label label={core.string.Enum} />
<div class="ml-4">
{#if editable}
<EnumSelect label={core.string.Enum} bind:value {create} />
{:else if value}
{value.name}
{/if}
</div>
</span>
<div class="flex-row-center gap-2">
{#if editable}
<EnumSelect label={core.string.Enum} bind:value {create} {kind} {size} />
{:else if value}
{value.name}
{/if}
{#if value}
<div class="ml-2">
<Button
icon={setting.icon.Setting}
kind={'no-border'}
size={'small'}
showTooltip={{ label: presentation.string.Edit }}
on:click={edit}
/>
</div>
<Button
icon={setting.icon.Setting}
{kind}
{size}
showTooltip={{ label: presentation.string.Edit }}
on:click={edit}
/>
{/if}
</div>
{#if value && type}
<div class="flex-row-center mt-2">
<Label label={setting.string.DefaultValue} />
<div class="ml-2">
<EnumEditor
label={setting.string.SelectAValue}
kind={'no-border'}
size={'small'}
allowDeselect
{type}
value={defaultValue ?? ''}
onChange={(e) => {
defaultValue = e
dispatch('change', { type, defaultValue })
}}
/>
</div>
</div>
{/if}
</div>
{#if value && type}
<div class="hulyModal-content__settingsSet-line">
<span class="label">
<Label label={setting.string.DefaultValue} />
</span>
<div class="ml-2">
<EnumEditor
label={setting.string.SelectAValue}
{kind}
{size}
allowDeselect
{type}
value={defaultValue ?? ''}
onChange={(e) => {
defaultValue = e
dispatch('change', { type, defaultValue })
}}
/>
</div>
</div>
{/if}

View File

@ -19,9 +19,12 @@
import { DropdownLabelsIntl, Label } from '@hcengineering/ui'
import view from '@hcengineering/view-resources/src/plugin'
import { createEventDispatcher } from 'svelte'
import type { ButtonKind, ButtonSize } from '@hcengineering/ui'
export let type: RefTo<Doc> | undefined
export let editable: boolean = true
export let kind: ButtonKind = 'regular'
export let size: ButtonSize = 'medium'
const dispatch = createEventDispatcher()
const client = getClient()
@ -48,13 +51,13 @@
$: refClass && dispatch('change', { type: TypeRef(refClass) })
</script>
<div class="flex-row-center flex-grow">
<Label label={core.string.Class} />
<div class="ml-4">
{#if editable}
<DropdownLabelsIntl label={core.string.Class} items={classes} width="8rem" bind:selected={refClass} />
{:else if selected}
<Label label={selected.label} />
{/if}
</div>
<div class="hulyModal-content__settingsSet-line">
<span class="label">
<Label label={core.string.Class} />
</span>
{#if editable}
<DropdownLabelsIntl label={core.string.Class} items={classes} width="8rem" bind:selected={refClass} {kind} {size} />
{:else if selected}
<Label label={selected.label} />
{/if}
</div>

View File

@ -0,0 +1,131 @@
<!--
// 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 from '@hcengineering/core'
import { getClient } from '@hcengineering/presentation'
import { Label } from '@hcengineering/ui'
import { DropdownIntlItem } from '@hcengineering/ui/src/types'
import { createEventDispatcher } from 'svelte'
import view from '@hcengineering/view'
const dispatch = createEventDispatcher()
const client = getClient()
const hierarchy = client.getHierarchy()
function getTypes (): DropdownIntlItem[] {
const descendants = hierarchy.getDescendants(core.class.Type)
const res: DropdownIntlItem[] = []
for (const descendant of descendants) {
const _class = hierarchy.getClass(descendant)
if (_class.label !== undefined && hierarchy.hasMixin(_class, view.mixin.ObjectEditor)) {
res.push({
label: _class.label,
id: _class._id
})
}
}
return res
}
const items = getTypes()
const handleSelection = (id: string | number) => {
dispatch('close', id)
}
</script>
<div class="hulyPopupMenu-container">
<div class="hulyPopupMenu-group">
{#each items as item}
<button
class="hulyPopupMenu-group__item"
on:click={() => {
handleSelection(item.id)
}}
>
<span class="hulyPopupMenu-group__item-label overflow-label">
<Label label={item.label} />
</span>
</button>
{/each}
</div>
</div>
<style lang="scss">
.hulyPopupMenu-container {
display: flex;
align-items: flex-start;
flex-shrink: 0;
width: 15rem;
min-width: 0;
min-height: 0;
background-color: var(--global-popover-BackgroundColor);
border: 1px solid var(--global-popover-BorderColor);
border-radius: var(--medium-BorderRadius);
.hulyPopupMenu-group {
display: flex;
flex: 1 0 0;
flex-direction: column;
justify-content: stretch;
align-items: flex-start;
align-self: stretch;
gap: var(--spacing-0_25);
padding: var(--spacing-0_5);
&__item {
box-sizing: border-box;
display: flex;
justify-content: space-between;
align-items: center;
flex-grow: 1;
margin: 0;
width: 100%;
border: 2px solid transparent;
border-radius: var(--extra-small-focus-BorderRadius);
outline: 2px solid transparent;
&.submenu {
padding: var(--spacing-1_5) var(--spacing-1_5) var(--spacing-1_5) var(--spacing-2);
}
&:not(.submenu) {
padding: var(--spacing-1_5) var(--spacing-2);
}
&-icon {
flex-shrink: 0;
width: var(--global-min-Size);
height: var(--global-min-Size);
color: var(--global-on-accent-TextColor);
}
&-label {
flex-grow: 1;
text-align: left;
color: var(--global-on-accent-TextColor);
}
&:hover {
background-color: var(--global-popover-hover-BackgroundColor);
}
&:focus {
background-color: var(--global-popover-hover-BackgroundColor);
border-color: var(--global-focus-inset-BorderColor);
outline-color: var(--global-focus-BorderColor);
}
}
}
}
</style>

View File

@ -50,6 +50,7 @@ import ClassAttributes from './components/ClassAttributes.svelte'
import ClassAttributesList from './components/ClassAttributesList.svelte'
export { ClassSetting, filterDescendants, ClassAttributes, ClassAttributesList }
export * from './store'
async function DeleteMixin (object: Mixin<Class<Doc>>): Promise<void> {
const docs = await getClient().findAll(object._id, {}, { limit: 1 })

View File

@ -0,0 +1,37 @@
//
// 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.
//
import { type ComponentType } from 'svelte'
import { writable } from 'svelte/store'
/**
* @public
*/
export interface SettingsStore {
component?: ComponentType | null
props?: object | null
}
/**
* @public
*/
export const settingsStore = writable<SettingsStore>({})
/**
* @public
*/
export const clearSettingsStore = (): void => {
settingsStore.set({ component: null, props: null })
}

View File

@ -22,6 +22,7 @@
import { onDestroy } from 'svelte'
import Types from './Types.svelte'
import { Resource } from '@hcengineering/platform'
import { clearSettingsStore } from '@hcengineering/setting-resources'
export let kind: 'navigation' | 'tools' | undefined
export let categoryName: string
@ -37,6 +38,7 @@
)
function selectProjectType (id: string): void {
clearSettingsStore()
const loc = getCurrentResolvedLocation()
loc.path[3] = categoryName
loc.path[4] = id