PageHeader.vue 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. <template lang="pug">
  2. .page-header.row
  3. //- PAGE ICON
  4. .col-auto.q-pl-md.flex.items-center
  5. q-btn.rounded-borders(
  6. v-if='editorStore.isActive'
  7. padding='none'
  8. size='37px'
  9. :icon='pageStore.icon'
  10. color='primary'
  11. flat
  12. )
  13. q-badge(color='grey' floating rounded)
  14. q-icon(name='las la-pen', size='xs', padding='xs xs')
  15. q-menu(content-class='shadow-7')
  16. icon-picker-dialog(v-model='pageStore.icon')
  17. q-icon.rounded-borders(
  18. v-else
  19. :name='pageStore.icon'
  20. size='64px'
  21. color='primary'
  22. )
  23. //- PAGE HEADER
  24. .col.q-pa-md
  25. .text-h4.page-header-title
  26. span {{pageStore.title}}
  27. template(v-if='editorStore.isActive')
  28. span.text-grey(v-if='!pageStore.title') {{ t(`editor.props.title`)}}
  29. q-btn.acrylic-btn.q-ml-md(
  30. icon='las la-pen'
  31. flat
  32. padding='xs'
  33. size='sm'
  34. )
  35. q-popup-edit(
  36. v-model='pageStore.title'
  37. auto-save
  38. v-slot='scope'
  39. )
  40. q-input(
  41. outlined
  42. style='width: 450px;'
  43. v-model='scope.value'
  44. dense
  45. autofocus
  46. @keyup.enter='scope.set'
  47. :label='t(`editor.props.title`)'
  48. )
  49. .text-subtitle2.page-header-subtitle
  50. span {{ pageStore.description }}
  51. template(v-if='editorStore.isActive')
  52. span.text-grey(v-if='!pageStore.description') {{ t(`editor.props.shortDescription`)}}
  53. q-btn.acrylic-btn.q-ml-md(
  54. icon='las la-pen'
  55. flat
  56. padding='none xs'
  57. size='xs'
  58. )
  59. q-popup-edit(
  60. v-model='pageStore.description'
  61. auto-save
  62. v-slot='scope'
  63. )
  64. q-input(
  65. outlined
  66. style='width: 450px;'
  67. v-model='scope.value'
  68. dense
  69. autofocus
  70. @keyup.enter='scope.set'
  71. :label='t(`editor.props.shortDescription`)'
  72. )
  73. //- PAGE ACTIONS
  74. .col-auto.q-pa-md.flex.items-center.justify-end
  75. template(v-if='!editorStore.isActive')
  76. q-btn.q-mr-md(
  77. flat
  78. dense
  79. icon='las la-bell'
  80. color='grey'
  81. aria-label='Watch Page'
  82. )
  83. q-tooltip Watch Page
  84. q-btn.q-mr-md(
  85. flat
  86. dense
  87. icon='las la-bookmark'
  88. color='grey'
  89. aria-label='Bookmark Page'
  90. )
  91. q-tooltip Bookmark Page
  92. q-btn.q-mr-md(
  93. flat
  94. dense
  95. icon='las la-share-alt'
  96. color='grey'
  97. aria-label='Share'
  98. )
  99. q-tooltip Share
  100. social-sharing-menu
  101. q-btn.q-mr-md(
  102. flat
  103. dense
  104. icon='las la-print'
  105. color='grey'
  106. aria-label='Print'
  107. )
  108. q-tooltip Print
  109. q-btn.q-mr-sm.acrylic-btn(
  110. v-if='editorStore.isActive'
  111. icon='las la-question-circle'
  112. flat
  113. color='grey'
  114. :href='siteStore.docsBase + `/editor/${editorStore.editor}`'
  115. target='_blank'
  116. type='a'
  117. )
  118. template(v-if='editorStore.isActive || editorStore.hasPendingChanges')
  119. q-btn.acrylic-btn.q-mr-sm(
  120. flat
  121. icon='las la-times'
  122. color='negative'
  123. label='Discard'
  124. aria-label='Discard'
  125. no-caps
  126. @click='discardChanges'
  127. )
  128. q-btn.acrylic-btn(
  129. flat
  130. icon='las la-check'
  131. color='positive'
  132. label='Save Changes'
  133. aria-label='Save Changes'
  134. no-caps
  135. @click='saveChanges'
  136. )
  137. template(v-else)
  138. q-btn.acrylic-btn(
  139. flat
  140. icon='las la-edit'
  141. color='deep-orange-9'
  142. label='Edit'
  143. aria-label='Edit'
  144. no-caps
  145. @click='editPage'
  146. )
  147. </template>
  148. <script setup>
  149. import { useQuasar } from 'quasar'
  150. import { computed, defineAsyncComponent, onMounted, reactive, ref, watch } from 'vue'
  151. import { useRouter, useRoute } from 'vue-router'
  152. import { useI18n } from 'vue-i18n'
  153. import { useEditorStore } from 'src/stores/editor'
  154. import { useFlagsStore } from 'src/stores/flags'
  155. import { usePageStore } from 'src/stores/page'
  156. import { useSiteStore } from 'src/stores/site'
  157. import { useUserStore } from 'src/stores/user'
  158. import IconPickerDialog from 'src/components/IconPickerDialog.vue'
  159. import SocialSharingMenu from 'src/components/SocialSharingMenu.vue'
  160. // QUASAR
  161. const $q = useQuasar()
  162. // STORES
  163. const editorStore = useEditorStore()
  164. const flagsStore = useFlagsStore()
  165. const pageStore = usePageStore()
  166. const siteStore = useSiteStore()
  167. const userStore = useUserStore()
  168. // ROUTER
  169. const router = useRouter()
  170. const route = useRoute()
  171. // I18N
  172. const { t } = useI18n()
  173. // COMPUTED
  174. const editMode = computed(() => {
  175. return pageStore.mode === 'edit'
  176. })
  177. const editCreateMode = computed(() => {
  178. return pageStore.mode === 'edit' && pageStore.mode === 'create'
  179. })
  180. const editUrl = computed(() => {
  181. let pagePath = siteStore.useLocales ? `${pageStore.locale}/` : ''
  182. pagePath += !pageStore.path ? 'home' : pageStore.path
  183. return `/_edit/${pagePath}`
  184. })
  185. // METHODS
  186. async function discardChanges () {
  187. // Is it the home page in create mode?
  188. if (editorStore.mode === 'create' && pageStore.path === '' && pageStore.locale === 'en') {
  189. editorStore.$patch({
  190. isActive: false,
  191. editor: ''
  192. })
  193. siteStore.overlay = 'Welcome'
  194. return
  195. }
  196. $q.loading.show()
  197. try {
  198. editorStore.$patch({
  199. isActive: false,
  200. editor: ''
  201. })
  202. await pageStore.pageLoad({ id: pageStore.id })
  203. $q.notify({
  204. type: 'positive',
  205. message: 'Page has been reverted to the last saved state.'
  206. })
  207. } catch (err) {
  208. $q.notify({
  209. type: 'negative',
  210. message: 'Failed to reload page state.'
  211. })
  212. }
  213. $q.loading.hide()
  214. }
  215. async function saveChanges () {
  216. $q.loading.show()
  217. try {
  218. await pageStore.pageSave()
  219. $q.notify({
  220. type: 'positive',
  221. message: 'Page saved successfully.'
  222. })
  223. } catch (err) {
  224. $q.notify({
  225. type: 'negative',
  226. message: 'Failed to save page changes.'
  227. })
  228. }
  229. $q.loading.hide()
  230. }
  231. function editPage () {
  232. editorStore.$patch({
  233. isActive: true,
  234. editor: 'markdown'
  235. })
  236. }
  237. </script>