Skip to content

Commit da28493

Browse files
committed
feat(ui): allow tag filtering (#30)
1 parent 256c500 commit da28493

File tree

7 files changed

+116
-40
lines changed

7 files changed

+116
-40
lines changed

demo/src/markdown/iconpicker.md

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export default {
6464

6565
If you are using a large icon set and find it is taking too long to load, you can pre-cache the UMD variant.
6666

67-
You can do this by adding to your **App.vue** (or, any other appropriate) file:
67+
You can do this by adding to your **App.vue** (or, any other appropriate) file, one or more of the UMD icon-set variants:
6868

6969
:::
7070
```html
@@ -195,3 +195,87 @@ Most icon sets are very large which may cause performance issues.
195195
::: tip
196196
In order to work properly, QIconPicker needs a specified height in it's style (or parent style).
197197
:::
198+
199+
# Categories (tags)
200+
Added in **v1.0.7**, you can now get categories (tags) for the associated loaded icon set.
201+
202+
As of this writing, the **Eva** and **Material Design** icon sets are done. The **Fontawesome v5** icon set is partially done. If you need an icon set that **needs** to be completed and is not, PRs are welcomed or DM me on the Discord channel.
203+
204+
You can get the tags viw the `tag` event.
205+
206+
```html
207+
<q-icon-picker
208+
v-model="name"
209+
:filter="filter"
210+
:icon-set="iconSet"
211+
:tags="tags"
212+
font-size="3em"
213+
tooltips
214+
:pagination.sync="pagination"
215+
@tags="onTags"
216+
style="height: calc(100vh - 140px)"
217+
/>
218+
```
219+
220+
Notice the `@tags="onTags"`. Capturing this is a bit tricky. You need to set a guard to stop potential end-less loop in your Vue code (depending on how you use it). In your `data ()` function set a guard variable; in this case `loaded`:
221+
222+
```js
223+
data () {
224+
return {
225+
loaded: false, // guard var
226+
tags: [], // user selected tags to pass to QIconPicker
227+
categories: [], // keep track of categories
228+
selected: {} // keep track of user selected categories
229+
}
230+
```
231+
232+
in your `methods` section, add the event handler, and put the guard in to stop potential recursion:
233+
234+
```js
235+
methods: {
236+
onTags (tags) {
237+
if (this.loaded !== true) {
238+
let cats = []
239+
let t = [ ...tags ]
240+
cats.splice(0, 0, ...t)
241+
this.categories.splice(0, this.categories.length, ...cats)
242+
this.categories.concat(...cats)
243+
this.categories.forEach(cat => {
244+
this.$set(this.selected, cat, false)
245+
})
246+
this.loaded = true
247+
}
248+
}
249+
}
250+
```
251+
252+
This is all good and well, until you need to select a different icon-set. We can create the proper handlers in the `watch` section:
253+
254+
```js
255+
watch: {
256+
iconSet (val) {
257+
this.loaded = false
258+
this.tags.splice(0, this.tags.length)
259+
},
260+
filter (val) {
261+
this.loaded = false
262+
},
263+
selected: {
264+
handler (val) {
265+
let tags = []
266+
this.categories.forEach(cat => {
267+
// if user has selected this tag...
268+
if (val[cat] === true) {
269+
// ...then keep track of it
270+
tags.push(cat)
271+
}
272+
})
273+
// push all user selected tags to QIconPicker
274+
this.tags.splice(0, this.tags.length, ...tags)
275+
},
276+
deep: true
277+
}
278+
},
279+
```
280+
281+
Notice in the above code, the ares where the guard is reset with `this.loaded = false`.

demo/src/pages/Icons.vue

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,14 @@
3838
<div class="column col-grow">
3939
<q-resize-observer @resize="onResize" />
4040
<q-icon-picker
41-
ref="icons"
4241
v-model="name"
4342
:filter="filter"
4443
:icon-set="iconSet"
4544
:tags="tags"
4645
font-size="3em"
4746
tooltips
4847
:pagination.sync="pagination"
49-
@loaded="onLoaded"
48+
@tags="onTags"
5049
style="height: calc(100vh - 140px)"
5150
/>
5251
</div>
@@ -104,6 +103,7 @@ export default {
104103
watch: {
105104
iconSet (val) {
106105
this.loaded = false
106+
this.tags.splice(0, this.tags.length)
107107
},
108108
filter (val) {
109109
this.loaded = false
@@ -117,26 +117,23 @@ export default {
117117
}
118118
})
119119
this.tags.splice(0, this.tags.length, ...tags)
120-
console.log(this.tags)
121120
},
122121
deep: true
123122
}
124123
},
125124
126125
methods: {
127-
onLoaded () {
126+
onTags (tags) {
128127
if (this.loaded !== true) {
129128
let cats = []
130-
if (this.$refs.icons) {
131-
let tags = [ ...this.$refs.icons.getTags() ]
132-
cats.splice(0, 0, ...tags)
133-
this.loaded = true
134-
}
129+
let t = [ ...tags ]
130+
cats.splice(0, 0, ...t)
135131
this.categories.splice(0, this.categories.length, ...cats)
136132
this.categories.concat(...cats)
137133
this.categories.forEach(cat => {
138134
this.$set(this.selected, cat, false)
139135
})
136+
this.loaded = true
140137
}
141138
},
142139

ui/build/icons/build.eva.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ fileContents
4747
const tags = oldIcons[line].tags.split(',').map(tag => {
4848
if (tag === '') return tag
4949
return "'" + tag + "'"
50-
}).join(',')
50+
}).join(', ')
5151
icons.push(`{ name: '${line}', tags: [${tags}] }`)
5252
} else {
5353
icons.push(`{ name: '${line}', tags: [] }`)

ui/build/icons/build.ion.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ fileContents
4444
const tags = oldIcons[line].tags.split(',').map(tag => {
4545
if (tag === '') return tag
4646
return "'" + tag + "'"
47-
}).join(',')
47+
}).join(', ')
4848
icons.push(`{ name: '${line}', tags: [${tags}] }`)
4949
} else {
5050
icons.push(`{ name: '${line}', tags: [] }`)

ui/build/icons/build.mdi.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ fileContents
6161
const tags = oldIcons[line].tags.split(',').map(tag => {
6262
if (tag === '') return tag
6363
return "'" + tag + "'"
64-
}).join(',')
64+
}).join(', ')
6565
icons.push(`{ name: '${line}', tags: [${tags}] }`)
6666
} else {
6767
icons.push(`{ name: '${line}', tags: [] }`)

ui/src/components/QIconPicker.js

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ export default {
2323
page: 1,
2424
itemsPerPage: 0,
2525
totalPages: 0
26-
}
26+
},
27+
categories: []
2728
}
2829
},
2930

@@ -163,7 +164,6 @@ export default {
163164
},
164165

165166
tags (val) {
166-
console.log('tags changed:', val)
167167
// whenever the tags change, it resets pagination page to page 1
168168
this.__setPagination({ page: 1, totalPages: this.pagesNumber })
169169
this.__updatePagination()
@@ -181,14 +181,17 @@ export default {
181181
const iconsSet = window.QIconPicker.iconSet[name]
182182
this.iconsList = iconsSet.icons
183183
} else {
184+
// eslint-disable-next-line no-console
184185
console.error(`QIconPicker: no icon set loaded called '${set}'`)
186+
// eslint-disable-next-line no-console
185187
console.error('Be sure to load the UMD version of the icon set in a script tag before using with UMD')
186188
}
187189
} else {
188190
try {
189191
const iconsSet = require(`@quasar/quasar-ui-qiconpicker/src/components/icon-set/${set}.js`).default
190192
this.iconsList = iconsSet.icons
191193
} catch (e) {
194+
// eslint-disable-next-line no-console
192195
console.error(`QIconPicker: cannot find icon set found called '${set}'`)
193196
}
194197
}
@@ -252,9 +255,9 @@ export default {
252255
}
253256
},
254257

255-
getTags (name) {
258+
__getCategories () {
256259
let t = []
257-
this.displayedIcons.forEach(icon => {
260+
this.iconsList.forEach(icon => {
258261
const tags = icon.tags
259262
tags.forEach(tag => {
260263
if (t.includes(tag) !== true) {
@@ -263,7 +266,8 @@ export default {
263266
})
264267
})
265268
t.sort()
266-
return t
269+
this.categories = t
270+
return true
267271
},
268272

269273
__renderBody (h) {
@@ -370,13 +374,19 @@ export default {
370374
},
371375

372376
render (h) {
373-
return h('div', this.setBothColors(this.color, this.backgroundColor, {
377+
const picker = h('div', this.setBothColors(this.color, this.backgroundColor, {
374378
ref: 'icon-picker',
375379
staticClass: 'q-icon-picker flex'
376380
}), [
377381
this.__renderBody(h),
378-
this.noFooter !== true && this.pagination !== void 0 && this.__renderFooter(h),
379-
this.$emit('loaded') && void 0
382+
this.noFooter !== true && this.pagination !== void 0 && this.__renderFooter(h)
380383
])
384+
385+
this.$nextTick(() => {
386+
this.__getCategories()
387+
this.$emit('tags', this.categories)
388+
})
389+
390+
return picker
381391
}
382392
}

ui/src/components/QIconPicker.json

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,10 @@
137137
"input": {
138138
"type": "String",
139139
"desc": "`v-model`; Value from when the selection changes"
140+
},
141+
"tags": {
142+
"type": "Array",
143+
"desc": "An array for categories (tags) for the selected icon set"
140144
}
141145
},
142146
"scopedSlots": {
@@ -161,25 +165,6 @@
161165
},
162166
"nextPage": {
163167
"desc": "If paginated, will go to next page, if not on last page"
164-
},
165-
"getTags": {
166-
"desc": "Returns an array of tags associated with the passed in icon name",
167-
"params": {
168-
"name": {
169-
"type": "Array",
170-
"desc": "The categories associated with the current icon set",
171-
"examples": [
172-
"[ 'file', 'food', 'nature', 'people' ]"
173-
]
174-
}
175-
},
176-
"returns": {
177-
"type": "Array",
178-
"desc": "An array of tags",
179-
"examples": [
180-
"['accessibility', 'media']"
181-
]
182-
}
183168
}
184169
}
185170
}

0 commit comments

Comments
 (0)