PageRelationDialog.vue 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. <template lang="pug">
  2. q-card.page-relation-dialog(style='width: 500px;')
  3. q-toolbar.bg-primary.text-white
  4. .text-subtitle2(v-if='isEditMode') {{t('editor.pageRel.titleEdit')}}
  5. .text-subtitle2(v-else) {{t('editor.pageRel.title')}}
  6. q-card-section
  7. .text-overline {{t('editor.pageRel.position')}}
  8. q-form.q-gutter-md.q-pt-md
  9. div
  10. q-btn-toggle(
  11. v-model='state.pos'
  12. push
  13. glossy
  14. no-caps
  15. toggle-color='primary'
  16. :options=`[
  17. { label: t('editor.pageRel.left'), value: 'left' },
  18. { label: t('editor.pageRel.center'), value: 'center' },
  19. { label: t('editor.pageRel.right'), value: 'right' }
  20. ]`
  21. )
  22. .text-overline {{t('editor.pageRel.button')}}
  23. q-input(
  24. ref='iptRelLabel'
  25. outlined
  26. dense
  27. :label='t(`editor.pageRel.label`)'
  28. v-model='state.label'
  29. )
  30. template(v-if='state.pos !== `center`')
  31. q-input(
  32. outlined
  33. dense
  34. :label='t(`editor.pageRel.caption`)'
  35. v-model='state.caption'
  36. )
  37. q-btn.rounded-borders(
  38. :label='t(`editor.pageRel.selectIcon`)'
  39. color='primary'
  40. outline
  41. )
  42. q-menu(content-class='shadow-7')
  43. icon-picker-dialog(v-model='state.icon')
  44. .text-overline {{t('editor.pageRel.target')}}
  45. q-btn.rounded-borders(
  46. :label='t(`editor.pageRel.selectPage`)'
  47. color='primary'
  48. outline
  49. )
  50. .text-overline {{t('editor.pageRel.preview')}}
  51. q-btn(
  52. v-if='state.pos === `left`'
  53. padding='sm md'
  54. outline
  55. :icon='state.icon'
  56. no-caps
  57. color='primary'
  58. )
  59. .column.text-left.q-pl-md
  60. .text-body2: strong {{state.label}}
  61. .text-caption {{state.caption}}
  62. q-btn.full-width(
  63. v-else-if='state.pos === `center`'
  64. :label='state.label'
  65. color='primary'
  66. flat
  67. no-caps
  68. :icon='state.icon'
  69. )
  70. q-btn(
  71. v-else-if='state.pos === `right`'
  72. padding='sm md'
  73. outline
  74. :icon-right='state.icon'
  75. no-caps
  76. color='primary'
  77. )
  78. .column.text-left.q-pr-md
  79. .text-body2: strong {{state.label}}
  80. .text-caption {{state.caption}}
  81. q-card-actions.card-actions
  82. q-space
  83. q-btn.acrylic-btn(
  84. icon='las la-times'
  85. :label='t(`common.actions.discard`)'
  86. color='grey-7'
  87. padding='xs md'
  88. v-close-popup
  89. flat
  90. )
  91. q-btn(
  92. v-if='isEditMode'
  93. :disabled='!canSubmit'
  94. icon='las la-check'
  95. :label='t(`common.actions.save`)'
  96. unelevated
  97. color='primary'
  98. padding='xs md'
  99. @click='persist'
  100. v-close-popup
  101. )
  102. q-btn(
  103. v-else
  104. :disabled='!canSubmit'
  105. icon='las la-plus'
  106. :label='t(`common.actions.create`)'
  107. unelevated
  108. color='primary'
  109. padding='xs md'
  110. @click='create'
  111. v-close-popup
  112. )
  113. </template>
  114. <script setup>
  115. import { v4 as uuid } from 'uuid'
  116. import { cloneDeep, find } from 'lodash-es'
  117. import { useQuasar } from 'quasar'
  118. import { useI18n } from 'vue-i18n'
  119. import { computed, nextTick, onMounted, reactive, ref, watch } from 'vue'
  120. import IconPickerDialog from './IconPickerDialog.vue'
  121. import { usePageStore } from 'src/stores/page'
  122. import { useSiteStore } from 'src/stores/site'
  123. // PROPS
  124. const props = defineProps({
  125. editId: {
  126. type: String,
  127. default: null
  128. }
  129. })
  130. // QUASAR
  131. const $q = useQuasar()
  132. // STORES
  133. const pageStore = usePageStore()
  134. const siteStore = useSiteStore()
  135. // I18N
  136. const { t } = useI18n()
  137. // DATA
  138. const state = reactive({
  139. pos: 'left',
  140. label: '',
  141. caption: '',
  142. icon: 'las la-arrow-left',
  143. target: ''
  144. })
  145. // REFS
  146. const iptRelLabel = ref(null)
  147. // COMPUTED
  148. const canSubmit = computed(() => state.label.length > 0)
  149. const isEditMode = computed(() => Boolean(props.editId))
  150. // WATCHERS
  151. watch(() => state.pos, (newValue) => {
  152. switch (newValue) {
  153. case 'left': {
  154. state.icon = 'las la-arrow-left'
  155. break
  156. }
  157. case 'center': {
  158. state.icon = 'las la-book'
  159. break
  160. }
  161. case 'right': {
  162. state.icon = 'las la-arrow-right'
  163. break
  164. }
  165. }
  166. })
  167. // METHODS
  168. function create () {
  169. pageStore.$patch({
  170. relations: [
  171. ...pageStore.relations,
  172. {
  173. id: uuid(),
  174. position: state.pos,
  175. label: state.label,
  176. ...(state.pos !== 'center' ? { caption: state.caption } : {}),
  177. icon: state.icon,
  178. target: state.target
  179. }
  180. ]
  181. })
  182. }
  183. function persist () {
  184. const rels = cloneDeep(pageStore.relations)
  185. for (const rel of rels) {
  186. if (rel.id === props.editId) {
  187. rel.position = state.pos
  188. rel.label = state.label
  189. rel.caption = state.caption
  190. rel.icon = state.icon
  191. rel.target = state.target
  192. }
  193. }
  194. pageStore.$patch({
  195. relations: rels
  196. })
  197. }
  198. // MOUNTED
  199. onMounted(() => {
  200. if (props.editId) {
  201. const rel = find(pageStore.relations, ['id', props.editId])
  202. if (rel) {
  203. state.pos = rel.position
  204. state.label = rel.label
  205. state.caption = rel.caption || ''
  206. state.icon = rel.icon
  207. state.target = rel.target
  208. }
  209. }
  210. nextTick(() => {
  211. iptRelLabel.value.focus()
  212. })
  213. })
  214. </script>