DefaultHeaderPage.vue 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. <template>
  2. <div>
  3. <q-breadcrumbs
  4. v-if="displayBreadcrumbs != null"
  5. class="q-mb-xs"
  6. :class="$q.screen.lt.sm ? '' : 'q-pl-lg'"
  7. >
  8. <q-breadcrumbs-el
  9. v-for="crumb in displayBreadcrumbs"
  10. :key="crumb.name || crumb.label"
  11. :label="crumb.title"
  12. :to="crumb.name ? { name: crumb.name, params: crumb.params } : null"
  13. />
  14. </q-breadcrumbs>
  15. <div
  16. v-else
  17. style="max-width: 180px"
  18. :class="$q.screen.lt.sm ? '' : 'q-pl-lg'"
  19. >
  20. <q-skeleton type="text" />
  21. </div>
  22. <div class="flex items-center justify-between">
  23. <div
  24. class="flex items-center q-pl-xs"
  25. :class="$q.screen.lt.sm ? '' : 'q-pt-md'"
  26. >
  27. <span
  28. v-if="displayTitle"
  29. class="text-h6 text-primary text-weight-regular"
  30. >
  31. {{ displayTitle }}
  32. </span>
  33. <div v-else style="width: 280px">
  34. <q-skeleton type="text" height="40px" />
  35. </div>
  36. <q-icon
  37. v-if="showFilterIcon"
  38. name="mdi-filter-outline"
  39. color="background"
  40. size="sm"
  41. class="q-ml-sm bg-primary"
  42. style="border-radius: 8px; padding: 2px"
  43. />
  44. </div>
  45. <div
  46. class="flex items-center q-pr-sm"
  47. :class="$q.screen.lt.sm ? '' : 'q-pt-md'"
  48. >
  49. <slot name="after" />
  50. </div>
  51. </div>
  52. <q-separator class="q-my-sm" />
  53. </div>
  54. </template>
  55. <script setup>
  56. import { computed } from "vue";
  57. import { useRoute } from "vue-router";
  58. import { useI18n } from "vue-i18n";
  59. const { title, breadcrumbs } = defineProps({
  60. title: {
  61. type: Object,
  62. default: null,
  63. },
  64. breadcrumbs: {
  65. type: Object,
  66. default: null,
  67. },
  68. showFilterIcon: {
  69. type: Boolean,
  70. default: false,
  71. },
  72. });
  73. const route = useRoute();
  74. const { t } = useI18n();
  75. const displayTitle = computed(() => {
  76. if (title) {
  77. if (title.translate) {
  78. return t(title.value);
  79. } else {
  80. return title.value;
  81. }
  82. } else if (route.meta?.title) {
  83. if (route.meta?.title.translate) {
  84. return t(route.meta?.title.value);
  85. } else {
  86. return route.meta?.title.value;
  87. }
  88. }
  89. return null;
  90. });
  91. const displayBreadcrumbs = computed(() => {
  92. if (!breadcrumbs && breadcrumbs?.length <= 0) {
  93. return null;
  94. } else if (breadcrumbs && breadcrumbs?.length > 0) {
  95. return (breadcrumbs || []).map((b) => {
  96. if (b.translate) {
  97. return t(b.title);
  98. } else {
  99. return b.title;
  100. }
  101. });
  102. }
  103. if (!route.meta?.breadcrumbs && route.meta?.breadcrumbs?.length <= 0) {
  104. return null;
  105. } else if (route.meta?.breadcrumbs && route.meta?.breadcrumbs?.length > 0) {
  106. return (route.meta?.breadcrumbs || []).map((b) => {
  107. if (b.translate) {
  108. return {
  109. ...b,
  110. title: t(b.title),
  111. };
  112. } else {
  113. return {
  114. ...b,
  115. title: b.title,
  116. };
  117. }
  118. });
  119. }
  120. return null;
  121. });
  122. </script>