-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add range selector --------- Co-authored-by: Cees Voesenek <[email protected]>
- Loading branch information
1 parent
4613dcd
commit 8cd5cd1
Showing
3 changed files
with
349 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
<template> | ||
<div class="container"> | ||
<v-tooltip right> | ||
<template v-slot:activator="{ on: onTooltip }"> | ||
<v-menu v-model="showDatePicker"> | ||
<template v-slot:activator="{ on: onMenu, attrs }"> | ||
<v-text-field | ||
v-model="selectedDate" | ||
:label="label" | ||
:prepend-icon="prependDateIcon" | ||
readonly | ||
v-bind="attrs" | ||
v-on="{ ...onTooltip, ...onMenu }" | ||
/> | ||
</template> | ||
<v-date-picker | ||
v-model="selectedDate" | ||
no-title | ||
scrollable | ||
@input="onSelectedDateTimeChange" | ||
/> | ||
</v-menu> | ||
</template> | ||
<span> | ||
Set date for “{{ label }}” | ||
</span> | ||
</v-tooltip> | ||
|
||
<v-tooltip right> | ||
<template v-slot:activator="{ on: onTooltip }"> | ||
<v-menu v-model="showTimePicker"> | ||
<template v-slot:activator="{ on: onMenu, attrs }"> | ||
<v-text-field | ||
v-model="selectedTime" | ||
readonly | ||
:prepend-icon="prependTimeIcon" | ||
v-bind="attrs" | ||
v-on="{ ...onTooltip, ...onMenu }" | ||
/> | ||
</template> | ||
<v-time-picker | ||
v-model="selectedTime" | ||
no-title | ||
scrollable | ||
@input="onSelectedDateTimeChange" | ||
/> | ||
</v-menu> | ||
</template> | ||
<span> | ||
Set time for “{{ label }}” | ||
</span> | ||
</v-tooltip> | ||
|
||
<v-tooltip right> | ||
<template v-slot:activator="{ on, attrs }"> | ||
<v-btn | ||
v-bind="attrs" | ||
v-on="on" | ||
class="button" | ||
icon | ||
@click="setNow" | ||
> | ||
<v-icon> | ||
mdi-timeline-clock-outline | ||
</v-icon> | ||
</v-btn> | ||
</template> | ||
<span> | ||
Set current time for “{{ label }}” | ||
</span> | ||
</v-tooltip> | ||
</div> | ||
</template> | ||
|
||
<script lang="ts"> | ||
import { Component, Prop, Vue, Watch } from 'vue-property-decorator' | ||
import { DateTime } from 'luxon' | ||
@Component | ||
export default class DateTimeSelector extends Vue { | ||
@Prop({ default: null }) value!: Date | null | ||
@Prop({ default: 'Date' }) label!: string | ||
@Prop({ default: 'mdi-calendar' }) prependDateIcon!: string | ||
@Prop({ default: 'mdi-clock' }) prependTimeIcon!: string | ||
showDatePicker: boolean = false | ||
showTimePicker: boolean = false | ||
selectedDate: string | null = null | ||
selectedTime: string | null = null | ||
mounted() { | ||
this.onValueChange() | ||
} | ||
@Watch('value') | ||
onValueChange(): void { | ||
this.onExternalDateTimeChange(this.value) | ||
} | ||
setNow(): void { | ||
const now = new Date() | ||
this.onExternalDateTimeChange(now) | ||
this.$emit('input', now) | ||
} | ||
onExternalDateTimeChange(externalDateTime: Date | null): void { | ||
if (externalDateTime === null) { | ||
this.selectedDate = null | ||
this.selectedTime = null | ||
} else { | ||
const dateTime = DateTime.fromJSDate(externalDateTime) | ||
this.selectedDate = dateTime.toISODate() | ||
this.selectedTime = dateTime | ||
.startOf('minute') | ||
.toISOTime({ | ||
suppressSeconds: true, | ||
suppressMilliseconds: true, | ||
includeOffset: false | ||
}) | ||
} | ||
} | ||
onSelectedDateTimeChange(): void { | ||
// If the time was not set, use a default. | ||
if (!this.selectedTime) this.selectedTime = '00:00' | ||
const dateTimeString = `${this.selectedDate}T${this.selectedTime}` | ||
const dateTime = this.selectedDate ? DateTime.fromISO(dateTimeString).toJSDate() : null | ||
this.$emit('input', dateTime) | ||
} | ||
} | ||
</script> | ||
|
||
<style scoped> | ||
.container { | ||
display: flex; | ||
flex-direction: row; | ||
gap: 10px; | ||
align-items: center; | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
<template> | ||
<v-list class="interval-list"> | ||
<v-list-item-group | ||
v-model="selectedIndex" | ||
@change="onSelectInterval" | ||
mandatory | ||
> | ||
<!-- Empty list item to trick the list into show no selection, while still setting "mandatory" --> | ||
<v-list-item v-show="false"/> | ||
<v-list-item> | ||
<template v-slot:default="{ active }"> | ||
<v-list-item-title> | ||
Default | ||
</v-list-item-title> | ||
<v-list-item-icon> | ||
<v-icon v-show="active" small> | ||
mdi-check | ||
</v-icon> | ||
</v-list-item-icon> | ||
</template> | ||
</v-list-item> | ||
<v-list-item | ||
v-for="(item, index) in items" | ||
:key="index" | ||
> | ||
<template v-slot:default="{ active }"> | ||
<v-list-item-title> | ||
{{ intervalToLocaleString(item) }} | ||
</v-list-item-title> | ||
<v-list-item-icon> | ||
<v-icon v-show="active" small> | ||
mdi-check | ||
</v-icon> | ||
</v-list-item-icon> | ||
</template> | ||
</v-list-item> | ||
</v-list-item-group> | ||
</v-list> | ||
</template> | ||
|
||
<script lang="ts"> | ||
import { DateTime, Duration } from 'luxon' | ||
import { Component, Prop, Vue, Watch } from 'vue-property-decorator' | ||
@Component | ||
export default class IntervalSelector extends Vue { | ||
// The interval is either a string with an interval, which may be "default" for the Default value, | ||
// or null if an absolute start and end date have been selected. | ||
@Prop({ default: 'default' }) value!: string | null | ||
@Prop({ default: () => [] }) items!: string[] | ||
@Prop({ default: () => new Date() }) now!: Date | ||
selectedIndex: number | undefined = 0 | ||
mounted() { | ||
this.onValueChange() | ||
} | ||
@Watch('value') | ||
onValueChange(): void { | ||
if (this.value === null) { | ||
this.selectedIndex = 0 | ||
} else if (this.value === 'default') { | ||
this.selectedIndex = 1 | ||
} else { | ||
this.selectedIndex = this.items.findIndex((entry) => entry === this.value) + 2 | ||
} | ||
} | ||
intervalToLocaleString(interval: string) { | ||
const duration = Duration.fromISO(interval) | ||
const startDateTime = DateTime.fromJSDate(this.now).plus(duration) | ||
return startDateTime.toRelative() | ||
} | ||
onSelectInterval(index: number): void { | ||
let selectedInterval = undefined | ||
if (index === 0) { | ||
selectedInterval = null | ||
} else if (index === 1) { | ||
selectedInterval = 'default' | ||
} else { | ||
selectedInterval = this.items[index - 2] | ||
} | ||
this.$emit('input', selectedInterval) | ||
} | ||
} | ||
</script> | ||
|
||
<style scoped> | ||
.interval-list { | ||
max-height: 400px; | ||
overflow-y: auto; | ||
} | ||
</style> |
Oops, something went wrong.