IconPickerDialog.vue 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. <template lang="pug">
  2. q-card.icon-picker(flat, style='width: 400px;')
  3. q-tabs.text-primary(
  4. v-model='state.currentTab'
  5. no-caps
  6. inline-label
  7. )
  8. q-tab(
  9. name='icon'
  10. icon='las la-icons'
  11. label='Icon'
  12. )
  13. q-tab(
  14. name='img'
  15. icon='las la-image'
  16. label='Image'
  17. )
  18. q-separator
  19. q-tab-panels(
  20. v-model='state.currentTab'
  21. )
  22. q-tab-panel(name='icon')
  23. q-select(
  24. :options='iconPacks'
  25. v-model='state.selPack'
  26. emit-value
  27. map-options
  28. outlined
  29. dense
  30. transition-show='jump-down'
  31. transition-hide='jump-up'
  32. )
  33. template(v-slot:option='scope')
  34. q-item(
  35. v-bind='scope.itemProps'
  36. v-on='scope.itemEvents'
  37. :class='scope.selected ? `bg-primary text-white` : ``'
  38. )
  39. q-item-section(side)
  40. q-icon(
  41. name='las la-box'
  42. :color='scope.selected ? `white` : `grey`'
  43. )
  44. q-item-section
  45. q-item-label {{scope.opt.name}}
  46. q-item-label(caption): strong(:class='scope.selected ? `text-white` : `text-primary`') {{scope.opt.subset}}
  47. q-item-section(side, v-if='scope.opt.subset')
  48. q-chip(
  49. color='primary'
  50. text-color='white'
  51. rounded
  52. size='sm'
  53. ) {{scope.opt.subset.toUpperCase()}}
  54. q-input.q-mt-md(
  55. v-model='state.selIcon'
  56. outlined
  57. label='Icon Name'
  58. dense
  59. )
  60. .row.q-gutter-md.q-mt-none
  61. .col-auto
  62. q-avatar(
  63. size='64px'
  64. color='primary'
  65. rounded
  66. )
  67. q-icon(
  68. :name='iconName'
  69. color='white'
  70. size='64px'
  71. )
  72. .col
  73. .text-caption Learn how to #[a(href='https://docs.requarks.io') use icons].
  74. .text-caption.q-mt-sm View #[a(:href='iconPackRefWebsite', target='_blank') Icon Pack reference] for all possible options.
  75. q-tab-panel(name='img')
  76. .row.q-gutter-sm
  77. q-btn.col(
  78. label='Browse...'
  79. color='secondary'
  80. icon='las la-file-image'
  81. unelevated
  82. no-caps
  83. )
  84. q-btn.col(
  85. label='Upload...'
  86. color='secondary'
  87. icon='las la-upload'
  88. unelevated
  89. no-caps
  90. )
  91. .q-mt-md.text-center
  92. q-avatar(
  93. size='64px'
  94. rounded
  95. )
  96. q-img(
  97. transition='jump-down'
  98. :ratio='1'
  99. :src='state.imgPath'
  100. )
  101. q-separator
  102. q-card-actions
  103. q-space
  104. q-btn(
  105. icon='las la-times'
  106. label='Discard'
  107. outline
  108. color='grey-7'
  109. v-close-popup
  110. )
  111. q-btn(
  112. icon='las la-check'
  113. label='Apply'
  114. unelevated
  115. color='secondary'
  116. @click='apply'
  117. v-close-popup
  118. )
  119. </template>
  120. <script setup>
  121. import { find } from 'lodash-es'
  122. import { computed, onMounted, reactive } from 'vue'
  123. // PROPS
  124. const props = defineProps({
  125. modelValue: {
  126. type: String,
  127. required: true
  128. }
  129. })
  130. // EMITS
  131. const emit = defineEmits(['update:modelValue'])
  132. // DATA
  133. const state = reactive({
  134. currentTab: 'icon',
  135. selPack: 'las',
  136. selIcon: '',
  137. imgPath: 'https://placeimg.com/64/64/nature'
  138. })
  139. const iconPacks = [
  140. { value: 'las', label: 'Line Awesome (solid)', name: 'Line Awesome', subset: 'solid', prefix: 'las la-', reference: 'https://icons8.com/line-awesome' },
  141. { value: 'lab', label: 'Line Awesome (brands)', name: 'Line Awesome', subset: 'brands', prefix: 'lab la-', reference: 'https://icons8.com/line-awesome' },
  142. { value: 'mdi', label: 'Material Design Icons', name: 'Material Design Icons', prefix: 'mdi-', reference: 'https://materialdesignicons.com' },
  143. { value: 'fas', label: 'Font Awesome (solid)', name: 'Font Awesome', subset: 'solid', prefix: 'fas fa-', reference: 'https://fontawesome.com/icons' },
  144. { value: 'far', label: 'Font Awesome (regular)', name: 'Font Awesome', subset: 'regular', prefix: 'far fa-', reference: 'https://fontawesome.com/icons' },
  145. { value: 'fal', label: 'Font Awesome (light)', name: 'Font Awesome', subset: 'light', prefix: 'fal fa-', reference: 'https://fontawesome.com/icons' },
  146. { value: 'fad', label: 'Font Awesome (duotone)', name: 'Font Awesome', subset: 'duotone', prefix: 'fad fa-', reference: 'https://fontawesome.com/icons' },
  147. { value: 'fab', label: 'Font Awesome (brands)', name: 'Font Awesome', subset: 'brands', prefix: 'fab fa-', reference: 'https://fontawesome.com/icons' }
  148. ]
  149. // COMPUTED
  150. const iconName = computed(() => {
  151. return find(iconPacks, ['value', state.selPack]).prefix + state.selIcon
  152. })
  153. const iconPackRefWebsite = computed(() => {
  154. return find(iconPacks, ['value', state.selPack]).reference
  155. })
  156. // METHODS
  157. function apply () {
  158. if (state.currentTab === 'img') {
  159. emit('update:modelValue', `img:${state.imgPath}`)
  160. } else {
  161. emit('update:modelValue', state.iconName)
  162. }
  163. }
  164. // MOUNTED
  165. onMounted(() => {
  166. if (props.modelValue?.startsWith('img:')) {
  167. state.currentTab = 'img'
  168. state.imgPath = props.modelValue.substring(4)
  169. } else {
  170. state.currentTab = 'icon'
  171. for (const pack of iconPacks) {
  172. if (props.value?.startsWith(pack.prefix)) {
  173. state.selPack = pack.value
  174. state.selIcon = props.modelValue.substring(pack.prefix.length)
  175. break
  176. }
  177. }
  178. }
  179. })
  180. </script>
  181. <style lang="scss">
  182. .icon-picker {
  183. a {
  184. @at-root .body--light & {
  185. color: $blue-7;
  186. }
  187. @at-root .body--dark & {
  188. color: $blue-3;
  189. }
  190. }
  191. .q-tab-panels {
  192. @at-root .body--light & {
  193. background-color: $grey-1;
  194. }
  195. @at-root .body--dark & {
  196. background-color: $dark-4;
  197. }
  198. }
  199. .q-input .q-field__control, .q-select .q-field__control {
  200. @at-root .body--light & {
  201. background-color: #FFF;
  202. }
  203. @at-root .body--dark & {
  204. background-color: $dark-5;
  205. }
  206. }
  207. }
  208. </style>