[Refactoring] Architecture

This commit is contained in:
Matej Glasnák committed 2022-11-22 16:29:47 +01:00
1 parent 9af01fc34b
commit b374a85eac
34 files changed
+103 -51

No files matched your search

@@ -0,0 +1,3 @@
<svg width="9" height="16" viewBox="0 0 9 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.70711 0.292893C1.31658 -0.0976311 0.683418 -0.0976311 0.292893 0.292893C-0.0976311 0.683418 -0.0976311 1.31658 0.292893 1.70711L1.70711 0.292893ZM8 8L8.70711 8.70711C9.09763 8.31658 9.09763 7.68342 8.70711 7.29289L8 8ZM0.292893 14.2929C-0.0976311 14.6834 -0.0976311 15.3166 0.292893 15.7071C0.683418 16.0976 1.31658 16.0976 1.70711 15.7071L0.292893 14.2929ZM0.292893 1.70711L7.29289 8.70711L8.70711 7.29289L1.70711 0.292893L0.292893 1.70711ZM7.29289 7.29289L0.292893 14.2929L1.70711 15.7071L8.70711 8.70711L7.29289 7.29289Z" fill="#14181F"/>
</svg>

After

Width:  |  Height:  |  Size: 655 B

@@ -0,0 +1,3 @@
<svg width="10" height="17" viewBox="0 0 10 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.79289 16.2071C8.18342 16.5976 8.81658 16.5976 9.20711 16.2071C9.59763 15.8166 9.59763 15.1834 9.20711 14.7929L7.79289 16.2071ZM1.5 8.5L0.792893 7.79289C0.402369 8.18342 0.402369 8.81658 0.792893 9.20711L1.5 8.5ZM9.20711 2.20711C9.59763 1.81658 9.59763 1.18342 9.20711 0.792893C8.81658 0.402369 8.18342 0.402369 7.79289 0.792893L9.20711 2.20711ZM9.20711 14.7929L2.20711 7.79289L0.792893 9.20711L7.79289 16.2071L9.20711 14.7929ZM2.20711 9.20711L9.20711 2.20711L7.79289 0.792893L0.792893 7.79289L2.20711 9.20711Z" fill="#14181F"/>
</svg>

After

Width:  |  Height:  |  Size: 643 B

@@ -0,0 +1,81 @@
<template>
<v-row class="px-10 py-8 subheader">
<v-select
v-model="selectedEmployee"
class="subheader-input"
:items="employees"
label="Zamestnanec"
variant="outlined"
></v-select>
<div class="d-flex date-wrapper">
<v-btn class="subheader-icon-button " variant="outlined"><img :src="require('./_img/icon-prev.svg')" alt=""></v-btn>
<v-text-field
class="subheader-input disabled"
:items="items"
label="Dátum"
v-model="selectedDate"
variant="outlined"
append-inner-icon="mdi-calendar-blank-outline"
></v-text-field>
<v-btn class="subheader-icon-button " variant="outlined"><img :src="require('./_img/icon-next.svg')" alt=""></v-btn>
</div>
<v-text-field
class="subheader-input"
:items="items"
label="Nenaplánované hodiny"
v-model="plannedTime"
variant="outlined"
></v-text-field>
</v-row>
</template>
<script>
export default {
data() {
return {
employees: ['Foo', 'Bar', 'Fizz', 'Buzz'],
selectedDate: "13.11.2022 - 17.11.2022",
plannedTime: "35 h",
selectedEmployee: 'Bar'
}
},
}
</script>
<style lang="sass" scoped>
.subheader
max-width: 100%
margin: 0
border-bottom: 1px solid rgba(33, 33, 33, 0.08)
border-top: 1px solid rgba(33, 33, 33, 0.08)
gap: 30px
flex-wrap: wrap
.subheader-icon-button
border: 1px solid #ABABAB
height: 56px
width: 56px
min-width: auto !important
padding: 0
margin: 0 10px
&:deep(.v-btn__append)
margin: 0
.subheader-input
max-width: 250px !important
min-width: 180px
&:deep(.v-input__details)
display: none
&.disabled
pointer-events: none !important
.date-wrapper
flex: 0 1 402px
</style>
@@ -0,0 +1,326 @@
<template>
<div>
<v-sheet tile height="54" color="grey lighten-3" class="d-flex">
<v-btn icon class="ma-2" @click="$refs.calendar.prev()">
<v-icon>mdi-chevron-left</v-icon>
</v-btn>
<v-select v-model="type" :items="types" dense outlined hide-details class="ma-2" label="type"></v-select>
<v-select v-model="mode" :items="modes" dense outlined hide-details label="event-overlap-mode" class="ma-2"></v-select>
<v-select v-model="weekday" :items="weekdays" dense outlined hide-details label="weekdays" class="ma-2"></v-select>
<v-spacer></v-spacer>
<v-btn icon class="ma-2" @click="$refs.calendar.next()">
<v-icon>mdi-chevron-right</v-icon>
</v-btn>
</v-sheet>
<v-sheet height="600">
<v-calendar ref="calendar" v-model="value" :weekdays="weekday" :type="type" :events="events" :event-overlap-mode="mode" :event-overlap-threshold="60" :event-color="getEventColor" :event-ripple="false" @change="getEvents" @mousedown:event="startDrag" @mousedown:time="startTime" @mousemove:time="mouseMove" @mouseup:time="endDrag" @mouseleave="cancelDrag">
<template #event="{ event, timed }">
<div class="pl-1" v-html="getEventHTML(event, timed)"></div>
<div v-if="timed" class="v-event-drag-bottom" @mousedown.stop="extendBottom(event)"></div>
</template>
<template #day-body="{ date, week }">
<div class="v-current-time" :class="{ first: date === week[0].date }" :style="{ top: nowY }">
<div class="v-current-time-time">
{{ nowTime }}
</div>
</div>
</template>
&nbsp;
</v-calendar>
<!-- {{ lastEvent }} -->
</v-sheet>
</div>
</template>
<script>
export default {
data() {
return {
type: 'day',
types: ['month', 'week', 'day', '4day'],
mode: 'stack',
modes: ['stack', 'column'],
weekday: [0, 1, 2, 3, 4, 5, 6],
weekdays: [
{ text: 'Sun - Sat', value: [0, 1, 2, 3, 4, 5, 6] },
{ text: 'Mon - Sun', value: [1, 2, 3, 4, 5, 6, 0] },
{ text: 'Mon - Fri', value: [1, 2, 3, 4, 5] },
{ text: 'Mon, Wed, Fri', value: [1, 3, 5] }
],
value: '',
events: [],
colors: ['#2196F3', '#3F51B5', '#673AB7', '#00BCD4', '#4CAF50', '#FF9800', '#757575'],
names: ['Meeting', 'Holiday', 'PTO', 'Travel', 'Event', 'Birthday', 'Conference', 'Party'],
dragEvent: null,
dragStart: null,
lastEvent: '',
createEvent: null,
createStart: null,
extendOriginal: null,
isMounted: false
}
},
computed: {
nowY() {
const cal = this.$refs.calendar
if (!cal && !this.isMounted) {
return -1
}
return cal.timeToY(cal.times.now) + 'px'
},
nowTime() {
const cal = this.$refs.calendar
if (!cal && !this.isMounted) {
return -1
}
return cal.formatTime(cal.times.now)
}
},
mounted() {
const cal = this.$refs.calendar
this.isMounted = true
// scroll to the current time
const minutes = cal.times.now.hour * 60 + cal.times.now.minute
const firstTime = Math.max(0, minutes - (minutes % 30) - 30)
cal.scrollToTime(firstTime)
// every minute update the current time bar
setInterval(() => cal.updateTimes(), 60 * 1000)
},
methods: {
getEvents({ start, end }) {
const events = []
const min = new Date(`${start.date}T00:00:00`)
const max = new Date(`${end.date}T23:59:59`)
const days = (max.getTime() - min.getTime()) / 86400000
const eventCount = this.rnd(days, days + 20)
for (let i = 0; i < eventCount; i++) {
const allDay = this.rnd(0, 3) === 0
const firstTimestamp = this.rnd(min.getTime(), max.getTime())
const first = new Date(firstTimestamp - (firstTimestamp % 900000))
const secondTimestamp = this.rnd(2, allDay ? 288 : 8) * 900000
const second = new Date(first.getTime() + secondTimestamp)
events.push({
name: this.names[this.rnd(0, this.names.length - 1)],
start: this.formatDate(first, !allDay),
end: this.formatDate(second, !allDay),
color: this.colors[this.rnd(0, this.colors.length - 1)]
})
}
this.events = events
},
getEventColor(event) {
const rgb = parseInt(event.color.substring(1), 16)
const r = (rgb >> 16) & 0xff
const g = (rgb >> 8) & 0xff
const b = (rgb >> 0) & 0xff
return event === this.dragEvent ? `rgba(${r}, ${g}, ${b}, 0.5)` : event === this.createEvent ? `rgba(${r}, ${g}, ${b}, 0.5)` : event.color
},
getEventHTML(event, timed) {
const cal = this.$refs.calendar
let name = event.name
if (event.start.hasTime) {
if (timed) {
const showStart = event.start.hour < 12 && event.end.hour >= 12
const start = cal.formatTime(event.start, showStart)
const end = cal.formatTime(event.end, true)
// const singline = diffMinutes(event.start, event.end) <= this.parsedEventOverlapThreshold
const singline = event.end - event.start <= this.parsedEventOverlapThreshold
const separator = singline ? ', ' : '<br>'
return `<strong>${name}</strong>${separator}${start} - ${end}`
} else {
const time = this.formatTime(event.start, true)
return `<strong>${time}</strong> ${name}`
}
}
return name
},
rnd(a, b) {
return Math.floor((b - a + 1) * Math.random()) + a
},
formatDate(a, withTime) {
return withTime ? `${a.getFullYear()}-${a.getMonth() + 1}-${a.getDate()} ${a.getHours()}:${a.getMinutes()}` : `${a.getFullYear()}-${a.getMonth() + 1}-${a.getDate()}`
},
eventMove(e) {
console.log('eventMove', e)
},
startDrag(e) {
if (e.event && e.timed) {
this.dragEvent = e.event
this.dragTime = null
this.extendOriginal = null
}
this.lastEvent = 'startDrag'
},
startTime(e) {
const mouse = this.toDate(e)
if (this.dragEvent && this.dragTime === null) {
const start = this.toDate(this.dragEvent.start)
this.dragTime = mouse.getTime() - start.getTime()
} else {
this.createStart = this.roundTime(mouse.getTime())
this.createEvent = {
name: '(no title)',
start: this.toTimestamp(new Date(this.createStart)),
end: this.toTimestamp(new Date(this.createStart)),
color: this.colors[this.rnd(0, this.colors.length - 1)]
}
this.events.push(this.createEvent)
}
this.lastEvent = 'startTime'
},
extendBottom(event) {
this.createEvent = event
this.createStart = this.toDate(event.start).getTime()
this.extendOriginal = event.end
},
mouseMoveEvent(e) {
console.log('mouseMoveEvent', e)
},
mouseMove(e) {
if (this.dragEvent && this.dragTime !== null) {
const start = this.toDate(this.dragEvent.start)
const end = this.toDate(this.dragEvent.end)
const duration = end.getTime() - start.getTime()
const mouse = this.toDate(e)
const newStartTime = mouse.getTime() - this.dragTime
const newStart = new Date(this.roundTime(newStartTime))
const newEnd = new Date(newStart.getTime() + duration)
this.dragEvent.start = this.toTimestamp(newStart)
this.dragEvent.end = this.toTimestamp(newEnd)
} else if (this.createEvent && this.createStart !== null) {
const mouse = this.toDate(e).getTime()
const mouseRounded = this.roundTime(mouse, false)
const min = Math.min(mouseRounded, this.createStart)
const max = Math.max(mouseRounded, this.createStart)
this.createEvent.start = this.toTimestamp(new Date(min))
this.createEvent.end = this.toTimestamp(new Date(max))
}
},
endDrag(e) {
this.dragTime = null
this.dragEvent = null
this.createEvent = null
this.createStart = null
this.extendOriginal = null
this.lastEvent = 'endDrag'
},
cancelDrag(e) {
if (this.createEvent) {
if (this.extendOriginal) {
this.createEvent.end = this.extendOriginal
} else {
const i = this.events.indexOf(this.createEvent)
if (i !== -1) {
this.events.splice(i, 1)
}
}
}
this.createEvent = null
this.createStart = null
this.dragTime = null
this.dragEvent = null
this.lastEvent = 'cancelDrag'
},
roundTime(time, down = true) {
const roundDownTime = 15 * 60 * 1000 // 15 minutes
return down ? time - (time % roundDownTime) : time + (roundDownTime - (time % roundDownTime))
},
toDate(tms) {
return typeof tms === 'string' ? new Date(tms) : new Date(tms.year, tms.month - 1, tms.day, tms.hour, tms.minute)
},
toTimestamp(date) {
return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}`
}
}
}
</script>
<style lang="sass" scoped>
.v-calendar
user-select: none
-webkit-user-select: none
.v-event-drag-bottom
position: absolute
left: 0
right: 0
bottom: 4px
height: 4px
cursor: ns-resize
.v-event-drag-bottom::after
display: none
position: absolute
left: 50%
height: 4px
border-top: 1px solid white
border-bottom: 1px solid white
width: 20px
margin-left: -10px
opacity: 0.8
content: ''
.v-event-timed:hover .v-event-drag-bottom::after
display: block
.v-current-time
height: 1px
background-color: red
position: absolute
left: -1px
right: 0
pointer-events: none
&.first::after
content: ''
position: absolute
background-color: red
width: 7px
height: 7px
border-radius: 3.5px
margin-top: -3px
margin-left: -3px
.v-current-time-time
display: none
&.first .v-current-time-time
display: block
position: absolute
left: -60px
color: red
font-size: 10px
padding: 1px
background-color: white
width: 50px
height: 20px
text-align: right
top: -9px
</style>
@@ -0,0 +1,18 @@
<template>
<div>
<A-task-filter />
<Z-timeline />
</div>
</template>
<script>
import ATaskFilter from './_components/a-tasks-filter.vue'
import ZTimeline from './_components/z-timeline.vue'
export default {
components: {
ATaskFilter,
ZTimeline,
},
}
</script>