mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-15 21:03:30 +00:00
Calendar Week view and some fixes (#1220)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
parent
f003dcd5a0
commit
24dfc7f274
@ -33,6 +33,6 @@
|
|||||||
"@anticrm/tags-resources": "~0.6.0",
|
"@anticrm/tags-resources": "~0.6.0",
|
||||||
"@anticrm/ui": "~0.6.0",
|
"@anticrm/ui": "~0.6.0",
|
||||||
"@anticrm/model-core": "~0.6.0",
|
"@anticrm/model-core": "~0.6.0",
|
||||||
"@anticrm/model-view": "~0.6.0"
|
"@anticrm/model-view": "~0.6.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -407,6 +407,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.antiTable-body__border {
|
||||||
|
border: 1px solid var(--theme-button-border-hovered);
|
||||||
|
}
|
||||||
|
|
||||||
&.highlightRows .antiTable-body__row {
|
&.highlightRows .antiTable-body__row {
|
||||||
&:hover, &.checking { background-color: var(--theme-table-bg-hover); }
|
&:hover, &.checking { background-color: var(--theme-table-bg-hover); }
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script type="ts">
|
<script type="ts">
|
||||||
|
import { createEventDispatcher } from 'svelte'
|
||||||
import { areDatesEqual, day, firstDay, getWeekDayName, isWeekend, weekday } from './internal/DateUtils'
|
import { areDatesEqual, day, firstDay, getWeekDayName, isWeekend, weekday } from './internal/DateUtils'
|
||||||
|
|
||||||
export let mondayStart = true
|
export let mondayStart = true
|
||||||
@ -22,10 +23,13 @@
|
|||||||
export let currentDate: Date = new Date()
|
export let currentDate: Date = new Date()
|
||||||
export let displayedWeeksCount = 6
|
export let displayedWeeksCount = 6
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
$: firstDayOfCurrentMonth = firstDay(currentDate, mondayStart)
|
$: firstDayOfCurrentMonth = firstDay(currentDate, mondayStart)
|
||||||
|
|
||||||
function onSelect (date: Date) {
|
function onSelect (date: Date) {
|
||||||
value = date
|
value = date
|
||||||
|
dispatch('change', value)
|
||||||
}
|
}
|
||||||
|
|
||||||
const todayDate = new Date()
|
const todayDate = new Date()
|
||||||
|
103
packages/ui/src/components/calendar/WeekCalendar.svelte
Normal file
103
packages/ui/src/components/calendar/WeekCalendar.svelte
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<!--
|
||||||
|
// 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 type="ts">
|
||||||
|
import { createEventDispatcher } from 'svelte'
|
||||||
|
import { addZero, day, getMonday, getWeekDayName } from './internal/DateUtils'
|
||||||
|
|
||||||
|
export let mondayStart = true
|
||||||
|
export let cellHeight: string | undefined = undefined
|
||||||
|
export let value: Date = new Date()
|
||||||
|
export let currentDate: Date = new Date()
|
||||||
|
export let displayedDaysCount = 7
|
||||||
|
export let displayedHours = 24
|
||||||
|
// export let startHour = 0
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
|
$: weekMonday = getMonday(currentDate, mondayStart)
|
||||||
|
|
||||||
|
function onSelect (date: Date) {
|
||||||
|
value = date
|
||||||
|
dispatch('change', value)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<table class="antiTable">
|
||||||
|
<thead class="scroller-thead">
|
||||||
|
<tr class="scroller-thead__tr">
|
||||||
|
<th>Hours</th>
|
||||||
|
{#each [...Array(displayedDaysCount).keys()] as dayOfWeek}
|
||||||
|
<th>
|
||||||
|
<div class="antiTable-cells">
|
||||||
|
{getWeekDayName(day(weekMonday, dayOfWeek), 'short')}
|
||||||
|
{day(weekMonday, dayOfWeek).getDate()}
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
{/each}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{#if $$slots.cell}
|
||||||
|
<slot name="header" date={day(weekMonday, 0)} days={displayedDaysCount} />
|
||||||
|
{/if}
|
||||||
|
{#each [...Array(displayedHours).keys()] as hourOfDay, row}
|
||||||
|
<tr class="antiTable-body__row">
|
||||||
|
<td style="width: 50px;" class="calendar-td">
|
||||||
|
<div class="antiTable-cells__firstCell">
|
||||||
|
{addZero(hourOfDay)}:00
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
{#each [...Array(displayedDaysCount).keys()] as dayIndex}
|
||||||
|
<td
|
||||||
|
class="antiTable-body__border calendar-td cell"
|
||||||
|
style={`height: ${cellHeight};`}
|
||||||
|
on:click={(evt) => {
|
||||||
|
onSelect(day(weekMonday, dayIndex))
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{#if $$slots.cell}
|
||||||
|
<slot name="cell" date={day(weekMonday, dayIndex, hourOfDay * 60)} />
|
||||||
|
{/if}
|
||||||
|
</td>
|
||||||
|
{/each}
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.calendar-td {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.selected {
|
||||||
|
// border-radius: 3px;
|
||||||
|
background-color: var(--primary-button-enabled);
|
||||||
|
// border-color: var(--primary-button-focused-border);
|
||||||
|
color: var(--primary-button-color);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
height: calc(100% - 5px);
|
||||||
|
width: calc(100% - 5px);
|
||||||
|
}
|
||||||
|
.cell {
|
||||||
|
width: 8rem;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.cell:hover:not(.wrongMonth) {
|
||||||
|
// border: 1px solid var(--primary-button-focused-border);
|
||||||
|
background-color: var(--primary-button-enabled);
|
||||||
|
color: var(--primary-button-color);
|
||||||
|
}
|
||||||
|
</style>
|
@ -39,7 +39,7 @@
|
|||||||
{#each [...Array(12).keys()] as m}
|
{#each [...Array(12).keys()] as m}
|
||||||
<div class="antiComponentBox mt-2 mb-2 ml-2 mr-2 flex-grow" style={`min-width: ${minWidth};`}>
|
<div class="antiComponentBox mt-2 mb-2 ml-2 mr-2 flex-grow" style={`min-width: ${minWidth};`}>
|
||||||
{getMonthName(month(value, m))}
|
{getMonthName(month(value, m))}
|
||||||
<MonthCalendar {cellHeight} weekFormat="narrow" bind:value currentDate={month(currentDate, m)} {mondayStart}>
|
<MonthCalendar {cellHeight} weekFormat="narrow" bind:value currentDate={month(currentDate, m)} {mondayStart} on:change>
|
||||||
<!----> eslint-disable-next-line no-undef -->
|
<!----> eslint-disable-next-line no-undef -->
|
||||||
<svelte:fragment slot="cell" let:date={date}>
|
<svelte:fragment slot="cell" let:date={date}>
|
||||||
<slot name="cell" date={date} />
|
<slot name="cell" date={date} />
|
||||||
|
@ -11,9 +11,9 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
const DAYS_IN_WEEK = 7
|
const DAYS_IN_WEEK = 7
|
||||||
const MILLISECONDS_IN_DAY = 86400000
|
const MILLISECONDS_IN_DAY = 86400000
|
||||||
|
const MILLISECONDS_IN_MINUTE = 60000
|
||||||
|
|
||||||
export function firstDay (date: Date, mondayStart: boolean): Date {
|
export function firstDay (date: Date, mondayStart: boolean): Date {
|
||||||
const firstDayOfMonth = new Date(date)
|
const firstDayOfMonth = new Date(date)
|
||||||
@ -40,8 +40,8 @@ export function getWeekDayName (weekDay: Date, weekFormat: 'narrow' | 'short' |
|
|||||||
}).format(weekDay)
|
}).format(weekDay)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function day (firstDay: Date, offset: number): Date {
|
export function day (firstDay: Date, offset: number, minutes?: number): Date {
|
||||||
return new Date(firstDay.getTime() + offset * MILLISECONDS_IN_DAY)
|
return new Date(firstDay.getTime() + offset * MILLISECONDS_IN_DAY + (minutes ?? 0) * MILLISECONDS_IN_MINUTE)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function weekday (firstDay: Date, w: number, d: number): Date {
|
export function weekday (firstDay: Date, w: number, d: number): Date {
|
||||||
@ -67,3 +67,16 @@ export function getMonthName (date: Date): string {
|
|||||||
const locale = new Intl.NumberFormat().resolvedOptions().locale
|
const locale = new Intl.NumberFormat().resolvedOptions().locale
|
||||||
return new Intl.DateTimeFormat(locale, { month: 'long' }).format(date)
|
return new Intl.DateTimeFormat(locale, { month: 'long' }).format(date)
|
||||||
}
|
}
|
||||||
|
export function getMonday (d: Date, mondayStart: boolean): Date {
|
||||||
|
d = new Date(d)
|
||||||
|
const day = d.getDay()
|
||||||
|
const diff = d.getDate() - day + (day === 0 ? -6 : 1) // adjust when day is sunday
|
||||||
|
return new Date(d.setDate(diff))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addZero (value: number): string {
|
||||||
|
if (value < 10) {
|
||||||
|
return `0${value}`
|
||||||
|
}
|
||||||
|
return `${value}`
|
||||||
|
}
|
||||||
|
@ -120,3 +120,4 @@ export * from './colors'
|
|||||||
|
|
||||||
export { default as MonthCalendar } from './components/calendar/MonthCalendar.svelte'
|
export { default as MonthCalendar } from './components/calendar/MonthCalendar.svelte'
|
||||||
export { default as YearCalendar } from './components/calendar/YearCalendar.svelte'
|
export { default as YearCalendar } from './components/calendar/YearCalendar.svelte'
|
||||||
|
export { default as WeekCalendar } from './components/calendar/WeekCalendar.svelte'
|
||||||
|
@ -16,9 +16,11 @@
|
|||||||
import { Event } from '@anticrm/calendar'
|
import { Event } from '@anticrm/calendar'
|
||||||
import { Class, Doc, DocumentQuery, FindOptions, Ref, SortingOrder, Space } from '@anticrm/core'
|
import { Class, Doc, DocumentQuery, FindOptions, Ref, SortingOrder, Space } from '@anticrm/core'
|
||||||
import { createQuery } from '@anticrm/presentation'
|
import { createQuery } from '@anticrm/presentation'
|
||||||
import { Button, IconBack, IconForward, MonthCalendar, ScrollBox, YearCalendar } from '@anticrm/ui'
|
import { Button, IconBack, IconForward, MonthCalendar, ScrollBox, WeekCalendar, YearCalendar } from '@anticrm/ui'
|
||||||
|
import Scroller from '@anticrm/ui/src/components/Scroller.svelte'
|
||||||
import calendar from '../plugin'
|
import calendar from '../plugin'
|
||||||
import Day from './Day.svelte'
|
import Day from './Day.svelte'
|
||||||
|
import Hour from './Hour.svelte'
|
||||||
|
|
||||||
export let _class: Ref<Class<Doc>>
|
export let _class: Ref<Class<Doc>>
|
||||||
export let space: Ref<Space> | undefined = undefined
|
export let space: Ref<Space> | undefined = undefined
|
||||||
@ -38,7 +40,7 @@
|
|||||||
|
|
||||||
let loading = false
|
let loading = false
|
||||||
let resultQuery: DocumentQuery<Event>
|
let resultQuery: DocumentQuery<Event>
|
||||||
$: spaceOpt = (space ? { space } : {})
|
$: spaceOpt = space ? { space } : {}
|
||||||
$: resultQuery = search === '' ? { ...query, ...spaceOpt } : { ...query, $search: search, ...spaceOpt }
|
$: resultQuery = search === '' ? { ...query, ...spaceOpt } : { ...query, $search: search, ...spaceOpt }
|
||||||
|
|
||||||
let objects: Event[] = []
|
let objects: Event[] = []
|
||||||
@ -73,12 +75,48 @@
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function findEvents (events: Event[], date: Date): Event[] {
|
function isSameDay (firstDate: Date, secondDate: Date): boolean {
|
||||||
return events.filter(
|
return (
|
||||||
(it) => areDatesLess(new Date(it.date), date) && areDatesLess(date, new Date(it.dueDate ?? it.date))
|
firstDate.getFullYear() === secondDate.getFullYear() &&
|
||||||
|
firstDate.getMonth() === secondDate.getMonth() &&
|
||||||
|
firstDate.getDate() === secondDate.getDate()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findEvents (events: Event[], date: Date, minutes = false): Event[] {
|
||||||
|
return events.filter((it) => {
|
||||||
|
const d1 = new Date(it.date)
|
||||||
|
const d2 = new Date(it.dueDate ?? it.date)
|
||||||
|
const inDays = areDatesLess(d1, date) && areDatesLess(date, d2)
|
||||||
|
|
||||||
|
if (minutes) {
|
||||||
|
if (isSameDay(d1, date)) {
|
||||||
|
return (date.getTime() < d1.getTime() && d1.getTime() < date.getTime() + 3600 * 1000) ||
|
||||||
|
(d1.getTime() < date.getTime() && date.getTime() <= d2.getTime())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSameDay(d2, date)) {
|
||||||
|
return (date.getTime() < d2.getTime() && d2.getTime() < date.getTime() + 3600000) ||
|
||||||
|
(date.getTime() < d2.getTime() && d1.getTime() < date.getTime())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Somethere in middle
|
||||||
|
return inDays
|
||||||
|
}
|
||||||
|
return inDays
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function findDayEvents (events: Event[], date: Date): Event[] {
|
||||||
|
return events.filter((it) => {
|
||||||
|
const d1 = new Date(it.date)
|
||||||
|
const d2 = new Date(it.dueDate ?? it.date)
|
||||||
|
const inDays = areDatesLess(d1, date) && areDatesLess(date, d2)
|
||||||
|
|
||||||
|
return inDays && !isSameDay(d1, date) && !isSameDay(d2, date)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
interface ShiftType {
|
interface ShiftType {
|
||||||
yearShift: number
|
yearShift: number
|
||||||
monthShift: number
|
monthShift: number
|
||||||
@ -128,6 +166,12 @@
|
|||||||
month: 'long'
|
month: 'long'
|
||||||
}).format(date)
|
}).format(date)
|
||||||
}
|
}
|
||||||
|
function getWeekName (date: Date): string {
|
||||||
|
const onejan = new Date(date.getFullYear(), 0, 1)
|
||||||
|
const week = Math.ceil(((date.getTime() - onejan.getTime()) / 86400000 + onejan.getDay() + 1) / 7)
|
||||||
|
|
||||||
|
return `W${week}`
|
||||||
|
}
|
||||||
|
|
||||||
function currentDate (date: Date, shifts: ShiftType): Date {
|
function currentDate (date: Date, shifts: ShiftType): Date {
|
||||||
const res = new Date(date)
|
const res = new Date(date)
|
||||||
@ -152,7 +196,7 @@
|
|||||||
return `${date.getDate()} ${getMonthName(date)} ${date.getFullYear()}`
|
return `${date.getDate()} ${getMonthName(date)} ${date.getFullYear()}`
|
||||||
}
|
}
|
||||||
case CalendarMode.Week: {
|
case CalendarMode.Week: {
|
||||||
return `${getMonthName(date)} ${date.getFullYear()}`
|
return `${getWeekName(date)} ${getMonthName(date)} ${date.getFullYear()}`
|
||||||
}
|
}
|
||||||
case CalendarMode.Month: {
|
case CalendarMode.Month: {
|
||||||
return `${getMonthName(date)} ${date.getFullYear()}`
|
return `${getMonthName(date)} ${date.getFullYear()}`
|
||||||
@ -175,14 +219,14 @@
|
|||||||
on:click={() => {
|
on:click={() => {
|
||||||
mode = CalendarMode.Day
|
mode = CalendarMode.Day
|
||||||
}}
|
}}
|
||||||
/>
|
/> -->
|
||||||
<Button
|
<Button
|
||||||
size={'small'}
|
size={'small'}
|
||||||
label={calendar.string.ModeWeek}
|
label={calendar.string.ModeWeek}
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
mode = CalendarMode.Week
|
mode = CalendarMode.Week
|
||||||
}}
|
}}
|
||||||
/> -->
|
/>
|
||||||
<Button
|
<Button
|
||||||
size={'small'}
|
size={'small'}
|
||||||
label={calendar.string.ModeMonth}
|
label={calendar.string.ModeMonth}
|
||||||
@ -238,7 +282,15 @@
|
|||||||
|
|
||||||
{#if mode === CalendarMode.Year}
|
{#if mode === CalendarMode.Year}
|
||||||
<ScrollBox bothScroll>
|
<ScrollBox bothScroll>
|
||||||
<YearCalendar {mondayStart} cellHeight={'2.5rem'} bind:value currentDate={currentDate(date, shifts)}>
|
<YearCalendar
|
||||||
|
{mondayStart}
|
||||||
|
cellHeight={'2.5rem'}
|
||||||
|
bind:value
|
||||||
|
currentDate={currentDate(date, shifts)}
|
||||||
|
on:change={(evt) => {
|
||||||
|
date = evt.detail
|
||||||
|
}}
|
||||||
|
>
|
||||||
<svelte:fragment slot="cell" let:date>
|
<svelte:fragment slot="cell" let:date>
|
||||||
<Day
|
<Day
|
||||||
events={findEvents(objects, date)}
|
events={findEvents(objects, date)}
|
||||||
@ -254,7 +306,15 @@
|
|||||||
</ScrollBox>
|
</ScrollBox>
|
||||||
{:else if mode === CalendarMode.Month}
|
{:else if mode === CalendarMode.Month}
|
||||||
<div class="flex flex-grow">
|
<div class="flex flex-grow">
|
||||||
<MonthCalendar {mondayStart} cellHeight={'8.5rem'} bind:value currentDate={currentDate(date, shifts)}>
|
<MonthCalendar
|
||||||
|
{mondayStart}
|
||||||
|
cellHeight={'8.5rem'}
|
||||||
|
bind:value
|
||||||
|
currentDate={currentDate(date, shifts)}
|
||||||
|
on:change={(evt) => {
|
||||||
|
date = evt.detail
|
||||||
|
}}
|
||||||
|
>
|
||||||
<svelte:fragment slot="cell" let:date>
|
<svelte:fragment slot="cell" let:date>
|
||||||
<Day
|
<Day
|
||||||
events={findEvents(objects, date)}
|
events={findEvents(objects, date)}
|
||||||
@ -269,4 +329,37 @@
|
|||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</MonthCalendar>
|
</MonthCalendar>
|
||||||
</div>
|
</div>
|
||||||
|
{:else if mode === CalendarMode.Week}
|
||||||
|
<Scroller>
|
||||||
|
<WeekCalendar
|
||||||
|
{mondayStart}
|
||||||
|
cellHeight={'4.5rem'}
|
||||||
|
bind:value
|
||||||
|
currentDate={currentDate(date, shifts)}
|
||||||
|
on:change={(evt) => {
|
||||||
|
date = evt.detail
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svelte:fragment slot="cell" let:date>
|
||||||
|
<Hour
|
||||||
|
events={findEvents(objects, date, true)}
|
||||||
|
{date}
|
||||||
|
{_class}
|
||||||
|
{baseMenuClass}
|
||||||
|
{options}
|
||||||
|
{config}
|
||||||
|
query={resultQuery}
|
||||||
|
/>
|
||||||
|
</svelte:fragment>
|
||||||
|
|
||||||
|
<svelte:fragment slot="header" let:date let:days>
|
||||||
|
<tr class="antiTable-body__row">
|
||||||
|
<td class="whitespace-nowrap">All day</td>
|
||||||
|
{#each [...Array(days).keys()] as day}
|
||||||
|
<td class="antiTable-body__border" />
|
||||||
|
{/each}
|
||||||
|
</tr>
|
||||||
|
</svelte:fragment>
|
||||||
|
</WeekCalendar>
|
||||||
|
</Scroller>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -80,7 +80,6 @@
|
|||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.cell {
|
.cell {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-grow: 1;
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
.marker {
|
.marker {
|
||||||
|
83
plugins/calendar-resources/src/components/Hour.svelte
Normal file
83
plugins/calendar-resources/src/components/Hour.svelte
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
<!--
|
||||||
|
// 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 { Event } from '@anticrm/calendar'
|
||||||
|
import { Class, Doc, DocumentQuery, FindOptions, Ref } from '@anticrm/core'
|
||||||
|
import { Tooltip } from '@anticrm/ui'
|
||||||
|
import { addZero } from '@anticrm/ui/src/components/calendar/internal/DateUtils'
|
||||||
|
import calendar from '../plugin'
|
||||||
|
import EventsPopup from './EventsPopup.svelte'
|
||||||
|
|
||||||
|
export let events: Event[]
|
||||||
|
export let date: Date
|
||||||
|
|
||||||
|
export let _class: Ref<Class<Doc>>
|
||||||
|
export let query: DocumentQuery<Event> = {}
|
||||||
|
export let options: FindOptions<Event> | undefined = undefined
|
||||||
|
export let baseMenuClass: Ref<Class<Event>> | undefined = undefined
|
||||||
|
export let config: string[]
|
||||||
|
|
||||||
|
$: sorted = Array.from(events).sort((a, b) => a.date - b.date)
|
||||||
|
|
||||||
|
function from (eDate: number, date: Date): string {
|
||||||
|
const dd = new Date(Math.max(eDate, date.getTime()))
|
||||||
|
return `${addZero(date.getHours())}:${addZero(dd.getMinutes())}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function to (dueDate: number, date:Date): string {
|
||||||
|
return `${addZero(date.getHours())}:${addZero(Math.min(59, Math.floor((dueDate - date.getTime()) / 60000)))}`
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if events.length > 0}
|
||||||
|
<Tooltip
|
||||||
|
fill={true}
|
||||||
|
label={calendar.string.Events}
|
||||||
|
component={EventsPopup}
|
||||||
|
props={{ value: events, _class, query, options, baseMenuClass, config }}
|
||||||
|
>
|
||||||
|
<div class="cell">
|
||||||
|
<div class="flex flex-col flex-grow">
|
||||||
|
{#each sorted.slice(0, 4) as e, ei}
|
||||||
|
<div class="overflow-label flex flex-between">
|
||||||
|
{e.title}
|
||||||
|
<div>
|
||||||
|
{from(e.date, date)}
|
||||||
|
-
|
||||||
|
{to(e.dueDate ?? e.date, date)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
{#if events.length > 4}
|
||||||
|
And {events.length - 4} more
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.cell {
|
||||||
|
padding: 0.5rem;
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: var(--theme-dialog-accent);
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
align-self: flex-start;
|
||||||
|
}
|
||||||
|
</style>
|
@ -3,7 +3,6 @@
|
|||||||
"version": "0.6.0",
|
"version": "0.6.0",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"author": "Anticrm Platform Contributors",
|
"author": "Anticrm Platform Contributors",
|
||||||
"template": "@anticrm/platform-package",
|
|
||||||
"license": "EPL-2.0",
|
"license": "EPL-2.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "echo 'no build for ui'",
|
"build": "echo 'no build for ui'",
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"author": "Anticrm Platform Contributors",
|
"author": "Anticrm Platform Contributors",
|
||||||
"license": "EPL-2.0",
|
"license": "EPL-2.0",
|
||||||
|
"template": "@anticrm/platform-package",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "heft build",
|
"build": "heft build",
|
||||||
"build:watch": "tsc",
|
"build:watch": "tsc",
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
"@anticrm/platform-rig": "~0.6.0",
|
"@anticrm/platform-rig": "~0.6.0",
|
||||||
"svelte-loader":"^3.1.2",
|
"svelte-loader":"^3.1.2",
|
||||||
"sass":"^1.37.5",
|
"sass":"^1.37.5",
|
||||||
"svelte-preprocess":"^4.7.4",
|
"svelte-preprocess":"^4.10.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
||||||
"@typescript-eslint/parser": "^5.4.0",
|
"@typescript-eslint/parser": "^5.4.0",
|
||||||
"eslint-config-standard-with-typescript": "^21.0.1",
|
"eslint-config-standard-with-typescript": "^21.0.1",
|
||||||
@ -31,6 +31,8 @@
|
|||||||
"svelte": "^3.37.0"
|
"svelte": "^3.37.0"
|
||||||
},
|
},
|
||||||
"#replaces": [
|
"#replaces": [
|
||||||
".eslintrc.js"
|
".eslintrc.js",
|
||||||
|
"postcss.config.js",
|
||||||
|
"svelte.config.js"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user