@globalbrain/sefirot 3.16.0 → 3.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/components/SActionList.vue +1 -0
- package/lib/components/SActionListItem.vue +12 -3
- package/lib/components/SActionMenu.vue +84 -0
- package/lib/components/SControlActionMenu.vue +43 -0
- package/lib/components/SControlPagination.vue +7 -0
- package/lib/components/SDropdown.vue +1 -1
- package/lib/components/SDropdownSection.vue +7 -1
- package/lib/components/SDropdownSectionDateRange.vue +126 -0
- package/lib/components/SDropdownSectionDateRangeDateFromTo.vue +88 -0
- package/lib/components/SDropdownSectionDateRangeYear.vue +73 -0
- package/lib/components/SDropdownSectionDateRangeYearHalf.vue +94 -0
- package/lib/components/SDropdownSectionDateRangeYearQuarter.vue +96 -0
- package/lib/components/SDropdownSectionMenu.vue +5 -34
- package/lib/composables/Dropdown.ts +47 -9
- package/lib/composables/V.ts +5 -5
- package/lib/mixins/Control.ts +6 -0
- package/lib/support/DateRange.ts +227 -0
- package/package.json +11 -11
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { type IconifyIcon } from '@iconify/vue/dist/offline'
|
|
3
|
+
import { computed } from 'vue'
|
|
3
4
|
import SIcon from './SIcon.vue'
|
|
4
5
|
import SLink from './SLink.vue'
|
|
5
6
|
|
|
6
7
|
export interface ActionListItem {
|
|
7
8
|
leadIcon?: IconifyIcon
|
|
8
|
-
text: string
|
|
9
9
|
link?: string
|
|
10
|
+
label?: string
|
|
11
|
+
disabled?: boolean
|
|
10
12
|
onClick?(): void
|
|
13
|
+
|
|
14
|
+
/** @deprecated Use `:label` instead. */
|
|
15
|
+
text?: string
|
|
11
16
|
}
|
|
12
17
|
|
|
13
|
-
defineProps<ActionListItem>()
|
|
18
|
+
const props = defineProps<ActionListItem>()
|
|
19
|
+
|
|
20
|
+
const _label = computed(() => {
|
|
21
|
+
return props.label ?? props.text
|
|
22
|
+
})
|
|
14
23
|
</script>
|
|
15
24
|
|
|
16
25
|
<template>
|
|
@@ -23,7 +32,7 @@ defineProps<ActionListItem>()
|
|
|
23
32
|
<span v-if="leadIcon" class="lead-icon">
|
|
24
33
|
<SIcon class="lead-icon-svg" :icon="leadIcon" />
|
|
25
34
|
</span>
|
|
26
|
-
<span class="text">{{
|
|
35
|
+
<span class="text">{{ _label }}</span>
|
|
27
36
|
</component>
|
|
28
37
|
</template>
|
|
29
38
|
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import { type DropdownSection, useManualDropdownPosition } from '../composables/Dropdown'
|
|
4
|
+
import { useFlyout } from '../composables/Flyout'
|
|
5
|
+
import SButton, { type Mode, type Size, type Tooltip, type Type } from './SButton.vue'
|
|
6
|
+
import SDropdown from './SDropdown.vue'
|
|
7
|
+
|
|
8
|
+
export type { Mode, Size, Tooltip, Type }
|
|
9
|
+
|
|
10
|
+
const props = defineProps<{
|
|
11
|
+
tag?: string
|
|
12
|
+
size?: Size
|
|
13
|
+
type?: Type
|
|
14
|
+
mode?: Mode
|
|
15
|
+
icon?: any
|
|
16
|
+
iconMode?: Mode
|
|
17
|
+
label?: string
|
|
18
|
+
labelMode?: Mode
|
|
19
|
+
rounded?: boolean
|
|
20
|
+
block?: boolean
|
|
21
|
+
loading?: boolean
|
|
22
|
+
disabled?: boolean
|
|
23
|
+
tooltip?: Tooltip
|
|
24
|
+
options: DropdownSection[]
|
|
25
|
+
}>()
|
|
26
|
+
|
|
27
|
+
const container = ref<any>(null)
|
|
28
|
+
|
|
29
|
+
const { isOpen, toggle } = useFlyout(container)
|
|
30
|
+
const { position, update: updatePosition } = useManualDropdownPosition(container)
|
|
31
|
+
|
|
32
|
+
async function onOpen() {
|
|
33
|
+
if (!props.disabled) {
|
|
34
|
+
updatePosition()
|
|
35
|
+
toggle()
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<template>
|
|
41
|
+
<div class="SActionMenu" :class="[block]" ref="container">
|
|
42
|
+
<div class="button">
|
|
43
|
+
<SButton
|
|
44
|
+
:tag="tag"
|
|
45
|
+
:size="size"
|
|
46
|
+
:type="type"
|
|
47
|
+
:mode="mode"
|
|
48
|
+
:icon="icon"
|
|
49
|
+
:icon-mode="iconMode"
|
|
50
|
+
:label="label"
|
|
51
|
+
:label-mode="labelMode"
|
|
52
|
+
:rounded="rounded"
|
|
53
|
+
:block="block"
|
|
54
|
+
:loading="loading"
|
|
55
|
+
:disabled="disabled"
|
|
56
|
+
:tooltip="tooltip"
|
|
57
|
+
@click="onOpen"
|
|
58
|
+
/>
|
|
59
|
+
</div>
|
|
60
|
+
<div v-if="isOpen" class="dropdown" :class="position">
|
|
61
|
+
<SDropdown :sections="options" />
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
</template>
|
|
65
|
+
|
|
66
|
+
<style scoped lang="postcss">
|
|
67
|
+
.SActionMenu {
|
|
68
|
+
position: relative;
|
|
69
|
+
display: inline-block;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.dropdown {
|
|
73
|
+
position: absolute;
|
|
74
|
+
left: 0;
|
|
75
|
+
z-index: var(--z-index-dropdown);
|
|
76
|
+
|
|
77
|
+
&.top { bottom: calc(100% + 8px); }
|
|
78
|
+
&.bottom { top: calc(100% + 8px); }
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.SActionMenu.block {
|
|
82
|
+
display: block;
|
|
83
|
+
}
|
|
84
|
+
</style>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useControlSize } from '../composables/Control'
|
|
3
|
+
import { type DropdownSection } from '../composables/Dropdown'
|
|
4
|
+
import SActionMenu, { type Mode, type Tooltip, type Type } from './SActionMenu.vue'
|
|
5
|
+
|
|
6
|
+
defineProps<{
|
|
7
|
+
tag?: string
|
|
8
|
+
type?: Type
|
|
9
|
+
mode?: Mode
|
|
10
|
+
icon?: any
|
|
11
|
+
iconMode?: Mode
|
|
12
|
+
label?: string
|
|
13
|
+
labelMode?: Mode
|
|
14
|
+
href?: string
|
|
15
|
+
loading?: boolean
|
|
16
|
+
disabled?: boolean
|
|
17
|
+
tooltip?: Tooltip
|
|
18
|
+
options: DropdownSection[]
|
|
19
|
+
}>()
|
|
20
|
+
|
|
21
|
+
const size = useControlSize()
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<template>
|
|
25
|
+
<div class="SControlActionMenu">
|
|
26
|
+
<SActionMenu
|
|
27
|
+
:tag="tag"
|
|
28
|
+
:size="size"
|
|
29
|
+
:type="type"
|
|
30
|
+
:mode="mode"
|
|
31
|
+
:icon="icon"
|
|
32
|
+
:icon-mode="iconMode"
|
|
33
|
+
:label="label"
|
|
34
|
+
:label-mode="labelMode"
|
|
35
|
+
:href="href"
|
|
36
|
+
:tooltip="tooltip"
|
|
37
|
+
:options="options"
|
|
38
|
+
block
|
|
39
|
+
:loading="loading"
|
|
40
|
+
:disabled="disabled"
|
|
41
|
+
/>
|
|
42
|
+
</div>
|
|
43
|
+
</template>
|
|
@@ -9,6 +9,11 @@ defineProps<{
|
|
|
9
9
|
perPage: number
|
|
10
10
|
}>()
|
|
11
11
|
|
|
12
|
+
defineEmits<{
|
|
13
|
+
(e: 'prev'): void
|
|
14
|
+
(e: 'next'): void
|
|
15
|
+
}>()
|
|
16
|
+
|
|
12
17
|
const size = useControlSize()
|
|
13
18
|
const position = useControlPosition()
|
|
14
19
|
</script>
|
|
@@ -21,6 +26,8 @@ const position = useControlPosition()
|
|
|
21
26
|
:total="total"
|
|
22
27
|
:page="page"
|
|
23
28
|
:per-page="perPage"
|
|
29
|
+
@prev="$emit('prev')"
|
|
30
|
+
@next="$emit('next')"
|
|
24
31
|
/>
|
|
25
32
|
</div>
|
|
26
33
|
</template>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { type DropdownSection } from '../composables/Dropdown'
|
|
3
3
|
import SDropdownSectionActions from './SDropdownSectionActions.vue'
|
|
4
4
|
import SDropdownSectionComponent from './SDropdownSectionComponent.vue'
|
|
5
|
+
import SDropdownSectionDateRange from './SDropdownSectionDateRange.vue'
|
|
5
6
|
import SDropdownSectionFilter from './SDropdownSectionFilter.vue'
|
|
6
7
|
import SDropdownSectionMenu from './SDropdownSectionMenu.vue'
|
|
7
8
|
|
|
@@ -22,8 +23,13 @@ defineProps<{
|
|
|
22
23
|
:options="section.options"
|
|
23
24
|
:on-click="section.onClick"
|
|
24
25
|
/>
|
|
26
|
+
<SDropdownSectionDateRange
|
|
27
|
+
v-else-if="section.type === 'date-range'"
|
|
28
|
+
:range="section.range"
|
|
29
|
+
:on-apply="section.onApply"
|
|
30
|
+
/>
|
|
25
31
|
<SDropdownSectionActions
|
|
26
|
-
v-if="section.type === 'actions'"
|
|
32
|
+
v-else-if="section.type === 'actions'"
|
|
27
33
|
:options="section.options"
|
|
28
34
|
/>
|
|
29
35
|
<SDropdownSectionComponent
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { type MaybeRefOrGetter, computed, shallowRef, toValue } from 'vue'
|
|
3
|
+
import { type DropdownSectionActionsOption } from '../composables/Dropdown'
|
|
4
|
+
import { useTrans } from '../composables/Lang'
|
|
5
|
+
import { useV } from '../composables/V'
|
|
6
|
+
import { DateRange, type DateRangePreset, type DateRangePresetType } from '../support/DateRange'
|
|
7
|
+
import SDropdownSectionActions from './SDropdownSectionActions.vue'
|
|
8
|
+
import SDropdownSectionDateRangeDateFromTo from './SDropdownSectionDateRangeDateFromTo.vue'
|
|
9
|
+
import SDropdownSectionDateRangeYear from './SDropdownSectionDateRangeYear.vue'
|
|
10
|
+
import SDropdownSectionDateRangeYearHalf from './SDropdownSectionDateRangeYearHalf.vue'
|
|
11
|
+
import SDropdownSectionDateRangeYearQuarter from './SDropdownSectionDateRangeYearQuarter.vue'
|
|
12
|
+
import SInputSelect from './SInputSelect.vue'
|
|
13
|
+
|
|
14
|
+
const props = defineProps<{
|
|
15
|
+
range: MaybeRefOrGetter<DateRange>
|
|
16
|
+
onApply: (range: DateRange) => void
|
|
17
|
+
}>()
|
|
18
|
+
|
|
19
|
+
const { t } = useTrans({
|
|
20
|
+
en: {
|
|
21
|
+
p_date_from_to: 'Custom period',
|
|
22
|
+
p_year: 'Year',
|
|
23
|
+
p_year_half: 'Year half',
|
|
24
|
+
p_year_quarter: 'Year quarter',
|
|
25
|
+
a_apply: 'Apply'
|
|
26
|
+
},
|
|
27
|
+
ja: {
|
|
28
|
+
p_date_from_to: '日付指定',
|
|
29
|
+
p_year: '年',
|
|
30
|
+
p_year_half: '半期',
|
|
31
|
+
p_year_quarter: '四半期',
|
|
32
|
+
a_apply: '適用する'
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
const _range = shallowRef(toValue(props.range))
|
|
37
|
+
|
|
38
|
+
const presetValue = computed(() => {
|
|
39
|
+
return _range.value.preset.type
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const presetOptions = [
|
|
43
|
+
{ label: t.p_date_from_to, value: 'date-from-to' },
|
|
44
|
+
{ label: t.p_year, value: 'year' },
|
|
45
|
+
{ label: t.p_year_half, value: 'year-half' },
|
|
46
|
+
{ label: t.p_year_quarter, value: 'year-quarter' }
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
const actions: DropdownSectionActionsOption[] = [
|
|
50
|
+
{ label: t.a_apply, mode: 'info', onClick: onApply }
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
const { validate } = useV()
|
|
54
|
+
|
|
55
|
+
function onPresetChange(value: any) {
|
|
56
|
+
_range.value = new DateRange().setPreset(value as DateRangePresetType)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function onValueChange(value: DateRangePreset) {
|
|
60
|
+
_range.value = new DateRange().setPreset(value)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function onApply() {
|
|
64
|
+
if (await validate()) {
|
|
65
|
+
props.onApply(_range.value)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<template>
|
|
71
|
+
<div class="SDropdownSectionDateRange">
|
|
72
|
+
<div class="preset">
|
|
73
|
+
<SInputSelect
|
|
74
|
+
size="mini"
|
|
75
|
+
:options="presetOptions"
|
|
76
|
+
:value="presetValue"
|
|
77
|
+
@change="onPresetChange"
|
|
78
|
+
/>
|
|
79
|
+
</div>
|
|
80
|
+
<div class="control">
|
|
81
|
+
<SDropdownSectionDateRangeDateFromTo
|
|
82
|
+
v-if="_range.preset.type === 'date-from-to'"
|
|
83
|
+
:preset="_range.preset"
|
|
84
|
+
@change="onValueChange"
|
|
85
|
+
/>
|
|
86
|
+
<SDropdownSectionDateRangeYear
|
|
87
|
+
v-else-if="_range.preset.type === 'year'"
|
|
88
|
+
:preset="_range.preset"
|
|
89
|
+
@change="onValueChange"
|
|
90
|
+
/>
|
|
91
|
+
<SDropdownSectionDateRangeYearHalf
|
|
92
|
+
v-else-if="_range.preset.type === 'year-half'"
|
|
93
|
+
:preset="_range.preset"
|
|
94
|
+
@change="onValueChange"
|
|
95
|
+
/>
|
|
96
|
+
<SDropdownSectionDateRangeYearQuarter
|
|
97
|
+
v-else-if="_range.preset.type === 'year-quarter'"
|
|
98
|
+
:preset="_range.preset"
|
|
99
|
+
@change="onValueChange"
|
|
100
|
+
/>
|
|
101
|
+
</div>
|
|
102
|
+
<div class="actions">
|
|
103
|
+
<SDropdownSectionActions
|
|
104
|
+
:options="actions"
|
|
105
|
+
/>
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
</template>
|
|
109
|
+
|
|
110
|
+
<style scoped lang="postcss">
|
|
111
|
+
.SDropdownSectionDateRange {
|
|
112
|
+
display: flex;
|
|
113
|
+
flex-direction: column;
|
|
114
|
+
gap: 1px;
|
|
115
|
+
background-color: var(--c-bg-elv-1);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.preset {
|
|
119
|
+
padding: 8px;
|
|
120
|
+
background-color: var(--c-bg-elv-3);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.control {
|
|
124
|
+
background-color: var(--c-bg-elv-3);
|
|
125
|
+
}
|
|
126
|
+
</style>
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useV } from '../composables/V'
|
|
3
|
+
import { DateFromTo } from '../support/DateRange'
|
|
4
|
+
import { type Day } from '../support/Day'
|
|
5
|
+
import { required } from '../validation/rules'
|
|
6
|
+
import SInputDate from './SInputDate.vue'
|
|
7
|
+
|
|
8
|
+
const props = defineProps<{
|
|
9
|
+
preset: DateFromTo
|
|
10
|
+
}>()
|
|
11
|
+
|
|
12
|
+
const emit = defineEmits<{
|
|
13
|
+
(e: 'change', value: DateFromTo): void
|
|
14
|
+
}>()
|
|
15
|
+
|
|
16
|
+
const { validation } = useV(() => ({
|
|
17
|
+
from: props.preset.from,
|
|
18
|
+
to: props.preset.to
|
|
19
|
+
}), {
|
|
20
|
+
from: { required: required() },
|
|
21
|
+
to: { required: required() }
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
function onFromChange(value: Day | null) {
|
|
25
|
+
emit('change', new DateFromTo().setFrom(value).setTo(props.preset.to))
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function onToChange(value: Day | null) {
|
|
29
|
+
emit('change', new DateFromTo().setFrom(props.preset.from).setTo(value))
|
|
30
|
+
}
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<template>
|
|
34
|
+
<div class="SDropdownSectionDateRangeDateFromTo">
|
|
35
|
+
<div class="group">
|
|
36
|
+
<div class="label">From</div>
|
|
37
|
+
<div class="input">
|
|
38
|
+
<SInputDate
|
|
39
|
+
size="mini"
|
|
40
|
+
block
|
|
41
|
+
:model-value="preset.from"
|
|
42
|
+
:validation="validation.from"
|
|
43
|
+
hide-error
|
|
44
|
+
@change="onFromChange"
|
|
45
|
+
/>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
<div class="group">
|
|
49
|
+
<div class="label">To</div>
|
|
50
|
+
<div class="input">
|
|
51
|
+
<SInputDate
|
|
52
|
+
size="mini"
|
|
53
|
+
block
|
|
54
|
+
:model-value="preset.to"
|
|
55
|
+
:validation="validation.to"
|
|
56
|
+
hide-error
|
|
57
|
+
@change="onToChange"
|
|
58
|
+
/>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</template>
|
|
63
|
+
|
|
64
|
+
<style scoped lang="postcss">
|
|
65
|
+
.SDropdownSectionDateRangeDateFromTo {
|
|
66
|
+
display: flex;
|
|
67
|
+
flex-direction: column;
|
|
68
|
+
gap: 8px;
|
|
69
|
+
padding: 8px 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.group {
|
|
73
|
+
display: flex;
|
|
74
|
+
align-items: center;
|
|
75
|
+
padding: 0 8px 0 16px;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.label {
|
|
79
|
+
flex-shrink: 0;
|
|
80
|
+
width: 64px;
|
|
81
|
+
font-size: 12px;
|
|
82
|
+
color: var(--c-text-2);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.input {
|
|
86
|
+
flex-grow: 1;
|
|
87
|
+
}
|
|
88
|
+
</style>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useV } from '../composables/V'
|
|
3
|
+
import { Year } from '../support/DateRange'
|
|
4
|
+
import { maxValue, minValue, required } from '../validation/rules'
|
|
5
|
+
import SInputNumber from './SInputNumber.vue'
|
|
6
|
+
|
|
7
|
+
const props = defineProps<{
|
|
8
|
+
preset: Year
|
|
9
|
+
}>()
|
|
10
|
+
|
|
11
|
+
const emit = defineEmits<{
|
|
12
|
+
(e: 'change', value: Year): void
|
|
13
|
+
}>()
|
|
14
|
+
|
|
15
|
+
const { validation } = useV(() => ({
|
|
16
|
+
year: props.preset.year
|
|
17
|
+
}), {
|
|
18
|
+
year: {
|
|
19
|
+
required: required(),
|
|
20
|
+
minValue: minValue(1),
|
|
21
|
+
maxValue: maxValue(9999)
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
function onInput(value: number | null) {
|
|
26
|
+
emit('change', new Year().setYear(value))
|
|
27
|
+
}
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<template>
|
|
31
|
+
<div class="SDropdownSectionDateRangeYear">
|
|
32
|
+
<div class="group">
|
|
33
|
+
<div class="label">Year</div>
|
|
34
|
+
<div class="input">
|
|
35
|
+
<SInputNumber
|
|
36
|
+
size="mini"
|
|
37
|
+
placeholder="YYYY"
|
|
38
|
+
block
|
|
39
|
+
:model-value="preset.year"
|
|
40
|
+
:validation="validation.year"
|
|
41
|
+
hide-error
|
|
42
|
+
@input="onInput"
|
|
43
|
+
/>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
</template>
|
|
48
|
+
|
|
49
|
+
<style scoped lang="postcss">
|
|
50
|
+
.SDropdownSectionDateRangeYear {
|
|
51
|
+
display: flex;
|
|
52
|
+
flex-direction: column;
|
|
53
|
+
gap: 8px;
|
|
54
|
+
padding: 8px 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.group {
|
|
58
|
+
display: flex;
|
|
59
|
+
align-items: center;
|
|
60
|
+
padding: 0 8px 0 16px;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.label {
|
|
64
|
+
flex-shrink: 0;
|
|
65
|
+
width: 64px;
|
|
66
|
+
font-size: 12px;
|
|
67
|
+
color: var(--c-text-2);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.input {
|
|
71
|
+
flex-grow: 1;
|
|
72
|
+
}
|
|
73
|
+
</style>
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useV } from '../composables/V'
|
|
3
|
+
import { YearHalf } from '../support/DateRange'
|
|
4
|
+
import { maxValue, minValue, required } from '../validation/rules'
|
|
5
|
+
import SInputNumber from './SInputNumber.vue'
|
|
6
|
+
import SInputSelect from './SInputSelect.vue'
|
|
7
|
+
|
|
8
|
+
const props = defineProps<{
|
|
9
|
+
preset: YearHalf
|
|
10
|
+
}>()
|
|
11
|
+
|
|
12
|
+
const emit = defineEmits<{
|
|
13
|
+
(e: 'change', value: YearHalf): void
|
|
14
|
+
}>()
|
|
15
|
+
|
|
16
|
+
const { validation } = useV(() => ({
|
|
17
|
+
year: props.preset.year
|
|
18
|
+
}), {
|
|
19
|
+
year: {
|
|
20
|
+
required: required(),
|
|
21
|
+
minValue: minValue(1),
|
|
22
|
+
maxValue: maxValue(9999)
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
const halfOptions = [
|
|
27
|
+
{ label: 'H1', value: 1 },
|
|
28
|
+
{ label: 'H2', value: 2 }
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
function onYearInput(value: number | null) {
|
|
32
|
+
emit('change', new YearHalf().setYear(value).setHalf(props.preset.half))
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function onHalfChange(value: any) {
|
|
36
|
+
emit('change', new YearHalf().setYear(props.preset.year).setHalf(value))
|
|
37
|
+
}
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<template>
|
|
41
|
+
<div class="SDropdownSectionDateRangeYearHalf">
|
|
42
|
+
<div class="group">
|
|
43
|
+
<div class="label">Year</div>
|
|
44
|
+
<div class="input">
|
|
45
|
+
<SInputNumber
|
|
46
|
+
size="mini"
|
|
47
|
+
placeholder="YYYY"
|
|
48
|
+
block
|
|
49
|
+
:model-value="preset.year"
|
|
50
|
+
:validation="validation.year"
|
|
51
|
+
hide-error
|
|
52
|
+
@input="onYearInput"
|
|
53
|
+
/>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
<div class="group">
|
|
57
|
+
<div class="label">Half</div>
|
|
58
|
+
<div class="input">
|
|
59
|
+
<SInputSelect
|
|
60
|
+
size="mini"
|
|
61
|
+
:options="halfOptions"
|
|
62
|
+
:model-value="preset.half"
|
|
63
|
+
@change="onHalfChange"
|
|
64
|
+
/>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
</template>
|
|
69
|
+
|
|
70
|
+
<style scoped lang="postcss">
|
|
71
|
+
.SDropdownSectionDateRangeYearHalf {
|
|
72
|
+
display: flex;
|
|
73
|
+
flex-direction: column;
|
|
74
|
+
gap: 8px;
|
|
75
|
+
padding: 8px 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.group {
|
|
79
|
+
display: flex;
|
|
80
|
+
align-items: center;
|
|
81
|
+
padding: 0 8px 0 16px;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.label {
|
|
85
|
+
flex-shrink: 0;
|
|
86
|
+
width: 64px;
|
|
87
|
+
font-size: 12px;
|
|
88
|
+
color: var(--c-text-2);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.input {
|
|
92
|
+
flex-grow: 1;
|
|
93
|
+
}
|
|
94
|
+
</style>
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useV } from '../composables/V'
|
|
3
|
+
import { YearQuarter } from '../support/DateRange'
|
|
4
|
+
import { maxValue, minValue, required } from '../validation/rules'
|
|
5
|
+
import SInputNumber from './SInputNumber.vue'
|
|
6
|
+
import SInputSelect from './SInputSelect.vue'
|
|
7
|
+
|
|
8
|
+
const props = defineProps<{
|
|
9
|
+
preset: YearQuarter
|
|
10
|
+
}>()
|
|
11
|
+
|
|
12
|
+
const emit = defineEmits<{
|
|
13
|
+
(e: 'change', value: YearQuarter): void
|
|
14
|
+
}>()
|
|
15
|
+
|
|
16
|
+
const { validation } = useV(() => ({
|
|
17
|
+
year: props.preset.year
|
|
18
|
+
}), {
|
|
19
|
+
year: {
|
|
20
|
+
required: required(),
|
|
21
|
+
minValue: minValue(1),
|
|
22
|
+
maxValue: maxValue(9999)
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
const quarterOptions = [
|
|
27
|
+
{ label: 'Q1', value: 1 },
|
|
28
|
+
{ label: 'Q2', value: 2 },
|
|
29
|
+
{ label: 'Q3', value: 3 },
|
|
30
|
+
{ label: 'Q4', value: 4 }
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
function onYearInput(value: number | null) {
|
|
34
|
+
emit('change', new YearQuarter().setYear(value).setQuarter(props.preset.quarter))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function onQuarterChange(value: any) {
|
|
38
|
+
emit('change', new YearQuarter().setYear(props.preset.year).setQuarter(value))
|
|
39
|
+
}
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<template>
|
|
43
|
+
<div class="SDropdownSectionDateRangeYearQuarter">
|
|
44
|
+
<div class="group">
|
|
45
|
+
<div class="label">Year</div>
|
|
46
|
+
<div class="input">
|
|
47
|
+
<SInputNumber
|
|
48
|
+
size="mini"
|
|
49
|
+
placeholder="YYYY"
|
|
50
|
+
block
|
|
51
|
+
:model-value="preset.year"
|
|
52
|
+
:validation="validation.year"
|
|
53
|
+
hide-error
|
|
54
|
+
@input="onYearInput"
|
|
55
|
+
/>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
<div class="group">
|
|
59
|
+
<div class="label">Quarter</div>
|
|
60
|
+
<div class="input">
|
|
61
|
+
<SInputSelect
|
|
62
|
+
size="mini"
|
|
63
|
+
:options="quarterOptions"
|
|
64
|
+
:model-value="preset.quarter"
|
|
65
|
+
@change="onQuarterChange"
|
|
66
|
+
/>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
</template>
|
|
71
|
+
|
|
72
|
+
<style scoped lang="postcss">
|
|
73
|
+
.SDropdownSectionDateRangeYearQuarter {
|
|
74
|
+
display: flex;
|
|
75
|
+
flex-direction: column;
|
|
76
|
+
gap: 8px;
|
|
77
|
+
padding: 8px 0;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.group {
|
|
81
|
+
display: flex;
|
|
82
|
+
align-items: center;
|
|
83
|
+
padding: 0 8px 0 16px;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.label {
|
|
87
|
+
flex-shrink: 0;
|
|
88
|
+
width: 64px;
|
|
89
|
+
font-size: 12px;
|
|
90
|
+
color: var(--c-text-2);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.input {
|
|
94
|
+
flex-grow: 1;
|
|
95
|
+
}
|
|
96
|
+
</style>
|
|
@@ -1,23 +1,15 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { type
|
|
2
|
+
import SActionList, { type ActionList } from './SActionList.vue'
|
|
3
3
|
|
|
4
4
|
defineProps<{
|
|
5
|
-
options:
|
|
5
|
+
options: ActionList
|
|
6
6
|
}>()
|
|
7
7
|
</script>
|
|
8
8
|
|
|
9
9
|
<template>
|
|
10
|
-
<
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
class="button"
|
|
14
|
-
@click="option.onClick"
|
|
15
|
-
:disabled="option.disabled"
|
|
16
|
-
>
|
|
17
|
-
{{ option.label }}
|
|
18
|
-
</button>
|
|
19
|
-
</li>
|
|
20
|
-
</ul>
|
|
10
|
+
<div class="SDropdownSectionMenu">
|
|
11
|
+
<SActionList :list="options" />
|
|
12
|
+
</div>
|
|
21
13
|
</template>
|
|
22
14
|
|
|
23
15
|
<style scoped lang="postcss">
|
|
@@ -25,25 +17,4 @@ defineProps<{
|
|
|
25
17
|
padding: 8px;
|
|
26
18
|
background-color: var(--c-bg-elv-3);
|
|
27
19
|
}
|
|
28
|
-
|
|
29
|
-
.button {
|
|
30
|
-
display: block;
|
|
31
|
-
border-radius: 6px;
|
|
32
|
-
padding: 0 8px;
|
|
33
|
-
width: 100%;
|
|
34
|
-
text-align: left;
|
|
35
|
-
line-height: 32px;
|
|
36
|
-
font-size: 14px;
|
|
37
|
-
font-weight: 400;
|
|
38
|
-
transition: color 0.25s, background-color 0.25s;
|
|
39
|
-
|
|
40
|
-
&:hover:not(:disabled) {
|
|
41
|
-
background-color: var(--c-bg-mute-1);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
&:disabled {
|
|
45
|
-
color: var(--c-text-3);
|
|
46
|
-
cursor: not-allowed;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
20
|
</style>
|
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
import { useElementBounding, useWindowSize } from '@vueuse/core'
|
|
2
|
-
import { type Component, type MaybeRef, type Ref, ref, unref } from 'vue'
|
|
2
|
+
import { type Component, type MaybeRef, type MaybeRefOrGetter, type Ref, ref, unref } from 'vue'
|
|
3
|
+
import { type ActionList } from '../components/SActionList.vue'
|
|
4
|
+
import { type DateRange } from '../support/DateRange'
|
|
3
5
|
|
|
4
6
|
export type DropdownSection =
|
|
5
7
|
| DropdownSectionMenu
|
|
6
8
|
| DropdownSectionFilter
|
|
9
|
+
| DropdownSectionDateRange
|
|
7
10
|
| DropdownSectionComponent
|
|
8
11
|
| DropdownSectionActions
|
|
9
12
|
|
|
10
|
-
export type DropdownSectionType =
|
|
13
|
+
export type DropdownSectionType =
|
|
14
|
+
| 'menu'
|
|
15
|
+
| 'filter'
|
|
16
|
+
| 'date-range'
|
|
17
|
+
| 'actions'
|
|
18
|
+
| 'component'
|
|
11
19
|
|
|
12
20
|
export interface DropdownSectionBase {
|
|
13
21
|
type: DropdownSectionType
|
|
@@ -15,13 +23,7 @@ export interface DropdownSectionBase {
|
|
|
15
23
|
|
|
16
24
|
export interface DropdownSectionMenu extends DropdownSectionBase {
|
|
17
25
|
type: 'menu'
|
|
18
|
-
options:
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface DropdownSectionMenuOption {
|
|
22
|
-
label: string
|
|
23
|
-
disabled?: boolean
|
|
24
|
-
onClick(): void
|
|
26
|
+
options: ActionList
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
export interface DropdownSectionFilter extends DropdownSectionBase {
|
|
@@ -60,6 +62,12 @@ export interface DropdownSectionFilterOptionAvatar extends DropdownSectionFilter
|
|
|
60
62
|
image?: string | null
|
|
61
63
|
}
|
|
62
64
|
|
|
65
|
+
export interface DropdownSectionDateRange extends DropdownSectionBase {
|
|
66
|
+
type: 'date-range'
|
|
67
|
+
range: MaybeRefOrGetter<DateRange>
|
|
68
|
+
onApply(range: DateRange): void
|
|
69
|
+
}
|
|
70
|
+
|
|
63
71
|
export interface DropdownSectionActions extends DropdownSectionBase {
|
|
64
72
|
type: 'actions'
|
|
65
73
|
options: DropdownSectionActionsOption[]
|
|
@@ -87,6 +95,36 @@ export function createDropdown(section: DropdownSection[]): DropdownSection[] {
|
|
|
87
95
|
return section
|
|
88
96
|
}
|
|
89
97
|
|
|
98
|
+
export function createDropdownDateRange(
|
|
99
|
+
section: Omit<DropdownSectionDateRange, 'type'>
|
|
100
|
+
): DropdownSectionDateRange {
|
|
101
|
+
return { type: 'date-range', ...section }
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function createDropdownMenu(
|
|
105
|
+
section: Omit<DropdownSectionMenu, 'type'>
|
|
106
|
+
): DropdownSectionMenu {
|
|
107
|
+
return { type: 'menu', ...section }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function createDropdownFilter(
|
|
111
|
+
section: Omit<DropdownSectionFilter, 'type'>
|
|
112
|
+
): DropdownSectionFilter {
|
|
113
|
+
return { type: 'filter', ...section }
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function createDropdownActions(
|
|
117
|
+
section: Omit<DropdownSectionActions, 'type'>
|
|
118
|
+
): DropdownSectionActions {
|
|
119
|
+
return { type: 'actions', ...section }
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function createDropdownComponent(
|
|
123
|
+
section: Omit<DropdownSectionComponent, 'type'>
|
|
124
|
+
): DropdownSectionComponent {
|
|
125
|
+
return { type: 'component', ...section }
|
|
126
|
+
}
|
|
127
|
+
|
|
90
128
|
export function useManualDropdownPosition(
|
|
91
129
|
container?: Ref<any>,
|
|
92
130
|
initPosition?: 'top' | 'bottom'
|
package/lib/composables/V.ts
CHANGED
|
@@ -28,8 +28,8 @@ export function useV<
|
|
|
28
28
|
Data extends { [key in keyof Rules]: any },
|
|
29
29
|
Rules extends ValidationArgs = ValidationArgs
|
|
30
30
|
>(
|
|
31
|
-
data
|
|
32
|
-
rules
|
|
31
|
+
data?: MaybeRefOrGetter<Data>,
|
|
32
|
+
rules?: MaybeRefOrGetter<Rules>
|
|
33
33
|
): V<Data, Rules> {
|
|
34
34
|
const { t } = useTrans({
|
|
35
35
|
en: { notify: 'Form contains errors. Please correct them and try again.' },
|
|
@@ -38,10 +38,10 @@ export function useV<
|
|
|
38
38
|
|
|
39
39
|
const snackbars = useSnackbars()
|
|
40
40
|
|
|
41
|
-
const d = computed(() => toValue(data))
|
|
42
|
-
const r = computed(() => toValue(rules))
|
|
41
|
+
const d = computed(() => toValue(data) ?? {})
|
|
42
|
+
const r = computed(() => toValue(rules) ?? {})
|
|
43
43
|
|
|
44
|
-
const validation = useVuelidate(r, d)
|
|
44
|
+
const validation = useVuelidate(r, d) as any
|
|
45
45
|
|
|
46
46
|
function reset(): void {
|
|
47
47
|
validation.value.$reset()
|
package/lib/mixins/Control.ts
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
import { type App } from 'vue'
|
|
2
2
|
import SControl from '../components/SControl.vue'
|
|
3
|
+
import SControlActionMenu from '../components/SControlActionMenu.vue'
|
|
3
4
|
import SControlButton from '../components/SControlButton.vue'
|
|
4
5
|
import SControlCenter from '../components/SControlCenter.vue'
|
|
5
6
|
import SControlInputSearch from '../components/SControlInputSearch.vue'
|
|
6
7
|
import SControlLeft from '../components/SControlLeft.vue'
|
|
8
|
+
import SControlPagination from '../components/SControlPagination.vue'
|
|
7
9
|
import SControlRight from '../components/SControlRight.vue'
|
|
8
10
|
import SControlText from '../components/SControlText.vue'
|
|
9
11
|
|
|
10
12
|
export function mixin(app: App): void {
|
|
11
13
|
app.component('SControl', SControl)
|
|
14
|
+
app.component('SControlActionMenu', SControlActionMenu)
|
|
12
15
|
app.component('SControlButton', SControlButton)
|
|
13
16
|
app.component('SControlCenter', SControlCenter)
|
|
14
17
|
app.component('SControlInputSearch', SControlInputSearch)
|
|
15
18
|
app.component('SControlLeft', SControlLeft)
|
|
19
|
+
app.component('SControlPagination', SControlPagination)
|
|
16
20
|
app.component('SControlRight', SControlRight)
|
|
17
21
|
app.component('SControlText', SControlText)
|
|
18
22
|
}
|
|
@@ -20,10 +24,12 @@ export function mixin(app: App): void {
|
|
|
20
24
|
declare module 'vue' {
|
|
21
25
|
export interface GlobalComponents {
|
|
22
26
|
SControl: typeof SControl
|
|
27
|
+
SControlActionMenu: typeof SControlActionMenu
|
|
23
28
|
SControlButton: typeof SControlButton
|
|
24
29
|
SControlCenter: typeof SControlCenter
|
|
25
30
|
SControlInputSearch: typeof SControlInputSearch
|
|
26
31
|
SControlLeft: typeof SControlLeft
|
|
32
|
+
SControlPagination: typeof SControlPagination
|
|
27
33
|
SControlRight: typeof SControlRight
|
|
28
34
|
SControlText: typeof SControlText
|
|
29
35
|
}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { type Day, day } from './Day'
|
|
2
|
+
|
|
3
|
+
export type DateRangePreset =
|
|
4
|
+
| DateFromTo
|
|
5
|
+
| Year
|
|
6
|
+
| YearHalf
|
|
7
|
+
| YearQuarter
|
|
8
|
+
|
|
9
|
+
export type DateRangePresetType =
|
|
10
|
+
| 'date-from-to'
|
|
11
|
+
| 'year'
|
|
12
|
+
| 'year-half'
|
|
13
|
+
| 'year-quarter'
|
|
14
|
+
|
|
15
|
+
export type DateRangePresetDict = {
|
|
16
|
+
'date-from-to': typeof DateFromTo
|
|
17
|
+
'year': typeof Year
|
|
18
|
+
'year-half': typeof YearHalf
|
|
19
|
+
'year-quarter': typeof YearQuarter
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class DateRange {
|
|
23
|
+
preset: DateRangePreset
|
|
24
|
+
|
|
25
|
+
presetDict: DateRangePresetDict = {
|
|
26
|
+
'date-from-to': DateFromTo,
|
|
27
|
+
'year': Year,
|
|
28
|
+
'year-half': YearHalf,
|
|
29
|
+
'year-quarter': YearQuarter
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
constructor() {
|
|
33
|
+
this.preset = new DateFromTo()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
setPreset(preset: DateRangePreset | DateRangePresetType): this {
|
|
37
|
+
preset = typeof preset === 'string' ? new this.presetDict[preset]() : preset
|
|
38
|
+
|
|
39
|
+
this.preset = preset
|
|
40
|
+
|
|
41
|
+
return this
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
getFrom(): Day | null {
|
|
45
|
+
return this.preset.getFrom()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
getTo(): Day | null {
|
|
49
|
+
return this.preset.getTo()
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
getLabeltext(): string {
|
|
53
|
+
return this.preset.getLabeltext()
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export abstract class DateRangePresetBase {
|
|
58
|
+
abstract getFrom(): Day | null
|
|
59
|
+
abstract getTo(): Day | null
|
|
60
|
+
abstract getLabeltext(): string
|
|
61
|
+
|
|
62
|
+
protected getYear(year: number | null): Day | null {
|
|
63
|
+
if (!year) {
|
|
64
|
+
return null
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const d = day().year(year)
|
|
68
|
+
|
|
69
|
+
return d.isValid() ? d : null
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export class DateFromTo extends DateRangePresetBase {
|
|
74
|
+
type = 'date-from-to' as const
|
|
75
|
+
from: Day | null
|
|
76
|
+
to: Day | null
|
|
77
|
+
|
|
78
|
+
constructor() {
|
|
79
|
+
super()
|
|
80
|
+
this.from = day().subtract(30, 'days')
|
|
81
|
+
this.to = day()
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
getFrom(): Day | null {
|
|
85
|
+
return this.from
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
getTo(): Day | null {
|
|
89
|
+
return this.to
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
getLabeltext(): string {
|
|
93
|
+
const f = this.getFrom()?.format('YYYY-MM-DD')
|
|
94
|
+
const t = this.getTo()?.format('YYYY-MM-DD')
|
|
95
|
+
|
|
96
|
+
return (f && t) ? `${f} – ${t}` : 'Error'
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
setFrom(from: Day | null): this {
|
|
100
|
+
this.from = from
|
|
101
|
+
return this
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
setTo(to: Day | null): this {
|
|
105
|
+
this.to = to
|
|
106
|
+
return this
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export class Year extends DateRangePresetBase {
|
|
111
|
+
type = 'year' as const
|
|
112
|
+
year: number | null = null
|
|
113
|
+
|
|
114
|
+
constructor() {
|
|
115
|
+
super()
|
|
116
|
+
this.year = day().year()
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
getFrom(): Day | null {
|
|
120
|
+
return this.getYear(this.year)?.startOf('year') ?? null
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
getTo(): Day | null {
|
|
124
|
+
return this.getYear(this.year)?.endOf('year') ?? null
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
getLabeltext(): string {
|
|
128
|
+
return this.getYear(this.year)?.format('YYYY') ?? 'Error'
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
setYear(year: number | null): this {
|
|
132
|
+
this.year = year
|
|
133
|
+
return this
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export class YearHalf extends DateRangePresetBase {
|
|
138
|
+
type = 'year-half' as const
|
|
139
|
+
year: number | null
|
|
140
|
+
half: 1 | 2
|
|
141
|
+
|
|
142
|
+
protected monthDict: Record<number, number> = {
|
|
143
|
+
1: 0,
|
|
144
|
+
2: 6
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
constructor() {
|
|
148
|
+
super()
|
|
149
|
+
this.year = day().year()
|
|
150
|
+
this.half = 1
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
getFrom(): Day | null {
|
|
154
|
+
return this.getYear(this.year)
|
|
155
|
+
?.month(this.monthDict[this.half])
|
|
156
|
+
.startOf('month') ?? null
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
getTo(): Day | null {
|
|
160
|
+
return this.getYear(this.year)
|
|
161
|
+
?.month(this.monthDict[this.half] + 5)
|
|
162
|
+
.endOf('month') ?? null
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
getLabeltext(): string {
|
|
166
|
+
const y = this.getYear(this.year)?.format('YYYY')
|
|
167
|
+
|
|
168
|
+
return y ? `${y}H${this.half}` : 'Error'
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
setYear(year: number | null): this {
|
|
172
|
+
this.year = year
|
|
173
|
+
return this
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
setHalf(half: 1 | 2): this {
|
|
177
|
+
this.half = half
|
|
178
|
+
return this
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export class YearQuarter extends DateRangePresetBase {
|
|
183
|
+
type = 'year-quarter' as const
|
|
184
|
+
year: number | null
|
|
185
|
+
quarter: 1 | 2 | 3 | 4
|
|
186
|
+
|
|
187
|
+
protected monthDict: Record<number, number> = {
|
|
188
|
+
1: 0,
|
|
189
|
+
2: 3,
|
|
190
|
+
3: 6,
|
|
191
|
+
4: 9
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
constructor() {
|
|
195
|
+
super()
|
|
196
|
+
this.year = day().year()
|
|
197
|
+
this.quarter = 1
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
getFrom(): Day | null {
|
|
201
|
+
return this.getYear(this.year)
|
|
202
|
+
?.month(this.monthDict[this.quarter])
|
|
203
|
+
.startOf('month') ?? null
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
getTo(): Day | null {
|
|
207
|
+
return this.getYear(this.year)
|
|
208
|
+
?.month(this.monthDict[this.quarter] + 2)
|
|
209
|
+
.endOf('month') ?? null
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
getLabeltext(): string {
|
|
213
|
+
const y = this.getYear(this.year)?.format('YYYY')
|
|
214
|
+
|
|
215
|
+
return y ? `${y}Q${this.quarter}` : 'Error'
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
setYear(year: number | null): this {
|
|
219
|
+
this.year = year
|
|
220
|
+
return this
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
setQuarter(quarter: 1 | 2 | 3 | 4): this {
|
|
224
|
+
this.quarter = quarter
|
|
225
|
+
return this
|
|
226
|
+
}
|
|
227
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@globalbrain/sefirot",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.17.1",
|
|
4
4
|
"packageManager": "pnpm@8.12.1",
|
|
5
5
|
"description": "Vue Components for Global Brain Design System.",
|
|
6
6
|
"author": "Kia Ishii <ka.ishii@globalbrains.com>",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"postcss": "^8.4.32",
|
|
57
57
|
"postcss-nested": "^6.0.1",
|
|
58
58
|
"v-calendar": "^3.1.2",
|
|
59
|
-
"vue": "^3.3.
|
|
59
|
+
"vue": "^3.3.13",
|
|
60
60
|
"vue-router": "^4.2.5"
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
@@ -79,16 +79,16 @@
|
|
|
79
79
|
"@types/file-saver": "^2.0.7",
|
|
80
80
|
"@types/lodash-es": "^4.17.12",
|
|
81
81
|
"@types/markdown-it": "^13.0.7",
|
|
82
|
-
"@types/node": "^20.10.
|
|
83
|
-
"@types/qs": "^6.9.
|
|
82
|
+
"@types/node": "^20.10.5",
|
|
83
|
+
"@types/qs": "^6.9.11",
|
|
84
84
|
"@vitejs/plugin-vue": "^4.5.2",
|
|
85
|
-
"@vitest/coverage-v8": "^1.0
|
|
85
|
+
"@vitest/coverage-v8": "^1.1.0",
|
|
86
86
|
"@vue/test-utils": "^2.4.3",
|
|
87
87
|
"@vuelidate/core": "^2.0.3",
|
|
88
88
|
"@vuelidate/validators": "^2.0.4",
|
|
89
89
|
"@vueuse/core": "^10.7.0",
|
|
90
90
|
"body-scroll-lock": "4.0.0-beta.0",
|
|
91
|
-
"eslint": "^8.
|
|
91
|
+
"eslint": "^8.56.0",
|
|
92
92
|
"fuse.js": "^7.0.0",
|
|
93
93
|
"happy-dom": "^12.10.3",
|
|
94
94
|
"histoire": "^0.17.6",
|
|
@@ -102,11 +102,11 @@
|
|
|
102
102
|
"release-it": "^17.0.1",
|
|
103
103
|
"typescript": "~5.3.3",
|
|
104
104
|
"v-calendar": "^3.1.2",
|
|
105
|
-
"vite": "^5.0.
|
|
106
|
-
"vitepress": "1.0.0-rc.
|
|
107
|
-
"vitest": "^1.0
|
|
108
|
-
"vue": "^3.3.
|
|
105
|
+
"vite": "^5.0.10",
|
|
106
|
+
"vitepress": "1.0.0-rc.32",
|
|
107
|
+
"vitest": "^1.1.0",
|
|
108
|
+
"vue": "^3.3.13",
|
|
109
109
|
"vue-router": "^4.2.5",
|
|
110
|
-
"vue-tsc": "^1.8.
|
|
110
|
+
"vue-tsc": "^1.8.26"
|
|
111
111
|
}
|
|
112
112
|
}
|