mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-23 03:22:19 +03:00
Merge branch 'main' into storybook-7-infrastructure
Signed-off-by: Oleg Markelov <markelolegov@gmail.com>
This commit is contained in:
commit
babd91c87a
File diff suppressed because it is too large
Load Diff
@ -529,7 +529,7 @@ export function createModel (builder: Builder): void {
|
||||
{
|
||||
key: '',
|
||||
presenter: tracker.component.IssuePresenter,
|
||||
props: { type: 'issue', listProps: { fixed: 'left' } }
|
||||
props: { type: 'issue', listProps: { key: 'issue', fixed: 'left' } }
|
||||
},
|
||||
{
|
||||
key: '',
|
||||
@ -544,7 +544,11 @@ export function createModel (builder: Builder): void {
|
||||
presenter: tags.component.LabelsPresenter,
|
||||
props: { kind: 'list', full: false, lookupField: 'labels', listProps: { optional: true, compression: true } }
|
||||
},
|
||||
{ key: '', presenter: tracker.component.DueDatePresenter, props: { kind: 'list' } },
|
||||
{
|
||||
key: '',
|
||||
presenter: tracker.component.DueDatePresenter,
|
||||
props: { kind: 'list', listProps: { optional: true, compression: true } }
|
||||
},
|
||||
{
|
||||
key: '',
|
||||
presenter: tracker.component.ComponentEditor,
|
||||
@ -575,15 +579,17 @@ export function createModel (builder: Builder): void {
|
||||
}
|
||||
}
|
||||
},
|
||||
{ key: '', presenter: view.component.DividerPresenter, props: { type: 'divider' } },
|
||||
{
|
||||
key: '',
|
||||
presenter: tracker.component.EstimationEditor,
|
||||
props: { kind: 'list', size: 'small', listProps: { optional: true } }
|
||||
props: { kind: 'list', size: 'small', listProps: { key: 'estimation', fixed: 'left' } }
|
||||
},
|
||||
{ key: '', presenter: view.component.DividerPresenter, props: { type: 'divider' } },
|
||||
{
|
||||
key: 'modifiedOn',
|
||||
presenter: tracker.component.ModificationDatePresenter,
|
||||
props: { listProps: { fixed: 'right', optional: true } }
|
||||
props: { listProps: { key: 'modified', fixed: 'left' } }
|
||||
},
|
||||
{
|
||||
key: '$lookup.assignee',
|
||||
|
@ -210,7 +210,7 @@
|
||||
}
|
||||
|
||||
export function select (offset: 1 | -1 | 0, of?: Doc, dir?: 'vertical' | 'horizontal'): void {
|
||||
let pos = (of !== undefined ? objects.findIndex((it) => it._id === of._id) : selection) ?? -1
|
||||
let pos = (of != null ? objects.findIndex((it) => it._id === of._id) : selection) ?? -1
|
||||
if (pos === -1) {
|
||||
for (const st of categories) {
|
||||
const stateObjs = getGroupByValues(groupByDocs, st) ?? []
|
||||
@ -237,7 +237,7 @@
|
||||
if (objState === -1) {
|
||||
return
|
||||
}
|
||||
const stateObjs = getGroupByValues(groupByDocs, categories.indexOf(objState)) ?? []
|
||||
const stateObjs = getGroupByValues(groupByDocs, categories[objState]) ?? []
|
||||
const statePos = stateObjs.findIndex((it) => it._id === obj._id)
|
||||
if (statePos === undefined) {
|
||||
return
|
||||
@ -302,7 +302,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="kanban-container top-divider">
|
||||
<div class="kanban-container">
|
||||
<ScrollBox>
|
||||
<div class="kanban-content">
|
||||
{#each categories as state, si (typeof state === 'object' ? state.name : state)}
|
||||
@ -360,7 +360,6 @@
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: var(--board-bg-color);
|
||||
}
|
||||
.kanban-content {
|
||||
display: flex;
|
||||
|
@ -25,13 +25,13 @@
|
||||
align-items: center;
|
||||
padding: 0.75rem 1.5rem;
|
||||
color: var(--dark-color);
|
||||
background-color: var(--board-card-bg-color);
|
||||
border: 1px dotted var(--divider-color);
|
||||
background-color: var(--theme-kanban-card-bg-color);
|
||||
border: 1px dotted var(--theme-kanban-card-border);
|
||||
border-radius: 0.75rem;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: var(--caption-color);
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -14,7 +14,7 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { CategoryType, Doc, Ref } from '@hcengineering/core'
|
||||
import ui, { Button, IconMoreH } from '@hcengineering/ui'
|
||||
import ui, { Button, IconMoreH, mouseAttractor } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { slide } from 'svelte/transition'
|
||||
import { CardDragEvent, Item } from '../types'
|
||||
@ -69,7 +69,7 @@
|
||||
class="card-container"
|
||||
class:selection={selection !== undefined ? objects[selection]?._id === object._id : false}
|
||||
class:checked={checkedSet.has(object._id)}
|
||||
on:mouseover={() => dispatch('obj-focus', object)}
|
||||
on:mouseover={mouseAttractor(() => dispatch('obj-focus', object))}
|
||||
on:focus={() => {}}
|
||||
on:contextmenu={(evt) => showMenu(evt, object)}
|
||||
draggable={true}
|
||||
@ -106,13 +106,14 @@
|
||||
|
||||
<style lang="scss">
|
||||
.card-container {
|
||||
background-color: var(--board-card-bg-color);
|
||||
background-color: var(--theme-kanban-card-bg-color);
|
||||
border: 1px solid var(--theme-kanban-card-border);
|
||||
border-radius: 0.25rem;
|
||||
// transition: box-shadow .15s ease-in-out;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--board-card-bg-hover);
|
||||
}
|
||||
// &:hover {
|
||||
// background-color: var(--board-card-bg-hover);
|
||||
// }
|
||||
&.checked {
|
||||
background-color: var(--highlight-select);
|
||||
box-shadow: inset 0 0 1px 1px var(--highlight-select-border);
|
||||
@ -123,7 +124,7 @@
|
||||
}
|
||||
&.selection,
|
||||
&.checked.selection {
|
||||
box-shadow: inset 0 0 1px 1px var(--primary-bg-color);
|
||||
box-shadow: inset 0 0 1px 1px var(--primary-button-enabled);
|
||||
animation: anim-border 1s ease-in-out;
|
||||
|
||||
&:hover {
|
||||
|
@ -143,7 +143,10 @@
|
||||
<div class="popupPanel-body__mobile-content clear-mins" class:max={useMaxWidth}>
|
||||
<slot />
|
||||
{#if !withoutActivity}
|
||||
<Component is={activity.component.Activity} props={{ object, showCommenInput: !withoutInput }} />
|
||||
<Component
|
||||
is={activity.component.Activity}
|
||||
props={{ object, showCommenInput: !withoutInput, shouldScroll: embedded }}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
@ -151,7 +154,10 @@
|
||||
<div class="popupPanel-body__main-content py-8 clear-mins" class:max={useMaxWidth}>
|
||||
<slot />
|
||||
{#if !withoutActivity}
|
||||
<Component is={activity.component.Activity} props={{ object, showCommenInput: !withoutInput }} />
|
||||
<Component
|
||||
is={activity.component.Activity}
|
||||
props={{ object, showCommenInput: !withoutInput, shouldScroll: embedded }}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</Scroller>
|
||||
|
@ -19,6 +19,7 @@
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import presentation from '..'
|
||||
import { deviceOptionsStore as deviceInfo, resizeObserver } from '@hcengineering/ui'
|
||||
import IconForward from './icons/Forward.svelte'
|
||||
|
||||
export let label: IntlString
|
||||
export let labelProps: any | undefined = undefined
|
||||
@ -47,7 +48,7 @@
|
||||
<div class="antiCard-header__title-wrap">
|
||||
{#if $$slots.header}
|
||||
<slot name="header" />
|
||||
<span class="antiCard-header__divider">›</span>
|
||||
<span class="antiCard-header__divider"><IconForward size={'small'} /></span>
|
||||
{/if}
|
||||
<span class="antiCard-header__title">
|
||||
{#if $$slots.title}
|
||||
@ -83,6 +84,7 @@
|
||||
<slot name="pool" />
|
||||
</div>
|
||||
{/if}
|
||||
<div class="antiCard-pool__separator" />
|
||||
<div class="antiCard-footer reverse">
|
||||
<div class="buttons-group text-sm flex-no-shrink">
|
||||
{#if $$slots.buttons}
|
||||
@ -97,6 +99,7 @@
|
||||
disabled={!canSave}
|
||||
label={okLabel}
|
||||
kind={'primary'}
|
||||
size={'large'}
|
||||
on:click={() => {
|
||||
if (okProcessing) {
|
||||
return
|
||||
|
@ -61,7 +61,7 @@
|
||||
readonly={isReadonly}
|
||||
label={attribute?.label}
|
||||
placeholder={attribute?.label}
|
||||
kind={'link'}
|
||||
kind={'secondary'}
|
||||
size={'large'}
|
||||
width={'100%'}
|
||||
justify={'left'}
|
||||
|
@ -36,7 +36,7 @@
|
||||
<Button
|
||||
focus
|
||||
label={presentation.string.Ok}
|
||||
size={'small'}
|
||||
size={'large'}
|
||||
kind={'primary'}
|
||||
loading={processing}
|
||||
on:click={() => {
|
||||
@ -55,7 +55,7 @@
|
||||
{#if canSubmit}
|
||||
<Button
|
||||
label={presentation.string.Cancel}
|
||||
size={'small'}
|
||||
size={'large'}
|
||||
on:click={() => {
|
||||
dispatch('close', false)
|
||||
}}
|
||||
@ -71,14 +71,14 @@
|
||||
padding: 2rem 1.75rem 1.75rem;
|
||||
width: 30rem;
|
||||
max-width: 40rem;
|
||||
background: var(--popup-bg-color);
|
||||
background: var(--theme-bg-color);
|
||||
border-radius: 1.25rem;
|
||||
user-select: none;
|
||||
box-shadow: var(--popup-shadow);
|
||||
|
||||
.message {
|
||||
margin-bottom: 1.75rem;
|
||||
color: var(--accent-color);
|
||||
color: var(--theme-content-color);
|
||||
}
|
||||
.footer {
|
||||
flex-shrink: 0;
|
||||
|
@ -20,6 +20,7 @@
|
||||
export let onClick: ((event: MouseEvent) => void) | undefined = undefined
|
||||
export let noUnderline = false
|
||||
export let inline = false
|
||||
export let colorInherit: boolean = false
|
||||
export let shrink: number = 0
|
||||
|
||||
function clickHandler (e: MouseEvent) {
|
||||
@ -53,13 +54,14 @@
|
||||
class:cursor-pointer={!disableClick}
|
||||
class:noUnderline
|
||||
class:inline
|
||||
class:colorInherit
|
||||
style:flex-shrink={shrink}
|
||||
on:click={clickHandler}
|
||||
>
|
||||
<slot />
|
||||
</span>
|
||||
{:else}
|
||||
<a {href} class:noUnderline class:inline style:flex-shrink={shrink} on:click={clickHandler}>
|
||||
<a {href} class:noUnderline class:inline class:colorInherit style:flex-shrink={shrink} on:click={clickHandler}>
|
||||
<slot />
|
||||
</a>
|
||||
{/if}
|
||||
@ -70,32 +72,41 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
color: var(--accent-color);
|
||||
// overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
cursor: pointer;
|
||||
font-weight: inherit;
|
||||
|
||||
&:not(.colorInherit) {
|
||||
color: var(--theme-content-color);
|
||||
}
|
||||
&.colorInherit {
|
||||
color: inherit;
|
||||
}
|
||||
&.inline {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&.noUnderline {
|
||||
color: var(--caption-color);
|
||||
font-weight: 500;
|
||||
&:not(.colorInherit) {
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.noUnderline) {
|
||||
&:hover {
|
||||
color: var(--caption-color);
|
||||
text-decoration: underline;
|
||||
&:not(.colorInherit) {
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:active {
|
||||
color: var(--accent-color);
|
||||
color: var(--theme-content-color);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -82,7 +82,7 @@
|
||||
<iframe
|
||||
class="pdfviewer-content"
|
||||
style:margin={$deviceInfo.minWidth ? '.5rem' : '1.5rem'}
|
||||
src={getFileUrl(file) + '#view=FitH'}
|
||||
src={getFileUrl(file) + '#view=FitH&navpanes=0'}
|
||||
title=""
|
||||
/>
|
||||
{/if}
|
||||
|
24
packages/presentation/src/components/icons/Forward.svelte
Normal file
24
packages/presentation/src/components/icons/Forward.svelte
Normal file
@ -0,0 +1,24 @@
|
||||
<!--
|
||||
// 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.4,7.7L5.7,2.1C5.5,1.9,5.2,1.9,5,2.1S4.8,2.6,5,2.8L10.3,8L5,13.3c-0.2,0.2-0.2,0.5,0,0.7c0.1,0.1,0.2,0.1,0.4,0.1s0.3,0,0.4-0.1l5.6-5.6c0.1-0.1,0.1-0.2,0.1-0.4S11.4,7.8,11.4,7.7z"
|
||||
/>
|
||||
</svg>
|
@ -361,7 +361,7 @@
|
||||
align-items: center;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
color: var(--caption-color);
|
||||
color: var(--theme-caption-color);
|
||||
opacity: 0.6;
|
||||
cursor: pointer;
|
||||
|
||||
@ -383,8 +383,8 @@
|
||||
|
||||
.formatPanelRef {
|
||||
padding: 0.5rem;
|
||||
background-color: var(--body-color);
|
||||
border: 1px solid var(--divider-color);
|
||||
background-color: var(--theme-comp-header-color);
|
||||
border: 1px solid var(--theme-divider-color);
|
||||
border-radius: 0.5rem 0.5rem 0 0;
|
||||
border-bottom: 0;
|
||||
|
||||
@ -402,8 +402,8 @@
|
||||
align-items: flex-end;
|
||||
min-height: 2.75rem;
|
||||
padding: 0.75rem 1rem;
|
||||
background-color: var(--body-accent);
|
||||
border: 1px solid var(--divider-color);
|
||||
background-color: var(--theme-refinput-color);
|
||||
border: 1px solid var(--theme-divider-color);
|
||||
border-radius: 0.5rem;
|
||||
|
||||
&.withoutTopBorder {
|
||||
@ -417,7 +417,7 @@
|
||||
align-items: center;
|
||||
width: calc(100% - 1.75rem);
|
||||
height: 100%;
|
||||
color: var(--content-color);
|
||||
color: var(--theme-content-color);
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
outline: none;
|
||||
@ -468,19 +468,18 @@
|
||||
.icon {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
color: var(--dark-color);
|
||||
color: var(--theme-dark-color);
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: var(--caption-color);
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
}
|
||||
&:focus {
|
||||
border: 1px solid var(--primary-button-focused-border);
|
||||
box-shadow: 0 0 0 3px var(--primary-button-outline);
|
||||
box-shadow: 0 0 0 2px var(--primary-button-focused-border);
|
||||
|
||||
& > .icon {
|
||||
color: var(--caption-color);
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,16 +15,17 @@
|
||||
|
||||
/* Common Colors */
|
||||
* {
|
||||
--primary-button-color: #fff;
|
||||
--primary-button-enabled: #4474F6;
|
||||
--primary-button-hovered: #2A5FF6;
|
||||
--primary-button-pressed: #194CD7;
|
||||
--primary-button-focused: #194CD7;
|
||||
--primary-button-disabled: #5771B9;
|
||||
--primary-button-focused-border: #7393EB;
|
||||
--primary-button-outline: rgba(87, 132, 255, .3);
|
||||
--primary-button-border: rgba(255, 255, 255, .09);
|
||||
// --primary-button-color: #fff;
|
||||
// --primary-button-enabled: #4474F6;
|
||||
// --primary-button-hovered: #2A5FF6;
|
||||
// --primary-button-pressed: #194CD7;
|
||||
// --primary-button-focused: #194CD7;
|
||||
// --primary-button-disabled: #5771B9;
|
||||
// --primary-button-focused-border: #7393EB;
|
||||
// --primary-button-outline: rgba(87, 132, 255, .3);
|
||||
// --primary-button-border: rgba(255, 255, 255, .09);
|
||||
|
||||
--white-color: #fff;
|
||||
--duotone-color: rgba(126, 134, 158, .25);
|
||||
|
||||
--system-error-color: #EE7A7A;
|
||||
@ -52,6 +53,70 @@
|
||||
|
||||
/* Dark Theme */
|
||||
.theme-dark {
|
||||
--primary-button-color: #fff;
|
||||
--primary-button-enabled: #205DC2;
|
||||
--primary-button-hovered: #1A53AF;
|
||||
--primary-button-pressed: #144CA8;
|
||||
--primary-button-focused: #144CA8;
|
||||
--primary-button-disabled: #6E9FED;
|
||||
--primary-button-focused-border: #6E9FED;
|
||||
--primary-button-border: rgba(255, 255, 255, .09);
|
||||
--primary-button-outline: rgba(87, 132, 255, .3); // OLD
|
||||
|
||||
--theme-button-enabled: rgba(255, 255, 255, .02);
|
||||
--theme-button-hovered: rgba(255, 255, 255, .04);
|
||||
--theme-button-pressed: rgba(255, 255, 255, .08);
|
||||
--theme-button-focused: rgba(255, 255, 255, .04);
|
||||
--theme-button-disabled: rgba(255, 255, 255, .02);
|
||||
--theme-button-border: rgba(255, 255, 255, .06);
|
||||
|
||||
--theme-refinput-color: rgba(255, 255, 255, .03);
|
||||
|
||||
--theme-bg-color: #1A1A28;
|
||||
--theme-back-color: #0f0f18;
|
||||
--theme-overlay-color: #0000007f;
|
||||
--theme-statusbar-color: #2C2C35;
|
||||
--theme-navpanel-color: #14141F;
|
||||
--theme-navpanel-hovered: rgba(255, 255, 255, .04);
|
||||
--theme-navpanel-selected: rgba(255, 255, 255, .07);
|
||||
--theme-navpanel-divider: rgba(255, 255, 255, .1);
|
||||
--theme-navpanel-border: transparent;
|
||||
--theme-navpanel-icons-color: #7F7F7F;
|
||||
--theme-comp-header-color: #1F1F2C;
|
||||
--theme-divider-color: rgba(255, 255, 255, .06);
|
||||
|
||||
--theme-trans-color: rgba(255, 255, 255, .3);
|
||||
--theme-darker-color: rgba(255, 255, 255, .4);
|
||||
--theme-halfcontent-color: rgba(255, 255, 255, .5);
|
||||
--theme-dark-color: rgba(255, 255, 255, .6);
|
||||
--theme-content-color: rgba(255, 255, 255, .8);
|
||||
--theme-caption-color: #FFF;
|
||||
|
||||
--theme-list-border-color: rgba(255, 255, 255, .05);
|
||||
--theme-list-header-color: #C88C65;
|
||||
--theme-list-subheader-color: #262634;
|
||||
--theme-list-row-color: #21212F;
|
||||
--theme-list-button-color: #262633;
|
||||
--theme-list-divider-color: rgba(255, 255, 255, .09);
|
||||
--theme-list-subheader-divider: transparent;
|
||||
|
||||
--theme-table-border-color: rgba(255, 255, 255, .1);
|
||||
--theme-table-header-color: #1C1C29;
|
||||
--theme-table-row-color: #21212F;
|
||||
|
||||
--theme-kanban-card-bg-color: rgba(222, 222, 240, .04);
|
||||
--theme-kanban-card-border: transparent;
|
||||
--theme-kanban-card-footer: #D9D9D9;
|
||||
|
||||
--theme-tablist-color: rgba(0, 0, 0, .02);
|
||||
--theme-checkbox-color: #000;
|
||||
--theme-checkbox-bg-color: #FFF;
|
||||
--theme-checkbox-border: rgba(0, 0, 0, .12);
|
||||
--theme-checkbox-disabled: #999;
|
||||
--theme-progress-color: #FFFFFF;
|
||||
--theme-popup-color: #292938;
|
||||
--theme-popup-divider: rgba(255, 255, 255, .1);
|
||||
|
||||
--body-color: #1f2023;
|
||||
--body-accent: #222326;
|
||||
--board-bg-color: #1c1d1f;
|
||||
@ -61,7 +126,7 @@
|
||||
--accent-bg-color: #27282b;
|
||||
--accent-shadow: rgb(0 0 0 / 10%) 0px 2px 4px;
|
||||
|
||||
--highlight-hover: #28292b;
|
||||
--highlight-hover: #282834;
|
||||
--highlight-select: #252b3a;
|
||||
--highlight-select-border: #44506b;
|
||||
--highlight-select-hover: #2c3346;
|
||||
@ -106,7 +171,7 @@
|
||||
--button-bg-hover: #37383b;
|
||||
--button-border-color: #3c3f44;
|
||||
--button-border-hover: #45484e;
|
||||
--button-shadow: rgb(0 0 0 / 25%) 0px 1px 1px;
|
||||
--button-shadow: rgb(0 0 0 / 15%) 0px 1px 1px 1px;
|
||||
--button-disabled-color: #313236;
|
||||
--noborder-bg-color: #313236;
|
||||
--noborder-bg-hover: #37383b;
|
||||
@ -135,6 +200,70 @@
|
||||
|
||||
/* Light Theme */
|
||||
.theme-light {
|
||||
--primary-button-color: #fff;
|
||||
--primary-button-enabled: #2B5190;
|
||||
--primary-button-hovered: #1A53AF; // DARK
|
||||
--primary-button-pressed: #144CA8; // DARK
|
||||
--primary-button-focused: #144CA8; // DARK
|
||||
--primary-button-disabled: #6E9FED; // DARK
|
||||
--primary-button-focused-border: #6E9FED; // DARK
|
||||
--primary-button-border: rgba(255, 255, 255, .09);
|
||||
--primary-button-outline: rgba(87, 132, 255, .3); // OLD
|
||||
|
||||
--theme-button-enabled: rgba(0, 0, 0, .02);
|
||||
--theme-button-hovered: rgba(0, 0, 0, .04);
|
||||
--theme-button-pressed: rgba(0, 0, 0, .08);
|
||||
--theme-button-focused: rgba(0, 0, 0, .04);
|
||||
--theme-button-disabled: rgba(0, 0, 0, .02);
|
||||
--theme-button-border: rgba(0, 0, 0, .06);
|
||||
|
||||
--theme-refinput-color: rgba(0, 0, 0, .03);
|
||||
|
||||
--theme-bg-color: #F1F1F4;
|
||||
--theme-back-color: #D9D9DD;
|
||||
--theme-overlay-color: #0000007f;
|
||||
--theme-statusbar-color: #bfbfc6;
|
||||
--theme-navpanel-color: #E8E8ED;
|
||||
--theme-navpanel-hovered: rgba(218, 218, 231, .5);
|
||||
--theme-navpanel-selected: #DADAE7;
|
||||
--theme-navpanel-divider: rgba(0, 0, 0, .06);
|
||||
--theme-navpanel-border: rgba(0, 0, 0, .06);
|
||||
--theme-navpanel-icons-color: #7F7F7F;
|
||||
--theme-comp-header-color: #FBFBFC;
|
||||
--theme-divider-color: rgba(0, 0, 0, .06);
|
||||
|
||||
--theme-trans-color: rgba(0, 0, 0, .3);
|
||||
--theme-darker-color: rgba(0, 0, 0, .4);
|
||||
--theme-halfcontent-color: rgba(0, 0, 0, .5);
|
||||
--theme-dark-color: rgba(0, 0, 0, .6);
|
||||
--theme-content-color: rgba(0, 0, 0, .8);
|
||||
--theme-caption-color: #000;
|
||||
|
||||
--theme-list-border-color: rgba(0, 0, 0, .09);
|
||||
--theme-list-header-color: #ECD4CA;
|
||||
--theme-list-subheader-color: #EEEEF0;
|
||||
--theme-list-row-color: #F7F7F8;
|
||||
--theme-list-button-color: #F2F2F4;
|
||||
--theme-list-divider-color: rgba(0, 0, 0, .07);
|
||||
--theme-list-subheader-divider: rgba(0, 0, 0, .06);
|
||||
|
||||
--theme-table-border-color: rgba(0, 0, 0, .1);
|
||||
--theme-table-header-color: #EFEFF2;
|
||||
--theme-table-row-color: #F4F4F6;
|
||||
|
||||
--theme-kanban-card-bg-color: rgba(0, 0, 0, .03);
|
||||
--theme-kanban-card-border: rgba(0, 0, 0, .04);
|
||||
--theme-kanban-card-footer: rgba(0, 0, 0, .04);
|
||||
|
||||
--theme-tablist-color: rgba(0, 0, 0, .02);
|
||||
--theme-checkbox-color: #000;
|
||||
--theme-checkbox-bg-color: #FFF;
|
||||
--theme-checkbox-border: rgba(0, 0, 0, .12);
|
||||
--theme-checkbox-disabled: #999;
|
||||
--theme-progress-color: rgba(0, 0, 0, .5);
|
||||
--theme-popup-color: #F1F1F4;
|
||||
--theme-popup-divider: rgba(0, 0, 0, .1);
|
||||
|
||||
--body-color: #fff;
|
||||
--body-accent: #fafafa; // HZ
|
||||
--board-bg-color: #f4f5f8;
|
||||
@ -144,7 +273,7 @@
|
||||
--accent-bg-color: #eff0f2; // HZ
|
||||
--accent-shadow: rgb(0 0 0 / 10%) 0px 2px 4px; // Dark
|
||||
|
||||
--highlight-hover: #f9f9f9;
|
||||
--highlight-hover: #E8E8E9;
|
||||
--highlight-select: #f0f4ff;
|
||||
--highlight-select-border: #e6eaff;
|
||||
--highlight-select-hover: #e4ebff;
|
||||
@ -189,7 +318,7 @@
|
||||
--button-bg-hover: #f4f5f8;
|
||||
--button-border-color: #dfe1e4;
|
||||
--button-border-hover: #c9cbcd;
|
||||
--button-shadow: rgb(0 0 0 / 7%) 0px 1px 1px;
|
||||
--button-shadow: rgb(0 0 0 / 20%) 0px 1px 2px 1px;
|
||||
--button-disabled-color: #eff1f4;
|
||||
--noborder-bg-color: #eff1f4;
|
||||
--noborder-bg-hover: #f4f5f8;
|
||||
|
@ -218,6 +218,7 @@ input.search {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
.flex-col-reverse {
|
||||
@ -363,10 +364,11 @@ input.search {
|
||||
}
|
||||
}
|
||||
.buttons-divider {
|
||||
min-width: 1px;
|
||||
flex-shrink: 0;
|
||||
width: 1px;
|
||||
height: 1.5rem;
|
||||
background-color: var(--divider-color);
|
||||
max-height: 1.5rem;
|
||||
background-color: var(--theme-list-divider-color);
|
||||
}
|
||||
|
||||
.labels-row {
|
||||
@ -399,8 +401,8 @@ input.search {
|
||||
&.reverse > :last-child { margin-right: .375rem; }
|
||||
}
|
||||
.gap-2 {
|
||||
& > *:not(:first-child) { margin-left: .5rem; }
|
||||
&.reverse > :last-child { margin-right: .5rem; }
|
||||
&:not(.reverse) > *:not(:first-child) { margin-left: .5rem; }
|
||||
&.reverse > *:not(:last-child) { margin-right: .5rem; }
|
||||
}
|
||||
|
||||
/* --------- */
|
||||
@ -467,6 +469,7 @@ input.search {
|
||||
.mb-8 { margin-bottom: 2rem; }
|
||||
.mb-9 { margin-bottom: 2.25rem; }
|
||||
.mb-10 { margin-bottom: 2.5rem; }
|
||||
.mx-0-5 { margin: 0 .125rem; }
|
||||
.mx-1 { margin: 0 .25rem; }
|
||||
.mx-2 { margin: 0 .5rem; }
|
||||
.mx-3 { margin: 0 .75rem; }
|
||||
@ -475,6 +478,7 @@ input.search {
|
||||
.mx-auto { margin: 0 auto; }
|
||||
.my-2 { margin: .5rem 0; }
|
||||
.my-4 { margin: 1rem 0; }
|
||||
.my-5 { margin: 1.25rem 0; }
|
||||
|
||||
.m-0-5 { margin: .125rem; }
|
||||
.m-1 { margin: .25rem; }
|
||||
@ -484,6 +488,7 @@ input.search {
|
||||
.pl-3 { padding-left: .75rem; }
|
||||
.pl-4 { padding-left: 1rem; }
|
||||
.pl-8 { padding-left: 2rem; }
|
||||
.pl-10 { padding-left: 2.5rem; }
|
||||
.pr-1 { padding-right: .25rem; }
|
||||
.pr-2 { padding-right: .5rem; }
|
||||
.pr-3 { padding-right: .75rem; }
|
||||
@ -504,6 +509,7 @@ input.search {
|
||||
.px-2 { padding: 0 .5rem; }
|
||||
.px-3 { padding: 0 .75rem; }
|
||||
.px-4 { padding: 0 1rem; }
|
||||
.px-10 { padding: 0 2.5rem; }
|
||||
.py-1 { padding: 0.25rem 0; }
|
||||
.py-4 { padding: 1rem 0; }
|
||||
.py-8 { padding: 2rem 0; }
|
||||
@ -612,6 +618,7 @@ input.search {
|
||||
.min-w-min { min-width: min-content; }
|
||||
.min-h-0 { min-height: 0; }
|
||||
.min-h-2 { min-height: .5rem; }
|
||||
.min-h-4 { min-height: 1rem; }
|
||||
.min-h-7 { min-height: 1.75rem; }
|
||||
.min-h-30 { min-height: 7.5rem; }
|
||||
.min-h-60 { min-height: 15rem; }
|
||||
@ -623,7 +630,9 @@ input.search {
|
||||
.max-w-60 { max-width: 15rem; }
|
||||
.max-w-80 { max-width: 20rem; }
|
||||
.max-w-240 { max-width: 60rem; }
|
||||
.max-h-0 { max-height: 0; }
|
||||
.max-h-2 { max-height: .5rem; }
|
||||
.max-h-4 { max-height: 1rem; }
|
||||
.max-h-30 { max-height: 7.5rem; }
|
||||
.max-h-50 { max-height: 12.5rem; }
|
||||
.max-h-60 { max-height: 15rem; }
|
||||
@ -642,20 +651,20 @@ input.search {
|
||||
height: 1em;
|
||||
}
|
||||
.svg-x-small {
|
||||
width: .857em;
|
||||
height: .857em;
|
||||
width: .75rem;
|
||||
height: .75rem;
|
||||
}
|
||||
.svg-small {
|
||||
width: 1.143em;
|
||||
height: 1.143em;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
.svg-medium {
|
||||
width: 1.429em;
|
||||
height: 1.429em;
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
}
|
||||
.svg-large {
|
||||
width: 1.715em;
|
||||
height: 1.715em;
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
}
|
||||
.svg-full {
|
||||
width: inherit;
|
||||
@ -767,26 +776,26 @@ a.no-line {
|
||||
}
|
||||
|
||||
.focused-button {
|
||||
background-color: var(--button-bg-color);
|
||||
background-color: var(--theme-button-enabled);
|
||||
border: 1px solid transparent;
|
||||
|
||||
& > .icon { color: var(--accent-color); }
|
||||
& > .icon { color: var(--theme-content-color); }
|
||||
&.selected {
|
||||
background-color: var(--button-bg-hover);
|
||||
border: 1px solid var(--button-border-hover);
|
||||
background-color: var(--theme-button-pressed);
|
||||
border: 1px solid var(--theme-button-border);
|
||||
}
|
||||
&:hover {
|
||||
background-color: var(--button-bg-hover);
|
||||
border: 1px solid var(--button-border-hover);
|
||||
& > .icon { color: var(--caption-color); }
|
||||
background-color: var(--theme-button-hovered);
|
||||
border: 1px solid var(--theme-button-border);
|
||||
& > .icon { color: var(--theme-caption-color); }
|
||||
}
|
||||
&:focus {
|
||||
border: 1px solid var(--primary-button-focused-border);
|
||||
box-shadow: 0 0 0 3px var(--primary-button-outline);
|
||||
& > .icon { color: var(--caption-color); }
|
||||
border: 1px solid var(--theme-button-border);
|
||||
box-shadow: 0 0 0 2px var(--primary-button-focused-border);
|
||||
& > .icon { color: var(--theme-caption-color); }
|
||||
}
|
||||
|
||||
&.bordered { border-color: var(--button-border-color); }
|
||||
&.bordered { border-color: var(--theme-button-border); }
|
||||
}
|
||||
|
||||
.overflow-x-auto { overflow-x: auto; }
|
||||
@ -817,6 +826,8 @@ a.no-line {
|
||||
.background-primary-color { background-color: var(--primary-button-enabled); }
|
||||
.background-content-accent-color { background-color: var(--accent-color); }
|
||||
|
||||
.content-trans-color { color: var(--theme-trans-color); }
|
||||
|
||||
.dark-color,
|
||||
.content-dark-color { color: var(--dark-color); }
|
||||
.content-color { color: var(--content-color); }
|
||||
|
@ -15,15 +15,16 @@
|
||||
|
||||
/* Panels */
|
||||
* {
|
||||
--app-panel-width: 4rem;
|
||||
--app-panel-width: 4.25rem;
|
||||
}
|
||||
.antiPanel-application {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: var(--board-bg-color);
|
||||
|
||||
background-color: var(--theme-navpanel-color);
|
||||
border-right: 1px solid var(--theme-navpanel-divider);
|
||||
|
||||
&.vertical {
|
||||
flex-direction: column;
|
||||
min-width: var(--app-panel-width);
|
||||
@ -43,37 +44,39 @@
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
&.filled { background-color: var(--body-accent); }
|
||||
&.border-left { border-left: 1px solid var(--divider-color); }
|
||||
&.border-right { border-right: 1px solid var(--divider-color); }
|
||||
|
||||
&.filled { background-color: var(--theme-bg-color); }
|
||||
&.border-left { border-left: 1px solid var(--theme-divider-color); }
|
||||
&.border-right { border-right: 1px solid var(--theme-divider-color); }
|
||||
}
|
||||
.antiPanel-navigator {
|
||||
position: relative;
|
||||
min-width: 17.5rem;
|
||||
max-width: 17.5rem;
|
||||
width: 17.5rem;
|
||||
background-color: var(--theme-navpanel-color);
|
||||
border-right: 1px solid var(--theme-navpanel-border);
|
||||
}
|
||||
@media (max-width: 1024px) {
|
||||
.antiPanel-navigator {
|
||||
position: fixed;
|
||||
background-color: var(--body-accent);
|
||||
top: var(--status-bar-height);
|
||||
height: calc(100% - var(--status-bar-height));
|
||||
background-color: var(--theme-navpanel-color);
|
||||
filter: drop-shadow(2px 0 1px rgba(0, 0, 0, .2));
|
||||
z-index: 450;
|
||||
|
||||
&.portrait {
|
||||
top: var(--status-bar-height);
|
||||
left: 0;
|
||||
}
|
||||
&.landscape {
|
||||
top: var(--status-bar-height);
|
||||
left: var(--app-panel-width);
|
||||
left: var(--app-panel-width);
|
||||
}
|
||||
}
|
||||
}
|
||||
.antiPanel-component:not(.aside) {
|
||||
flex-grow: 1;
|
||||
// background-color: var(--board-bg-color);
|
||||
background-color: var(--theme-bg-color);
|
||||
}
|
||||
.antiPanel-component.aside {
|
||||
min-width: 30rem;
|
||||
@ -169,13 +172,13 @@
|
||||
}
|
||||
|
||||
&:hover, &.hovered, &.selected {
|
||||
background-color: var(--menu-bg-select);
|
||||
// background-color: var(--theme-navpanel-hovered);
|
||||
.an-element__icon,
|
||||
.an-element__label { color: var(--caption-color); }
|
||||
.an-element__icon-arrow { opacity: 1; }
|
||||
}
|
||||
&:hover, &.hovered { background-color: var(--highlight-hover); }
|
||||
&.selected { background-color: var(--menu-bg-select); }
|
||||
&:hover, &.hovered { background-color: var(--theme-navpanel-hovered); }
|
||||
&.selected { background-color: var(--theme-navpanel-selected); }
|
||||
&:hover .an-element__tool, &.hovered .an-element__tool { visibility: visible; }
|
||||
|
||||
&:not(.collapsed) .an-element__icon-arrow { opacity: 1; }
|
||||
@ -220,7 +223,7 @@
|
||||
margin: .5rem 0;
|
||||
height: 1px;
|
||||
|
||||
&.line { background-color: var(--divider-color); }
|
||||
&.line { background-color: var(--theme-navpanel-divider); }
|
||||
&.short { margin: .25rem 1rem; }
|
||||
}
|
||||
.antiNav-space {
|
||||
@ -231,7 +234,7 @@
|
||||
flex-shrink: 0;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background-color: var(--divider-color);
|
||||
background-color: var(--theme-navpanel-divider);
|
||||
}
|
||||
.antiNav-footer-grower {
|
||||
flex-shrink: 10;
|
||||
@ -297,7 +300,7 @@
|
||||
margin: .25rem 0;
|
||||
min-height: 1px;
|
||||
height: 1px;
|
||||
background-color: var(--divider-color);
|
||||
background-color: var(--theme-divider-color);
|
||||
|
||||
&.dark { background-color: var(--body-accent); }
|
||||
&.noMargin { margin: 0; }
|
||||
@ -351,20 +354,7 @@
|
||||
border-radius: .5rem .5rem 0 0;
|
||||
}
|
||||
&__counter {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
flex-shrink: 0;
|
||||
padding: 0.25rem 0.5rem;
|
||||
min-width: 1.325rem;
|
||||
text-align: center;
|
||||
font-weight: 500;
|
||||
font-size: 1rem;
|
||||
line-height: 1rem;
|
||||
color: var(--accent-color);
|
||||
background-color: var(--body-color);
|
||||
border: 1px solid var(--divider-color);
|
||||
border-radius: 1rem;
|
||||
color: var(--theme-darker-color);
|
||||
}
|
||||
&__tag {
|
||||
display: flex;
|
||||
@ -431,17 +421,17 @@
|
||||
// Emphasized
|
||||
.antiEmphasized {
|
||||
padding: .75rem;
|
||||
background-color: var(--body-accent);
|
||||
border: 1px solid var(--button-border-color);
|
||||
border-radius: .5rem;
|
||||
background-color: var(--theme-comp-header-color);
|
||||
border: 1px solid var(--theme-popup-divider);
|
||||
border-radius: .25rem;
|
||||
transition-property: border, background-color;
|
||||
transition-duration: .15s;
|
||||
transition-timing-function: var(--timing-main);
|
||||
|
||||
&:hover,
|
||||
&:focus-within {
|
||||
background-color: var(--body-color);
|
||||
border-color: var(--button-border-hover);
|
||||
// background-color: var(--body-color);
|
||||
border-color: var(--theme-list-divider-color);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,10 +20,15 @@
|
||||
height: 100%;
|
||||
|
||||
.ac-header {
|
||||
padding: 0.5rem 1.5rem 0.5rem 2.5rem;
|
||||
padding: 0.5rem 2.25rem;
|
||||
background-color: var(--theme-comp-header-color);
|
||||
// height: 3.5rem;
|
||||
// min-height: 2.5rem;
|
||||
|
||||
&.caption-height {
|
||||
min-height: 3.25rem;
|
||||
}
|
||||
&.search-start { padding-left: 1.75rem; }
|
||||
&.short {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -31,21 +36,23 @@
|
||||
}
|
||||
&.full,
|
||||
&-full {
|
||||
display: grid;
|
||||
grid-template-columns: auto;
|
||||
grid-auto-flow: column;
|
||||
grid-auto-columns: max-content;
|
||||
gap: .75rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
|
||||
&:not(.small-gap, .medium-gap) > *:not(:last-child) { margin-right: 1.25rem; }
|
||||
&.small-gap > *:not(:last-child) { margin-right: .75rem; }
|
||||
&.medium-gap > *:not(:last-child) { margin-right: 1rem; }
|
||||
}
|
||||
&.withSettings { padding-right: .75rem; }
|
||||
// &.withSettings { padding-right: .75rem; }
|
||||
&.mini {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
&.mirror {
|
||||
justify-content: space-between;
|
||||
padding: 0 1rem;
|
||||
// padding: 0 1rem;
|
||||
|
||||
&-tool {
|
||||
justify-content: space-between;
|
||||
@ -53,7 +60,7 @@
|
||||
}
|
||||
}
|
||||
&.divide {
|
||||
border-bottom: 1px solid var(--divider-color);
|
||||
border-bottom: 1px solid var(--theme-divider-color);
|
||||
}
|
||||
.secondRow {
|
||||
align-self: flex-end;
|
||||
@ -77,23 +84,30 @@
|
||||
|
||||
.ac-header__icon {
|
||||
margin-right: 0.5rem;
|
||||
color: var(--content-color);
|
||||
color: var(--theme-content-color);
|
||||
}
|
||||
.ac-header__title {
|
||||
flex-shrink: 1;
|
||||
min-width: 0;
|
||||
font-weight: 500;
|
||||
font-size: 1rem;
|
||||
color: var(--caption-color);
|
||||
color: var(--theme-caption-color);
|
||||
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
user-select: none;
|
||||
}
|
||||
.ac-header__counter {
|
||||
flex-shrink: 0;
|
||||
margin-left: .25rem;
|
||||
min-width: 0;
|
||||
font-size: 1rem;
|
||||
color: var(--theme-darker-color);
|
||||
}
|
||||
.ac-header__description {
|
||||
min-width: 0;
|
||||
font-size: 0.75rem;
|
||||
color: var(--dark-color);
|
||||
color: var(--theme-dark-color);
|
||||
|
||||
overflow: hidden;
|
||||
visibility: visible;
|
||||
@ -316,14 +330,14 @@
|
||||
// height: 1.5rem;
|
||||
}
|
||||
&__element {
|
||||
fill: var(--accent-bg-color);
|
||||
stroke: var(--divider-color);
|
||||
fill: var(--theme-button-enabled);
|
||||
stroke: var(--theme-button-border);
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
|
||||
&:hover { fill: var(--button-bg-color); }
|
||||
&:hover { fill: var(--theme-button-hovered); }
|
||||
}
|
||||
&__selected { fill: var(--button-bg-hover); }
|
||||
&__selected { fill: var(--theme-button-pressed); }
|
||||
|
||||
.asb-label__container {
|
||||
position: absolute;
|
||||
@ -338,11 +352,11 @@
|
||||
height: 100%;
|
||||
font-weight: 500;
|
||||
font-size: 0.8125rem;
|
||||
color: var(--dark-color);
|
||||
color: var(--theme-dark-color);
|
||||
pointer-events: none;
|
||||
|
||||
&.selected {
|
||||
color: var(--caption-color);
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -360,18 +374,24 @@
|
||||
&:last-child { padding-right: 0; }
|
||||
}
|
||||
th {
|
||||
height: 2.5rem;
|
||||
font-weight: 500;
|
||||
font-size: .75rem;
|
||||
color: var(--dark-color);
|
||||
box-shadow: inset 0 -1px 0 0 var(--divider-color);
|
||||
height: 3rem;
|
||||
font-weight: 600;
|
||||
font-size: .625rem;
|
||||
letter-spacing: .5px;
|
||||
text-transform: uppercase;
|
||||
color: var(--theme-dark-color);
|
||||
box-shadow: inset 0 -1px 0 0 var(--theme-table-border-color);
|
||||
user-select: none;
|
||||
// z-index: 5;
|
||||
|
||||
&.sortable { cursor: pointer; }
|
||||
&.sorted .icon {
|
||||
margin-left: .25rem;
|
||||
opacity: .6;
|
||||
&.sorted {
|
||||
color: var(--theme-caption-color);
|
||||
|
||||
.icon {
|
||||
margin-left: .25rem;
|
||||
opacity: .6;
|
||||
}
|
||||
}
|
||||
&:hover .antiTable-cells__checkCell { visibility: visible; }
|
||||
.checkall { visibility: visible; }
|
||||
@ -379,7 +399,7 @@
|
||||
|
||||
&.editable {
|
||||
th, td, tr {
|
||||
border: 1px dashed var(--divider-color);
|
||||
border: 1px dashed var(--theme-divider-color);
|
||||
}
|
||||
}
|
||||
|
||||
@ -424,10 +444,12 @@
|
||||
}
|
||||
|
||||
.antiTable-body__row {
|
||||
position: relative;
|
||||
height: 3.25rem;
|
||||
color: var(--caption-color);
|
||||
color: var(--theme-caption-color);
|
||||
background-color: var(--theme-table-row-color);
|
||||
border-bottom: 1px solid var(--theme-divider-color);
|
||||
|
||||
&:not(:last-child) { border-bottom: 1px solid var(--accent-bg-color); }
|
||||
&:hover .antiTable-cells__firstCell .antiTable-cells__firstCell-menuRow { visibility: visible; }
|
||||
&:hover, &.checking {
|
||||
.antiTable-cells__checkCell { visibility: visible; }
|
||||
@ -442,14 +464,14 @@
|
||||
}
|
||||
|
||||
.antiTable-body__border {
|
||||
border: 1px solid var(--divider-color);
|
||||
border: 1px solid var(--theme-divider-color);
|
||||
}
|
||||
|
||||
&.highlightRows .antiTable-body__row {
|
||||
&.selected { background-color: var(--highlight-hover); }
|
||||
&.checking {
|
||||
background-color: var(--highlight-select);
|
||||
border-bottom-color: var(--highlight-select-border);
|
||||
// border-bottom-color: var(--highlight-select-border);
|
||||
|
||||
&:hover { background-color: var(--highlight-select-hover); }
|
||||
}
|
||||
@ -460,8 +482,8 @@
|
||||
position: sticky;
|
||||
z-index: 2;
|
||||
top: 0;
|
||||
height: 2.5rem;
|
||||
background-color: var(--body-color);
|
||||
height: 3rem;
|
||||
background-color: var(--theme-table-header-color);
|
||||
}
|
||||
|
||||
.scroller-tfoot {
|
||||
@ -469,10 +491,10 @@
|
||||
z-index: 2;
|
||||
bottom: 0;
|
||||
height: 2.5rem;
|
||||
background-color: var(--body-color);
|
||||
background-color: var(--theme-table-header-color);
|
||||
|
||||
tr {
|
||||
box-shadow: inset 0 1px 0 0 var(--divider-color);
|
||||
box-shadow: inset 0 1px 0 0 var(--theme-divider-color);
|
||||
}
|
||||
}
|
||||
|
||||
@ -480,9 +502,22 @@
|
||||
th, td {
|
||||
&:first-child {
|
||||
position: sticky;
|
||||
z-index: 1;
|
||||
padding: 0;
|
||||
left: 0;
|
||||
background-color: var(--body-color);
|
||||
background-color: var(--theme-bg-color);
|
||||
border-right: 1px solid transparent !important;
|
||||
z-index: 1;
|
||||
}
|
||||
.fullfill {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: .5rem;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: var(--theme-bg-color);
|
||||
border-right: 1px solid var(--theme-divider-color);
|
||||
|
||||
&.center { justify-content: center; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -497,12 +532,12 @@
|
||||
// Basic component view.
|
||||
.antiComponentBox {
|
||||
padding: 0.5rem;
|
||||
background-color: var(--board-card-bg-color);
|
||||
border: 1px solid var(--divider-color);
|
||||
background-color: var(--theme-list-row-color);
|
||||
border: 1px solid var(--theme-list-divider-color);
|
||||
border-radius: .75rem;
|
||||
|
||||
&.antiComponentBoxFocused {
|
||||
background-color: var(--board-card-bg-hover);
|
||||
background-color: var(--theme-button-hovered);
|
||||
}
|
||||
}
|
||||
|
||||
@ -649,3 +684,46 @@
|
||||
&.inter { font-size: 1em; }
|
||||
}
|
||||
}
|
||||
|
||||
/* ListView - global style */
|
||||
.list-container .category-container .categoryHeader.subLevel.closed {
|
||||
border-bottom: 1px solid var(--theme-list-border-color);
|
||||
border-radius: 0 0 0.25rem 0.25rem;
|
||||
}
|
||||
.list-container .category-container .categoryHeader.closed:not(.subLevel) {
|
||||
border-radius: 0 0 .25rem .25rem;
|
||||
|
||||
&::before {
|
||||
border-bottom-color: var(--theme-list-border-color);
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
}
|
||||
.list-container .category-container .listGrid {
|
||||
.fix-margin { margin-left: .875rem; }
|
||||
.name { margin-left: .375rem; }
|
||||
|
||||
.optional-bar {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-shrink: 1;
|
||||
min-width: 0;
|
||||
|
||||
.label-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-shrink: 10;
|
||||
width: auto;
|
||||
min-width: 0;
|
||||
}
|
||||
& > *:not(:last-child) {
|
||||
flex-shrink: 10;
|
||||
width: min-content;
|
||||
}
|
||||
& > *:last-child {
|
||||
flex-shrink: 0;
|
||||
width: max-content;
|
||||
}
|
||||
& > * { margin-left: .375rem; }
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
background-color: var(--card-overlay-color);
|
||||
background-color: var(--theme-overlay-color);
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
background: var(--popup-bg-color);
|
||||
background: var(--theme-popup-color);
|
||||
border-radius: .5rem;
|
||||
box-shadow: var(--card-shadow);
|
||||
|
||||
@ -39,18 +39,26 @@
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
padding: 1rem 1rem 1.5rem;
|
||||
padding: 1.5rem 1.5rem .5rem 1.75rem;
|
||||
font-size: .8125rem;
|
||||
|
||||
&__title-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
|
||||
& > *:not(:last-child) { margin-right: .5rem; }
|
||||
}
|
||||
&__title {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
user-select: none;
|
||||
min-width: 0;
|
||||
font-weight: 500;
|
||||
font-size: 1rem;
|
||||
color: var(--accent-color);
|
||||
line-height: 150%;
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
&__divider { color: var(--theme-content-color); }
|
||||
&__error {
|
||||
min-width: 0;
|
||||
flex-grow: 1;
|
||||
@ -71,8 +79,9 @@
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
margin: 0 1rem;
|
||||
padding: 1rem 1.75rem;
|
||||
height: fit-content;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
|
||||
& > *:not(:last-child) { margin-bottom: 1rem; }
|
||||
@ -81,36 +90,50 @@
|
||||
.antiCard-pool {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0 1rem .75rem;
|
||||
color: var(--caption-color);
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
margin: .5rem 1.25rem 0 1.75rem;
|
||||
min-width: 0;
|
||||
font-size: .8125rem;
|
||||
color: var(--theme-caption-color);
|
||||
|
||||
&__separator {
|
||||
margin: 1rem 0;
|
||||
flex-shrink: 0;
|
||||
margin-top: 1.25rem;
|
||||
height: 1px;
|
||||
background-color: var(--divider-color);
|
||||
background-color: var(--theme-popup-divider);
|
||||
}
|
||||
& > * { margin: .5rem .5rem 0 0; }
|
||||
}
|
||||
|
||||
.antiCard-footer {
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
direction: rtl;
|
||||
justify-content: flex-start;
|
||||
direction: ltr;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
column-gap: .75rem;
|
||||
padding: 1.5rem 1rem 1rem;
|
||||
height: 4.5rem;
|
||||
padding: 1rem 1.75rem;
|
||||
height: 4.25rem;
|
||||
border-radius: 0 0 .5rem .5rem;
|
||||
|
||||
&.reverse { flex-direction: row-reverse; }
|
||||
&__error {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
margin-left: .375rem;
|
||||
min-width: 0;
|
||||
font-weight: 500;
|
||||
font-size: .75rem;
|
||||
color: var(--system-error-color);
|
||||
&:empty { visibility: hidden; }
|
||||
}
|
||||
}
|
||||
|
||||
.antiCard-group {
|
||||
padding: .5rem 1rem;
|
||||
|
||||
&:not(:last-child) { border-bottom: 1px solid var(--popup-divider); }
|
||||
&:not(:last-child) { border-bottom: 1px solid var(--theme-divider-color); }
|
||||
&.grid {
|
||||
display: grid;
|
||||
grid-template-columns: 5rem auto;
|
||||
@ -124,7 +147,7 @@
|
||||
font-weight: 500;
|
||||
font-size: .75rem;
|
||||
line-height: .75rem;
|
||||
color: var(--content-color);
|
||||
color: var(--theme-content-color);
|
||||
}
|
||||
.value {
|
||||
display: flex;
|
||||
@ -148,26 +171,14 @@
|
||||
width: 90vw;
|
||||
max-width: 90vw;
|
||||
max-height: 90vh;
|
||||
}
|
||||
&.dialog,
|
||||
&.mobile {
|
||||
|
||||
.antiCard-header {
|
||||
padding: .75rem .75rem .375rem;
|
||||
|
||||
&__title-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
|
||||
& > *:not(:first-child) { margin-left: .375rem; }
|
||||
}
|
||||
|
||||
&__divider, &__title {
|
||||
font-weight: 400;
|
||||
font-size: .8125rem;
|
||||
}
|
||||
&__divider { color: var(--content-color); }
|
||||
&__title { color: var(--accent-color); }
|
||||
}
|
||||
.antiCard-content { margin: .5rem 1.125rem 1rem; }
|
||||
.antiCard-pool {
|
||||
@ -175,29 +186,10 @@
|
||||
align-items: center;
|
||||
margin: 0 .5rem .25rem;
|
||||
font-size: .75rem;
|
||||
|
||||
& > * { margin: 0 .25rem .5rem; }
|
||||
}
|
||||
.antiCard-footer {
|
||||
direction: ltr;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: .75rem;
|
||||
height: auto;
|
||||
border-top: 1px solid var(--divider-color);
|
||||
|
||||
&.reverse { flex-direction: row-reverse; }
|
||||
&__error {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
margin-left: .375rem;
|
||||
min-width: 0;
|
||||
font-weight: 500;
|
||||
font-size: .75rem;
|
||||
color: var(--system-error-color);
|
||||
&:empty { visibility: hidden; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ body {
|
||||
font-weight: 400;
|
||||
font-size: var(--body-font-size);
|
||||
color: var(--content-color);
|
||||
background-color: var(--body-color);
|
||||
background-color: var(--theme-bg-color);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@
|
||||
|
||||
&:not(.embedded) {
|
||||
border-radius: .5rem;
|
||||
box-shadow: var(--popup-panel-shadow);
|
||||
// box-shadow: var(--popup-panel-shadow);
|
||||
}
|
||||
|
||||
.popupPanel-title {
|
||||
@ -87,9 +87,9 @@
|
||||
&__bordered {
|
||||
min-width: 0;
|
||||
min-height: 3rem;
|
||||
background-color: var(--board-card-bg-color);
|
||||
background-color: var(--theme-comp-header-color);
|
||||
&:not(.embedded) {
|
||||
border: 1px solid var(--divider-color);
|
||||
border: 1px solid var(--theme-divider-color);
|
||||
border-bottom: none;
|
||||
border-radius: .5rem .5rem 0 0;
|
||||
}
|
||||
@ -116,8 +116,8 @@
|
||||
min-height: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: var(--body-color);
|
||||
border: 1px solid var(--divider-color);
|
||||
background-color: var(--theme-bg-color);
|
||||
border: 1px solid var(--theme-divider-color);
|
||||
&:not(.embedded) {
|
||||
border-radius: 0 0 .5rem .5rem;
|
||||
}
|
||||
@ -184,8 +184,8 @@
|
||||
min-width: 320px;
|
||||
}
|
||||
|
||||
&.bottom-divider { border-bottom: 1px solid var(--divider-color); }
|
||||
&.top-divider { border-top: 1px solid var(--divider-color); }
|
||||
&.bottom-divider { border-bottom: 1px solid var(--theme-divider-color); }
|
||||
&.top-divider { border-top: 1px solid var(--theme-divider-color); }
|
||||
.header-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -214,7 +214,7 @@
|
||||
bottom: 1rem;
|
||||
left: 0;
|
||||
width: 0;
|
||||
border-left: 1px solid var(--divider-color);
|
||||
border-left: 1px solid var(--theme-divider-color);
|
||||
}
|
||||
|
||||
&.float {
|
||||
@ -226,8 +226,8 @@
|
||||
min-width: 0;
|
||||
max-width: 320px;
|
||||
height: 100%;
|
||||
background-color: var(--board-card-bg-color);
|
||||
border-left: 1px solid var(--divider-color);
|
||||
background-color: var(--theme-list-row-color);
|
||||
border-left: 1px solid var(--theme-divider-color);
|
||||
border-bottom-right-radius: .45rem;
|
||||
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0);
|
||||
transition: box-shadow 150ms ease 0s, transform 150ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||
|
@ -422,7 +422,7 @@
|
||||
flex-direction: column;
|
||||
padding: .5rem;
|
||||
min-height: 22rem;
|
||||
background: var(--popup-bg-color);
|
||||
background: var(--theme-popup-color);
|
||||
border-radius: .5rem;
|
||||
box-shadow: var(--popup-shadow);
|
||||
|
||||
|
@ -27,7 +27,11 @@
|
||||
"AddDueDate": "Add due date",
|
||||
"EditDueDate": "Edit due date",
|
||||
"SaveDueDate": "Save due date",
|
||||
"IssueNeedsToBeCompletedByThisDate": "Issue needs to be completed by this date",
|
||||
"NeedsToBeCompletedByThisDate": "Needs to be completed by this date",
|
||||
"DueDatePopupTitle": "Due on {value}",
|
||||
"DueDatePopupOverdueTitle": "Was due on {value}",
|
||||
"DueDatePopupDescription": "{value, plural, =0 {Today} =1 {Tomorrow} other {# days remaining}}",
|
||||
"DueDatePopupOverdueDescription": "{value, plural, =1 {1 day overdue} other {# days overdue}}",
|
||||
"English": "English",
|
||||
"Russian": "Russian",
|
||||
"MinutesBefore": "{minutes, plural, =1 {a minute before} other {# minutes before}}",
|
||||
|
@ -27,7 +27,11 @@
|
||||
"AddDueDate": "Установить дату",
|
||||
"EditDueDate": "Изменить дату",
|
||||
"SaveDueDate": "Сохранить дату",
|
||||
"IssueNeedsToBeCompletedByThisDate": "Задача должна быть завершена к этой дате",
|
||||
"NeedsToBeCompletedByThisDate": "Должно быть завершено к этой дате",
|
||||
"DueDatePopupTitle": "Срок {value}",
|
||||
"DueDatePopupOverdueTitle": "Должно было завершится {value}",
|
||||
"DueDatePopupDescription": "{value, plural, =0 {Сегодня} =1 {Завтра} other {# дней осталось}}",
|
||||
"DueDatePopupOverdueDescription": "{value, plural, =1 {1 день опоздания} other {# дней опаздания}}",
|
||||
"English": "Английский",
|
||||
"Russian": "Русский",
|
||||
"MinutesBefore": "{minutes, plural, =1 {за минуту} other {за # минут}}",
|
||||
|
@ -36,6 +36,7 @@
|
||||
"@hcengineering/platform": "^0.6.8",
|
||||
"@hcengineering/theme": "^0.6.2",
|
||||
"@hcengineering/core": "^0.6.23",
|
||||
"just-clone": "~6.2.0",
|
||||
"svelte": "3.55.1",
|
||||
"fast-equals": "^2.0.3"
|
||||
},
|
||||
|
@ -106,3 +106,58 @@ export function numberToRGB (color: number, alpha?: number): string {
|
||||
|
||||
return `rgba(${r}, ${g}, ${b}, ${alpha === undefined ? '1' : alpha})`
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function hsvToRGB (h: number, s: number, v: number): { r: number, g: number, b: number, rgb: string } {
|
||||
let r: number = 0
|
||||
let g: number = 0
|
||||
let b: number = 0
|
||||
const i = Math.floor(h * 6)
|
||||
const f = h * 6 - i
|
||||
const p = v * (1 - s)
|
||||
const q = v * (1 - f * s)
|
||||
const t = v * (1 - (1 - f) * s)
|
||||
switch (i % 6) {
|
||||
case 0:
|
||||
r = v
|
||||
g = t
|
||||
b = p
|
||||
break
|
||||
case 1:
|
||||
r = q
|
||||
g = v
|
||||
b = p
|
||||
break
|
||||
case 2:
|
||||
r = p
|
||||
g = v
|
||||
b = t
|
||||
break
|
||||
case 3:
|
||||
r = p
|
||||
g = q
|
||||
b = v
|
||||
break
|
||||
case 4:
|
||||
r = t
|
||||
g = p
|
||||
b = v
|
||||
break
|
||||
case 5:
|
||||
r = v
|
||||
g = p
|
||||
b = q
|
||||
break
|
||||
}
|
||||
r = Math.round(r * 255)
|
||||
g = Math.round(g * 255)
|
||||
b = Math.round(b * 255)
|
||||
return {
|
||||
r,
|
||||
g,
|
||||
b,
|
||||
rgb: '#' + r.toString(16) + g.toString(16) + b.toString(16)
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
<script lang="ts">
|
||||
import type { IntlString, Asset } from '@hcengineering/platform'
|
||||
import type { AnySvelteComponent, TooltipAlignment } from '../types'
|
||||
import { ComponentType } from 'svelte'
|
||||
|
||||
import Icon from './Icon.svelte'
|
||||
import { tooltip } from '../tooltips'
|
||||
@ -22,7 +23,7 @@
|
||||
export let label: IntlString = '' as IntlString
|
||||
export let labelProps: any = undefined
|
||||
export let direction: TooltipAlignment | undefined = undefined
|
||||
export let icon: Asset | AnySvelteComponent
|
||||
export let icon: Asset | AnySvelteComponent | ComponentType
|
||||
export let iconProps: any | undefined = undefined
|
||||
export let size: 'x-small' | 'small' | 'medium' | 'large'
|
||||
export let action: (ev: MouseEvent) => Promise<void> | void = async () => {}
|
||||
|
@ -17,7 +17,7 @@
|
||||
import { onMount, ComponentType } from 'svelte'
|
||||
import { registerFocus } from '../focus'
|
||||
import { tooltip } from '../tooltips'
|
||||
import type { AnySvelteComponent, ButtonKind, ButtonShape, ButtonSize, LabelAndProps } from '../types'
|
||||
import type { AnySvelteComponent, ButtonKind, ButtonShape, ButtonSize, LabelAndProps, IconSize } from '../types'
|
||||
import Icon from './Icon.svelte'
|
||||
import Label from './Label.svelte'
|
||||
import Spinner from './Spinner.svelte'
|
||||
@ -29,6 +29,8 @@
|
||||
export let shape: ButtonShape = undefined
|
||||
export let icon: Asset | AnySvelteComponent | ComponentType | undefined = undefined
|
||||
export let iconProps: any | undefined = undefined
|
||||
export let iconRight: Asset | AnySvelteComponent | ComponentType | undefined = undefined
|
||||
export let iconRightProps: any | undefined = undefined
|
||||
export let justify: 'left' | 'center' = 'center'
|
||||
export let disabled: boolean = false
|
||||
export let loading: boolean = false
|
||||
@ -45,10 +47,14 @@
|
||||
export let id: string | undefined = undefined
|
||||
export let input: HTMLButtonElement | undefined = undefined
|
||||
export let showTooltip: LabelAndProps | undefined = undefined
|
||||
export let iconSize: IconSize = size === 'inline' ? 'inline' : 'small'
|
||||
export let iconRightSize: IconSize = 'x-small'
|
||||
export let short: boolean = false
|
||||
|
||||
let iconSize: ButtonSize
|
||||
$: iconSize = size === 'inline' ? 'inline' : 'small'
|
||||
$: iconOnly = label === undefined && ($$slots.content === undefined || $$slots.icon !== undefined)
|
||||
// $: iconSize = size === 'inline' ? 'inline' : 'small'
|
||||
$: iconOnly =
|
||||
label === undefined &&
|
||||
($$slots.content === undefined || $$slots.icon !== undefined || $$slots.iconRight !== undefined)
|
||||
|
||||
onMount(() => {
|
||||
if (focus && input) {
|
||||
@ -95,6 +101,7 @@
|
||||
class:selected
|
||||
class:notSelected
|
||||
disabled={disabled || loading}
|
||||
class:short
|
||||
style:width
|
||||
style:height
|
||||
{title}
|
||||
@ -113,7 +120,7 @@
|
||||
{/if}
|
||||
{#if loading}
|
||||
<div class="btn-icon pointer-events-none caption-color spinner" class:resetIconSize>
|
||||
<Spinner size={iconSize} />
|
||||
<Spinner size={iconSize === 'inline' ? 'inline' : 'small'} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if label}
|
||||
@ -121,8 +128,14 @@
|
||||
<Label {label} params={labelParams} />
|
||||
</span>
|
||||
{/if}
|
||||
{#if iconRight}
|
||||
<div class="btn-right-icon pointer-events-none" class:resetIconSize>
|
||||
<Icon bind:icon={iconRight} size={iconRightSize} iconProps={iconRightProps} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if $$slots.icon}<slot name="icon" />{/if}
|
||||
{#if $$slots.content}<slot name="content" />{/if}
|
||||
{#if $$slots.iconRight}<slot name="iconRight" />{/if}
|
||||
</button>
|
||||
|
||||
<style lang="scss">
|
||||
@ -142,9 +155,9 @@
|
||||
}
|
||||
}
|
||||
.medium {
|
||||
height: 1.75rem;
|
||||
height: 2rem;
|
||||
&.only-icon {
|
||||
width: 1.75rem;
|
||||
width: 2rem;
|
||||
}
|
||||
}
|
||||
.large {
|
||||
@ -164,24 +177,33 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
padding: 0 0.5rem;
|
||||
padding: 0 0.625rem;
|
||||
font-weight: 500;
|
||||
min-width: 1.375rem;
|
||||
white-space: nowrap;
|
||||
color: var(--accent-color);
|
||||
color: var(--theme-caption-color);
|
||||
background-color: transparent;
|
||||
border: 1px solid transparent;
|
||||
transition-property: border, background-color, color, box-shadow;
|
||||
transition-duration: 0.15s;
|
||||
|
||||
.btn-icon {
|
||||
color: var(--content-color);
|
||||
color: var(--theme-content-color);
|
||||
transition: color 0.15s;
|
||||
pointer-events: none;
|
||||
}
|
||||
.btn-right-icon {
|
||||
margin-left: 0.5rem;
|
||||
color: var(--theme-halfcontent-color);
|
||||
transition: color 0.15s;
|
||||
pointer-events: none;
|
||||
}
|
||||
&:not(.only-icon) .btn-icon:not(.spinner) {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
&:not(.only-icon) .btn-right-icon {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
&.no-border:not(.only-icon) .btn-icon,
|
||||
&.link-bordered:not(.only-icon) .btn-icon,
|
||||
&.list:not(.only-icon) .btn-icon,
|
||||
@ -189,6 +211,9 @@
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
|
||||
&.short {
|
||||
max-width: 7rem;
|
||||
}
|
||||
&.sh-no-shape {
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
@ -217,25 +242,22 @@
|
||||
}
|
||||
|
||||
&.highlight {
|
||||
box-shadow: inset 0 0 1px 1px var(--primary-bg-color);
|
||||
box-shadow: inset 0 0 1px 1px var(--primary-button-enabled);
|
||||
|
||||
&:hover {
|
||||
box-shadow: inset 0 0 1px 1px var(--primary-bg-hover);
|
||||
box-shadow: inset 0 0 1px 1px var(--primary-button-hovered);
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
color: var(--accent-color);
|
||||
transition-duration: 0;
|
||||
|
||||
.btn-icon {
|
||||
color: var(--caption-color);
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
}
|
||||
&:focus {
|
||||
border-color: var(--primary-edit-border-color) !important;
|
||||
box-shadow: 0 0 0 2px var(--primary-button-focused-border);
|
||||
}
|
||||
&:disabled {
|
||||
color: rgb(var(--caption-color) / 40%);
|
||||
color: var(--theme-dark-color);
|
||||
cursor: not-allowed;
|
||||
|
||||
.btn-icon {
|
||||
@ -254,58 +276,64 @@
|
||||
}
|
||||
|
||||
&.secondary {
|
||||
background-color: var(--button-bg-color);
|
||||
border-color: var(--button-border-color);
|
||||
box-shadow: var(--button-shadow);
|
||||
background-color: var(--theme-button-enabled);
|
||||
border-color: var(--theme-button-border);
|
||||
|
||||
// &.medium:not(.only-icon) {
|
||||
// padding: 0 0.75rem;
|
||||
// }
|
||||
&:hover {
|
||||
background-color: var(--button-bg-hover);
|
||||
border-color: var(--button-border-hover);
|
||||
background-color: var(--theme-button-hovered);
|
||||
}
|
||||
&:active {
|
||||
background-color: var(--theme-button-pressed);
|
||||
}
|
||||
&:focus {
|
||||
background-color: var(--theme-button-focused);
|
||||
}
|
||||
&:disabled {
|
||||
background-color: var(--button-disabled-color);
|
||||
border-color: transparent;
|
||||
background-color: var(--theme-button-disabled);
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background-color: var(--button-bg-hover);
|
||||
border-color: var(--button-border-hover);
|
||||
color: var(--caption-color);
|
||||
|
||||
background-color: var(--theme-button-hovered);
|
||||
.btn-icon {
|
||||
color: var(--accent-color);
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
&.no-border {
|
||||
font-weight: 400;
|
||||
color: var(--accent-color);
|
||||
background-color: var(--noborder-bg-color);
|
||||
color: var(--theme-content-color);
|
||||
background-color: var(--theme-button-enabled);
|
||||
box-shadow: var(--button-shadow);
|
||||
|
||||
&:hover {
|
||||
color: var(--caption-color);
|
||||
background-color: var(--noborder-bg-hover);
|
||||
color: var(--theme-caption-color);
|
||||
background-color: var(--theme-button-hovered);
|
||||
|
||||
.btn-icon {
|
||||
color: var(--caption-color);
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
}
|
||||
&:disabled {
|
||||
color: var(--content-color);
|
||||
background-color: var(--button-disabled-color);
|
||||
color: var(--theme-trans-color);
|
||||
background-color: var(--theme-list-button-color);
|
||||
cursor: default;
|
||||
.btn-icon {
|
||||
color: var(--theme-trans-color);
|
||||
}
|
||||
&:hover {
|
||||
color: var(--content-color);
|
||||
color: var(--theme-trans-color);
|
||||
.btn-icon {
|
||||
color: var(--content-color);
|
||||
color: var(--theme-trans-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&.transparent {
|
||||
&:hover {
|
||||
background-color: var(--highlight-hover);
|
||||
background-color: var(--theme-button-hovered);
|
||||
}
|
||||
&.selected {
|
||||
background-color: var(--highlight-select);
|
||||
@ -317,72 +345,79 @@
|
||||
&.link {
|
||||
padding: 0 0.875rem;
|
||||
&:hover {
|
||||
color: var(--caption-color);
|
||||
background-color: var(--body-color);
|
||||
border-color: var(--divider-color);
|
||||
color: var(--theme-caption-color);
|
||||
background-color: var(--theme-bg-color);
|
||||
border-color: var(--theme-divider-color);
|
||||
.btn-icon {
|
||||
color: var(--content-color);
|
||||
color: var(--theme-content-color);
|
||||
}
|
||||
}
|
||||
&:disabled {
|
||||
color: var(--accent-color);
|
||||
color: var(--theme-dark-color);
|
||||
background-color: transparent;
|
||||
border-color: transparent;
|
||||
cursor: auto;
|
||||
|
||||
.btn-icon {
|
||||
color: var(--content-color);
|
||||
color: var(--theme-content-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
&.link-bordered {
|
||||
padding: 0 0.375rem;
|
||||
color: var(--accent-color);
|
||||
border-color: var(--divider-color);
|
||||
padding: 0 0.5rem;
|
||||
color: var(--theme-content-color);
|
||||
border-color: var(--theme-divider-color);
|
||||
&:hover {
|
||||
color: var(--accent-color);
|
||||
background-color: var(--button-bg-hover);
|
||||
border-color: var(--button-border-hover);
|
||||
color: var(--theme-caption-color);
|
||||
background-color: var(--theme-button-hovered);
|
||||
border-color: var(--theme-list-divider-color);
|
||||
.btn-icon {
|
||||
color: var(--accent-color);
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
&.list {
|
||||
padding: 0 0.625em 0 0.5rem;
|
||||
padding: 0 0.625em;
|
||||
min-height: 1.75rem;
|
||||
color: var(--content-color);
|
||||
background-color: var(--body-color);
|
||||
border: 1px solid var(--divider-color);
|
||||
border-radius: 3rem;
|
||||
transition-property: border, color, background-color;
|
||||
transition-duration: 0.15s;
|
||||
color: var(--theme-halfcontent-color);
|
||||
background-color: var(--theme-list-button-color);
|
||||
border: 1px solid var(--theme-button-border);
|
||||
border-radius: 1.5rem;
|
||||
// transition-property: border, color, background-color;
|
||||
// transition-duration: 0.15s;
|
||||
|
||||
.btn-icon {
|
||||
color: var(--theme-dark-color);
|
||||
}
|
||||
&:hover {
|
||||
color: var(--caption-color);
|
||||
background-color: var(--board-card-bg-color);
|
||||
border-color: var(--button-border-color);
|
||||
color: var(--theme-halfcontent-color);
|
||||
background-color: var(--theme-list-button-color);
|
||||
border-color: var(--theme-button-border);
|
||||
}
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
&.primary {
|
||||
padding: 0 0.75rem;
|
||||
color: var(--white-color);
|
||||
background-color: var(--primary-bg-color);
|
||||
border-color: var(--primary-bg-color);
|
||||
box-shadow: var(--primary-shadow);
|
||||
color: var(--primary-button-color);
|
||||
background-color: var(--primary-button-enabled);
|
||||
border-color: var(--primary-button-border);
|
||||
|
||||
.btn-icon {
|
||||
color: var(--white-color);
|
||||
}
|
||||
&:hover {
|
||||
background-color: var(--primary-bg-hover);
|
||||
background-color: var(--primary-button-hovered);
|
||||
}
|
||||
&:active {
|
||||
background-color: var(--primary-button-pressed);
|
||||
}
|
||||
&:focus {
|
||||
border-color: var(--primary-edit-border-color);
|
||||
background-color: var(--primary-button-focused);
|
||||
}
|
||||
&:disabled {
|
||||
background-color: #5e6ad255;
|
||||
border-color: #5e6ad255;
|
||||
background-color: var(--primary-button-disabled);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
export let checked: boolean = false
|
||||
export let symbol: 'check' | 'minus' = 'check'
|
||||
export let size: 'small' | 'medium' = 'small'
|
||||
export let circle: boolean = false
|
||||
export let primary: boolean = false
|
||||
export let readonly = false
|
||||
@ -34,7 +35,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<label class="checkbox" class:circle class:primary class:readonly class:checked>
|
||||
<label class="checkbox {size}" class:circle class:primary class:readonly class:checked>
|
||||
<input class="chBox" disabled={readonly} type="checkbox" bind:checked on:change={handleValueChanged} />
|
||||
<svg class="checkSVG" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
{#if checked}
|
||||
@ -53,27 +54,32 @@
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 0.875rem;
|
||||
height: 0.875rem;
|
||||
border: 1px solid var(--dark-color);
|
||||
background-color: var(--theme-button-hovered);
|
||||
border: 1px solid var(--theme-checkbox-border);
|
||||
border-radius: 0.25rem;
|
||||
|
||||
&.small {
|
||||
width: 0.875rem;
|
||||
height: 0.875rem;
|
||||
}
|
||||
&.medium {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
&.circle {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
border-radius: 50%;
|
||||
}
|
||||
&.checked {
|
||||
background-color: var(--primary-bg-color);
|
||||
border-color: transparent;
|
||||
background-color: var(--theme-checkbox-bg-color);
|
||||
}
|
||||
&.primary.checked {
|
||||
background-color: var(--primary-bg-color);
|
||||
background-color: var(--primary-button-enabled);
|
||||
border-color: transparent;
|
||||
}
|
||||
&.readonly.checked {
|
||||
background-color: var(--dark-color);
|
||||
border-color: transparent;
|
||||
background-color: var(--theme-checkbox-disabled);
|
||||
}
|
||||
|
||||
.chBox {
|
||||
@ -89,7 +95,7 @@
|
||||
&:checked + .checkSVG {
|
||||
& .check {
|
||||
visibility: visible;
|
||||
fill: var(--white-color);
|
||||
fill: var(--theme-checkbox-color);
|
||||
&.primary {
|
||||
fill: var(--primary-button-color);
|
||||
}
|
||||
@ -99,7 +105,7 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
&:disabled + .checkSVG .check {
|
||||
fill: var(--content-color);
|
||||
fill: var(--theme-checkbox-disabled);
|
||||
}
|
||||
}
|
||||
.checkSVG {
|
||||
@ -108,7 +114,7 @@
|
||||
|
||||
.check {
|
||||
visibility: hidden;
|
||||
fill: var(--button-bg-color);
|
||||
fill: var(--theme-checkbox-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,13 +15,13 @@
|
||||
<script lang="ts">
|
||||
import type { Asset, IntlString } from '@hcengineering/platform'
|
||||
import { translate } from '@hcengineering/platform'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { createEventDispatcher, ComponentType } from 'svelte'
|
||||
import plugin from '../plugin'
|
||||
import type { AnySvelteComponent } from '../types'
|
||||
import Icon from './Icon.svelte'
|
||||
import IconClose from './icons/Close.svelte'
|
||||
|
||||
export let icon: Asset | AnySvelteComponent
|
||||
export let icon: Asset | AnySvelteComponent | ComponentType
|
||||
export let width: string | undefined = undefined
|
||||
export let value: string | undefined = undefined
|
||||
export let placeholder: IntlString = plugin.string.EditBoxPlaceholder
|
||||
@ -65,9 +65,9 @@
|
||||
.editbox {
|
||||
padding: 0 0.5rem 0 0.5rem;
|
||||
min-width: 10rem;
|
||||
color: var(--caption-color);
|
||||
background-color: var(--body-color);
|
||||
border: 1px solid var(--button-border-color);
|
||||
color: var(--theme-caption-color);
|
||||
// background-color: var(--body-color);
|
||||
border: 1px solid transparent;
|
||||
border-radius: 0.25rem;
|
||||
|
||||
&.small {
|
||||
@ -77,9 +77,11 @@
|
||||
height: 2rem;
|
||||
}
|
||||
&:focus-within {
|
||||
border-color: var(--primary-edit-border-color);
|
||||
border-color: var(--theme-button-border);
|
||||
box-shadow: 0 0 0 2px var(--primary-button-focused-border);
|
||||
|
||||
.icon {
|
||||
color: var(--menu-icon-hover);
|
||||
color: var(--theme-dark-color);
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,19 +91,19 @@
|
||||
border-radius: 0.25rem;
|
||||
|
||||
&::placeholder {
|
||||
color: var(--content-color);
|
||||
color: var(--theme-halfcontent-color);
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
color: var(--content-color);
|
||||
color: var(--theme-dark-color);
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
color: var(--caption-color);
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
}
|
||||
.icon {
|
||||
color: var(--content-color);
|
||||
color: var(--theme-dark-color);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -71,8 +71,8 @@
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 1.5rem;
|
||||
background-color: var(--board-bg-color);
|
||||
border: 1px solid var(--accent-bg-color);
|
||||
background-color: var(--theme-list-row-color);
|
||||
border: 1px solid var(--theme-list-divider-color);
|
||||
border-radius: 0.25rem;
|
||||
|
||||
.bar {
|
||||
|
@ -50,14 +50,17 @@
|
||||
closePanel()
|
||||
}
|
||||
|
||||
$: props = $panelstore.panel
|
||||
|
||||
$: if (props !== undefined) {
|
||||
component = undefined
|
||||
|
||||
getResource(props.component).then((r) => {
|
||||
component = r
|
||||
})
|
||||
$: if ($panelstore.panel !== undefined) {
|
||||
if ($panelstore.panel.component === undefined) {
|
||||
props = $panelstore.panel
|
||||
} else {
|
||||
getResource($panelstore.panel.component).then((r) => {
|
||||
component = r
|
||||
props = $panelstore.panel
|
||||
})
|
||||
}
|
||||
} else {
|
||||
props = undefined
|
||||
}
|
||||
|
||||
function escapeClose () {
|
||||
@ -163,7 +166,7 @@
|
||||
background-color: transparent;
|
||||
|
||||
&.bg {
|
||||
background-color: var(--body-color);
|
||||
background-color: var(--theme-back-color);
|
||||
}
|
||||
.panel-container {
|
||||
padding: 0.5rem;
|
||||
|
@ -26,6 +26,7 @@
|
||||
export let autoscroll: boolean = false
|
||||
export let bottomStart: boolean = false
|
||||
export let fade: FadeOptions = defaultSP
|
||||
export let noFade: boolean = false
|
||||
export let invertScroll: boolean = false
|
||||
export let horizontal: boolean = false
|
||||
export let contentDirection: 'vertical' | 'vertical-reverse' | 'horizontal' = 'vertical'
|
||||
@ -33,6 +34,7 @@
|
||||
export let buttons: boolean = false
|
||||
export let shrink: boolean = false
|
||||
export let divScroll: HTMLElement | undefined = undefined
|
||||
export let checkForHeaders = false
|
||||
|
||||
export function scroll (top: number, left?: number, behavior: 'auto' | 'smooth' = 'auto') {
|
||||
if (divScroll) {
|
||||
@ -74,10 +76,13 @@
|
||||
let timerH: number
|
||||
|
||||
const inter = new Set<Element>()
|
||||
let hasLastCategories: boolean = false
|
||||
|
||||
$: fz = $themeOptions.fontSize
|
||||
$: shiftTop = fade.multipler?.top ? fade.multipler?.top * fz : 0
|
||||
$: shiftBottom = fade.multipler?.bottom ? fade.multipler?.bottom * fz : 0
|
||||
$: shiftLeft = fade.multipler?.left ? fade.multipler?.left * fz : 0
|
||||
$: shiftRight = fade.multipler?.right ? fade.multipler?.right * fz : 0
|
||||
$: orientir = contentDirection === 'horizontal' ? 'horizontal' : 'vertical'
|
||||
|
||||
const checkBar = (): void => {
|
||||
@ -85,22 +90,42 @@
|
||||
const trackH = divScroll.clientHeight - shiftTop - shiftBottom - 4
|
||||
const scrollH = divScroll.scrollHeight
|
||||
const proc = scrollH / trackH
|
||||
divBar.style.height = divScroll.clientHeight / proc + 'px'
|
||||
divBar.style.top = divScroll.scrollTop / proc + shiftTop + 2 + 'px'
|
||||
if (mask === 'none') divBar.style.visibility = 'hidden'
|
||||
else {
|
||||
divBar.style.visibility = 'visible'
|
||||
|
||||
const newHeight = divScroll.clientHeight / proc + 'px'
|
||||
if (divBar.style.height !== 'newHeight') {
|
||||
divBar.style.height = newHeight
|
||||
}
|
||||
const newTop = divScroll.scrollTop / proc + shiftTop + 2 + 'px'
|
||||
if (divBar.style.top !== newTop) {
|
||||
divBar.style.top = newTop
|
||||
}
|
||||
if (mask === 'none') {
|
||||
if (divBar.style.visibility !== 'hidden') {
|
||||
divBar.style.visibility = 'hidden'
|
||||
}
|
||||
} else {
|
||||
if (divBar.style.visibility !== 'visible') {
|
||||
divBar.style.visibility = 'visible'
|
||||
}
|
||||
if (divBar) {
|
||||
if (timer) {
|
||||
clearTimeout(timer)
|
||||
divBar.style.opacity = '1'
|
||||
if (divBar.style.opacity !== '1') {
|
||||
divBar.style.opacity = '1'
|
||||
}
|
||||
}
|
||||
timer = setTimeout(() => {
|
||||
if (divBar) divBar.style.opacity = '0'
|
||||
if (divBar) {
|
||||
divBar.style.opacity = '0'
|
||||
}
|
||||
}, 1500)
|
||||
}
|
||||
}
|
||||
if (divScroll.clientHeight >= divScroll.scrollHeight) divBar.style.visibility = 'hidden'
|
||||
if (divScroll.clientHeight >= divScroll.scrollHeight) {
|
||||
if (divBar.style.visibility !== 'hidden') {
|
||||
divBar.style.visibility = 'hidden'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const checkBarH = (): void => {
|
||||
@ -183,7 +208,7 @@
|
||||
}
|
||||
|
||||
const renderFade = () => {
|
||||
if (divScroll) {
|
||||
if (divScroll && !noFade) {
|
||||
const th = shiftTop + (topCrop === 'top' ? 2 * fz - topCropValue : 0)
|
||||
const tf =
|
||||
topCrop === 'full'
|
||||
@ -205,15 +230,24 @@
|
||||
if (divHScroll && horizontal) {
|
||||
const gradientH = `linear-gradient(
|
||||
90deg,
|
||||
rgba(0, 0, 0, 0) 0,
|
||||
rgba(0, 0, 0, 1) ${maskH === 'none' || maskH === 'left' ? '0px' : '2rem'},
|
||||
rgba(0, 0, 0, 1) calc(100% - ${maskH === 'none' || maskH === 'right' ? '0px' : '2rem'}),
|
||||
rgba(0, 0, 0, 0) 100%
|
||||
rgba(0, 0, 0, 1) ${shiftLeft}px,
|
||||
rgba(0, 0, 0, 0) ${shiftLeft}px,
|
||||
rgba(0, 0, 0, 1) ${shiftLeft + (maskH === 'both' || maskH === 'right' ? 2 * fz : 0)}px,
|
||||
rgba(0, 0, 0, 1) calc(100% - ${shiftRight + (maskH === 'both' || maskH === 'left' ? 2 * fz : 0)}px),
|
||||
rgba(0, 0, 0, 0) calc(100% - ${shiftRight}px),
|
||||
rgba(0, 0, 0, 1) calc(100% - ${shiftRight}px)
|
||||
)`
|
||||
divHScroll.style.webkitMaskImage = gradientH
|
||||
}
|
||||
}
|
||||
|
||||
let checkBarTimeout: any | undefined = undefined
|
||||
|
||||
const delayCall = (op: () => void) => {
|
||||
clearTimeout(checkBarTimeout)
|
||||
checkBarTimeout = setTimeout(op, 50)
|
||||
}
|
||||
|
||||
const checkFade = (): void => {
|
||||
if (divScroll) {
|
||||
beforeContent = divScroll.scrollTop
|
||||
@ -234,8 +268,8 @@
|
||||
if (inter.size) checkIntersectionFade()
|
||||
renderFade()
|
||||
}
|
||||
if (!isScrolling) checkBar()
|
||||
if (!isScrolling && horizontal) checkBarH()
|
||||
if (!isScrolling) delayCall(checkBar)
|
||||
if (!isScrolling && horizontal) delayCall(checkBarH)
|
||||
}
|
||||
|
||||
function checkAutoScroll () {
|
||||
@ -252,17 +286,47 @@
|
||||
|
||||
const checkIntersection = (entries: IntersectionObserverEntry[], observer: IntersectionObserver) => {
|
||||
const interArr: Element[] = []
|
||||
const catEntries: IntersectionObserverEntry[] = []
|
||||
const lastCatEntries: IntersectionObserverEntry[] = []
|
||||
|
||||
entries.forEach((el) => {
|
||||
if (el.isIntersecting) {
|
||||
if (el.isIntersecting && el.target.classList.contains('categoryHeader')) {
|
||||
inter.add(el.target)
|
||||
interArr.push(el.target)
|
||||
} else inter.delete(el.target)
|
||||
if (hasLastCategories) {
|
||||
if (el.isIntersecting && el.target.classList.contains('categoryHeader')) catEntries.push(el)
|
||||
if (el.isIntersecting && el.target.classList.contains('lastCat')) lastCatEntries.push(el)
|
||||
}
|
||||
})
|
||||
|
||||
if (interArr.length > 0) {
|
||||
dispatch('lastScrolledCategory', interArr[interArr.length - 1]?.getAttribute('id'))
|
||||
dispatch('firstScrolledCategory', interArr[0]?.getAttribute('id'))
|
||||
const interCats: string[] = interArr.map((it) => it.getAttribute('id') as string)
|
||||
dispatch('scrolledCategories', interCats)
|
||||
}
|
||||
if (hasLastCategories) {
|
||||
const targets = new Set<Element>()
|
||||
const closed = new Set<Element>()
|
||||
lastCatEntries.forEach((last) => {
|
||||
catEntries.forEach((cat) => {
|
||||
if (last.target !== cat.target) {
|
||||
if (
|
||||
last.boundingClientRect.top < cat.boundingClientRect.top + 8 &&
|
||||
last.boundingClientRect.top >= cat.boundingClientRect.top
|
||||
) {
|
||||
targets.add(cat.target)
|
||||
}
|
||||
if (cat.target.classList.contains('closed') && !closed.has(cat.target)) closed.add(cat.target)
|
||||
}
|
||||
})
|
||||
})
|
||||
closed.forEach((el) => {
|
||||
if (!targets.has(el)) el.classList.remove('closed')
|
||||
})
|
||||
targets.forEach((el) => el.classList.add('closed'))
|
||||
}
|
||||
}
|
||||
|
||||
const checkIntersectionFade = () => {
|
||||
@ -300,8 +364,8 @@
|
||||
if (divScroll && divBox) {
|
||||
divScroll.addEventListener('wheel', wheelEvent)
|
||||
divScroll.addEventListener('scroll', checkFade)
|
||||
checkBar()
|
||||
if (horizontal) checkBarH()
|
||||
delayCall(checkBar)
|
||||
if (horizontal) delayCall(checkBarH)
|
||||
}
|
||||
})
|
||||
onDestroy(() => {
|
||||
@ -313,26 +377,46 @@
|
||||
})
|
||||
|
||||
let oldTop: number
|
||||
beforeUpdate(() => {
|
||||
if (divBox && divScroll) oldTop = divScroll.scrollTop
|
||||
})
|
||||
afterUpdate(() => {
|
||||
if (divBox && divScroll) {
|
||||
if (oldTop !== divScroll.scrollTop) divScroll.scrollTop = oldTop
|
||||
|
||||
const tempEls = divBox.querySelectorAll('.categoryHeader')
|
||||
observer = new IntersectionObserver(checkIntersection, { root: null, rootMargin: '0px', threshold: 0.1 })
|
||||
tempEls.forEach((el) => observer.observe(el))
|
||||
}
|
||||
})
|
||||
if (checkForHeaders) {
|
||||
beforeUpdate(() => {
|
||||
if (divBox && divScroll) {
|
||||
oldTop = divScroll.scrollTop
|
||||
}
|
||||
})
|
||||
|
||||
afterUpdate(() => {
|
||||
if (divBox && divScroll) {
|
||||
if (oldTop !== divScroll.scrollTop) {
|
||||
divScroll.scrollTop = oldTop
|
||||
}
|
||||
|
||||
delayCall(() => {
|
||||
const tempEls = divBox.querySelectorAll('.categoryHeader')
|
||||
observer = new IntersectionObserver(checkIntersection, { root: null, rootMargin: '0px', threshold: 0.1 })
|
||||
tempEls.forEach((el) => observer.observe(el))
|
||||
const tempCats = divBox.querySelectorAll('.lastCat')
|
||||
if (tempCats.length > 0) {
|
||||
hasLastCategories = true
|
||||
tempCats.forEach((el) => observer.observe(el))
|
||||
} else {
|
||||
hasLastCategories = false
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
let divHeight: number
|
||||
const _resize = (): void => checkFade()
|
||||
|
||||
const tapScroll = (n: number, dir: 'up' | 'down') => {
|
||||
if (divScroll) {
|
||||
if (orientir === 'horizontal') divScroll.scrollBy({ top: 0, left: dir === 'up' ? -n : n, behavior: 'smooth' })
|
||||
else divScroll.scrollBy({ top: dir === 'up' ? -n : n, left: 0, behavior: 'smooth' })
|
||||
if (orientir === 'horizontal') {
|
||||
divScroll.scrollBy({ top: 0, left: dir === 'up' ? -n : n, behavior: 'smooth' })
|
||||
} else {
|
||||
divScroll.scrollBy({ top: dir === 'up' ? -n : n, left: 0, behavior: 'smooth' })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -549,6 +633,7 @@
|
||||
height: 100%;
|
||||
}
|
||||
.scroll {
|
||||
will-change: opacity;
|
||||
flex-grow: 1;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
|
@ -12,7 +12,6 @@
|
||||
|
||||
<EditWithIcon
|
||||
icon={IconSearch}
|
||||
size={'small'}
|
||||
width={'12rem'}
|
||||
placeholder={plugin.string.Search}
|
||||
bind:value={_search}
|
||||
|
@ -78,9 +78,9 @@
|
||||
|
||||
word-wrap: none;
|
||||
font-size: 0.75rem;
|
||||
color: var(--caption-color);
|
||||
background: var(--popup-bg-color);
|
||||
border: 0.5px solid var(--popup-divider);
|
||||
color: var(--theme-caption-color);
|
||||
background: var(--theme-list-row-color);
|
||||
border: 0.5px solid var(--theme-list-divider-color);
|
||||
box-shadow: 0px 8px 15px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 2.5rem;
|
||||
// z-index: 1;
|
||||
@ -92,7 +92,7 @@
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
&:hover {
|
||||
background: var(--popup-bg-hover);
|
||||
background: var(--theme-list-button-color);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -22,7 +22,7 @@
|
||||
.container {
|
||||
user-select: none;
|
||||
font-size: 14px;
|
||||
color: var(--content-color);
|
||||
color: var(--theme-content-color);
|
||||
&.WARNING {
|
||||
color: yellow;
|
||||
}
|
||||
|
@ -72,14 +72,14 @@
|
||||
padding: 0;
|
||||
min-width: 3rem;
|
||||
height: 3.25rem;
|
||||
background-color: var(--accent-bg-color);
|
||||
border: 1px solid var(--button-border-color);
|
||||
background-color: var(--theme-button-enabled);
|
||||
border: 1px solid var(--theme-button-border);
|
||||
border-radius: 0.75rem;
|
||||
caret-color: var(--caret-color);
|
||||
|
||||
&:focus-within {
|
||||
background-color: var(--body-accent);
|
||||
border-color: var(--button-border-hover);
|
||||
background-color: var(--theme-button-focused);
|
||||
border-color: var(--theme-list-divider-color);
|
||||
}
|
||||
input {
|
||||
height: 3.25rem;
|
||||
@ -98,7 +98,7 @@
|
||||
top: 1rem;
|
||||
left: 1.25rem;
|
||||
font-size: 0.75rem;
|
||||
color: var(--caption-color);
|
||||
color: var(--theme-caption-color);
|
||||
opacity: 0.3;
|
||||
transition: top 200ms;
|
||||
pointer-events: none;
|
||||
|
@ -15,7 +15,7 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { tooltip } from '../tooltips'
|
||||
import type { TabItem } from '../types'
|
||||
import type { TabItem, IconSize } from '../types'
|
||||
import Icon from './Icon.svelte'
|
||||
import Label from './Label.svelte'
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
export let multiselect: boolean = false
|
||||
export let items: TabItem[]
|
||||
export let kind: 'normal' | 'secondary' = 'normal'
|
||||
export let short: boolean = false
|
||||
export let onlyIcons: boolean = false
|
||||
export let size: 'small' | 'medium' = 'medium'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
@ -38,6 +38,9 @@
|
||||
return res
|
||||
}
|
||||
const tabs: HTMLElement[] = []
|
||||
|
||||
let iconSize: IconSize
|
||||
$: iconSize = onlyIcons ? (size === 'small' ? 'small' : 'medium') : size === 'small' ? 'x-small' : 'small'
|
||||
</script>
|
||||
|
||||
{#if items.length > 0}
|
||||
@ -47,9 +50,10 @@
|
||||
<div
|
||||
bind:this={tabs[i]}
|
||||
class="button"
|
||||
class:short
|
||||
class:onlyIcons
|
||||
class:selected={getSelected(item.id)}
|
||||
data-view={item.tooltip}
|
||||
data-id={`tab-${item.id}`}
|
||||
use:tooltip={{ label: item.tooltip ?? undefined, element: tabs[i] ?? undefined }}
|
||||
on:click={() => {
|
||||
if (multiselect) {
|
||||
@ -64,7 +68,7 @@
|
||||
>
|
||||
{#if item.icon}
|
||||
<div class="icon">
|
||||
<Icon icon={item.icon} size={size === 'small' ? 'x-small' : 'small'} fill={item.color ?? 'currentColor'} />
|
||||
<Icon icon={item.icon} size={iconSize} fill={item.color ?? 'currentColor'} />
|
||||
</div>
|
||||
{:else if item.color}
|
||||
<div class="color" style:background-color={item.color} />
|
||||
@ -110,10 +114,11 @@
|
||||
}
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: 0.35rem;
|
||||
top: 50%;
|
||||
left: -1.5px;
|
||||
height: 0.8rem;
|
||||
height: 70%;
|
||||
border-left: 1px solid var(--button-border-color);
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
.button:not(.selected) + .button:not(.selected)::before {
|
||||
@ -123,6 +128,10 @@
|
||||
&.small {
|
||||
.button {
|
||||
padding: 0 0.5rem;
|
||||
|
||||
&.onlyIcons {
|
||||
padding: 0.375rem;
|
||||
}
|
||||
}
|
||||
&.normal .button {
|
||||
height: 1.5rem;
|
||||
@ -132,29 +141,30 @@
|
||||
}
|
||||
}
|
||||
&.medium .button {
|
||||
height: 1.75rem;
|
||||
height: 2rem;
|
||||
padding: 0.25rem 0.75rem;
|
||||
&.short {
|
||||
padding: 0.5rem;
|
||||
|
||||
&.onlyIcons {
|
||||
padding: 0.375rem;
|
||||
}
|
||||
}
|
||||
&.normal {
|
||||
background-color: var(--accent-bg-color);
|
||||
border-radius: 0.5rem;
|
||||
background-color: var(--theme-tablist-color);
|
||||
border-radius: 0.25rem;
|
||||
|
||||
.button {
|
||||
background-color: var(--accent-bg-color);
|
||||
color: var(--theme-trans-color);
|
||||
border: 1px solid transparent;
|
||||
border-radius: calc(0.5rem - 1px);
|
||||
border-radius: 0.25rem;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--button-bg-hover);
|
||||
}
|
||||
&.selected {
|
||||
color: var(--caption-color);
|
||||
background-color: var(--button-bg-color);
|
||||
border-color: var(--button-border-color);
|
||||
box-shadow: var(--accent-shadow);
|
||||
color: var(--theme-caption-color);
|
||||
background-color: var(--theme-button-enabled);
|
||||
border-color: var(--theme-button-border);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--theme-button-hovered);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,17 @@
|
||||
|
||||
let time: string = ''
|
||||
|
||||
function calculateMonthsPassed (now: number, value: number): number {
|
||||
const startDate: Date = new Date(value)
|
||||
const endDate: Date = new Date(now)
|
||||
const startYear = startDate.getFullYear()
|
||||
const startMonth = startDate.getMonth()
|
||||
const endYear = endDate.getFullYear()
|
||||
const endMonth = endDate.getMonth()
|
||||
|
||||
return (endYear - startYear) * 12 + (endMonth - startMonth)
|
||||
}
|
||||
|
||||
async function formatTime (now: number, value: number) {
|
||||
let passed = now - value
|
||||
if (passed < 0) passed = 0
|
||||
@ -42,7 +53,7 @@
|
||||
} else if (passed < MONTH) {
|
||||
time = await translate(ui.string.Days, { days: Math.floor(passed / DAY) })
|
||||
} else if (passed < YEAR) {
|
||||
time = await translate(ui.string.Months, { months: Math.floor(passed / MONTH) })
|
||||
time = await translate(ui.string.Months, { months: calculateMonthsPassed(now, value) })
|
||||
} else {
|
||||
time = await translate(ui.string.Years, { years: Math.floor(passed / YEAR) })
|
||||
}
|
||||
|
@ -13,21 +13,22 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import { afterUpdate, createEventDispatcher } from 'svelte'
|
||||
import ui from '../../plugin'
|
||||
import ActionIcon from '../ActionIcon.svelte'
|
||||
import Button from '../Button.svelte'
|
||||
import Icon from '../Icon.svelte'
|
||||
import IconClose from '../icons/Close.svelte'
|
||||
import Label from '../Label.svelte'
|
||||
import { daysInMonth } from './internal/DateUtils'
|
||||
import IconClose from '../icons/Close.svelte'
|
||||
import MonthSquare from './MonthSquare.svelte'
|
||||
import { daysInMonth } from './internal/DateUtils'
|
||||
|
||||
export let currentDate: Date | null
|
||||
export let withTime: boolean = false
|
||||
export let mondayStart: boolean = true
|
||||
export let label = currentDate != null ? ui.string.EditDueDate : ui.string.AddDueDate
|
||||
export let detail = ui.string.IssueNeedsToBeCompletedByThisDate
|
||||
export let detail: IntlString | undefined = undefined
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@ -242,8 +243,10 @@
|
||||
<div class="content">
|
||||
<div class="label">
|
||||
<span class="bold"><Label {label} /></span>
|
||||
<span class="divider">-</span>
|
||||
<Label label={detail} />
|
||||
{#if detail}
|
||||
<span class="divider">-</span>
|
||||
<Label label={detail} />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="datetime-input">
|
||||
|
@ -16,15 +16,16 @@
|
||||
import type { IntlString } from '@hcengineering/platform'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
import { DateRangeMode } from '@hcengineering/core'
|
||||
import ui from '../../plugin'
|
||||
import { showPopup } from '../../popups'
|
||||
import { ButtonKind, ButtonSize } from '../../types'
|
||||
import Icon from '../Icon.svelte'
|
||||
import Label from '../Label.svelte'
|
||||
import DatePopup from './DatePopup.svelte'
|
||||
import DPCalendar from './icons/DPCalendar.svelte'
|
||||
import DPCalendarOver from './icons/DPCalendarOver.svelte'
|
||||
import { getMonthName } from './internal/DateUtils'
|
||||
import DatePopup from './DatePopup.svelte'
|
||||
import { DateRangeMode } from '@hcengineering/core'
|
||||
|
||||
export let value: number | null | undefined
|
||||
export let mode: DateRangeMode = DateRangeMode.DATE
|
||||
@ -35,10 +36,10 @@
|
||||
export let labelNull: IntlString = ui.string.NoDate
|
||||
export let showIcon = true
|
||||
export let shouldShowLabel: boolean = true
|
||||
export let size: 'x-small' | 'small' = 'small'
|
||||
export let kind: 'transparent' | 'primary' | 'link' | 'list' = 'primary'
|
||||
export let size: ButtonSize | 'x-small' = 'small'
|
||||
export let kind: ButtonKind = 'link'
|
||||
export let label = ui.string.DueDate
|
||||
export let detail = ui.string.IssueNeedsToBeCompletedByThisDate
|
||||
export let detail = ui.string.NeedsToBeCompletedByThisDate
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@ -64,14 +65,14 @@
|
||||
</script>
|
||||
|
||||
<button
|
||||
class="datetime-button {kind}"
|
||||
class="datetime-button {kind} {size}"
|
||||
class:editable
|
||||
class:dateTimeButtonNoLabel={!shouldShowLabel}
|
||||
class:h-6={size === 'small'}
|
||||
class:h-3={size === 'x-small'}
|
||||
class:text-xs={size === 'x-small'}
|
||||
on:click={() => {
|
||||
on:click={(e) => {
|
||||
if (editable && !opened) {
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
opened = true
|
||||
showPopup(
|
||||
DatePopup,
|
||||
@ -122,10 +123,22 @@
|
||||
font-weight: 400;
|
||||
width: auto;
|
||||
white-space: nowrap;
|
||||
color: var(--accent-color);
|
||||
|
||||
color: var(--theme-content-color);
|
||||
cursor: default;
|
||||
|
||||
&.x-small {
|
||||
height: 0.75rem;
|
||||
}
|
||||
&.small {
|
||||
height: 1.5rem;
|
||||
}
|
||||
&.medium {
|
||||
height: 2rem;
|
||||
}
|
||||
&.large {
|
||||
height: 2.25rem;
|
||||
}
|
||||
|
||||
&.primary {
|
||||
padding: 0 0.5rem;
|
||||
min-width: 1.5rem;
|
||||
@ -251,6 +264,40 @@
|
||||
border-color: var(--button-border-color);
|
||||
}
|
||||
}
|
||||
&.link-bordered {
|
||||
padding: 0 0.375rem;
|
||||
color: var(--accent-color);
|
||||
border-color: var(--divider-color);
|
||||
&:hover {
|
||||
color: var(--accent-color);
|
||||
background-color: var(--button-bg-hover);
|
||||
border-color: var(--button-border-hover);
|
||||
.btn-icon {
|
||||
color: var(--accent-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
&.secondary {
|
||||
padding: 0 0.625rem;
|
||||
color: var(--theme-caption-color);
|
||||
background-color: var(--theme-button-enabled);
|
||||
border-color: var(--theme-button-border);
|
||||
border-radius: 0.25rem;
|
||||
|
||||
.btn-icon {
|
||||
color: var(--theme-content-color);
|
||||
}
|
||||
&:hover {
|
||||
background-color: var(--theme-button-hovered);
|
||||
border-color: var(--theme-divider-color);
|
||||
.btn-icon {
|
||||
color: var(--theme-content-color);
|
||||
}
|
||||
}
|
||||
// &.edit {
|
||||
// padding: 0 0.5rem;
|
||||
// }
|
||||
}
|
||||
|
||||
.time-divider {
|
||||
flex-shrink: 0;
|
||||
|
@ -32,7 +32,8 @@
|
||||
export let icon: 'normal' | 'warning' | 'overdue' = 'normal'
|
||||
export let labelOver: IntlString | undefined = undefined // label instead of date
|
||||
export let labelNull: IntlString = ui.string.NoDate
|
||||
export let kind: 'no-border' | 'link' = 'no-border'
|
||||
export let kind: 'no-border' | 'link' | 'secondary' = 'no-border'
|
||||
export let size: 'small' | 'medium' | 'large' = 'small'
|
||||
export let noShift: boolean = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
@ -315,7 +316,7 @@
|
||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||
<button
|
||||
bind:this={datePresenter}
|
||||
class="datetime-button {kind}"
|
||||
class="datetime-button {kind} {size}"
|
||||
class:editable
|
||||
class:edit
|
||||
on:click={() => {
|
||||
@ -455,17 +456,26 @@
|
||||
padding: 0 0.5rem;
|
||||
font-weight: 400;
|
||||
min-width: 1.5rem;
|
||||
width: auto;
|
||||
height: 1.5rem;
|
||||
width: min-content;
|
||||
white-space: nowrap;
|
||||
line-height: 1.5rem;
|
||||
color: var(--accent-color);
|
||||
color: var(--theme-content-color);
|
||||
border: 1px solid transparent;
|
||||
border-radius: 0.25rem;
|
||||
transition-property: border, background-color, color, box-shadow;
|
||||
transition-duration: 0.15s;
|
||||
cursor: pointer;
|
||||
|
||||
&.small {
|
||||
height: 1.5rem;
|
||||
}
|
||||
&.medium {
|
||||
height: 2rem;
|
||||
}
|
||||
&.large {
|
||||
height: 2.25rem;
|
||||
}
|
||||
|
||||
.btn-icon {
|
||||
margin-right: 0.375rem;
|
||||
width: 0.875rem;
|
||||
@ -474,7 +484,7 @@
|
||||
pointer-events: none;
|
||||
|
||||
&.normal {
|
||||
color: var(--content-color);
|
||||
color: var(--theme-content-color);
|
||||
}
|
||||
&.warning {
|
||||
color: var(--warning-color);
|
||||
@ -486,27 +496,31 @@
|
||||
|
||||
&.no-border {
|
||||
font-weight: 400;
|
||||
color: var(--accent-color);
|
||||
background-color: var(--noborder-bg-color);
|
||||
color: var(--theme-content-color);
|
||||
background-color: var(--theme-button-enabled);
|
||||
box-shadow: var(--button-shadow);
|
||||
|
||||
&:hover {
|
||||
color: var(--caption-color);
|
||||
background-color: var(--noborder-bg-hover);
|
||||
color: var(--theme-caption-color);
|
||||
background-color: var(--theme-button-hovered);
|
||||
transition-duration: 0;
|
||||
|
||||
.btn-icon {
|
||||
color: var(--caption-color);
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
}
|
||||
&:disabled {
|
||||
color: var(--content-color);
|
||||
background-color: var(--button-disabled-color);
|
||||
color: var(--theme-trans-color);
|
||||
background-color: var(--theme-button-disabled);
|
||||
cursor: default;
|
||||
|
||||
.btn-icon {
|
||||
color: var(--theme-trans-color);
|
||||
}
|
||||
&:hover {
|
||||
color: var(--content-color);
|
||||
color: var(--theme-trans-color);
|
||||
.btn-icon {
|
||||
color: var(--content-color);
|
||||
color: var(--theme-trans-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -515,7 +529,7 @@
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--noborder-bg-hover);
|
||||
background-color: var(--theme-button-hovered);
|
||||
.btn-icon {
|
||||
&.normal {
|
||||
color: var(--caption-color);
|
||||
@ -528,14 +542,14 @@
|
||||
}
|
||||
}
|
||||
.time-divider {
|
||||
background-color: var(--button-border-hover);
|
||||
background-color: var(--theme-divider-color);
|
||||
}
|
||||
}
|
||||
&:focus-within {
|
||||
background-color: var(--button-bg-color);
|
||||
background-color: var(--theme-button-focused);
|
||||
border-color: var(--primary-edit-border-color);
|
||||
&:hover {
|
||||
background-color: var(--button-bg-color);
|
||||
background-color: var(--theme-button-hovered);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -553,13 +567,12 @@
|
||||
&.link {
|
||||
padding: 0 0.875rem;
|
||||
width: 100%;
|
||||
height: 2.25rem;
|
||||
color: var(--caption-color);
|
||||
color: var(--theme-caption-color);
|
||||
&:hover {
|
||||
background-color: var(--body-color);
|
||||
border-color: var(--divider-color);
|
||||
background-color: var(--theme-bg-color);
|
||||
border-color: var(--theme-divider-color);
|
||||
.btn-icon {
|
||||
color: var(--content-color);
|
||||
color: var(--theme-content-color);
|
||||
}
|
||||
}
|
||||
&.edit {
|
||||
@ -567,6 +580,27 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.secondary {
|
||||
padding: 0 0.625rem;
|
||||
color: var(--theme-caption-color);
|
||||
background-color: var(--theme-button-enabled);
|
||||
border-color: var(--theme-button-border);
|
||||
|
||||
.btn-icon {
|
||||
color: var(--theme-content-color);
|
||||
}
|
||||
&:hover {
|
||||
background-color: var(--theme-button-hovered);
|
||||
border-color: var(--theme-divider-color);
|
||||
.btn-icon {
|
||||
color: var(--theme-content-color);
|
||||
}
|
||||
}
|
||||
// &.edit {
|
||||
// padding: 0 0.5rem;
|
||||
// }
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@ -574,15 +608,15 @@
|
||||
margin: 0 0.25rem;
|
||||
width: 0.75rem;
|
||||
height: 0.75rem;
|
||||
color: var(--content-color);
|
||||
background-color: var(--button-bg-color);
|
||||
color: var(--theme-content-color);
|
||||
background-color: var(--theme-button-enabled);
|
||||
outline: none;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: var(--accent-color);
|
||||
background-color: var(--button-bg-hover);
|
||||
background-color: var(--theme-button-hovered);
|
||||
}
|
||||
}
|
||||
|
||||
@ -614,7 +648,7 @@
|
||||
width: 1px;
|
||||
min-width: 1px;
|
||||
height: 0.75rem;
|
||||
background-color: var(--button-border-color);
|
||||
background-color: var(--theme-divider-color);
|
||||
}
|
||||
.separator {
|
||||
margin: 0 0.1rem;
|
||||
|
@ -13,8 +13,11 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Icon, Label, IconDPCalendarOver, IconDPCalendar } from '@hcengineering/ui'
|
||||
import tracker from '../plugin'
|
||||
import DPCalendar from './icons/DPCalendar.svelte'
|
||||
import DPCalendarOver from './icons/DPCalendarOver.svelte'
|
||||
import ui from '../../plugin'
|
||||
import Icon from '../Icon.svelte'
|
||||
import Label from '../Label.svelte'
|
||||
|
||||
export let formattedDate: string = ''
|
||||
export let daysDifference: number = 0
|
||||
@ -29,18 +32,18 @@
|
||||
class:mIconContainerWarning={iconModifier === 'warning'}
|
||||
class:mIconContainerCritical={iconModifier === 'critical' || iconModifier === 'overdue'}
|
||||
>
|
||||
<Icon icon={isOverdue ? IconDPCalendarOver : IconDPCalendar} size={'small'} />
|
||||
<Icon icon={isOverdue ? DPCalendarOver : DPCalendar} size={'small'} />
|
||||
</div>
|
||||
<div class="messageContainer">
|
||||
<div class="title">
|
||||
<Label
|
||||
label={isOverdue ? tracker.string.DueDatePopupOverdueTitle : tracker.string.DueDatePopupTitle}
|
||||
label={isOverdue ? ui.string.DueDatePopupOverdueTitle : ui.string.DueDatePopupTitle}
|
||||
params={{ value: formattedDate }}
|
||||
/>
|
||||
</div>
|
||||
<div class="description">
|
||||
<Label
|
||||
label={isOverdue ? tracker.string.DueDatePopupOverdueDescription : tracker.string.DueDatePopupDescription}
|
||||
label={isOverdue ? ui.string.DueDatePopupOverdueDescription : ui.string.DueDatePopupDescription}
|
||||
params={{ value: daysDifference }}
|
||||
/>
|
||||
</div>
|
89
packages/ui/src/components/calendar/DueDatePresenter.svelte
Normal file
89
packages/ui/src/components/calendar/DueDatePresenter.svelte
Normal file
@ -0,0 +1,89 @@
|
||||
<!--
|
||||
// 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 { Timestamp } from '@hcengineering/core'
|
||||
import DueDatePopup from './DueDatePopup.svelte'
|
||||
import { tooltip } from '../../tooltips'
|
||||
import DatePresenter from './DatePresenter.svelte'
|
||||
import { getDaysDifference } from './internal/DateUtils'
|
||||
import { ButtonKind } from '../../types'
|
||||
|
||||
export let value: number | null = null
|
||||
export let shouldRender: boolean = true
|
||||
export let onChange: (newDate: number | null) => void
|
||||
export let kind: ButtonKind = 'link'
|
||||
export let editable: boolean = true
|
||||
|
||||
const today = new Date(new Date(Date.now()).setHours(0, 0, 0, 0))
|
||||
$: isOverdue = value !== null && value < today.getTime()
|
||||
$: dueDate = value === null ? null : new Date(value)
|
||||
$: daysDifference = dueDate === null ? null : getDaysDifference(today, dueDate)
|
||||
$: iconModifier = getDueDateIconModifier(isOverdue, daysDifference)
|
||||
let formattedDate = getFormattedDate(value)
|
||||
$: formattedDate = getFormattedDate(value)
|
||||
|
||||
function getFormattedDate (value: number | null): string {
|
||||
return !value ? '' : new Date(value).toLocaleString('default', { month: 'short', day: 'numeric' })
|
||||
}
|
||||
|
||||
const handleDueDateChanged = async (event: CustomEvent<Timestamp>) => {
|
||||
const newDate = event.detail
|
||||
|
||||
if (newDate === undefined || value === newDate || !editable) {
|
||||
return
|
||||
}
|
||||
|
||||
onChange(newDate)
|
||||
}
|
||||
|
||||
const WARNING_DAYS = 7
|
||||
|
||||
const getDueDateIconModifier = (
|
||||
isOverdue: boolean,
|
||||
daysDifference: number | null
|
||||
): 'overdue' | 'critical' | 'warning' | undefined => {
|
||||
if (isOverdue) {
|
||||
return 'overdue'
|
||||
}
|
||||
|
||||
if (daysDifference === 0) {
|
||||
return 'critical'
|
||||
}
|
||||
|
||||
if (daysDifference !== null && daysDifference <= WARNING_DAYS) {
|
||||
return 'warning'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if shouldRender}
|
||||
<div
|
||||
class="clear-mins"
|
||||
use:tooltip={formattedDate
|
||||
? {
|
||||
direction: 'top',
|
||||
component: DueDatePopup,
|
||||
props: {
|
||||
formattedDate,
|
||||
daysDifference,
|
||||
isOverdue,
|
||||
iconModifier
|
||||
}
|
||||
}
|
||||
: undefined}
|
||||
>
|
||||
<DatePresenter {value} {editable} icon={iconModifier} {kind} on:change={handleDueDateChanged} />
|
||||
</div>
|
||||
{/if}
|
@ -87,9 +87,6 @@
|
||||
grid-auto-columns: max-content;
|
||||
grid-template-columns: repeat(7, minmax(0, 1fr));
|
||||
}
|
||||
.weekend {
|
||||
background-color: var(--button-bg-color);
|
||||
}
|
||||
.cell {
|
||||
height: calc(100% - 5px);
|
||||
width: calc(100% - 5px);
|
||||
@ -98,10 +95,16 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
.cell:hover {
|
||||
background-color: var(--toggle-bg-hover);
|
||||
color: var(--primary-button-color);
|
||||
background-color: var(--highlight-hover);
|
||||
}
|
||||
.weekend {
|
||||
background-color: var(--highlight-select);
|
||||
&:hover {
|
||||
background-color: var(--highlight-select-hover);
|
||||
}
|
||||
}
|
||||
.wrongMonth {
|
||||
color: var(--grayscale-grey-03);
|
||||
color: var(--theme-trans-color);
|
||||
}
|
||||
</style>
|
||||
|
@ -43,6 +43,7 @@
|
||||
{#each [...Array(displayedDaysCount).keys()] as dayOfWeek}
|
||||
{@const day = getDay(weekMonday, dayOfWeek)}
|
||||
<th>
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
class="antiTable-cells cursor-pointer uppercase flex-col-center"
|
||||
class:today={areDatesEqual(todayDate, day)}
|
||||
@ -88,7 +89,7 @@
|
||||
width: 5rem;
|
||||
}
|
||||
.today {
|
||||
color: var(--caption-color);
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
.calendar-td {
|
||||
padding: 0;
|
||||
@ -99,7 +100,7 @@
|
||||
width: calc(calc(100% - 50px) / 7);
|
||||
}
|
||||
.cell:hover:not(.wrongMonth) {
|
||||
background-color: var(--toggle-bg-hover);
|
||||
color: var(--primary-button-color);
|
||||
background-color: var(--highlight-hover);
|
||||
}
|
||||
</style>
|
||||
|
@ -37,8 +37,8 @@
|
||||
|
||||
<div class="year-erp-calendar">
|
||||
{#each [...Array(12).keys()] as m}
|
||||
<div class="antiComponentBox flex-grow flex-wrap" style={`min-width: ${minWidth};`}>
|
||||
{getMonthName(month(currentDate, m))}
|
||||
<div class="antiComponentBox flex-col flex-grow flex-wrap" style={`min-width: ${minWidth};`}>
|
||||
<span class="month-caption">{getMonthName(month(currentDate, m))}</span>
|
||||
<MonthCalendar
|
||||
{cellHeight}
|
||||
weekFormat="narrow"
|
||||
@ -63,4 +63,11 @@
|
||||
column-gap: 1rem;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.month-caption {
|
||||
margin: 0.5rem 0.75rem 0.75rem;
|
||||
font-weight: 500;
|
||||
font-size: 0.8125rem;
|
||||
text-transform: uppercase;
|
||||
color: var(--theme-dark-color);
|
||||
}
|
||||
</style>
|
||||
|
@ -20,6 +20,6 @@
|
||||
|
||||
<svg class="svg-{size}" {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M12.6429 7.69048L8.92925 11.4041C7.48164 12.8517 5.34347 13.0101 4.16667 11.8333C2.98733 10.654 3.14447 8.52219 4.59216 7.07451L8.00206 3.66461C8.93557 2.73109 10.2976 2.63095 11.0333 3.36667C11.7681 4.10139 11.6658 5.4675 10.7361 6.39727L7.32363 9.8097C6.90202 10.2313 6.32171 10.2741 6.02381 9.97619C5.72651 9.6789 5.76949 9.09718 6.1989 8.66776L9.29048 5.57619C9.56662 5.30005 9.56662 4.85233 9.29048 4.57619C9.01433 4.30005 8.56662 4.30005 8.29048 4.57619L5.1989 7.66776C4.24737 8.6193 4.13865 10.091 5.02381 10.9762C5.9095 11.8619 7.37984 11.7535 8.32363 10.8097L11.7361 7.39727C13.1876 5.94573 13.3564 3.68975 12.0333 2.36667C10.7099 1.04326 8.45782 1.20884 7.00206 2.66461L3.59216 6.07451C1.62229 8.04437 1.39955 11.0662 3.16667 12.8333C4.93146 14.5981 7.9596 14.3737 9.92925 12.4041L13.6429 8.69048C13.919 8.41433 13.919 7.96662 13.6429 7.69048C13.3667 7.41433 12.919 7.41433 12.6429 7.69048Z"
|
||||
d="M3,8.5L8.1,3c1.1-1.2,2.9-1.2,4,0c1.1,1.2,1.1,3,0,4.2l-5.9,6.3c-0.4,0.5-1.1,0.5-1.6,0c-0.4-0.5-0.4-1.2,0-1.7l5.9-6.3c0.2-0.2,0.2-0.6,0-0.8c-0.2-0.2-0.6-0.2-0.8,0L3.7,11c-0.9,0.9-0.9,2.4,0,3.3c0.9,0.9,2.3,0.9,3.2,0l5.9-6.3c1.5-1.6,1.5-4.2,0-5.8c-1.5-1.6-4-1.6-5.5,0L2.2,7.6c-0.2,0.2-0.2,0.6,0,0.8C2.4,8.7,2.7,8.7,3,8.5z"
|
||||
/>
|
||||
</svg>
|
||||
|
8
packages/ui/src/components/icons/CollapseArrow.svelte
Normal file
8
packages/ui/src/components/icons/CollapseArrow.svelte
Normal file
@ -0,0 +1,8 @@
|
||||
<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="M10.6572 8.00049L6.82861 4.17187L6.82861 11.8291L10.6572 8.00049Z" />
|
||||
</svg>
|
@ -16,6 +16,7 @@
|
||||
import { getContext } from 'svelte'
|
||||
import FontSize from './icons/FontSize.svelte'
|
||||
import { popupstore } from '../../popups'
|
||||
import { deviceOptionsStore as deviceInfo } from '../..'
|
||||
|
||||
const { currentFontSize, setFontSize } = getContext('fontsize') as {
|
||||
currentFontSize: string
|
||||
@ -31,6 +32,7 @@
|
||||
setFontSize(fontsizes[current % fontsizes.length])
|
||||
$popupstore = $popupstore
|
||||
}
|
||||
$: $deviceInfo.fontSize = fontsizes[current % fontsizes.length] === 'normal-font' ? 16 : 14
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
|
@ -175,7 +175,7 @@
|
||||
// min-width: 600px;
|
||||
font-size: 12px;
|
||||
line-height: 150%;
|
||||
background-color: var(--divider-color);
|
||||
background-color: var(--theme-statusbar-color);
|
||||
|
||||
.status-info {
|
||||
flex-grow: 1;
|
||||
|
@ -72,6 +72,7 @@ export { default as TimePopup } from './components/calendar/TimePopup.svelte'
|
||||
export { default as DateRangePresenter } from './components/calendar/DateRangePresenter.svelte'
|
||||
export { default as DateTimeRangePresenter } from './components/calendar/DateTimeRangePresenter.svelte'
|
||||
export { default as DatePresenter } from './components/calendar/DatePresenter.svelte'
|
||||
export { default as DueDatePresenter } from './components/calendar/DueDatePresenter.svelte'
|
||||
export { default as DateTimePresenter } from './components/calendar/DateTimePresenter.svelte'
|
||||
export { default as StylishEdit } from './components/StylishEdit.svelte'
|
||||
export { default as Grid } from './components/Grid.svelte'
|
||||
@ -150,6 +151,7 @@ export { default as IconMaxWidth } from './components/icons/MaxWidth.svelte'
|
||||
export { default as IconMixin } from './components/icons/Mixin.svelte'
|
||||
export { default as IconCircles } from './components/icons/Circles.svelte'
|
||||
export { default as IconLike } from './components/icons/Like.svelte'
|
||||
export { default as IconCollapseArrow } from './components/icons/CollapseArrow.svelte'
|
||||
|
||||
export { default as PanelInstance } from './components/PanelInstance.svelte'
|
||||
export { default as Panel } from './components/Panel.svelte'
|
||||
@ -205,6 +207,7 @@ export const deviceOptionsStore = writable<DeviceOptions>({
|
||||
docHeight: 0,
|
||||
isPortrait: false,
|
||||
isMobile: false,
|
||||
fontSize: 0,
|
||||
minWidth: false,
|
||||
twoRows: false
|
||||
})
|
||||
|
@ -13,9 +13,10 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { writable, derived } from 'svelte/store'
|
||||
import { Location as PlatformLocation } from './types'
|
||||
import { derived, writable } from 'svelte/store'
|
||||
import { closePopup } from './popups'
|
||||
import justClone from 'just-clone'
|
||||
import { Location as PlatformLocation } from './types'
|
||||
|
||||
export function locationToUrl (location: PlatformLocation): string {
|
||||
let result = '/'
|
||||
@ -103,12 +104,23 @@ export function getCurrentLocation (): PlatformLocation {
|
||||
return parseLocation(window.location)
|
||||
}
|
||||
|
||||
export function getCurrentResolvedLocation (): PlatformLocation {
|
||||
return justClone(resolvedLocation)
|
||||
}
|
||||
|
||||
const locationWritable = writable(getCurrentLocation())
|
||||
window.addEventListener('popstate', () => {
|
||||
locationWritable.set(getCurrentLocation())
|
||||
})
|
||||
|
||||
export const location = derived(locationWritable, (loc) => loc)
|
||||
export const resolvedLocationStore = writable(getCurrentLocation())
|
||||
let resolvedLocation = getCurrentLocation()
|
||||
|
||||
export function setResolvedLocation (location: PlatformLocation): void {
|
||||
resolvedLocation = location
|
||||
resolvedLocationStore.set(justClone(location))
|
||||
}
|
||||
|
||||
export function navigate (location: PlatformLocation, store = true): void {
|
||||
closePopup()
|
||||
|
@ -52,7 +52,7 @@ export const uis = plugin(uiId, {
|
||||
AddDueDate: '' as IntlString,
|
||||
EditDueDate: '' as IntlString,
|
||||
SaveDueDate: '' as IntlString,
|
||||
IssueNeedsToBeCompletedByThisDate: '' as IntlString,
|
||||
NeedsToBeCompletedByThisDate: '' as IntlString,
|
||||
English: '' as IntlString,
|
||||
Russian: '' as IntlString,
|
||||
MinutesBefore: '' as IntlString,
|
||||
@ -70,7 +70,11 @@ export const uis = plugin(uiId, {
|
||||
DD: '' as IntlString,
|
||||
MM: '' as IntlString,
|
||||
YYYY: '' as IntlString,
|
||||
HH: '' as IntlString
|
||||
HH: '' as IntlString,
|
||||
DueDatePopupTitle: '' as IntlString,
|
||||
DueDatePopupOverdueTitle: '' as IntlString,
|
||||
DueDatePopupDescription: '' as IntlString,
|
||||
DueDatePopupOverdueDescription: '' as IntlString
|
||||
},
|
||||
metadata: {
|
||||
DefaultApplication: '' as Metadata<AnyComponent>,
|
||||
|
@ -307,7 +307,7 @@ export function fitPopupElement (
|
||||
newProps.top = `${rect.top}px`
|
||||
// newProps.bottom = `${Math.min(document.body.clientHeight - rect.bottom + 1, window.innerHeight - rect.top - 1)}px`
|
||||
newProps.height = `${Math.min(rect.height, window.innerHeight - rect.top)}px`
|
||||
newProps.left = `${rect.left + 1}px`
|
||||
newProps.left = `${rect.left}px`
|
||||
// newProps.right = `${Math.min(document.body.clientWidth - rect.right, window.innerWidth - rect.left - 5)}px`
|
||||
newProps.width = `${Math.min(rect.width, window.innerWidth - rect.left)}px`
|
||||
} else if (element === 'middle') {
|
||||
|
@ -12,8 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
import type { Asset, IntlString } from '@hcengineering/platform'
|
||||
import { Timestamp } from '@hcengineering/core'
|
||||
import type { Asset, IntlString } from '@hcengineering/platform'
|
||||
import { /* Metadata, Plugin, plugin, */ Resource /*, Service */ } from '@hcengineering/platform'
|
||||
import { /* getContext, */ SvelteComponent } from 'svelte'
|
||||
|
||||
@ -28,7 +28,6 @@ export interface Location {
|
||||
|
||||
export interface ResolvedLocation {
|
||||
loc: Location
|
||||
shouldNavigate: boolean
|
||||
defaultLocation: Location
|
||||
}
|
||||
|
||||
@ -168,7 +167,7 @@ export type TooltipAlignment = 'top' | 'bottom' | 'left' | 'right'
|
||||
export type VerticalAlignment = 'top' | 'bottom'
|
||||
export type HorizontalAlignment = 'left' | 'right'
|
||||
|
||||
export type IconSize = 'inline' | 'tiny' | 'x-small' | 'small' | 'medium' | 'large' | 'x-large' | 'full'
|
||||
export type IconSize = 'inline' | 'tiny' | 'x-small' | 'smaller' | 'small' | 'medium' | 'large' | 'x-large' | 'full'
|
||||
|
||||
export interface DateOrShift {
|
||||
date?: number
|
||||
@ -234,10 +233,10 @@ export interface FadeOptions {
|
||||
multipler?: Sides<number>
|
||||
}
|
||||
export const defaultSP: FadeOptions = { multipler: { top: 0, bottom: 0 } }
|
||||
export const tableSP: FadeOptions = { multipler: { top: 2.5, bottom: 2.5 } }
|
||||
export const tableSP: FadeOptions = { multipler: { top: 3, bottom: 2.5 } }
|
||||
export const topSP: FadeOptions = { multipler: { top: 2.5, bottom: 0 } }
|
||||
export const tableHRscheduleY: FadeOptions = { multipler: { top: 5, bottom: 0 } }
|
||||
export const issueSP: FadeOptions = { multipler: { top: 3, bottom: 0 } }
|
||||
export const issueSP: FadeOptions = { multipler: { top: 2.75, bottom: 0 } }
|
||||
export const emojiSP: FadeOptions = { multipler: { top: 1.5, bottom: 0 } }
|
||||
|
||||
export interface DeviceOptions {
|
||||
@ -245,6 +244,7 @@ export interface DeviceOptions {
|
||||
docHeight: number
|
||||
isPortrait: boolean
|
||||
isMobile: boolean
|
||||
fontSize: number
|
||||
minWidth: boolean
|
||||
twoRows: boolean
|
||||
theme?: any
|
||||
|
@ -105,3 +105,21 @@ export function tableToCSV (tableId: string, separator = ','): string {
|
||||
* @public
|
||||
*/
|
||||
export const networkStatus = writable<number>(0)
|
||||
|
||||
let attractorMx = 0
|
||||
let attractorMy = 0
|
||||
/**
|
||||
* perform mouse movement checks and call method if they was
|
||||
*/
|
||||
export function mouseAttractor (op: () => void, diff = 5): (evt: MouseEvent) => void {
|
||||
return (evt: MouseEvent) => {
|
||||
const dx = evt.clientX - attractorMx
|
||||
const dy = evt.clientY - attractorMy
|
||||
attractorMx = evt.clientX
|
||||
attractorMy = evt.clientY
|
||||
|
||||
if (Math.sqrt(dx * dx + dy * dy) > diff) {
|
||||
op()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@
|
||||
export let object: Doc
|
||||
export let showCommenInput: boolean = true
|
||||
export let transparent: boolean = false
|
||||
export let shouldScroll: boolean = false
|
||||
|
||||
getResource(notification.function.GetNotificationClient).then((res) => {
|
||||
updatesStore = res().docUpdatesStore
|
||||
@ -83,11 +84,26 @@
|
||||
|
||||
let filtered: DisplayTx[] = []
|
||||
|
||||
let newTxIndexes: number[] = []
|
||||
$: newTxIndexes = getNewTxes(filtered, newTxes)
|
||||
|
||||
function getNewTxes (filtered: DisplayTx[], newTxes: [Ref<TxCUD<Doc>>, number][]): number[] {
|
||||
const res: number[] = []
|
||||
for (let i = 0; i < filtered.length; i++) {
|
||||
if (isNew(filtered[i], newTxes)) {
|
||||
res.push(i)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
function isNew (tx: DisplayTx | undefined, newTxes: [Ref<TxCUD<Doc>>, number][]): boolean {
|
||||
if (tx === undefined) return false
|
||||
const index = newTxes.findIndex((p) => p[0] === tx.originTx._id)
|
||||
return index !== -1
|
||||
}
|
||||
|
||||
$: scrollIndex = shouldScroll ? newTxIndexes[0] ?? -1 : -1
|
||||
</script>
|
||||
|
||||
<div class="antiSection-header high mt-9" class:invisible={transparent}>
|
||||
@ -105,7 +121,13 @@
|
||||
{#if filtered}
|
||||
<Grid column={1} rowGap={0.75}>
|
||||
{#each filtered as tx, i}
|
||||
<TxView {tx} {viewlets} isNew={isNew(tx, newTxes)} isNextNew={isNew(filtered[i + 1], newTxes)} />
|
||||
<TxView
|
||||
{tx}
|
||||
{viewlets}
|
||||
isNew={newTxIndexes.includes(i)}
|
||||
isNextNew={newTxIndexes.includes(i + 1)}
|
||||
shouldScroll={i === scrollIndex}
|
||||
/>
|
||||
{/each}
|
||||
</Grid>
|
||||
{/if}
|
||||
|
@ -40,6 +40,7 @@
|
||||
import { getValue, TxDisplayViewlet, updateViewlet } from '../utils'
|
||||
import TxViewTx from './TxViewTx.svelte'
|
||||
import Edit from './icons/Edit.svelte'
|
||||
import { tick } from 'svelte'
|
||||
|
||||
export let tx: DisplayTx
|
||||
export let viewlets: Map<ActivityKey, TxViewlet>
|
||||
@ -47,6 +48,7 @@
|
||||
export let isNew: boolean = false
|
||||
export let isNextNew: boolean = false
|
||||
export let contentHidden: boolean = false
|
||||
export let shouldScroll: boolean = false
|
||||
// export let showDocument = false
|
||||
|
||||
let ptx: DisplayTx | undefined
|
||||
@ -87,6 +89,9 @@
|
||||
modelIcon = result.modelIcon
|
||||
iconComponent = result.iconComponent
|
||||
props = getProps(result.props, edit)
|
||||
if (shouldScroll) {
|
||||
tick().then(scrollIntoView)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@ -164,10 +169,24 @@
|
||||
$: withAvatar = isComment || isMentioned || isAttached
|
||||
$: isEmphasized = viewlet?.display === 'emphasized' || model.every((m) => isMessageType(m.attribute))
|
||||
$: isColumn = isComment || isEmphasized || hasMessageType
|
||||
|
||||
let htmlElement: HTMLDivElement
|
||||
|
||||
function scrollIntoView () {
|
||||
htmlElement?.scrollIntoView({ behavior: 'auto', block: 'start' })
|
||||
shouldScroll = false
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if (viewlet !== undefined && !((viewlet?.hideOnRemove ?? false) && tx.removed)) || model.length > 0}
|
||||
<div class="msgactivity-container" class:showIcon class:withAvatar class:isNew class:isNextNew>
|
||||
<div
|
||||
class="msgactivity-container"
|
||||
bind:this={htmlElement}
|
||||
class:showIcon
|
||||
class:withAvatar
|
||||
class:isNew
|
||||
class:isNextNew
|
||||
>
|
||||
{#if showIcon}
|
||||
{#if withAvatar}
|
||||
<div class="msgactivity-avatar">
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
const maxLenght: number = 16
|
||||
const maxLenght: number = 30
|
||||
const trimFilename = (fname: string): string =>
|
||||
fname.length > maxLenght ? fname.substr(0, (maxLenght - 1) / 2) + '...' + fname.substr(-(maxLenght - 1) / 2) : fname
|
||||
|
||||
@ -83,6 +83,7 @@
|
||||
class="remove-btn"
|
||||
on:click={(ev) => {
|
||||
ev.stopPropagation()
|
||||
ev.preventDefault()
|
||||
dispatch('remove')
|
||||
}}
|
||||
>
|
||||
|
@ -246,9 +246,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:paste={pasteAction} />
|
||||
|
||||
<div bind:this={refContainer}>
|
||||
<div bind:this={refContainer} on:paste={pasteAction}>
|
||||
<input
|
||||
bind:this={inputFile}
|
||||
multiple
|
||||
@ -302,17 +300,17 @@
|
||||
<style lang="scss">
|
||||
.list {
|
||||
padding: 0.5rem;
|
||||
color: var(--caption-color);
|
||||
color: var(--theme-caption-color);
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
background-color: var(--accent-bg-color);
|
||||
border: 1px solid var(--divider-color);
|
||||
background-color: var(--theme-refinput-color);
|
||||
border: 1px solid var(--theme-divider-color);
|
||||
border-radius: 0.5rem 0.5rem 0 0;
|
||||
border-bottom: none;
|
||||
|
||||
.item + .item {
|
||||
padding-left: 1rem;
|
||||
border-left: 1px solid var(--divider-color);
|
||||
border-left: 1px solid var(--theme-divider-color);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -298,8 +298,6 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:paste={(ev) => (fakeAttach === 'normal' ? pasteAction(ev) : undefined)} />
|
||||
|
||||
<input
|
||||
bind:this={inputFile}
|
||||
multiple
|
||||
@ -312,6 +310,7 @@
|
||||
|
||||
<div
|
||||
class="flex-col clear-mins"
|
||||
on:paste={(ev) => (fakeAttach === 'normal' ? pasteAction(ev) : undefined)}
|
||||
on:dragover|preventDefault={() => {}}
|
||||
on:dragleave={() => {}}
|
||||
on:drop|preventDefault|stopPropagation={(ev) => {
|
||||
@ -367,16 +366,16 @@
|
||||
margin-top: 0.5rem;
|
||||
padding: 0.5rem;
|
||||
min-width: 0;
|
||||
color: var(--caption-color);
|
||||
color: var(--theme-caption-color);
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
background-color: var(--accent-bg-color);
|
||||
border: 1px solid var(--divider-color);
|
||||
border-radius: 0.5rem;
|
||||
background-color: var(--theme-button-enabled);
|
||||
border: 1px solid var(--theme-button-border);
|
||||
border-radius: 0.25rem;
|
||||
|
||||
.item + .item {
|
||||
padding-left: 1rem;
|
||||
border-left: 1px solid var(--divider-color);
|
||||
border-left: 1px solid var(--theme-divider-color);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -17,7 +17,7 @@
|
||||
import contact, { Employee, EmployeeAccount } from '@hcengineering/contact'
|
||||
import core, { Class, getCurrentAccount, Ref, Space } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import ui, { EditWithIcon, IconSearch, Label, Loading, location, navigate, TabList } from '@hcengineering/ui'
|
||||
import { ActionIcon, IconMoreH, Label, Loading, location, navigate, TabList, SearchEdit } from '@hcengineering/ui'
|
||||
import view from '@hcengineering/view'
|
||||
import { get } from 'svelte/store'
|
||||
import { dateFileBrowserFilters, FileBrowserSortMode, fileTypeFileBrowserFilters, sortModeToOptionObject } from '..'
|
||||
@ -101,14 +101,30 @@
|
||||
</script>
|
||||
|
||||
{#if withHeader}
|
||||
<div class="ac-header full divide">
|
||||
<div class="ac-header full divide caption-height">
|
||||
<div class="ac-header__wrap-title">
|
||||
<span class="ac-header__title"><Label label={attachment.string.FileBrowser} /></span>
|
||||
</div>
|
||||
<EditWithIcon icon={IconSearch} size={'small'} bind:value={search} placeholder={ui.string.SearchDots} />
|
||||
<div class="mb-1 clear-mins">
|
||||
<TabList
|
||||
items={[
|
||||
{ id: 'table', icon: view.icon.Table, tooltip: attachment.string.FileBrowserListView },
|
||||
{ id: 'card', icon: view.icon.Card, tooltip: attachment.string.FileBrowserGridView }
|
||||
]}
|
||||
selected={isListDisplayMode ? 'table' : 'card'}
|
||||
on:select={(result) => {
|
||||
if (result.detail !== undefined) isListDisplayMode = result.detail === 'table' ?? false
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="ac-header full">
|
||||
<div class="ac-header full divide search-start">
|
||||
<div class="ac-header-full small-gap">
|
||||
<SearchEdit bind:value={search} on:change={() => {}} />
|
||||
<ActionIcon icon={IconMoreH} size={'small'} />
|
||||
<div class="buttons-divider" />
|
||||
</div>
|
||||
<FileBrowserFilters
|
||||
{requestedSpaceClasses}
|
||||
{spaceId}
|
||||
@ -117,18 +133,6 @@
|
||||
bind:selectedDateId
|
||||
bind:selectedFileTypeId
|
||||
/>
|
||||
<TabList
|
||||
items={[
|
||||
{ id: 'table', icon: view.icon.Table, tooltip: attachment.string.FileBrowserListView },
|
||||
{ id: 'card', icon: view.icon.Card, tooltip: attachment.string.FileBrowserGridView }
|
||||
]}
|
||||
kind={'secondary'}
|
||||
size={'small'}
|
||||
selected={isListDisplayMode ? 'table' : 'card'}
|
||||
on:select={(result) => {
|
||||
if (result.detail !== undefined) isListDisplayMode = result.detail === 'table' ?? false
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="group">
|
||||
<div class="groupHeader">
|
||||
|
@ -29,54 +29,48 @@
|
||||
export let selectedFileTypeId: string
|
||||
</script>
|
||||
|
||||
<div class="filterBlockContainer">
|
||||
<div class="simpleFilterButton">
|
||||
<Component
|
||||
is={contact.component.UserBoxList}
|
||||
props={{
|
||||
items: selectedParticipants,
|
||||
label: attachment.string.FileBrowserFilterFrom
|
||||
}}
|
||||
on:update={(evt) => {
|
||||
selectedParticipants = evt.detail
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="simpleFilterButton">
|
||||
<SpaceMultiBoxList
|
||||
_classes={requestedSpaceClasses}
|
||||
label={attachment.string.FileBrowserFilterIn}
|
||||
selectedItems={spaceId ? [spaceId] : []}
|
||||
on:update={(evt) => {
|
||||
selectedSpaces = evt.detail
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="simpleFilterButton">
|
||||
<DropdownLabelsIntl
|
||||
items={dateFileBrowserFilters}
|
||||
label={attachment.string.FileBrowserFilterDate}
|
||||
bind:selected={selectedDateId}
|
||||
/>
|
||||
</div>
|
||||
<div class="simpleFilterButton">
|
||||
<DropdownLabelsIntl
|
||||
items={fileTypeFileBrowserFilters}
|
||||
label={attachment.string.FileBrowserFilterFileType}
|
||||
bind:selected={selectedFileTypeId}
|
||||
/>
|
||||
</div>
|
||||
<div class="filterBlockContainer clear-mins gap-2">
|
||||
<Component
|
||||
is={contact.component.UserBoxList}
|
||||
props={{
|
||||
items: selectedParticipants,
|
||||
label: attachment.string.FileBrowserFilterFrom,
|
||||
kind: 'transparent',
|
||||
size: 'medium'
|
||||
}}
|
||||
on:update={(evt) => {
|
||||
selectedParticipants = evt.detail
|
||||
}}
|
||||
/>
|
||||
<SpaceMultiBoxList
|
||||
_classes={requestedSpaceClasses}
|
||||
label={attachment.string.FileBrowserFilterIn}
|
||||
selectedItems={spaceId ? [spaceId] : []}
|
||||
kind={'transparent'}
|
||||
size={'medium'}
|
||||
on:update={(evt) => {
|
||||
selectedSpaces = evt.detail
|
||||
}}
|
||||
/>
|
||||
<DropdownLabelsIntl
|
||||
items={dateFileBrowserFilters}
|
||||
label={attachment.string.FileBrowserFilterDate}
|
||||
bind:selected={selectedDateId}
|
||||
kind={'transparent'}
|
||||
size={'medium'}
|
||||
/>
|
||||
<DropdownLabelsIntl
|
||||
items={fileTypeFileBrowserFilters}
|
||||
label={attachment.string.FileBrowserFilterFileType}
|
||||
bind:selected={selectedFileTypeId}
|
||||
kind={'transparent'}
|
||||
size={'medium'}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.filterBlockContainer {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.simpleFilterButton {
|
||||
max-width: 12rem;
|
||||
margin: 0.125rem 0.5rem 0.125rem 0;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,10 +1,10 @@
|
||||
<script lang="ts">
|
||||
import core, { Ref, Space, WithLookup } from '@hcengineering/core'
|
||||
import { Button, getCurrentLocation, navigate, location, TabList, Icon } from '@hcengineering/ui'
|
||||
import { createQuery } from '@hcengineering/presentation'
|
||||
import board from '../plugin'
|
||||
import { Button, Icon, TabList, getCurrentResolvedLocation, location, navigate } from '@hcengineering/ui'
|
||||
import { Viewlet } from '@hcengineering/view'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import board from '../plugin'
|
||||
|
||||
export let spaceId: Ref<Space> | undefined
|
||||
export let viewlets: WithLookup<Viewlet>[]
|
||||
@ -19,7 +19,7 @@
|
||||
})
|
||||
|
||||
function showMenu () {
|
||||
const loc = getCurrentLocation()
|
||||
const loc = getCurrentResolvedLocation()
|
||||
loc.path[4] = space._id
|
||||
navigate(loc)
|
||||
}
|
||||
|
@ -95,7 +95,7 @@
|
||||
|
||||
let kanbanUI: KanbanUI
|
||||
const listProvider = new ListSelectionProvider((offset: 1 | -1 | 0, of?: Doc, dir?: SelectDirection) => {
|
||||
kanbanUI.select(offset, of, dir)
|
||||
kanbanUI?.select(offset, of, dir)
|
||||
})
|
||||
onMount(() => {
|
||||
;(document.activeElement as HTMLElement)?.blur()
|
||||
@ -125,6 +125,7 @@
|
||||
...options
|
||||
}
|
||||
)
|
||||
$: listProvider.update(cards)
|
||||
$: groupByDocs = groupBy(cards, 'state')
|
||||
|
||||
const getUpdateProps = (doc: Doc, category: CategoryType): DocumentUpdate<DocWithRank> | undefined => {
|
||||
@ -151,11 +152,8 @@
|
||||
getGroupByValues={(groupByDocs, category) => getGroupByValues(groupByDocs, category)}
|
||||
{setGroupByValues}
|
||||
categories={states.map((it) => it._id)}
|
||||
on:content={(evt) => {
|
||||
listProvider.update(evt.detail)
|
||||
}}
|
||||
on:obj-focus={(evt) => {
|
||||
listProvider.updateFocus(evt.detail)
|
||||
listProvider.updateFocus(evt.detail.object)
|
||||
}}
|
||||
{groupByDocs}
|
||||
{getUpdateProps}
|
||||
|
@ -26,7 +26,8 @@
|
||||
Scroller,
|
||||
showPopup,
|
||||
WeekCalendar,
|
||||
YearCalendar
|
||||
YearCalendar,
|
||||
defaultSP
|
||||
} from '@hcengineering/ui'
|
||||
import { BuildModelKey } from '@hcengineering/view'
|
||||
import { CalendarMode } from '../index'
|
||||
@ -166,173 +167,166 @@
|
||||
let indexes = new Map<Ref<Event>, number>()
|
||||
</script>
|
||||
|
||||
<div class="fs-title ml-10 mb-2 flex-row-center">
|
||||
<div class="text-lg fs-bold px-10 my-4 flex-no-shrink clear-mins">
|
||||
{label(currentDate, mode)}
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2 mb-4 ml-10">
|
||||
<Button
|
||||
size={'small'}
|
||||
label={calendar.string.ModeDay}
|
||||
on:click={() => {
|
||||
mode = CalendarMode.Day
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
size={'small'}
|
||||
label={calendar.string.ModeWeek}
|
||||
on:click={() => {
|
||||
mode = CalendarMode.Week
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
size={'small'}
|
||||
label={calendar.string.ModeMonth}
|
||||
on:click={() => {
|
||||
mode = CalendarMode.Month
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
size={'small'}
|
||||
label={calendar.string.ModeYear}
|
||||
on:click={() => {
|
||||
mode = CalendarMode.Year
|
||||
}}
|
||||
/>
|
||||
<div class="flex ml-4 gap-2">
|
||||
<div class="flex-between mb-4 px-10 flex-no-shrink clear-mins">
|
||||
<div class="flex-row-center gap-2">
|
||||
<Button
|
||||
icon={IconBack}
|
||||
size={'small'}
|
||||
kind={'transparent'}
|
||||
on:click={() => {
|
||||
inc(-1)
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
size={'small'}
|
||||
label={calendar.string.Today}
|
||||
kind={'transparent'}
|
||||
on:click={() => {
|
||||
inc(0)
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
icon={IconForward}
|
||||
size={'small'}
|
||||
kind={'transparent'}
|
||||
on:click={() => {
|
||||
inc(1)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="flex-row-center gap-2 clear-mins">
|
||||
<Button
|
||||
label={calendar.string.ModeDay}
|
||||
on:click={() => {
|
||||
mode = CalendarMode.Day
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
label={calendar.string.ModeWeek}
|
||||
on:click={() => {
|
||||
mode = CalendarMode.Week
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
label={calendar.string.ModeMonth}
|
||||
on:click={() => {
|
||||
mode = CalendarMode.Month
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
label={calendar.string.ModeYear}
|
||||
on:click={() => {
|
||||
mode = CalendarMode.Year
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ml-10 mr-6 h-full clear-mins">
|
||||
<Scroller
|
||||
padding={'0 2.25rem'}
|
||||
fade={mode === CalendarMode.Week || mode === CalendarMode.Day ? { multipler: { top: 3, bottom: 0 } } : defaultSP}
|
||||
>
|
||||
{#if mode === CalendarMode.Year}
|
||||
<Scroller>
|
||||
<YearCalendar
|
||||
{mondayStart}
|
||||
cellHeight={'2.5rem'}
|
||||
bind:selectedDate
|
||||
bind:currentDate
|
||||
on:change={(e) => {
|
||||
currentDate = e.detail
|
||||
if (areDatesEqual(selectedDate, currentDate)) {
|
||||
mode = CalendarMode.Month
|
||||
}
|
||||
selectedDate = e.detail
|
||||
}}
|
||||
>
|
||||
<svelte:fragment slot="cell" let:date let:today let:selected let:wrongMonth>
|
||||
<Day
|
||||
events={findEvents(objects, date)}
|
||||
{date}
|
||||
{_class}
|
||||
{baseMenuClass}
|
||||
{options}
|
||||
{config}
|
||||
{today}
|
||||
{selected}
|
||||
{wrongMonth}
|
||||
{query}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
</YearCalendar>
|
||||
</Scroller>
|
||||
<YearCalendar
|
||||
{mondayStart}
|
||||
cellHeight={'2.5rem'}
|
||||
bind:selectedDate
|
||||
bind:currentDate
|
||||
on:change={(e) => {
|
||||
currentDate = e.detail
|
||||
if (areDatesEqual(selectedDate, currentDate)) {
|
||||
mode = CalendarMode.Month
|
||||
}
|
||||
selectedDate = e.detail
|
||||
}}
|
||||
>
|
||||
<svelte:fragment slot="cell" let:date let:today let:selected let:wrongMonth>
|
||||
<Day
|
||||
events={findEvents(objects, date)}
|
||||
{date}
|
||||
{_class}
|
||||
{baseMenuClass}
|
||||
{options}
|
||||
{config}
|
||||
{today}
|
||||
{selected}
|
||||
{wrongMonth}
|
||||
{query}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
</YearCalendar>
|
||||
{:else if mode === CalendarMode.Month}
|
||||
<div class="flex flex-grow">
|
||||
<MonthCalendar {mondayStart} cellHeight={'8.5rem'} bind:selectedDate bind:currentDate>
|
||||
<svelte:fragment slot="cell" let:date let:today let:selected let:wrongMonth>
|
||||
<Day
|
||||
events={findEvents(objects, date)}
|
||||
{date}
|
||||
size={'huge'}
|
||||
{_class}
|
||||
{baseMenuClass}
|
||||
{options}
|
||||
{config}
|
||||
{today}
|
||||
{selected}
|
||||
{wrongMonth}
|
||||
{query}
|
||||
on:select={(e) => {
|
||||
currentDate = e.detail
|
||||
if (areDatesEqual(selectedDate, currentDate)) {
|
||||
mode = CalendarMode.Day
|
||||
}
|
||||
selectedDate = e.detail
|
||||
}}
|
||||
on:create={(e) => {
|
||||
showCreateDialog(e.detail, false)
|
||||
}}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
</MonthCalendar>
|
||||
</div>
|
||||
<MonthCalendar {mondayStart} cellHeight={'8.5rem'} bind:selectedDate bind:currentDate>
|
||||
<svelte:fragment slot="cell" let:date let:today let:selected let:wrongMonth>
|
||||
<Day
|
||||
events={findEvents(objects, date)}
|
||||
{date}
|
||||
size={'huge'}
|
||||
{_class}
|
||||
{baseMenuClass}
|
||||
{options}
|
||||
{config}
|
||||
{today}
|
||||
{selected}
|
||||
{wrongMonth}
|
||||
{query}
|
||||
on:select={(e) => {
|
||||
currentDate = e.detail
|
||||
if (areDatesEqual(selectedDate, currentDate)) {
|
||||
mode = CalendarMode.Day
|
||||
}
|
||||
selectedDate = e.detail
|
||||
}}
|
||||
on:create={(e) => {
|
||||
showCreateDialog(e.detail, false)
|
||||
}}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
</MonthCalendar>
|
||||
{:else if mode === CalendarMode.Week}
|
||||
<Scroller>
|
||||
<WeekCalendar
|
||||
{mondayStart}
|
||||
cellHeight={'4.5rem'}
|
||||
bind:selectedDate
|
||||
bind:currentDate
|
||||
on:select={(e) => {
|
||||
currentDate = e.detail
|
||||
selectedDate = e.detail
|
||||
mode = CalendarMode.Day
|
||||
}}
|
||||
>
|
||||
<svelte:fragment slot="cell" let:date>
|
||||
<Hour
|
||||
events={findEvents(objects, date, true)}
|
||||
{date}
|
||||
bind:indexes
|
||||
on:create={(e) => {
|
||||
showCreateDialog(e.detail, true)
|
||||
}}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
</WeekCalendar>
|
||||
</Scroller>
|
||||
<WeekCalendar
|
||||
{mondayStart}
|
||||
cellHeight={'4.5rem'}
|
||||
bind:selectedDate
|
||||
bind:currentDate
|
||||
on:select={(e) => {
|
||||
currentDate = e.detail
|
||||
selectedDate = e.detail
|
||||
mode = CalendarMode.Day
|
||||
}}
|
||||
>
|
||||
<svelte:fragment slot="cell" let:date>
|
||||
<Hour
|
||||
events={findEvents(objects, date, true)}
|
||||
{date}
|
||||
bind:indexes
|
||||
on:create={(e) => {
|
||||
showCreateDialog(e.detail, true)
|
||||
}}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
</WeekCalendar>
|
||||
{:else if mode === CalendarMode.Day}
|
||||
<Scroller>
|
||||
<WeekCalendar
|
||||
{mondayStart}
|
||||
displayedDaysCount={1}
|
||||
startFromWeekStart={false}
|
||||
cellHeight={'4.5rem'}
|
||||
bind:selectedDate
|
||||
bind:currentDate
|
||||
>
|
||||
<svelte:fragment slot="cell" let:date>
|
||||
<Hour
|
||||
events={findEvents(objects, date, true)}
|
||||
{date}
|
||||
bind:indexes
|
||||
wide
|
||||
on:create={(e) => {
|
||||
showCreateDialog(e.detail, true)
|
||||
}}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
</WeekCalendar>
|
||||
</Scroller>
|
||||
<WeekCalendar
|
||||
{mondayStart}
|
||||
displayedDaysCount={1}
|
||||
startFromWeekStart={false}
|
||||
cellHeight={'4.5rem'}
|
||||
bind:selectedDate
|
||||
bind:currentDate
|
||||
>
|
||||
<svelte:fragment slot="cell" let:date>
|
||||
<Hour
|
||||
events={findEvents(objects, date, true)}
|
||||
{date}
|
||||
bind:indexes
|
||||
wide
|
||||
on:create={(e) => {
|
||||
showCreateDialog(e.detail, true)
|
||||
}}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
</WeekCalendar>
|
||||
{/if}
|
||||
</div>
|
||||
</Scroller>
|
||||
<div class="min-h-4 max-h-4 h-4 flex-no-shrink" />
|
||||
|
@ -104,6 +104,8 @@
|
||||
labelNull={ui.string.SelectDate}
|
||||
on:change={async (event) => await handleNewStartDate(event.detail)}
|
||||
mode={DateRangeMode.DATETIME}
|
||||
kind={'secondary'}
|
||||
size={'large'}
|
||||
editable
|
||||
/>
|
||||
<DateRangePresenter
|
||||
@ -112,8 +114,10 @@
|
||||
labelNull={calendar.string.DueTo}
|
||||
on:change={async (event) => await handleNewDueDate(event.detail)}
|
||||
mode={DateRangeMode.DATETIME}
|
||||
kind={'secondary'}
|
||||
size={'large'}
|
||||
editable
|
||||
/>
|
||||
<UserBoxList bind:items={participants} label={calendar.string.Participants} />
|
||||
<UserBoxList bind:items={participants} label={calendar.string.Participants} kind={'secondary'} size={'large'} />
|
||||
</svelte:fragment>
|
||||
</Card>
|
||||
|
@ -72,7 +72,14 @@
|
||||
<EditBox bind:value={title} placeholder={calendar.string.Title} kind={'large-style'} focus />
|
||||
<svelte:fragment slot="pool">
|
||||
<!-- <TimeShiftPicker title={calendar.string.Date} bind:value direction="after" /> -->
|
||||
<DateRangePresenter bind:value mode={DateRangeMode.DATETIME} editable={true} labelNull={ui.string.SelectDate} />
|
||||
<UserBoxList bind:items={participants} label={calendar.string.Participants} />
|
||||
<DateRangePresenter
|
||||
bind:value
|
||||
mode={DateRangeMode.DATETIME}
|
||||
editable={true}
|
||||
labelNull={ui.string.SelectDate}
|
||||
kind={'secondary'}
|
||||
size={'large'}
|
||||
/>
|
||||
<UserBoxList bind:items={participants} label={calendar.string.Participants} kind={'secondary'} size={'large'} />
|
||||
</svelte:fragment>
|
||||
</Card>
|
||||
|
@ -21,13 +21,14 @@
|
||||
AnyComponent,
|
||||
Button,
|
||||
Component,
|
||||
Icon,
|
||||
IconAdd,
|
||||
ActionIcon,
|
||||
Label,
|
||||
Loading,
|
||||
SearchEdit,
|
||||
showPopup,
|
||||
TabList
|
||||
TabList,
|
||||
IconMoreH,
|
||||
IconAdd
|
||||
} from '@hcengineering/ui'
|
||||
import view, { Viewlet, ViewletPreference } from '@hcengineering/view'
|
||||
import {
|
||||
@ -38,7 +39,7 @@
|
||||
viewOptionStore
|
||||
} from '@hcengineering/view-resources'
|
||||
import calendar from '../plugin'
|
||||
import { deviceOptionsStore as deviceInfo } from '@hcengineering/ui'
|
||||
// import { deviceOptionsStore as deviceInfo } from '@hcengineering/ui'
|
||||
|
||||
export let _class: Ref<Class<Event>> = calendar.class.Event
|
||||
export let space: Ref<Space> | undefined = undefined
|
||||
@ -107,45 +108,42 @@
|
||||
}
|
||||
})
|
||||
|
||||
$: twoRows = $deviceInfo.twoRows
|
||||
// $: twoRows = $deviceInfo.twoRows
|
||||
|
||||
$: viewOptions = getViewOptions(selectedViewlet, $viewOptionStore)
|
||||
</script>
|
||||
|
||||
<div class="ac-header withSettings" class:full={!twoRows} class:mini={twoRows}>
|
||||
<div class:ac-header-full={!twoRows} class:flex-between={twoRows}>
|
||||
<div class="ac-header__wrap-title mr-3">
|
||||
<div class="ac-header__icon"><Icon icon={viewIcon} size={'small'} /></div>
|
||||
<span class="ac-header__title"><Label label={viewLabel} /></span>
|
||||
<div class="ml-4"><FilterButton {_class} /></div>
|
||||
</div>
|
||||
|
||||
<SearchEdit
|
||||
bind:value={search}
|
||||
on:change={() => {
|
||||
updateResultQuery(search)
|
||||
}}
|
||||
/>
|
||||
<div class="ac-header full divide">
|
||||
<div class="ac-header__wrap-title mr-3">
|
||||
<span class="ac-header__title"><Label label={viewLabel} /></span>
|
||||
</div>
|
||||
<div class="ac-header-full" class:secondRow={twoRows}>
|
||||
<Button icon={IconAdd} label={createLabel} kind={'primary'} size={'small'} on:click={showCreateDialog} />
|
||||
|
||||
<div class="ac-header-full medium-gap mb-1">
|
||||
{#if viewlets.length > 1}
|
||||
<TabList
|
||||
items={viewslist}
|
||||
multiselect={false}
|
||||
selected={selectedViewlet?._id}
|
||||
kind={'secondary'}
|
||||
size={'small'}
|
||||
on:select={(result) => {
|
||||
if (result.detail !== undefined) selectedViewlet = viewlets.find((vl) => vl._id === result.detail.id)
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
<ViewletSettingButton bind:viewOptions viewlet={selectedViewlet} />
|
||||
<Button icon={IconAdd} label={createLabel} kind={'primary'} on:click={showCreateDialog} />
|
||||
</div>
|
||||
</div>
|
||||
<div class="ac-header full divide search-start">
|
||||
<div class="ac-header-full small-gap">
|
||||
<SearchEdit bind:value={search} on:change={() => updateResultQuery(search)} />
|
||||
<ActionIcon icon={IconMoreH} size={'small'} />
|
||||
<div class="buttons-divider" />
|
||||
<FilterButton {_class} />
|
||||
</div>
|
||||
<div class="ac-header-full medium-gap">
|
||||
<ViewletSettingButton bind:viewOptions viewlet={selectedViewlet} />
|
||||
<ActionIcon icon={IconMoreH} size={'small'} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if selectedViewlet?.$lookup?.descriptor?.component}
|
||||
{#if loading}
|
||||
<Loading />
|
||||
|
@ -198,6 +198,7 @@
|
||||
</script>
|
||||
|
||||
<div class="flex-col vScroll" bind:this={div} on:scroll={handleScroll}>
|
||||
<div class="grower" />
|
||||
{#if showFixed}
|
||||
<div class="ml-2 pr-2 fixed">
|
||||
<JumpToDateSelector {selectedDate} fixed on:jumpToDate={handleJumpToDate} />
|
||||
@ -224,6 +225,10 @@
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.grower {
|
||||
flex-grow: 10;
|
||||
flex-shrink: 5;
|
||||
}
|
||||
.fixed {
|
||||
position: absolute;
|
||||
align-self: center;
|
||||
|
@ -38,7 +38,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="ac-header divide full">
|
||||
<div class="ac-header divide full caption-height">
|
||||
{#if channel}
|
||||
<Header
|
||||
icon={channel.private ? Lock : classIcon(client, channel._class)}
|
||||
|
@ -48,7 +48,7 @@
|
||||
</script>
|
||||
|
||||
<div class="flex-col h-full">
|
||||
<div class="ac-header divide full">
|
||||
<div class="ac-header divide full caption-height">
|
||||
<Header icon={workbench.icon.Search} intlLabel={plugin.string.ChunterBrowser} />
|
||||
</div>
|
||||
<div class="h-full browser">
|
||||
|
@ -54,10 +54,11 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="ac-header divide full">
|
||||
<div class="ac-header divide full caption-height">
|
||||
{#if dm}
|
||||
{#await getDmName(client, dm) then name}
|
||||
{#await getEmpolyeeIds() then empolyeeIds}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div class="ac-header__wrap-title" on:click={onSpaceEdit}>
|
||||
<div class="ac-header__icon">
|
||||
<CombineAvatars _class={contact.class.Employee} items={empolyeeIds} size={'x-small'} />
|
||||
|
@ -18,8 +18,8 @@
|
||||
import { AttachmentPresenter, FileDownload } from '@hcengineering/attachment-resources'
|
||||
import { ChunterSpace } from '@hcengineering/chunter'
|
||||
import { Doc, SortingOrder, getCurrentAccount } from '@hcengineering/core'
|
||||
import { createQuery, getFileUrl, getClient } from '@hcengineering/presentation'
|
||||
import { getCurrentLocation, showPopup, IconMoreV, Label, navigate, Icon, Menu } from '@hcengineering/ui'
|
||||
import { createQuery, getClient, getFileUrl } from '@hcengineering/presentation'
|
||||
import { Icon, IconMoreV, Label, Menu, getCurrentResolvedLocation, navigate, showPopup } from '@hcengineering/ui'
|
||||
|
||||
export let channel: ChunterSpace | undefined
|
||||
const myAccId = getCurrentAccount()._id
|
||||
@ -98,7 +98,7 @@
|
||||
<div
|
||||
class="showMoreAttachmentsButton"
|
||||
on:click={() => {
|
||||
const loc = getCurrentLocation()
|
||||
const loc = getCurrentResolvedLocation()
|
||||
loc.path[3] = 'fileBrowser'
|
||||
loc.query = channel ? { spaceId: channel._id } : {}
|
||||
navigate(loc)
|
||||
|
@ -28,6 +28,7 @@
|
||||
</script>
|
||||
|
||||
<div class="ac-header__wrap-description">
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div class="ac-header__wrap-title" on:click>
|
||||
{#if icon}<div class="ac-header__icon"><Icon {icon} size={'small'} /></div>{/if}
|
||||
{#if label}
|
||||
|
@ -15,11 +15,11 @@
|
||||
$: isCurrentYear = time ? new Date(time).getFullYear() === new Date().getFullYear() : undefined
|
||||
</script>
|
||||
|
||||
<div id={fixed ? '' : time?.toString()} class="flex justify-center mt-5 pr-1 dateSelector">
|
||||
<div id={fixed ? '' : time?.toString()} class="flex-center clear-mins dateSelector">
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
bind:this={div}
|
||||
class="mb-1 p-1 border-radius-2 over-underline dateSelectorButton"
|
||||
class="border-radius-4 over-underline dateSelectorButton clear-mins"
|
||||
on:click={() => {
|
||||
showPopup(DateRangePopup, {}, div, (v) => {
|
||||
if (v) {
|
||||
@ -30,28 +30,37 @@
|
||||
}}
|
||||
>
|
||||
{#if time}
|
||||
<div>
|
||||
{new Date(time).toLocaleDateString('default', {
|
||||
weekday: 'short',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
year: isCurrentYear ? undefined : 'numeric'
|
||||
})}
|
||||
</div>
|
||||
{new Date(time).toLocaleDateString('default', {
|
||||
weekday: 'short',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
year: isCurrentYear ? undefined : 'numeric'
|
||||
})}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.dateSelector {
|
||||
&:not(:first-child) {
|
||||
border-top: 1px solid var(--divider-color);
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
margin: 0.25rem 0;
|
||||
|
||||
&:not(:first-child)::after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
top: 50%;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background-color: var(--theme-divider-color);
|
||||
}
|
||||
.dateSelectorButton {
|
||||
padding: 0.25rem 0.5rem;
|
||||
height: max-content;
|
||||
background-color: var(--theme-list-row-color);
|
||||
border: 1px solid var(--theme-divider-color);
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
|
||||
.dateSelectorButton {
|
||||
margin-top: -1rem;
|
||||
background-color: var(--body-color);
|
||||
border: 1px solid var(--divider-color);
|
||||
}
|
||||
</style>
|
||||
|
@ -221,10 +221,10 @@
|
||||
let loading = false
|
||||
</script>
|
||||
|
||||
<div class="container" class:highlighted={isHighlighted} id={message._id}>
|
||||
<div class="container clear-mins" class:highlighted={isHighlighted} id={message._id}>
|
||||
<div class="avatar"><Avatar size={'medium'} avatar={employee?.avatar} /></div>
|
||||
<div class="message">
|
||||
<div class="header">
|
||||
<div class="message clear-mins">
|
||||
<div class="header clear-mins">
|
||||
{#if employee}
|
||||
<EmployeePresenter value={employee} shouldShowAvatar={false} inline />
|
||||
{/if}
|
||||
@ -270,7 +270,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="buttons" class:menuShowed>
|
||||
<div class="buttons clear-mins" class:menuShowed>
|
||||
<div class="tool">
|
||||
<ActionIcon
|
||||
icon={IconMoreH}
|
||||
@ -305,6 +305,7 @@
|
||||
.container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
padding: 0.5rem 2rem;
|
||||
|
||||
&.highlighted {
|
||||
@ -327,7 +328,7 @@
|
||||
font-weight: 500;
|
||||
font-size: 1rem;
|
||||
line-height: 150%;
|
||||
color: var(--caption-color);
|
||||
color: var(--theme-caption-color);
|
||||
margin-bottom: 0.25rem;
|
||||
|
||||
span {
|
||||
@ -379,7 +380,7 @@
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--board-card-bg-hover);
|
||||
background-color: var(--highlight-hover);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -85,7 +85,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="ac-header full divide">
|
||||
<div class="ac-header full divide caption-height">
|
||||
<div class="ac-header__wrap-title">
|
||||
<span class="ac-header__title"><Label label={chunter.string.SavedItems} /></span>
|
||||
</div>
|
||||
@ -93,7 +93,8 @@
|
||||
<Scroller>
|
||||
{#if savedMessages.length > 0 || savedAttachments.length > 0}
|
||||
{#each savedMessages as message}
|
||||
<div on:click={() => openMessageFromSpecial(message)}>
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div class="clear-mins flex-no-shrink" on:click={() => openMessageFromSpecial(message)}>
|
||||
<Message
|
||||
{message}
|
||||
on:openThread
|
||||
@ -105,7 +106,8 @@
|
||||
</div>
|
||||
{/each}
|
||||
{#each savedAttachments as att}
|
||||
<div class="attachmentContainer" on:click={() => openAttachment(att)}>
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div class="attachmentContainer flex-no-shrink clear-mins" on:click={() => openAttachment(att)}>
|
||||
<AttachmentPreview value={att} isSaved={true} />
|
||||
<div class="label">
|
||||
<Label
|
||||
|
@ -163,7 +163,7 @@
|
||||
let loading = false
|
||||
</script>
|
||||
|
||||
<div class="ml-8 mt-4">
|
||||
<div class="flex-col ml-8 mt-4 flex-no-shrink">
|
||||
{#if parent}
|
||||
{#await getChannel(parent.space) then channel}
|
||||
{#if channel?._class === chunter.class.Channel}
|
||||
@ -178,13 +178,13 @@
|
||||
{/await}
|
||||
{/if}
|
||||
</div>
|
||||
<div class="flex-col content">
|
||||
<div class="flex-col content flex-no-shrink">
|
||||
{#if parent}
|
||||
<MsgView message={parent} thread {savedAttachmentsIds} />
|
||||
{#if total > comments.length}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
class="label pb-2 pt-2 pl-8 over-underline"
|
||||
class="label pb-2 pt-2 pl-8 over-underline clear-mins"
|
||||
on:click={() => {
|
||||
showAll = true
|
||||
}}
|
||||
@ -195,7 +195,7 @@
|
||||
{#each comments as comment (comment._id)}
|
||||
<MsgView message={comment} thread {savedAttachmentsIds} />
|
||||
{/each}
|
||||
<div class="mr-4 ml-4 mb-4 mt-2">
|
||||
<div class="mr-4 ml-4 pb-4 mt-2 clear-mins">
|
||||
<AttachmentRefInput
|
||||
space={parent.space}
|
||||
_class={chunter.class.ThreadMessage}
|
||||
@ -206,17 +206,19 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="min-h-4 max-h-4 h-4 flex-no-shrink" />
|
||||
|
||||
<style lang="scss">
|
||||
.content {
|
||||
overflow: hidden;
|
||||
margin: 1rem 1rem 0px;
|
||||
background-color: var(--board-bg-color);
|
||||
border: 1px solid var(--divider-color);
|
||||
margin: 1rem 1rem 0;
|
||||
padding-top: 0.5rem;
|
||||
background-color: var(--theme-list-row-color);
|
||||
border: 1px solid var(--theme-divider-color);
|
||||
border-radius: 0.75rem;
|
||||
}
|
||||
|
||||
.label:hover {
|
||||
background-color: var(--board-card-bg-hover);
|
||||
background-color: var(--theme-button-hovered);
|
||||
}
|
||||
</style>
|
||||
|
@ -16,11 +16,11 @@
|
||||
import attachment, { Attachment } from '@hcengineering/attachment'
|
||||
import { AttachmentRefInput } from '@hcengineering/attachment-resources'
|
||||
import type { ChunterMessage, Message, ThreadMessage } from '@hcengineering/chunter'
|
||||
import core, { generateId, getCurrentAccount, Ref, Space } from '@hcengineering/core'
|
||||
import core, { Ref, Space, generateId, getCurrentAccount } from '@hcengineering/core'
|
||||
import { LastView } from '@hcengineering/notification'
|
||||
import { NotificationClientImpl } from '@hcengineering/notification-resources'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { getCurrentLocation, IconClose, Label, navigate } from '@hcengineering/ui'
|
||||
import { IconClose, Label, getCurrentResolvedLocation, navigate } from '@hcengineering/ui'
|
||||
import { afterUpdate, beforeUpdate, createEventDispatcher } from 'svelte'
|
||||
import { createBacklinks } from '../backlinks'
|
||||
import chunter from '../plugin'
|
||||
@ -81,7 +81,7 @@
|
||||
message = res[0]
|
||||
|
||||
if (!message) {
|
||||
const loc = getCurrentLocation()
|
||||
const loc = getCurrentResolvedLocation()
|
||||
loc.path.length = 4
|
||||
navigate(loc)
|
||||
}
|
||||
|
@ -49,19 +49,16 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="ac-header full divide">
|
||||
<div class="ac-header full divide caption-height">
|
||||
<div class="ac-header__wrap-title">
|
||||
<span class="ac-header__title"><Label label={chunter.string.Threads} /></span>
|
||||
</div>
|
||||
</div>
|
||||
<Scroller>
|
||||
{#each threads as thread (thread)}
|
||||
<div class="item"><Thread _id={thread} {savedAttachmentsIds} /></div>
|
||||
{#each threads as thread, i (thread)}
|
||||
<Thread _id={thread} {savedAttachmentsIds} />
|
||||
{#if i < threads.length - 1}
|
||||
<div class="antiDivider" />
|
||||
{/if}
|
||||
{/each}
|
||||
</Scroller>
|
||||
|
||||
<style lang="scss">
|
||||
.item + .item {
|
||||
margin-top: 3rem;
|
||||
}
|
||||
</style>
|
||||
|
@ -4,7 +4,14 @@ import { employeeByIdStore } from '@hcengineering/contact-resources'
|
||||
import { Class, Client, Doc, getCurrentAccount, IdMap, Obj, Ref, Space, Timestamp } from '@hcengineering/core'
|
||||
import { Asset } from '@hcengineering/platform'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { getCurrentLocation, getPanelURI, location, Location, navigate, ResolvedLocation } from '@hcengineering/ui'
|
||||
import {
|
||||
getPanelURI,
|
||||
location,
|
||||
Location,
|
||||
navigate,
|
||||
ResolvedLocation,
|
||||
getCurrentResolvedLocation
|
||||
} from '@hcengineering/ui'
|
||||
import view from '@hcengineering/view'
|
||||
import { workbenchId } from '@hcengineering/workbench'
|
||||
import { get, Unsubscriber, writable } from 'svelte/store'
|
||||
@ -133,14 +140,14 @@ export function scrollAndHighLight (): void {
|
||||
|
||||
export async function getLink (doc: Doc): Promise<string> {
|
||||
const fragment = await getTitle(doc)
|
||||
const location = getCurrentLocation()
|
||||
const location = getCurrentResolvedLocation()
|
||||
return await Promise.resolve(
|
||||
`${window.location.protocol}//${window.location.host}/${workbenchId}/${location.path[1]}/${chunterId}#${fragment}`
|
||||
)
|
||||
}
|
||||
|
||||
export async function getFragment (doc: Doc): Promise<Location> {
|
||||
const loc = getCurrentLocation()
|
||||
const loc = getCurrentResolvedLocation()
|
||||
loc.path.length = 2
|
||||
loc.fragment = undefined
|
||||
loc.query = undefined
|
||||
@ -213,7 +220,6 @@ async function generateLocation (loc: Location, shortLink: string): Promise<Reso
|
||||
path: [appComponent, workspace, chunterId, doc.space],
|
||||
fragment: doc._id
|
||||
},
|
||||
shouldNavigate: true,
|
||||
defaultLocation: {
|
||||
path: [appComponent, workspace, chunterId, doc.space],
|
||||
fragment: doc._id
|
||||
@ -230,7 +236,6 @@ async function generateLocation (loc: Location, shortLink: string): Promise<Reso
|
||||
path: [appComponent, workspace],
|
||||
fragment: getPanelURI(component, comment.attachedTo, comment.attachedToClass, 'content')
|
||||
},
|
||||
shouldNavigate: false,
|
||||
defaultLocation: {
|
||||
path: [appComponent, workspace],
|
||||
fragment: getPanelURI(component, comment.attachedTo, comment.attachedToClass, 'content')
|
||||
@ -244,7 +249,6 @@ async function generateLocation (loc: Location, shortLink: string): Promise<Reso
|
||||
path: [appComponent, workspace, chunterId, doc.space, msg.attachedTo],
|
||||
fragment: doc._id
|
||||
},
|
||||
shouldNavigate: true,
|
||||
defaultLocation: {
|
||||
path: [appComponent, workspace, chunterId, doc.space],
|
||||
fragment: doc._id
|
||||
|
@ -16,7 +16,7 @@
|
||||
"SelectFolder": "Select folder",
|
||||
"OrganizationsFolder": "Companies folder",
|
||||
"PersonsFolder": "Persons folder",
|
||||
"ContactCreateLabel": "Contact",
|
||||
"ContactCreateLabel": "Create contact",
|
||||
"SearchEmployee": "Search for employee...",
|
||||
"SearchPerson": "Search for person...",
|
||||
"SearchOrganization": "Search for company...",
|
||||
|
@ -16,7 +16,7 @@
|
||||
"SelectFolder": "Выбрать папку",
|
||||
"OrganizationsFolder": "Папка с компаниями",
|
||||
"PersonsFolder": "Папка с людьми",
|
||||
"ContactCreateLabel": "Контакт",
|
||||
"ContactCreateLabel": "Создать контакт",
|
||||
"SearchEmployee": "Поиск сотрудника...",
|
||||
"SearchPerson": "Поиск персоны...",
|
||||
"SearchOrganization": "Поиск компании...",
|
||||
|
@ -153,7 +153,7 @@
|
||||
<div class="flex-presenter">
|
||||
{#if icon}
|
||||
<div class="icon" class:small-gap={size === 'inline' || size === 'small'}>
|
||||
<Icon {icon} size={kind === 'link' ? 'small' : size} />
|
||||
<Icon {icon} size={kind === 'link' || kind === 'secondary' ? 'small' : size} />
|
||||
</div>
|
||||
{/if}
|
||||
<div class="label no-underline">
|
||||
|
@ -126,6 +126,10 @@
|
||||
width: 1.5rem; // 24
|
||||
height: 1.5rem;
|
||||
}
|
||||
.ava-smaller {
|
||||
width: 1.75rem; // 32
|
||||
height: 1.75rem;
|
||||
}
|
||||
.ava-small {
|
||||
width: 2rem; // 32
|
||||
height: 2rem;
|
||||
@ -157,6 +161,8 @@
|
||||
.ava-inline.no-img,
|
||||
.ava-x-small .ava-mask,
|
||||
.ava-x-small.no-img,
|
||||
.ava-smaller .ava-mask,
|
||||
.ava-smaller.no-img,
|
||||
.ava-small .ava-mask,
|
||||
.ava-small.no-img,
|
||||
.ava-medium .ava-mask,
|
||||
|
@ -16,7 +16,7 @@
|
||||
<script lang="ts">
|
||||
import { Doc, DocumentQuery } from '@hcengineering/core'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { Button, Icon, IconAdd, Label, Loading, SearchEdit, showPopup } from '@hcengineering/ui'
|
||||
import { Button, Label, Loading, SearchEdit, showPopup, IconMoreH, ActionIcon } from '@hcengineering/ui'
|
||||
import view, { Viewlet, ViewletPreference } from '@hcengineering/view'
|
||||
import {
|
||||
ActionContext,
|
||||
@ -30,7 +30,7 @@
|
||||
} from '@hcengineering/view-resources'
|
||||
import contact from '../plugin'
|
||||
import CreateContact from './CreateContact.svelte'
|
||||
import { deviceOptionsStore as deviceInfo } from '@hcengineering/ui'
|
||||
// import { deviceOptionsStore as deviceInfo } from '@hcengineering/ui'
|
||||
|
||||
let search = ''
|
||||
let searchQuery: DocumentQuery<Doc> = {}
|
||||
@ -74,7 +74,7 @@
|
||||
showPopup(CreateContact, { space: contact.space.Contacts, targetElement: ev.target }, ev.target as HTMLElement)
|
||||
}
|
||||
|
||||
$: twoRows = $deviceInfo.twoRows
|
||||
// $: twoRows = $deviceInfo.twoRows
|
||||
|
||||
$: viewOptions = getViewOptions(viewlet, $viewOptionStore)
|
||||
</script>
|
||||
@ -85,30 +85,29 @@
|
||||
}}
|
||||
/>
|
||||
<div class="antiPanel-component">
|
||||
<div class="ac-header withSettings" class:full={!twoRows} class:mini={twoRows}>
|
||||
<div class:ac-header-full={!twoRows} class:flex-between={twoRows}>
|
||||
<div class="ac-header__wrap-title mr-3">
|
||||
<div class="ac-header__icon"><Icon icon={contact.icon.Person} size={'small'} /></div>
|
||||
<span class="ac-header__title"><Label label={contact.string.Contacts} /></span>
|
||||
<div class="ml-4"><FilterButton _class={contact.class.Contact} /></div>
|
||||
</div>
|
||||
|
||||
<SearchEdit
|
||||
bind:value={search}
|
||||
on:change={() => {
|
||||
updateResultQuery(search)
|
||||
}}
|
||||
/>
|
||||
<div class="ac-header full divide">
|
||||
<div class="ac-header__wrap-title mr-3">
|
||||
<span class="ac-header__title"><Label label={contact.string.Contacts} /></span>
|
||||
</div>
|
||||
<div class="ac-header-full" class:secondRow={twoRows}>
|
||||
<div class="mb-1 clear-mins">
|
||||
<Button
|
||||
icon={IconAdd}
|
||||
label={contact.string.ContactCreateLabel}
|
||||
kind={'primary'}
|
||||
size={'small'}
|
||||
size={'medium'}
|
||||
on:click={(ev) => showCreateDialog(ev)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ac-header full divide search-start">
|
||||
<div class="ac-header-full small-gap">
|
||||
<SearchEdit bind:value={search} on:change={() => updateResultQuery(search)} />
|
||||
<ActionIcon icon={IconMoreH} size={'small'} />
|
||||
<div class="buttons-divider" />
|
||||
<FilterButton _class={contact.class.Contact} />
|
||||
</div>
|
||||
<div class="ac-header-full medium-gap">
|
||||
<ViewletSettingButton bind:viewOptions {viewlet} />
|
||||
<ActionIcon icon={IconMoreH} size={'small'} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -169,7 +169,8 @@
|
||||
<ChannelsDropdown
|
||||
bind:value={channels}
|
||||
focusIndex={10}
|
||||
kind={'no-border'}
|
||||
kind={'secondary'}
|
||||
size={'large'}
|
||||
editable
|
||||
restricted={[contact.channelProvider.Email]}
|
||||
/>
|
||||
|
@ -103,6 +103,8 @@
|
||||
<ChannelsDropdown
|
||||
bind:value={channels}
|
||||
focusIndex={10}
|
||||
kind={'secondary'}
|
||||
size={'large'}
|
||||
editable
|
||||
highlighted={matchedChannels.map((it) => it.provider)}
|
||||
/>
|
||||
|
@ -120,6 +120,6 @@
|
||||
</div>
|
||||
</div>
|
||||
<svelte:fragment slot="pool">
|
||||
<ChannelsDropdown bind:value={channels} focusIndex={10} kind={'no-border'} editable />
|
||||
<ChannelsDropdown bind:value={channels} focusIndex={10} kind={'secondary'} size={'large'} editable />
|
||||
</svelte:fragment>
|
||||
</Card>
|
||||
|
@ -12,6 +12,8 @@
|
||||
export let kind: ButtonKind = 'link'
|
||||
export let tooltipLabels: PersonLabelTooltip | undefined = undefined
|
||||
export let onChange: ((value: Ref<Employee>) => void) | undefined = undefined
|
||||
export let colorInherit: boolean = false
|
||||
export let accent: boolean = false
|
||||
export let inline = false
|
||||
|
||||
$: employee = value ? $employeeByIdStore.get(value) : undefined
|
||||
@ -47,7 +49,9 @@
|
||||
shouldShowPlaceholder
|
||||
defaultName={contact.string.NotSpecified}
|
||||
shouldShowName={kind !== 'list'}
|
||||
avatarSize={kind === 'list-header' ? 'small' : 'x-small'}
|
||||
avatarSize={kind === 'list-header' ? 'smaller' : 'x-small'}
|
||||
disableClick
|
||||
{colorInherit}
|
||||
{accent}
|
||||
/>
|
||||
{/if}
|
||||
|
@ -2,6 +2,7 @@
|
||||
import { Employee } from '@hcengineering/contact'
|
||||
import { WithLookup } from '@hcengineering/core'
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import { IconSize } from '@hcengineering/ui'
|
||||
import { PersonLabelTooltip } from '..'
|
||||
import PersonPresenter from '../components/PersonPresenter.svelte'
|
||||
import contact from '../plugin'
|
||||
@ -12,10 +13,12 @@
|
||||
export let shouldShowName: boolean = true
|
||||
export let shouldShowPlaceholder = false
|
||||
export let onEmployeeEdit: ((event: MouseEvent) => void) | undefined = undefined
|
||||
export let avatarSize: 'inline' | 'tiny' | 'x-small' | 'small' | 'medium' | 'large' | 'x-large' = 'x-small'
|
||||
export let avatarSize: IconSize = 'x-small'
|
||||
export let isInteractive = true
|
||||
export let inline = false
|
||||
export let disableClick = false
|
||||
export let colorInherit: boolean = false
|
||||
export let accent: boolean = false
|
||||
export let defaultName: IntlString | undefined = undefined
|
||||
export let element: HTMLElement | undefined = undefined
|
||||
</script>
|
||||
@ -31,6 +34,8 @@
|
||||
{shouldShowPlaceholder}
|
||||
isInteractive={isInteractive && !disableClick}
|
||||
{inline}
|
||||
{colorInherit}
|
||||
{accent}
|
||||
{defaultName}
|
||||
statusLabel={value?.active === false && shouldShowName ? contact.string.Inactive : undefined}
|
||||
/>
|
||||
|
@ -9,17 +9,19 @@
|
||||
export let kind: ButtonKind = 'link'
|
||||
export let tooltipLabels: PersonLabelTooltip | undefined = undefined
|
||||
export let onChange: ((value: Ref<Employee>) => void) | undefined = undefined
|
||||
export let colorInherit: boolean = false
|
||||
export let accent: boolean = false
|
||||
export let inline = false
|
||||
</script>
|
||||
|
||||
{#if Array.isArray(value)}
|
||||
<div class="inline-content">
|
||||
{#each value as employee}
|
||||
<EmployeeAttributePresenter value={employee} {kind} {tooltipLabels} {onChange} {inline} />
|
||||
<EmployeeAttributePresenter value={employee} {kind} {tooltipLabels} {onChange} {inline} {colorInherit} {accent} />
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<EmployeeAttributePresenter {value} {kind} {tooltipLabels} {onChange} {inline} />
|
||||
<EmployeeAttributePresenter {value} {kind} {tooltipLabels} {onChange} {inline} {colorInherit} {accent} />
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
|
@ -16,6 +16,7 @@
|
||||
import { Employee, getName, Person } from '@hcengineering/contact'
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import { Label, LabelAndProps, tooltip } from '@hcengineering/ui'
|
||||
import type { IconSize } from '@hcengineering/ui'
|
||||
import { DocNavLink } from '@hcengineering/view-resources'
|
||||
import Avatar from './Avatar.svelte'
|
||||
|
||||
@ -27,11 +28,13 @@
|
||||
export let shouldShowPlaceholder = false
|
||||
export let defaultName: IntlString | undefined = undefined
|
||||
export let statusLabel: IntlString | undefined = undefined
|
||||
export let avatarSize: 'inline' | 'tiny' | 'x-small' | 'small' | 'medium' | 'large' | 'x-large' = 'x-small'
|
||||
export let avatarSize: IconSize = 'x-small'
|
||||
export let onEdit: ((event: MouseEvent) => void) | undefined = undefined
|
||||
export let showTooltip: LabelAndProps | undefined = undefined
|
||||
export let enlargedText = false
|
||||
export let element: HTMLElement | undefined = undefined
|
||||
export let colorInherit: boolean = false
|
||||
export let accent: boolean = false
|
||||
|
||||
const onEditClick = (evt: MouseEvent) => {
|
||||
if (isInteractive) {
|
||||
@ -41,7 +44,7 @@
|
||||
</script>
|
||||
|
||||
{#if value}
|
||||
<DocNavLink object={value} onClick={onEdit} disableClick={!isInteractive} {inline}>
|
||||
<DocNavLink object={value} onClick={onEdit} disableClick={!isInteractive} {inline} {colorInherit}>
|
||||
<span
|
||||
use:tooltip={showTooltip}
|
||||
class="contentPresenter"
|
||||
@ -58,7 +61,7 @@
|
||||
</span>
|
||||
{/if}
|
||||
{#if shouldShowName}
|
||||
<span class="eContentPresenterLabel">{getName(value)}</span>
|
||||
<span class="eContentPresenterLabel" class:colorInherit>{getName(value)}</span>
|
||||
{/if}
|
||||
</span>
|
||||
</DocNavLink>
|
||||
@ -80,7 +83,7 @@
|
||||
</span>
|
||||
{/if}
|
||||
{#if shouldShowName && defaultName}
|
||||
<span class="eContentPresenterLabel">
|
||||
<span class="eContentPresenterLabel" class:colorInherit>
|
||||
<Label label={defaultName} />
|
||||
</span>
|
||||
{#if statusLabel}
|
||||
@ -109,7 +112,7 @@
|
||||
min-width: 0;
|
||||
font-weight: 500;
|
||||
text-align: left;
|
||||
color: var(--accent-color);
|
||||
color: var(--theme-caption-color);
|
||||
|
||||
overflow: hidden;
|
||||
visibility: visible;
|
||||
@ -119,14 +122,18 @@
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
user-select: none;
|
||||
|
||||
&.colorInherit {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
.eContentPresenterIcon {
|
||||
color: var(--caption-color);
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
.eContentPresenterLabel {
|
||||
text-decoration: underline;
|
||||
color: var(--caption-color);
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
<script lang="ts">
|
||||
import { getName, Person } from '@hcengineering/contact'
|
||||
import { getEmbeddedLabel, IntlString } from '@hcengineering/platform'
|
||||
import { LabelAndProps } from '@hcengineering/ui'
|
||||
import type { LabelAndProps, IconSize } from '@hcengineering/ui'
|
||||
import { PersonLabelTooltip } from '..'
|
||||
import PersonContent from './PersonContent.svelte'
|
||||
|
||||
@ -29,9 +29,11 @@
|
||||
export let defaultName: IntlString | undefined = undefined
|
||||
export let statusLabel: IntlString | undefined = undefined
|
||||
export let tooltipLabels: PersonLabelTooltip | undefined = undefined
|
||||
export let avatarSize: 'inline' | 'tiny' | 'x-small' | 'small' | 'medium' | 'large' | 'x-large' = 'x-small'
|
||||
export let avatarSize: IconSize = 'x-small'
|
||||
export let onEdit: ((event: MouseEvent) => void) | undefined = undefined
|
||||
export let element: HTMLElement | undefined = undefined
|
||||
export let colorInherit: boolean = false
|
||||
export let accent: boolean = false
|
||||
|
||||
function getTooltip (
|
||||
tooltipLabels: PersonLabelTooltip | undefined,
|
||||
@ -73,6 +75,8 @@
|
||||
{shouldShowPlaceholder}
|
||||
{enlargedText}
|
||||
{statusLabel}
|
||||
{colorInherit}
|
||||
{accent}
|
||||
bind:element
|
||||
/>
|
||||
{/if}
|
||||
|
@ -51,6 +51,10 @@
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
.smaller {
|
||||
width: 1.125rem;
|
||||
height: 1.125rem;
|
||||
}
|
||||
.small {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
|
@ -30,7 +30,13 @@ import {
|
||||
import { Client, Doc, getCurrentAccount, IdMap, ObjQueryType, Ref, Timestamp, toIdMap } from '@hcengineering/core'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { TemplateDataProvider } from '@hcengineering/templates'
|
||||
import { DropdownIntlItem, getCurrentLocation, getPanelURI, Location, ResolvedLocation } from '@hcengineering/ui'
|
||||
import {
|
||||
DropdownIntlItem,
|
||||
getCurrentResolvedLocation,
|
||||
getPanelURI,
|
||||
Location,
|
||||
ResolvedLocation
|
||||
} from '@hcengineering/ui'
|
||||
import view, { Filter } from '@hcengineering/view'
|
||||
import { FilterQuery } from '@hcengineering/view-resources'
|
||||
import { get, writable } from 'svelte/store'
|
||||
@ -180,7 +186,7 @@ export async function getContactChannel (value: Contact, provider: Ref<ChannelPr
|
||||
}
|
||||
|
||||
export async function getContactLink (doc: Doc): Promise<Location> {
|
||||
const loc = getCurrentLocation()
|
||||
const loc = getCurrentResolvedLocation()
|
||||
loc.path.length = 2
|
||||
loc.fragment = undefined
|
||||
loc.query = undefined
|
||||
@ -213,7 +219,6 @@ async function generateLocation (loc: Location, id: Ref<Contact>): Promise<Resol
|
||||
path: [appComponent, workspace],
|
||||
fragment: getPanelURI(view.component.EditDoc, doc._id, doc._class, 'content')
|
||||
},
|
||||
shouldNavigate: false,
|
||||
defaultLocation: {
|
||||
path: [appComponent, workspace, contactId],
|
||||
fragment: getPanelURI(view.component.EditDoc, doc._id, doc._class, 'content')
|
||||
|
@ -121,28 +121,28 @@
|
||||
<svelte:fragment slot="pool">
|
||||
<UserBoxList
|
||||
items={object.authors}
|
||||
size="small"
|
||||
label={document.string.Authors}
|
||||
emptyLabel={document.string.Authors}
|
||||
kind="no-border"
|
||||
kind={'secondary'}
|
||||
size={'large'}
|
||||
width={'min-content'}
|
||||
on:update={({ detail }) => (object.authors = detail)}
|
||||
/>
|
||||
<UserBoxList
|
||||
items={object.approvers}
|
||||
size="small"
|
||||
label={document.string.Approvers}
|
||||
emptyLabel={document.string.Approvers}
|
||||
kind="no-border"
|
||||
kind={'secondary'}
|
||||
size={'large'}
|
||||
width={'min-content'}
|
||||
on:update={({ detail }) => (object.approvers = detail)}
|
||||
/>
|
||||
<UserBoxList
|
||||
items={object.reviewers}
|
||||
size="small"
|
||||
label={document.string.Reviewers}
|
||||
emptyLabel={document.string.Reviewers}
|
||||
kind="no-border"
|
||||
kind={'secondary'}
|
||||
size={'large'}
|
||||
width={'min-content'}
|
||||
on:update={({ detail }) => (object.reviewers = detail)}
|
||||
/>
|
||||
|
@ -18,7 +18,7 @@
|
||||
import { Doc, DocumentQuery } from '@hcengineering/core'
|
||||
import { Document } from '@hcengineering/document'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { deviceOptionsStore as deviceInfo, Icon, Label, Loading, SearchEdit } from '@hcengineering/ui'
|
||||
import { ActionIcon, IconMoreH, Label, Loading, SearchEdit } from '@hcengineering/ui'
|
||||
import view, { Viewlet, ViewletPreference } from '@hcengineering/view'
|
||||
import {
|
||||
ActionContext,
|
||||
@ -70,8 +70,8 @@
|
||||
}
|
||||
})
|
||||
|
||||
let twoRows: boolean
|
||||
$: twoRows = $deviceInfo.docWidth <= 680
|
||||
// let twoRows: boolean
|
||||
// $: twoRows = $deviceInfo.docWidth <= 680
|
||||
|
||||
$: viewOptions = getViewOptions(viewlet, $viewOptionStore)
|
||||
</script>
|
||||
@ -82,23 +82,21 @@
|
||||
}}
|
||||
/>
|
||||
<div class="antiPanel-component">
|
||||
<div class="ac-header withSettings" class:full={!twoRows} class:mini={twoRows}>
|
||||
<div class:ac-header-full={!twoRows} class:flex-between={twoRows}>
|
||||
<div class="ac-header__wrap-title mr-3">
|
||||
<div class="ac-header__icon"><Icon icon={document.icon.Document} size={'small'} /></div>
|
||||
<span class="ac-header__title"><Label label={document.string.Documents} /></span>
|
||||
<div class="ml-4"><FilterButton _class={document.class.Document} /></div>
|
||||
</div>
|
||||
|
||||
<SearchEdit
|
||||
bind:value={search}
|
||||
on:change={() => {
|
||||
updateResultQuery(search, query)
|
||||
}}
|
||||
/>
|
||||
<div class="ac-header full divide caption-height">
|
||||
<div class="ac-header__wrap-title mr-3">
|
||||
<span class="ac-header__title"><Label label={document.string.Documents} /></span>
|
||||
</div>
|
||||
<div class="ac-header-full" class:secondRow={twoRows}>
|
||||
</div>
|
||||
<div class="ac-header full divide search-start">
|
||||
<div class="ac-header-full small-gap">
|
||||
<SearchEdit bind:value={search} on:change={() => updateResultQuery(search, query)} />
|
||||
<ActionIcon icon={IconMoreH} size={'small'} />
|
||||
<div class="buttons-divider" />
|
||||
<FilterButton _class={document.class.Document} />
|
||||
</div>
|
||||
<div class="ac-header-full medium-gap">
|
||||
<ViewletSettingButton bind:viewOptions {viewlet} />
|
||||
<ActionIcon icon={IconMoreH} size={'small'} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -75,13 +75,21 @@
|
||||
</div>
|
||||
</div>
|
||||
<svelte:fragment slot="header">
|
||||
<SpaceSelector _class={hr.class.Department} label={hr.string.ParentDepartmentLabel} bind:space />
|
||||
<SpaceSelector
|
||||
_class={hr.class.Department}
|
||||
label={hr.string.ParentDepartmentLabel}
|
||||
bind:space
|
||||
kind={'secondary'}
|
||||
size={'large'}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="pool">
|
||||
<EmployeeBox
|
||||
focusIndex={3}
|
||||
label={hr.string.TeamLead}
|
||||
placeholder={hr.string.TeamLead}
|
||||
kind={'secondary'}
|
||||
size={'large'}
|
||||
bind:value={lead}
|
||||
allowDeselect
|
||||
showNavigate={false}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user