Skip to content

Commit d4946d1

Browse files
committed
Merge branch 'feature/filter'
2 parents 568fb47 + e8f16ca commit d4946d1

File tree

6 files changed

+200
-25
lines changed

6 files changed

+200
-25
lines changed

src/components/DgFilter.vue

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
<template lang="pug">
2+
.filter(:class="{'filter--active': isActive}")
3+
img.square(src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")
4+
.button(@click="onActive")
5+
icon.icon--filter(symbol="filter")
6+
transition(name="fade")
7+
.panel(v-if="isActive")
8+
.control
9+
p.control-label SORT
10+
round-checkbox.sortOption(v-for="(val, key) in sort", :label="key", :value="sort[key]", :isBlock="false", @input="onSortCheck(key, $event)")
11+
.control
12+
p.control-label LIMIT RANGE
13+
14+
</template>
15+
16+
<script>
17+
import RoundCheckbox from 'components/RoundCheckbox'
18+
import Icon from 'components/Icon'
19+
20+
export default {
21+
props: {
22+
isActive: Boolean
23+
},
24+
data () {
25+
return {
26+
sort: {
27+
ascending: false,
28+
descending: false
29+
}
30+
}
31+
},
32+
components: {
33+
RoundCheckbox,
34+
Icon
35+
},
36+
methods: {
37+
onActive () {
38+
this.$emit('change', !this.isActive)
39+
},
40+
onSortCheck (key, value) {
41+
let order = 0
42+
this.sort[key] = value
43+
if (value) {
44+
for (let prop in this.sort) {
45+
if (prop !== key) {
46+
this.sort[prop] = false
47+
}
48+
}
49+
}
50+
if (this.sort.ascending) {
51+
order = 1
52+
} else if (this.sort.descending) {
53+
order = -1
54+
}
55+
this.$emit('sort', order)
56+
}
57+
}
58+
}
59+
60+
</script>
61+
62+
<style lang="sass" scoped>
63+
@import "../sass/variables"
64+
@import "../sass/utils"
65+
@import "../sass/transition"
66+
67+
.filter
68+
position: absolute
69+
top: 0
70+
right: 0
71+
height: 100%
72+
z-index: $popup-index
73+
cursor: pointer
74+
transition: background $medium
75+
76+
.filter--active
77+
background: $cell-color
78+
box-shadow: $half-shadow
79+
80+
.button
81+
position: absolute
82+
top: 0
83+
left: 0
84+
right: 0
85+
bottom: 0
86+
text-align: center
87+
88+
.square
89+
display: block
90+
height: 100%
91+
width: auto
92+
93+
.icon--filter
94+
width: 1.6em
95+
height: 1.6em
96+
margin-top: 50%
97+
transform: translateY(-50%)
98+
99+
.panel
100+
position: absolute
101+
top: 100%
102+
right: 0
103+
width: 240px
104+
padding: 0.5em 1em
105+
background: $cell-color
106+
box-shadow: $shadow
107+
108+
.control
109+
@extend %clearfix
110+
padding: 0.5em 0
111+
112+
.control-label
113+
margin: 0.5em 0
114+
font-weight: 900
115+
116+
.sortOption
117+
&:first-of-type
118+
float: left
119+
&:last-of-type
120+
float: right
121+
</style>

src/components/DgMenu.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,19 @@
22
.dg-menu(:style="posStyle")
33
.panel
44
.option(v-for="(value, key) in options", v-if="!shouldBeEscaped(key)")
5-
round-check-box(:label="key | capitalize", v-model="options[key]", :isBlock="true")
5+
round-checkbox(:label="key | capitalize", v-model="options[key]", :isBlock="true")
66
</template>
77

88
<script>
9-
import RoundCheckBox from 'components/RoundCheckBox'
9+
import RoundCheckbox from 'components/RoundCheckbox'
1010
export default {
1111
props: {
1212
position: Object,
1313
options: Object,
1414
escaped: Array
1515
},
1616
components: {
17-
RoundCheckBox
17+
RoundCheckbox
1818
},
1919
computed: {
2020
posStyle () {

src/components/DgTable.vue

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
th.header--date(key="header-date")
77
th.header(v-for="attribute in filteredAttributes",
88
:key="'header--'+attribute", :class="headerClass(attribute)",
9-
@click="onHeaderClick(attribute, $event)", @contextmenu.prevent="openMenu") {{ attribute | capitalize }}
9+
@click.self="onHeaderClick(attribute, $event)", @contextmenu.prevent="openMenu") {{ attribute | capitalize }}
10+
dg-filter(v-if="filterables.includes(attribute)", :isActive="activefilterables[attribute]",
11+
@change="onFilterMenuChange(attribute, $event)", @sort="onSort(attribute, $event)")
1012
tbody
1113
transition-group(v-for="(record, index) in sortedRecords", name="fade", tag="tr")
1214
td.cell.cell--date(v-if="isfirstOfDateGroup(index)", key="cell-date", :rowspan="getNumOfDateGroupByIndex(index)")
@@ -30,11 +32,13 @@ import moment from 'moment'
3032
import _ from 'lodash'
3133
import { TweenMax, Linear } from 'gsap'
3234
import { records } from '../data.json'
35+
import settings from '../tableSettings'
3336
import { toCurrency, toMMMMYYYY, capitalize, toGMapQuery } from 'utils/filters'
3437
import { offsets } from 'utils/mouse'
3538
import DgMenu from 'components/DgMenu'
3639
import DgCellMenu from 'components/DgCellMenu'
3740
import DgCellDetail from 'components/DgCellDetail'
41+
import DgFilter from 'components/DgFilter'
3842
3943
Vue.filter('toCurrency', toCurrency)
4044
Vue.filter('toMMMMYYYY', toMMMMYYYY)
@@ -44,26 +48,28 @@ export default {
4448
components: {
4549
DgMenu,
4650
DgCellMenu,
47-
DgCellDetail
51+
DgCellDetail,
52+
DgFilter
4853
},
4954
data () {
55+
let sortOrders = {}
56+
let activefilterables = {}
57+
settings.filterables.forEach((attribute) => {
58+
sortOrders[attribute] = 0
59+
activefilterables[attribute] = false
60+
})
5061
return {
51-
attributes: {
52-
customer: true,
53-
company: true,
54-
contact: true,
55-
address: true,
56-
revenue: true,
57-
VAT: true,
58-
totalPrice: true,
59-
status: true
60-
},
61-
expandables: ['company', 'contact', 'address'],
62-
interactables: ['revenue', 'VAT', 'totalPrice'],
63-
currencies: ['revenue', 'VAT', 'totalPrice'],
64-
hasDetails: ['address'],
65-
omitOnMenu: ['customer'],
6662
records: records,
63+
attributes: settings.attributes,
64+
expandables: settings.expandables,
65+
interactables: settings.interactables,
66+
currencies: settings.currencies,
67+
hasDetails: settings.hasDetails,
68+
filterables: settings.filterables,
69+
omitOnMenu: settings.omitOnMenu,
70+
sortAttribute: '',
71+
sortOrders: sortOrders,
72+
activefilterables: activefilterables,
6773
expanding: '',
6874
focusCell: {
6975
recordId: '',
@@ -79,9 +85,22 @@ export default {
7985
},
8086
computed: {
8187
sortedRecords () {
82-
return this.records.sort((a, b) => {
83-
return moment(a.date).isBefore(b.date) ? -1 : 1
84-
})
88+
let {sortAttribute, sortOrders, records} = this
89+
const order = sortOrders[sortAttribute] || 0
90+
if (sortAttribute) {
91+
return records.slice().sort((a, b) => {
92+
const aSort = a[sortAttribute]
93+
const bSort = b[sortAttribute]
94+
const localOrder = (aSort === bSort ? 0 : aSort > bSort ? 1 : -1) * order
95+
const aDate = moment(a.date.replace(/(-\d+)$/, ''))
96+
const bDate = moment(b.date.replace(/(-\d+)$/, ''))
97+
return moment(aDate).isSame(bDate) ? localOrder : moment(aDate).isBefore(bDate) ? -1 : 1
98+
})
99+
} else {
100+
return records.slice().sort((a, b) => {
101+
return moment(a.date).isBefore(b.date) ? -1 : 1
102+
})
103+
}
85104
},
86105
filteredAttributes () {
87106
return Object.keys(this.attributes).filter((el) => {
@@ -158,6 +177,7 @@ export default {
158177
},
159178
onHeaderClick (attribute, event) {
160179
this.clearFocusCell()
180+
this.closeFilterMenu()
161181
this.expandCol(attribute, event)
162182
},
163183
onCellClick (attribute, id, event) {
@@ -183,6 +203,16 @@ export default {
183203
clearFocusCell () {
184204
this.focusCell.recordId = ''
185205
this.focusCell.attribute = ''
206+
},
207+
closeFilterMenu () {
208+
for (let attribute in this.activefilterables) this.activefilterables[attribute] = false
209+
},
210+
onSort (attribute, order) {
211+
this.sortAttribute = order ? attribute : ''
212+
this.sortOrders[attribute] = order
213+
},
214+
onFilterMenuChange (attribute, active) {
215+
this.activefilterables[attribute] = active
186216
}
187217
}
188218
}
@@ -247,7 +277,7 @@ table
247277
248278
.cell--focus, .cell--focus:hover
249279
background: $cell-color
250-
box-shadow: 4px 0 2px 0 rgba(#000, 0.24)
280+
box-shadow: $half-shadow
251281
252282
253283
.cell-content
@@ -267,5 +297,4 @@ table
267297
.cell--customer
268298
background: $hover-color
269299
270-
271300
</style>

src/sass/_utils.sass

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,8 @@
22

33
@function fitted-cell-width($len)
44
@return $cell-padding + ($len / 2)
5+
6+
%clearfix::after
7+
content: ''
8+
display: block
9+
clear: both

src/sass/_variables.sass

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,5 @@ $medium: 0.4s
2020
/* STYLE */
2121
$shadow: 4px 4px 2px 0 $shadow-color
2222
$half-shadow: 4px 0 2px 0 $shadow-color
23+
24+
$popup-index: 100

src/tableSettings.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
export default {
2+
attributes: {
3+
customer: true,
4+
company: true,
5+
contact: true,
6+
address: true,
7+
revenue: true,
8+
VAT: true,
9+
totalPrice: true,
10+
status: true
11+
},
12+
expandables: ['company', 'contact', 'address'],
13+
interactables: ['revenue', 'VAT', 'totalPrice'],
14+
currencies: ['revenue', 'VAT', 'totalPrice'],
15+
hasDetails: ['address'],
16+
filterables: ['VAT'],
17+
omitOnMenu: ['customer']
18+
}

0 commit comments

Comments
 (0)