mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-22 21:50:34 +03:00
Upd: DataPicker with region selection. Presenters. (#1153)
Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
parent
5abfbe64ac
commit
338901ab51
@ -6,7 +6,7 @@
|
||||
"Save": "Сохранить",
|
||||
"Download": "Загрузить",
|
||||
"Close": "Закрыть",
|
||||
"NotSelected": "Не выделено",
|
||||
"NotSelected": "Не выбрано",
|
||||
"Deselect": "Снять выделение",
|
||||
"AddSocialLinks": "Добавить контактную информацию"
|
||||
}
|
||||
|
@ -66,7 +66,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex-row-center container" bind:this={container}
|
||||
<div class="antiSelect" bind:this={container}
|
||||
on:click|preventDefault={() => {
|
||||
btn.focus()
|
||||
if (!opened) {
|
||||
@ -85,36 +85,14 @@
|
||||
}
|
||||
}}
|
||||
>
|
||||
<button class="focused-button btn" class:selected bind:this={btn}>
|
||||
<button class="button circle" class:selected={value} bind:this={btn}>
|
||||
<Avatar avatar={selected ? selected.avatar : undefined} size={'medium'} />
|
||||
</button>
|
||||
|
||||
<div class="selectUser">
|
||||
<div class="title"><Label label={title} /></div>
|
||||
<div class="overflow-label" class:caption-color={selected} class:content-dark-color={!selected}>
|
||||
<div class="group">
|
||||
<span class="label"><Label label={title} /></span>
|
||||
<span class="result" class:selected={value} class:not-selected={!value}>
|
||||
{#if selected}{getName(selected)}{:else}<Label label={presentation.string.NotSelected} />{/if}
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.container { cursor: pointer; }
|
||||
.btn {
|
||||
width: 2.25rem;
|
||||
height: 2.25rem;
|
||||
background-color: transparent;
|
||||
border: 1px solid var(--theme-card-divider);
|
||||
border-radius: 50%;
|
||||
}
|
||||
.selected { border: none; }
|
||||
|
||||
.selectUser {
|
||||
margin-left: .75rem;
|
||||
min-width: 0;
|
||||
.title {
|
||||
font-size: .75rem;
|
||||
font-weight: 500;
|
||||
color: var(--theme-content-accent-color);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -159,6 +159,8 @@ p:last-child { margin-block-end: 0; }
|
||||
.flex-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
min-height: 0;
|
||||
}
|
||||
.flex-col-center {
|
||||
display: flex;
|
||||
@ -175,6 +177,7 @@ p:last-child { margin-block-end: 0; }
|
||||
.items-baseline { align-items: baseline; }
|
||||
|
||||
.flex-presenter, .inline-presenter {
|
||||
flex-wrap: nowrap;
|
||||
cursor: pointer;
|
||||
|
||||
.icon {
|
||||
@ -195,11 +198,20 @@ p:last-child { margin-block-end: 0; }
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
user-select: none;
|
||||
}
|
||||
&:hover .icon { color: var(--theme-caption-color); }
|
||||
&:hover .label {
|
||||
text-decoration: underline;
|
||||
color: var(--theme-caption-color);
|
||||
|
||||
&.nowrap { white-space: nowrap; }
|
||||
}
|
||||
.action {
|
||||
visibility: hidden;
|
||||
margin-left: .75rem;
|
||||
}
|
||||
&:hover {
|
||||
.icon { color: var(--theme-caption-color); }
|
||||
.label {
|
||||
text-decoration: underline;
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
.action { visibility: visible; }
|
||||
}
|
||||
}
|
||||
.flex-presenter {
|
||||
|
@ -424,3 +424,106 @@
|
||||
border-radius: .75rem;
|
||||
box-shadow: 0px 3px 3px rgba(0, 0, 0, .2);
|
||||
}
|
||||
|
||||
/* Select */
|
||||
.antiSelect {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
min-width: 0;
|
||||
cursor: pointer;
|
||||
|
||||
.button {
|
||||
width: 2.25rem;
|
||||
height: 2.25rem;
|
||||
background-color: transparent;
|
||||
border: 1px solid var(--theme-card-divider);
|
||||
|
||||
&.circle { border-radius: 50%; }
|
||||
&.round-2 { border-radius: .5rem; }
|
||||
|
||||
& > .icon { color: var(--theme-content-trans-color); }
|
||||
&.selected {
|
||||
background-color: var(--theme-button-bg-focused);
|
||||
border: none;
|
||||
}
|
||||
&:focus {
|
||||
border: 1px solid var(--primary-button-focused-border);
|
||||
box-shadow: 0 0 0 3px var(--primary-button-outline);
|
||||
& > .icon { color: var(--theme-caption-color); }
|
||||
}
|
||||
}
|
||||
&:hover .button {
|
||||
background-color: var(--theme-button-bg-pressed);
|
||||
border: 1px solid var(--theme-bg-accent-color);
|
||||
& > .icon { color: var(--theme-caption-color); }
|
||||
}
|
||||
|
||||
.label, .result {
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
user-select: none;
|
||||
min-width: 0;
|
||||
}
|
||||
.label {
|
||||
font-size: .75rem;
|
||||
font-weight: 500;
|
||||
color: var(--theme-content-accent-color);
|
||||
}
|
||||
.result {
|
||||
&.selected { color: var(--theme-caption-color); }
|
||||
&.not-selected { color: var(--theme-content-dark-color); }
|
||||
&.highlight {
|
||||
font-weight: 500;
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
margin-left: .75rem;
|
||||
min-height: 0;
|
||||
}
|
||||
.wrap {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
min-width: 0;
|
||||
|
||||
&::after, &::before {
|
||||
position: absolute;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
background-color: var(--primary-button-enabled);
|
||||
}
|
||||
&::before {
|
||||
top: -2px;
|
||||
left: -4px;
|
||||
clip-path: path('M0,6v-6h6v1h-5v5z');
|
||||
}
|
||||
&::after {
|
||||
bottom: -2px;
|
||||
right: -4px;
|
||||
clip-path: path('M0,6h6v-6h-1v5h-5z');
|
||||
}
|
||||
&.wraped::before, &.wraped::after { content: ''; }
|
||||
}
|
||||
|
||||
.divider {
|
||||
margin: 0 .125rem;
|
||||
font-weight: 500;
|
||||
font-size: .75em;
|
||||
color: var(--theme-content-dark-color);
|
||||
|
||||
&.inter { font-size: 1em; }
|
||||
&.max {
|
||||
margin: 0 .5rem;
|
||||
font-size: .75rem;
|
||||
color: var(--theme-content-trans-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,8 @@
|
||||
"Suggested": "Suggested",
|
||||
"TimeTooltip": "{value}",
|
||||
"None": "None",
|
||||
"NotSelected": "Not selected",
|
||||
"Today": "Today",
|
||||
"English": "English",
|
||||
"Russian": "Russian"
|
||||
}
|
||||
|
@ -12,6 +12,8 @@
|
||||
"Suggested": "Предложено",
|
||||
"TimeTooltip": "{value}",
|
||||
"None": "Нет",
|
||||
"NotSelected": "Не выбрано",
|
||||
"Today": "Сегодня",
|
||||
"English": "Английский",
|
||||
"Russian": "Русский"
|
||||
}
|
||||
|
@ -13,64 +13,83 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { onMount } from 'svelte'
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import Label from './Label.svelte'
|
||||
import Calendar from './icons/Calendar.svelte'
|
||||
import Close from './icons/Close.svelte'
|
||||
import { DatePopup, showPopup } from '..'
|
||||
import ui, { Label, DatePopup, DatePresenter, showPopup } from '..'
|
||||
|
||||
export let title: IntlString
|
||||
export let selected: Date = new Date(Date.now())
|
||||
export let value: Date | null | undefined = null
|
||||
export let range: Date | null | undefined = undefined
|
||||
export let bigDay: boolean = false
|
||||
export let show: boolean = false
|
||||
let container: HTMLElement
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let opened: boolean = false
|
||||
let secondSelect: boolean = false
|
||||
let container: HTMLElement
|
||||
let btn: HTMLElement
|
||||
|
||||
onMount(() => {
|
||||
if (btn && show) {
|
||||
btn.click()
|
||||
show = false
|
||||
}
|
||||
})
|
||||
|
||||
const splitRes = (result: any): void => {
|
||||
if (result !== undefined) {
|
||||
if (result[0] !== value) value = result[0]
|
||||
if (result[1] !== range) range = result[1]
|
||||
dispatch('change', [value, range])
|
||||
}
|
||||
}
|
||||
const onClosePopup = (result: any): void => {
|
||||
splitRes(result)
|
||||
opened = false
|
||||
secondSelect = false
|
||||
}
|
||||
const onUpdatePopup = (result: any): void => {
|
||||
secondSelect = true
|
||||
splitRes(result)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex-row-center">
|
||||
<div class="antiSelect"
|
||||
bind:this={container}
|
||||
on:click|preventDefault={() => {
|
||||
btn.focus()
|
||||
if (!opened) {
|
||||
opened = true
|
||||
showPopup(DatePopup, { title, value, range }, container, onClosePopup, onUpdatePopup)
|
||||
}
|
||||
}}
|
||||
>
|
||||
<button
|
||||
bind:this={container}
|
||||
class="focused-button btn"
|
||||
class:selected={show}
|
||||
on:click|preventDefault={() => {
|
||||
show = true
|
||||
showPopup(DatePopup, { selected, title }, container, (result) => {
|
||||
if (result) {
|
||||
selected = result
|
||||
}
|
||||
show = false
|
||||
})
|
||||
}}
|
||||
bind:this={btn}
|
||||
class="button round-2"
|
||||
class:selected={value}
|
||||
>
|
||||
<div class="icon">
|
||||
{#if show}<Close size={'small'} />{:else}<Calendar size={'medium'} />{/if}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<div class="selectDate">
|
||||
<div class="label"><Label label={title} /></div>
|
||||
<div class="date">
|
||||
{selected.getMonth() + 1} / {selected.getDate()} / {selected.getFullYear()}
|
||||
</div>
|
||||
<div class="group">
|
||||
<span class="label"><Label label={title} /></span>
|
||||
{#if value !== undefined}
|
||||
<div class="flex-row-center">
|
||||
<DatePresenter {value} {bigDay} wraped={opened && !secondSelect} />
|
||||
{#if range !== undefined}
|
||||
<span class="divider max"> — </span>
|
||||
<DatePresenter value={range} {bigDay} wraped={opened && secondSelect} />
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<span class="result not-selected"><Label label={ui.string.NotSelected} /></span>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.btn {
|
||||
width: 2.25rem;
|
||||
height: 2.25rem;
|
||||
border-radius: .5rem;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.selectDate {
|
||||
margin-left: .75rem;
|
||||
.label {
|
||||
font-size: .75rem;
|
||||
font-weight: 500;
|
||||
color: var(--theme-content-accent-color);
|
||||
}
|
||||
.date {
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -14,16 +14,31 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import Label from './Label.svelte'
|
||||
import { translate } from '@anticrm/platform'
|
||||
import Back from './icons/Back.svelte'
|
||||
import Forward from './icons/Forward.svelte'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import ui, { Label } from '..'
|
||||
import type { TSelectDate, TCellStyle, ICell } from '../types'
|
||||
|
||||
export let title: IntlString
|
||||
export let selected: Date = new Date(Date.now())
|
||||
export let value: TSelectDate = null
|
||||
export let range: TSelectDate = undefined
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let view: Date = selected
|
||||
const getNow = (): Date => {
|
||||
let tempDate = new Date(Date.now())
|
||||
return new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())
|
||||
}
|
||||
let today: Date = getNow()
|
||||
let todayString: string
|
||||
async function todayStr() {
|
||||
todayString = await translate(ui.string.Today, {})
|
||||
}
|
||||
todayStr()
|
||||
|
||||
let view: Date = (value === null || value === undefined) ? today : new Date(value)
|
||||
const months: Array<string> = [
|
||||
'January',
|
||||
'February',
|
||||
@ -39,19 +54,47 @@
|
||||
'December'
|
||||
]
|
||||
let monthYear: string
|
||||
let days: Array<number>
|
||||
let days: Array<ICell> = []
|
||||
let firstClick: boolean = true
|
||||
let result: Array<TSelectDate> = [value, range]
|
||||
|
||||
const daysInMonth = (date: Date): number => {
|
||||
return 33 - new Date(date.getFullYear(), date.getMonth(), 33).getDate()
|
||||
}
|
||||
|
||||
$: {
|
||||
monthYear = months[view.getMonth()] + ' ' + view.getFullYear()
|
||||
const compareDates = (d1: Date, d2: Date): boolean => {
|
||||
if (d1.getFullYear() == d2.getFullYear() &&
|
||||
d1.getMonth() == d2.getMonth() &&
|
||||
d1.getDate() == d2.getDate()) return true
|
||||
return false
|
||||
}
|
||||
const getDateStyle = (date: Date): TCellStyle => {
|
||||
if (value !== undefined && value !== null && compareDates(value, date)) return 'selected-start'
|
||||
else if (value && value < date && range) {
|
||||
if (range && compareDates(range, date)) return 'selected-end'
|
||||
else if (date < range) return 'selected'
|
||||
else return 'not-selected'
|
||||
}
|
||||
return 'not-selected'
|
||||
}
|
||||
|
||||
const renderCellStyles = (): void => {
|
||||
days = []
|
||||
for (let i = 1; i <= daysInMonth(view); i++) {
|
||||
days.push(new Date(view.getFullYear(), view.getMonth(), i).getDay())
|
||||
const tempDate = new Date(view.getFullYear(), view.getMonth(), i)
|
||||
days.push({
|
||||
dayOfWeek: (tempDate.getDay() === 0) ? 7 : tempDate.getDay(),
|
||||
style: getDateStyle(tempDate),
|
||||
today: compareDates(tempDate, today)
|
||||
})
|
||||
}
|
||||
days = days
|
||||
}
|
||||
renderCellStyles()
|
||||
|
||||
$: monthYear = months[view.getMonth()] + ' ' + view.getFullYear()
|
||||
$: if (value) renderCellStyles()
|
||||
$: if (range) renderCellStyles()
|
||||
</script>
|
||||
|
||||
<div class="popup">
|
||||
@ -63,6 +106,7 @@
|
||||
on:click|preventDefault={() => {
|
||||
view.setMonth(view.getMonth() - 1)
|
||||
view = view
|
||||
renderCellStyles()
|
||||
}}><div class="icon"><Back size={'small'} /></div></button>
|
||||
<div class="monthYear">
|
||||
{monthYear}
|
||||
@ -72,6 +116,7 @@
|
||||
on:click|preventDefault={() => {
|
||||
view.setMonth(view.getMonth() + 1)
|
||||
view = view
|
||||
renderCellStyles()
|
||||
}}><div class="icon"><Forward size={'small'} /></div></button>
|
||||
</div>
|
||||
</div>
|
||||
@ -86,14 +131,25 @@
|
||||
<div class="caption">Su</div>
|
||||
{#each days as day, i}
|
||||
<div
|
||||
class="day"
|
||||
class:selected={i + 1 === selected.getDate() &&
|
||||
view.getMonth() === selected.getMonth() &&
|
||||
view.getFullYear() === selected.getFullYear()}
|
||||
style="grid-column: {day + 1}/{day + 2};"
|
||||
class="day {day.style}"
|
||||
class:today={day.today}
|
||||
data-today={day.today ? todayString : ''}
|
||||
style="grid-column: {day.dayOfWeek}/{day.dayOfWeek + 1};"
|
||||
on:click={() => {
|
||||
selected = new Date(view.getFullYear(), view.getMonth(), i + 1)
|
||||
dispatch('close', selected)
|
||||
if (firstClick) {
|
||||
result[0] = new Date(view.getFullYear(), view.getMonth(), i + 1)
|
||||
value = result[0]
|
||||
firstClick = false
|
||||
if (result[1] === undefined) dispatch('close', result)
|
||||
else dispatch('update', result)
|
||||
} else {
|
||||
result[1] = new Date(view.getFullYear(), view.getMonth(), i + 1)
|
||||
if (result[0] && result[1] && result[0].getTime() > result[1].getTime())
|
||||
[result[0], result[1]] = [result[1], result[0]]
|
||||
value = result[0]
|
||||
range = result[1]
|
||||
dispatch('close', result)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{i + 1}
|
||||
@ -152,17 +208,40 @@
|
||||
height: 2.25rem;
|
||||
color: var(--theme-content-dark-color);
|
||||
}
|
||||
.caption {
|
||||
font-size: .75rem;
|
||||
}
|
||||
.caption { font-size: .75rem; }
|
||||
.day {
|
||||
border-radius: .5rem;
|
||||
border: 1px solid transparent;
|
||||
cursor: pointer;
|
||||
|
||||
&.selected {
|
||||
background-color: var(--theme-button-bg-focused);
|
||||
border: 1px solid var(--theme-bg-accent-color);
|
||||
background-color: var(--primary-button-disabled);
|
||||
border-color: transparent;
|
||||
color: var(--theme-content-accent-color);
|
||||
|
||||
&-start, &-end {
|
||||
background-color: var(--primary-button-enabled);
|
||||
border-color: var(--primary-button-focused-border);
|
||||
color: var(--primary-button-color);
|
||||
}
|
||||
}
|
||||
&.today {
|
||||
position: relative;
|
||||
border-color: var(--theme-content-color);
|
||||
font-weight: 500;
|
||||
color: var(--theme-caption-color);
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
content: attr(data-today);
|
||||
top: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
font-weight: 600;
|
||||
font-size: .35rem;
|
||||
text-transform: uppercase;
|
||||
color: var(--theme-content-dark-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
41
packages/ui/src/components/DatePresenter.svelte
Normal file
41
packages/ui/src/components/DatePresenter.svelte
Normal file
@ -0,0 +1,41 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import type { TSelectDate } from '../types'
|
||||
|
||||
export let value: TSelectDate
|
||||
export let bigDay: boolean = false
|
||||
export let wraped: boolean = false
|
||||
|
||||
const { currentLanguage } = getContext('lang')
|
||||
let inter: boolean = (currentLanguage === 'ru') ?? false
|
||||
</script>
|
||||
|
||||
{#if value !== undefined}
|
||||
<div class="wrap" class:wraped>
|
||||
<span class="result" class:selected={value !== null} class:not-selected={value === null} class:highlight={inter && bigDay}>
|
||||
{#if value === null}--{:else}{inter ? value.getDate() : value.getMonth() + 1}{/if}
|
||||
</span>
|
||||
<span class="divider" class:inter>{inter ? '.' : '/'}</span>
|
||||
<span class="result" class:selected={value !== null} class:not-selected={value === null} class:highlight={!inter && bigDay}>
|
||||
{#if value === null}--{:else}{inter ? value.getMonth() + 1 : value.getDate()}{/if}
|
||||
</span>
|
||||
<span class="divider" class:inter>{inter ? '.' : '/'}</span>
|
||||
<span class="result" class:selected={value !== null} class:not-selected={value === null}>
|
||||
{#if value === null}--{:else}{value.getFullYear()}{/if}
|
||||
</span>
|
||||
</div>
|
||||
{/if}
|
@ -18,6 +18,6 @@
|
||||
</script>
|
||||
|
||||
{#each $modal as popup, i}
|
||||
<PopupInstance is={popup.is} props={popup.props} element={popup.element} onClose={popup.onClose} zIndex={(i + 1) * 500} top={$modal.length - 1 === i} close={popup.close}/>
|
||||
<PopupInstance is={popup.is} props={popup.props} element={popup.element} onClose={popup.onClose} onUpdate={popup.onUpdate} zIndex={(i + 1) * 500} top={$modal.length - 1 === i} close={popup.close}/>
|
||||
{/each}
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
export let props: object
|
||||
export let element: PopupAlignment | undefined
|
||||
export let onClose: ((result: any) => void) | undefined
|
||||
export let onUpdate: ((result: any) => void) | undefined
|
||||
export let zIndex: number
|
||||
export let top: boolean
|
||||
export let close: () => void
|
||||
@ -30,7 +31,12 @@
|
||||
let componentInstance: any
|
||||
let show: boolean = false
|
||||
|
||||
function _close (result: any) {
|
||||
function _update (result: any): void {
|
||||
if (onUpdate !== undefined) onUpdate(result)
|
||||
fitPopup()
|
||||
}
|
||||
|
||||
function _close (result: any): void {
|
||||
if (onClose !== undefined) onClose(result)
|
||||
close()
|
||||
}
|
||||
@ -104,7 +110,7 @@
|
||||
<svelte:window on:resize={fitPopup} on:keydown={handleKeydown} />
|
||||
|
||||
<div class="popup" bind:this={modalHTML} style={`z-index: ${zIndex + 1};`}>
|
||||
<svelte:component bind:this={componentInstance} this={is} {...props} on:update={fitPopup} on:close={ (ev) => _close(ev.detail) } />
|
||||
<svelte:component bind:this={componentInstance} this={is} {...props} on:update={(ev) => _update(ev.detail)} on:close={(ev) => _close(ev.detail)} />
|
||||
</div>
|
||||
<div class="modal-overlay" class:show style={`z-index: ${zIndex};`} on:click={() => escapeClose()} />
|
||||
|
||||
|
@ -46,6 +46,7 @@ export { default as TextArea } from './components/TextArea.svelte'
|
||||
export { default as Section } from './components/Section.svelte'
|
||||
export { default as DatePicker } from './components/DatePicker.svelte'
|
||||
export { default as DatePopup } from './components/DatePopup.svelte'
|
||||
export { default as DatePresenter } from './components/DatePresenter.svelte'
|
||||
export { default as StylishEdit } from './components/StylishEdit.svelte'
|
||||
export { default as Grid } from './components/Grid.svelte'
|
||||
export { default as Row } from './components/Row.svelte'
|
||||
|
@ -37,6 +37,8 @@ export default plugin(uiId, {
|
||||
Suggested: '' as IntlString,
|
||||
TimeTooltip: '' as IntlString,
|
||||
None: '' as IntlString,
|
||||
NotSelected: '' as IntlString,
|
||||
Today: '' as IntlString,
|
||||
English: '' as IntlString,
|
||||
Russian: '' as IntlString
|
||||
},
|
||||
|
@ -8,6 +8,7 @@ interface CompAndProps {
|
||||
props: any
|
||||
element?: PopupAlignment
|
||||
onClose?: (result: any) => void
|
||||
onUpdate?: (result: any) => void
|
||||
close: () => void
|
||||
}
|
||||
|
||||
@ -23,7 +24,8 @@ export function showPopup (
|
||||
component: AnySvelteComponent | AnyComponent,
|
||||
props: any,
|
||||
element?: PopupAlignment,
|
||||
onClose?: (result: any) => void
|
||||
onClose?: (result: any) => void,
|
||||
onUpdate?: (result: any) => void
|
||||
): () => void {
|
||||
const id = `${popupId++}`
|
||||
const closePopupOp = (): void => {
|
||||
@ -36,9 +38,9 @@ export function showPopup (
|
||||
})
|
||||
}
|
||||
if (typeof component === 'string') {
|
||||
getResource(component).then((resolved) => addPopup({ id, is: resolved, props, element, onClose, close: closePopupOp })).catch((err) => console.log(err))
|
||||
getResource(component).then((resolved) => addPopup({ id, is: resolved, props, element, onClose, onUpdate, close: closePopupOp })).catch((err) => console.log(err))
|
||||
} else {
|
||||
addPopup({ id, is: component, props, element, onClose, close: closePopupOp })
|
||||
addPopup({ id, is: component, props, element, onClose, onUpdate, close: closePopupOp })
|
||||
}
|
||||
return closePopupOp
|
||||
}
|
||||
|
@ -85,3 +85,11 @@ export interface DropdownTextItem {
|
||||
id: string
|
||||
label: string
|
||||
}
|
||||
|
||||
export type TSelectDate = Date | null | undefined
|
||||
export type TCellStyle = 'not-selected' | 'selected' | 'selected-start' | 'selected-end'
|
||||
export interface ICell {
|
||||
dayOfWeek: number
|
||||
style: TCellStyle
|
||||
today?: boolean
|
||||
}
|
||||
|
@ -58,7 +58,7 @@
|
||||
{#if transparent !== undefined && !transparent}
|
||||
<div class="ac-header short mirror-tool divide">
|
||||
<div class="ac-header__wrap-title">
|
||||
<div class="ac-header__icon flex-center icon"><IconActivity size={'small'} /></div>
|
||||
<div class="flex-center icon"><IconActivity size={'small'} /></div>
|
||||
<span class="ac-header__title"><Label label={activity.string.Activity} /></span>
|
||||
</div>
|
||||
</div>
|
||||
@ -90,7 +90,7 @@
|
||||
<div class="scroller-back">
|
||||
<div class="ac-header short mirror-tool">
|
||||
<div class="ac-header__wrap-title">
|
||||
<div class="ac-header__icon flex-center icon"><IconActivity size={'small'} /></div>
|
||||
<div class="flex-center icon"><IconActivity size={'small'} /></div>
|
||||
<span class="ac-header__title"><Label label={activity.string.Activity} /></span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -74,6 +74,7 @@
|
||||
"ReviewShortLabel": "RVE",
|
||||
"StartDate": "Start date",
|
||||
"DueDate": "Due date",
|
||||
"Period": "Period",
|
||||
"ReviewCategoryTitle":"Category",
|
||||
"Verdict": "Verdict",
|
||||
"OpinionSave": "Save",
|
||||
|
@ -75,6 +75,7 @@
|
||||
"ReviewShortLabel": "RVE",
|
||||
"StartDate": "Дата начала",
|
||||
"DueDate": "Дата конца",
|
||||
"Period": "Период",
|
||||
"ReviewCategoryTitle":"Категория",
|
||||
"Verdict": "Вердикт",
|
||||
"OpinionSave": "Сохранить",
|
||||
|
@ -22,6 +22,7 @@
|
||||
import view from '@anticrm/view'
|
||||
|
||||
export let value: Applicant
|
||||
export let inline: boolean = false
|
||||
|
||||
const client = getClient()
|
||||
const shortLabel = client.getHierarchy().getClass(value._class).shortLabel
|
||||
@ -32,7 +33,10 @@
|
||||
</script>
|
||||
|
||||
{#if value && shortLabel}
|
||||
<div class="sm-tool-icon" on:click={show}>
|
||||
<span class="icon"><Icon icon={recruit.icon.Application} size={'small'} /></span> {#if shortLabel}<Label label={shortLabel} />-{/if}{value.number}
|
||||
<div class="flex-presenter" class:inline-presenter={inline} on:click={show}>
|
||||
<div class="icon">
|
||||
<Icon icon={recruit.icon.Application} size={'small'} />
|
||||
</div>
|
||||
<span class="label nowrap">{#if shortLabel}<Label label={shortLabel} />-{/if}{value.number}</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -19,6 +19,7 @@
|
||||
import recruit from '../plugin'
|
||||
|
||||
export let value: Vacancy
|
||||
export let inline: boolean = false
|
||||
export let action: (item: Ref<Vacancy>) => void
|
||||
|
||||
function editVacancy ():void {
|
||||
@ -27,20 +28,13 @@
|
||||
</script>
|
||||
|
||||
{#if value}
|
||||
<div class="sm-tool-icon vacancy-item over-underline" on:click={() => (action(value._id))}>
|
||||
<span class="icon"><Icon icon={recruit.icon.Vacancy} size={'small'} /></span> {value.name}
|
||||
<div class='action ml-4'>
|
||||
<div class="flex-presenter" class:inline-presenter={inline} on:click={() => (action(value._id))}>
|
||||
<div class="icon">
|
||||
<Icon icon={recruit.icon.Vacancy} size={'small'} />
|
||||
</div>
|
||||
<span class="label">{value.name}</span>
|
||||
<div class="action">
|
||||
<ActionIcon label={recruit.string.Edit} size={'small'} icon={IconEdit} action={editVacancy}/>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<style type='scss'>
|
||||
.vacancy-item {
|
||||
&:hover .action {
|
||||
visibility: visible;
|
||||
}
|
||||
.action {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -20,6 +20,7 @@
|
||||
import { showPanel } from '@anticrm/ui/src/panelup'
|
||||
|
||||
export let value: Vacancy
|
||||
export let inline: boolean = false
|
||||
|
||||
function show () {
|
||||
showPanel(recruit.component.EditVacancy, value._id, value._class, 'right')
|
||||
@ -27,7 +28,10 @@
|
||||
</script>
|
||||
|
||||
{#if value}
|
||||
<div class="sm-tool-icon over-underline" on:click={show}>
|
||||
<span class="icon"><Icon icon={recruit.icon.Vacancy} size={'small'} /></span> {value.name}
|
||||
<div class="flex-presenter" class:inline-presenter={inline} on:click={show}>
|
||||
<div class="icon">
|
||||
<Icon icon={recruit.icon.Vacancy} size={'small'} />
|
||||
</div>
|
||||
<span class="label">{value.name}</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -145,17 +145,16 @@
|
||||
<StatusControl slot="error" {status} />
|
||||
<Grid column={1} rowGap={1.75}>
|
||||
{#if !preserveCandidate}
|
||||
<UserBox _class={contact.class.Person} title={recruit.string.Candidate} caption={recruit.string.Candidates} bind:value={doc.attachedTo} />
|
||||
{/if}
|
||||
<UserBox
|
||||
_class={contact.class.Employee}
|
||||
title={recruit.string.AssignRecruiter}
|
||||
caption={recruit.string.Recruiters}
|
||||
bind:value={doc.assignee}
|
||||
allowDeselect
|
||||
titleDeselect={recruit.string.UnAssignRecruiter}
|
||||
/>
|
||||
<DatePicker title={recruit.string.StartDate} bind:selected={startDate}/>
|
||||
<DatePicker title={recruit.string.DueDate} bind:selected={dueDate}/>
|
||||
<UserBox _class={contact.class.Person} title={recruit.string.Candidate} caption={recruit.string.Candidates} bind:value={doc.attachedTo} />
|
||||
{/if}
|
||||
<UserBox
|
||||
_class={contact.class.Employee}
|
||||
title={recruit.string.AssignRecruiter}
|
||||
caption={recruit.string.Recruiters}
|
||||
bind:value={doc.assignee}
|
||||
allowDeselect
|
||||
titleDeselect={recruit.string.UnAssignRecruiter}
|
||||
/>
|
||||
<DatePicker title={recruit.string.Period} bind:value={startDate} bind:range={dueDate} />
|
||||
</Grid>
|
||||
</Card>
|
||||
|
@ -22,6 +22,7 @@
|
||||
import view from '@anticrm/view'
|
||||
|
||||
export let value: Review
|
||||
export let inline: boolean = false
|
||||
|
||||
const client = getClient()
|
||||
let shortLabel = ''
|
||||
@ -41,7 +42,10 @@
|
||||
</script>
|
||||
|
||||
{#if value && shortLabel}
|
||||
<div class="sm-tool-icon" on:click={show}>
|
||||
<span class="icon"><Icon icon={recruit.icon.Application} size={'small'} /></span> {shortLabel}-{value.number}
|
||||
<div class="flex-presenter" class:inline-presenter={inline} on:click={show}>
|
||||
<div class="icon">
|
||||
<Icon icon={recruit.icon.Application} size={'small'} />
|
||||
</div>
|
||||
<span class="label nowrap">{shortLabel}-{value.number}</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -100,6 +100,7 @@ export default mergeIds(recruitId, recruit, {
|
||||
ReviewShortLabel: '' as IntlString,
|
||||
StartDate: '' as IntlString,
|
||||
DueDate: '' as IntlString,
|
||||
Period: '' as IntlString,
|
||||
CandidateReviews: '' as IntlString,
|
||||
Participants: '' as IntlString,
|
||||
NoParticipants: '' as IntlString,
|
||||
|
@ -62,9 +62,10 @@
|
||||
on:close={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
okLabel={plugin.string.TodoSave}>
|
||||
<Grid column={1} rowGap={1.75}>
|
||||
<EditBox
|
||||
okLabel={plugin.string.TodoSave}
|
||||
>
|
||||
<Grid column={1} rowGap={1.75}>
|
||||
<EditBox
|
||||
label={plugin.string.TodoDescription}
|
||||
bind:value={name}
|
||||
icon={task.icon.Task}
|
||||
@ -72,6 +73,6 @@
|
||||
maxWidth={'16rem'}
|
||||
focus
|
||||
/>
|
||||
<DatePicker title={plugin.string.TodoDueDate} bind:selected={dueTo} />
|
||||
<DatePicker title={plugin.string.TodoDueDate} bind:value={dueTo} />
|
||||
</Grid>
|
||||
</Card>
|
||||
|
@ -78,6 +78,6 @@
|
||||
maxWidth={'16rem'}
|
||||
focus
|
||||
/>
|
||||
<DatePicker title={plugin.string.TodoDueDate} bind:selected={dueTo} />
|
||||
<DatePicker title={plugin.string.TodoDueDate} bind:value={dueTo} />
|
||||
</Grid>
|
||||
</Card>
|
||||
|
@ -20,7 +20,7 @@
|
||||
import EditTodo from './EditTodo.svelte'
|
||||
|
||||
export let value: TodoItem
|
||||
|
||||
export let inline: boolean = false
|
||||
|
||||
function show (elm: EventTarget | null) {
|
||||
closeTooltip()
|
||||
@ -28,6 +28,11 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="sm-tool-icon" on:click={(evt) => show(evt.target)}>
|
||||
<span class="icon"><Icon icon={task.icon.Task} size={'small'} /></span>{value.name}
|
||||
</div>
|
||||
{#if value}
|
||||
<div class="flex-presenter" class:inline-presenter={inline} on:click={(ev) => show(ev.target)}>
|
||||
<div class="icon">
|
||||
<Icon icon={task.icon.Task} size={'small'} />
|
||||
</div>
|
||||
<span class="label">{value.name}</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -251,7 +251,7 @@ import Reconnect from './Reconnect.svelte';
|
||||
margin-right: 1rem;
|
||||
width: 2.25rem;
|
||||
height: 2.25rem;
|
||||
color: var(--theme-caption-color);
|
||||
color: var(--primary-button-color);
|
||||
background-color: var(--primary-button-enabled);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
@ -15,13 +15,16 @@
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { DatePresenter } from '@anticrm/ui'
|
||||
|
||||
export let value: number | Date | undefined
|
||||
|
||||
$: date = value ? new Date(value) : undefined
|
||||
</script>
|
||||
|
||||
<div class=".caption-color">
|
||||
<div class="antiSelect">
|
||||
{#if date}
|
||||
{date.getMonth() + 1} / {date.getDate()} / {date.getFullYear()}
|
||||
<DatePresenter value={date} />
|
||||
{:else}
|
||||
No date
|
||||
{/if}
|
||||
|
@ -53,7 +53,7 @@ test.describe('recruit tests', () => {
|
||||
await page.click('text=Create Cancel >> button')
|
||||
|
||||
await page.click('text=APP-4')
|
||||
await page.click('text=Assigned recruiter Not selected >> div')
|
||||
await page.click('text=Assigned recruiter Not selected >> span')
|
||||
await page.click('button:has-text("Rosamund Chen")')
|
||||
})
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user