@fy-/fws-vue 2.1.6 → 2.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/components/fws/CmsArticleBoxed.vue +23 -20
  2. package/components/fws/CmsArticleSingle.vue +74 -68
  3. package/components/fws/DataTable.vue +132 -125
  4. package/components/fws/FilterData.vue +99 -101
  5. package/components/fws/UserData.vue +33 -32
  6. package/components/fws/UserFlow.vue +163 -155
  7. package/components/fws/UserOAuth2.vue +73 -72
  8. package/components/fws/UserProfile.vue +98 -101
  9. package/components/fws/UserProfileStrict.vue +65 -64
  10. package/components/ssr/ClientOnly.ts +7 -7
  11. package/components/ui/DefaultBreadcrumb.vue +13 -13
  12. package/components/ui/DefaultConfirm.vue +35 -34
  13. package/components/ui/DefaultDateSelection.vue +19 -17
  14. package/components/ui/DefaultDropdown.vue +25 -25
  15. package/components/ui/DefaultDropdownLink.vue +15 -14
  16. package/components/ui/DefaultGallery.vue +179 -168
  17. package/components/ui/DefaultInput.vue +121 -126
  18. package/components/ui/DefaultLoader.vue +17 -17
  19. package/components/ui/DefaultModal.vue +35 -33
  20. package/components/ui/DefaultNotif.vue +50 -52
  21. package/components/ui/DefaultPaging.vue +92 -95
  22. package/components/ui/DefaultSidebar.vue +29 -25
  23. package/components/ui/DefaultTagInput.vue +121 -119
  24. package/components/ui/transitions/CollapseTransition.vue +1 -1
  25. package/components/ui/transitions/ExpandTransition.vue +1 -1
  26. package/components/ui/transitions/FadeTransition.vue +1 -1
  27. package/components/ui/transitions/ScaleTransition.vue +1 -1
  28. package/components/ui/transitions/SlideTransition.vue +3 -3
  29. package/composables/event-bus.ts +10 -8
  30. package/composables/rest.ts +59 -56
  31. package/composables/seo.ts +106 -95
  32. package/composables/ssr.ts +64 -62
  33. package/composables/templating.ts +57 -57
  34. package/composables/translations.ts +13 -13
  35. package/env.d.ts +6 -4
  36. package/index.ts +101 -98
  37. package/package.json +7 -7
  38. package/stores/serverRouter.ts +25 -25
  39. package/stores/user.ts +79 -72
  40. package/types.d.ts +65 -65
@@ -1,50 +1,47 @@
1
1
  <script setup lang="ts">
2
+ import type { Component } from 'vue'
3
+
2
4
  import {
3
- Dialog,
4
- DialogPanel,
5
- DialogTitle,
6
- TransitionRoot,
7
- } from "@headlessui/vue";
8
- import { ref, onMounted, onUnmounted } from "vue";
9
- import {
5
+ CheckCircleIcon,
10
6
  ExclamationTriangleIcon,
11
7
  LightBulbIcon,
12
- CheckCircleIcon,
13
- } from "@heroicons/vue/24/solid";
14
- import { useEventBus } from "../../composables/event-bus";
15
- import type { Component } from "vue";
16
- import ScaleTransition from "./transitions/ScaleTransition.vue";
8
+ } from '@heroicons/vue/24/solid'
9
+ import { onMounted, onUnmounted, ref } from 'vue'
10
+ import { useEventBus } from '../../composables/event-bus'
11
+ import ScaleTransition from './transitions/ScaleTransition.vue'
12
+
17
13
  interface NotifProps {
18
- imgSrc?: string;
19
- imgIcon?: Component;
20
- title: string;
21
- content?: string;
22
- ctaText?: string;
23
- ctaLink?: string;
24
- ctaAction?: () => void;
25
- type?: "info" | "warning" | "success";
26
- time?: number;
14
+ imgSrc?: string
15
+ imgIcon?: Component
16
+ title: string
17
+ content?: string
18
+ ctaText?: string
19
+ ctaLink?: string
20
+ ctaAction?: () => void
21
+ type?: 'info' | 'warning' | 'success'
22
+ time?: number
27
23
  }
28
- const notif = ref<HTMLElement | null>(null);
29
- const eventBus = useEventBus();
30
- const currentNotif = ref<NotifProps | null>(null);
31
- let currentTimeout: any | null = null;
32
- const onCall = (data: NotifProps) => {
24
+ const eventBus = useEventBus()
25
+ const currentNotif = ref<NotifProps | null>(null)
26
+ let currentTimeout: any | null = null
27
+ function onCall(data: NotifProps) {
33
28
  if (currentNotif.value !== null) {
34
- hideNotif();
29
+ hideNotif()
35
30
  }
36
- const actualIcon = ref(data.imgIcon);
31
+ const actualIcon = ref(data.imgIcon)
37
32
  if (data.imgIcon === undefined) {
38
- if (data.type === "info") {
39
- actualIcon.value = LightBulbIcon;
40
- } else if (data.type === "warning") {
41
- actualIcon.value = ExclamationTriangleIcon;
42
- } else if (data.type === "success") {
43
- actualIcon.value = CheckCircleIcon;
33
+ if (data.type === 'info') {
34
+ actualIcon.value = LightBulbIcon
35
+ }
36
+ else if (data.type === 'warning') {
37
+ actualIcon.value = ExclamationTriangleIcon
38
+ }
39
+ else if (data.type === 'success') {
40
+ actualIcon.value = CheckCircleIcon
44
41
  }
45
42
  }
46
43
  if (!data.time || data.time < 1000) {
47
- data.time = 5000;
44
+ data.time = 5000
48
45
  }
49
46
 
50
47
  currentNotif.value = {
@@ -57,27 +54,29 @@ const onCall = (data: NotifProps) => {
57
54
  time: data.time,
58
55
  type: data.type,
59
56
  ctaAction: data.ctaAction,
60
- };
57
+ }
61
58
 
62
- currentTimeout = setTimeout(hideNotif, currentNotif.value.time);
63
- };
59
+ currentTimeout = setTimeout(hideNotif, currentNotif.value.time)
60
+ }
64
61
 
65
- const hideNotif = () => {
66
- currentNotif.value = null;
62
+ function hideNotif() {
63
+ currentNotif.value = null
67
64
  if (currentTimeout !== null) {
68
- clearTimeout(currentTimeout);
65
+ clearTimeout(currentTimeout)
69
66
  }
70
- };
67
+ }
71
68
  onMounted(() => {
72
- eventBus.on("SendNotif", onCall);
73
- });
69
+ eventBus.on('SendNotif', onCall)
70
+ })
74
71
  onUnmounted(() => {
75
- eventBus.off("SendNotif", onCall);
76
- });
72
+ eventBus.off('SendNotif', onCall)
73
+ })
77
74
  </script>
75
+
78
76
  <template>
79
77
  <ScaleTransition>
80
78
  <div
79
+ v-if="currentNotif !== null"
81
80
  id="base-notif"
82
81
  class="p-2 mb-4 fixed bottom-4 right-8 !z-[2000] bg-fv-neutral-50/[.6] dark:bg-neutral-800/[.6]"
83
82
  role="alert"
@@ -89,33 +88,32 @@ onUnmounted(() => {
89
88
  'text-green-800 border border-green-300 rounded-lg dark:text-green-300 dark:border-green-800':
90
89
  currentNotif.type === 'success',
91
90
  }"
92
- v-if="currentNotif !== null"
93
91
  >
94
92
  <div class="flex items-center gap-2">
95
93
  <img
94
+ v-if="currentNotif.imgSrc"
96
95
  class="flex-shrink-0 w-6 h-6"
97
96
  :src="currentNotif.imgSrc"
98
97
  :alt="currentNotif.title"
99
- v-if="currentNotif.imgSrc"
100
- />
98
+ >
101
99
  <component
102
100
  :is="currentNotif.imgIcon"
103
- class="flex-shrink-0 w-6 h-6"
104
101
  v-else
102
+ class="flex-shrink-0 w-6 h-6"
105
103
  />
106
104
  <h3 class="text-lg font-medium" v-text="currentNotif.title" />
107
105
  </div>
108
106
  <div
107
+ v-if="currentNotif.content"
109
108
  class="mt-2text-sm"
110
109
  v-text="currentNotif.content"
111
- v-if="currentNotif.content"
112
110
  />
113
111
  <div class="flex justify-end gap-2 pt-3">
114
112
  <button
115
113
  type="button"
116
114
  class="btn neutral small"
117
- @click="hideNotif"
118
115
  aria-label="Close"
116
+ @click="hideNotif"
119
117
  >
120
118
  {{ $t("dismiss_cta") }}
121
119
  </button>
@@ -1,145 +1,142 @@
1
1
  <script setup lang="ts">
2
- // @ts-ignore
3
- import { ChevronLeftIcon, ChevronRightIcon } from "@heroicons/vue/24/solid";
2
+ import type {
3
+ WatchStopHandle,
4
+ } from 'vue'
5
+ import type { RouteLocationRaw } from 'vue-router'
6
+ import type { APIPaging } from '../../composables/rest'
7
+ import { getURL, hasFW } from '@fy-/fws-js'
8
+ import { ChevronLeftIcon, ChevronRightIcon } from '@heroicons/vue/24/solid'
9
+ import { useHead } from '@unhead/vue'
4
10
  import {
5
- watch,
11
+ computed,
12
+ onMounted,
6
13
  onUnmounted,
7
14
  ref,
8
- WatchStopHandle,
9
- onMounted,
10
- computed,
11
- } from "vue";
12
- import type { APIPaging } from "../../composables/rest";
13
- import { useEventBus } from "../../composables/event-bus";
14
- import { useServerRouter } from "../../stores/serverRouter";
15
- import { LocationQueryValue, RouteLocationRaw, useRoute } from "vue-router";
16
- import { useHead } from "@unhead/vue";
17
- import { hasFW, getURL } from "@fy-/fws-js";
15
+ watch,
16
+ } from 'vue'
17
+ import { useRoute } from 'vue-router'
18
+ import { useEventBus } from '../../composables/event-bus'
19
+ import { useServerRouter } from '../../stores/serverRouter'
18
20
 
19
21
  const props = withDefaults(
20
22
  defineProps<{
21
- items: APIPaging;
22
- id: string;
23
- hash?: string;
24
- showLegend?: boolean;
23
+ items: APIPaging
24
+ id: string
25
+ hash?: string
26
+ showLegend?: boolean
25
27
  }>(),
26
28
  {
27
29
  showLegend: true,
28
- hash: "",
30
+ hash: '',
29
31
  },
30
- );
31
- const route = useRoute();
32
- const eventBus = useEventBus();
33
- const history = useServerRouter();
34
- const prevNextSeo = ref<any>({});
35
- const isNewPage = (page: number) => {
32
+ )
33
+ const route = useRoute()
34
+ const eventBus = useEventBus()
35
+ const history = useServerRouter()
36
+ const prevNextSeo = ref<any>({})
37
+ function isNewPage(page: number) {
36
38
  return (
37
- page >= 1 && page <= props.items.page_max && page != props.items.page_no
38
- );
39
- };
40
- const pageWatcher = ref<WatchStopHandle>();
39
+ page >= 1 && page <= props.items.page_max && page !== props.items.page_no
40
+ )
41
+ }
42
+ const pageWatcher = ref<WatchStopHandle>()
41
43
 
42
- const next = () => {
43
- const page = props.items.page_no + 1;
44
+ function next() {
45
+ const page = props.items.page_no + 1
44
46
 
45
- if (!isNewPage(page)) return;
46
- const newQuery = { ...route.query };
47
- newQuery.page = page.toString();
47
+ if (!isNewPage(page)) return
48
+ const newQuery = { ...route.query }
49
+ newQuery.page = page.toString()
48
50
  history.push({
49
51
  path: history.currentRoute.path,
50
52
  query: newQuery,
51
- hash: props.hash != "" ? "#" + props.hash : undefined,
52
- });
53
- };
54
- const prev = () => {
55
- const page = props.items.page_no - 1;
56
- if (!isNewPage(page)) return;
57
- const newQuery = { ...route.query };
58
- newQuery.page = page.toString();
53
+ hash: props.hash !== '' ? `#${props.hash}` : undefined,
54
+ })
55
+ }
56
+ function prev() {
57
+ const page = props.items.page_no - 1
58
+ if (!isNewPage(page)) return
59
+ const newQuery = { ...route.query }
60
+ newQuery.page = page.toString()
59
61
  history.push({
60
62
  path: history.currentRoute.path,
61
63
  query: newQuery,
62
- hash: props.hash != "" ? "#" + props.hash : undefined,
63
- });
64
- };
64
+ hash: props.hash !== '' ? `#${props.hash}` : undefined,
65
+ })
66
+ }
65
67
 
66
- const page = (page: number): RouteLocationRaw => {
67
- const newQuery = { ...route.query };
68
- newQuery.page = page.toString();
68
+ function page(page: number): RouteLocationRaw {
69
+ const newQuery = { ...route.query }
70
+ newQuery.page = page.toString()
69
71
  return {
70
72
  path: history.currentRoute.path,
71
73
  query: newQuery,
72
- hash: props.hash != "" ? "#" + props.hash : undefined,
73
- };
74
- };
75
- const currentUrl = computed(() => {
76
- /*
77
- const url = getURL();
78
- return `${url.Path}?page=`;
79
- */
80
- // user router url instead of getURL
81
- return `${history.currentRoute.path}?page=`;
82
- });
74
+ hash: props.hash !== '' ? `#${props.hash}` : undefined,
75
+ }
76
+ }
83
77
 
84
- const checkPageNumber = (page: number = 1) => {
85
- prevNextSeo.value.next = undefined;
86
- prevNextSeo.value.prev = undefined;
87
- const pagePlus = page + 1;
88
- const pageMinus = page - 1;
78
+ function checkPageNumber(page: number = 1) {
79
+ prevNextSeo.value.next = undefined
80
+ prevNextSeo.value.prev = undefined
81
+ const pagePlus = page + 1
82
+ const pageMinus = page - 1
89
83
  if (hasFW()) {
90
- const url = getURL();
84
+ const url = getURL()
91
85
  if (pagePlus <= props.items.page_max && url) {
92
- prevNextSeo.value.next =
93
- `${url.Scheme}://${url.Host}${route.path}?page=${pagePlus}` +
94
- (props.hash != "" ? `#${props.hash}` : "");
86
+ prevNextSeo.value.next
87
+ = `${url.Scheme}://${url.Host}${route.path}?page=${pagePlus}${
88
+ props.hash !== '' ? `#${props.hash}` : ''}`
95
89
  }
96
90
  if (pageMinus >= 1 && url) {
97
- prevNextSeo.value.prev =
98
- `${url.Scheme}://${url.Host}${route.path}?page=${pageMinus}` +
99
- (props.hash != "" ? `#${props.hash}` : "");
91
+ prevNextSeo.value.prev
92
+ = `${url.Scheme}://${url.Host}${route.path}?page=${pageMinus}${
93
+ props.hash !== '' ? `#${props.hash}` : ''}`
100
94
  }
101
95
  }
102
- };
96
+ }
103
97
 
104
98
  pageWatcher.value = watch(
105
99
  () => route.query.page,
106
100
  (v) => {
107
- eventBus.emit(`${props.id}GoToPage`, v ? v : 1);
101
+ eventBus.emit(`${props.id}GoToPage`, v || 1)
108
102
  },
109
- );
103
+ )
110
104
  onMounted(() => {
111
- eventBus.on(`${props.id}GoToPage`, checkPageNumber);
112
- });
105
+ eventBus.on(`${props.id}GoToPage`, checkPageNumber)
106
+ })
113
107
  onUnmounted(() => {
114
- eventBus.off(`${props.id}GoToPage`, checkPageNumber);
115
- //if (pageWatcher.value) pageWatcher.value();
116
- });
108
+ eventBus.off(`${props.id}GoToPage`, checkPageNumber)
109
+ // if (pageWatcher.value) pageWatcher.value();
110
+ })
117
111
 
118
- checkPageNumber(props.items.page_no);
112
+ checkPageNumber(props.items.page_no)
119
113
  useHead({
120
114
  link: computed(() => {
121
- const result: any = [];
122
- if (prevNextSeo.value.next)
115
+ const result: any = []
116
+ if (prevNextSeo.value.next) {
123
117
  result.push({
124
118
  href: prevNextSeo.value.next,
125
- rel: "next",
126
- key: "next",
127
- });
128
- if (prevNextSeo.value.prev)
119
+ rel: 'next',
120
+ key: 'next',
121
+ })
122
+ }
123
+ if (prevNextSeo.value.prev) {
129
124
  result.push({
130
125
  href: prevNextSeo.value.prev,
131
- rel: "prev",
132
- key: "prev",
133
- });
126
+ rel: 'prev',
127
+ key: 'prev',
128
+ })
129
+ }
134
130
 
135
- return result;
131
+ return result
136
132
  }),
137
- });
133
+ })
138
134
  </script>
135
+
139
136
  <template>
140
137
  <div
141
- class="flex items-center justify-center"
142
138
  v-if="items && items.page_max > 1 && items.page_no"
139
+ class="flex items-center justify-center"
143
140
  >
144
141
  <div class="paging-container">
145
142
  <nav aria-label="Pagination">
@@ -147,8 +144,8 @@ useHead({
147
144
  <li v-if="items.page_no >= 2">
148
145
  <button
149
146
  type="button"
150
- @click="prev()"
151
147
  class="flex items-center justify-center px-1.5 h-8 leading-tight text-fv-neutral-500 bg-white border border-fv-neutral-300 hover:bg-fv-neutral-100 hover:text-fv-neutral-700 dark:bg-fv-neutral-800 dark:border-fv-neutral-700 dark:text-fv-neutral-400 dark:hover:bg-fv-neutral-700 dark:hover:text-white"
148
+ @click="prev()"
152
149
  >
153
150
  <span class="sr-only">{{ $t("previous_paging") }}</span>
154
151
  <ChevronLeftIcon class="w-4 h-4" />
@@ -193,8 +190,8 @@ useHead({
193
190
  </li>
194
191
  <template v-for="i in 2">
195
192
  <li
196
- :key="`page-x-${items.page_no + i}`"
197
193
  v-if="items.page_no + i <= items.page_max"
194
+ :key="`page-x-${items.page_no + i}`"
198
195
  >
199
196
  <router-link
200
197
  class="flex items-center justify-center px-3 h-8 leading-tight text-fv-neutral-500 bg-white border border-fv-neutral-300 hover:bg-fv-neutral-100 hover:text-fv-neutral-700 dark:bg-fv-neutral-800 dark:border-fv-neutral-700 dark:text-fv-neutral-400 dark:hover:bg-fv-neutral-700 dark:hover:text-white"
@@ -221,9 +218,9 @@ useHead({
221
218
  </li>
222
219
  <li v-if="items.page_no < items.page_max - 1">
223
220
  <button
224
- @click="next()"
225
221
  type="button"
226
222
  class="flex items-center justify-center px-1.5 h-8 leading-tight text-fv-neutral-500 bg-white border border-fv-neutral-300 hover:bg-fv-neutral-100 hover:text-fv-neutral-700 dark:bg-fv-neutral-800 dark:border-fv-neutral-700 dark:text-fv-neutral-400 dark:hover:bg-fv-neutral-700 dark:hover:text-white"
223
+ @click="next()"
227
224
  >
228
225
  <span class="sr-only">{{ $t("next_paging") }}</span>
229
226
  <ChevronRightIcon class="w-4 h-4" />
@@ -232,8 +229,8 @@ useHead({
232
229
  </ul>
233
230
  </nav>
234
231
  <p
235
- class="text-xs text-fv-neutral-700 dark:text-fv-neutral-400 pt-0.5"
236
232
  v-if="showLegend"
233
+ class="text-xs text-fv-neutral-700 dark:text-fv-neutral-400 pt-0.5"
237
234
  >
238
235
  {{
239
236
  $t("global_paging", {
@@ -1,34 +1,37 @@
1
1
  <script lang="ts" setup>
2
- import { NavLink } from "../../types";
3
- import { ArrowRightIcon, ArrowLeftIcon } from "@heroicons/vue/24/solid";
4
- import { useStorage } from "@vueuse/core";
5
- import { useRoute } from "vue-router";
2
+ import type { NavLink } from '../../types'
3
+ import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/vue/24/solid'
4
+ import { useStorage } from '@vueuse/core'
5
+ import { useRoute } from 'vue-router'
6
6
 
7
7
  const props = withDefaults(
8
8
  defineProps<{
9
- links: NavLink[];
10
- id?: string;
11
- baseUrl?: string;
9
+ links: NavLink[]
10
+ id?: string
11
+ baseUrl?: string
12
12
  }>(),
13
13
  {
14
- id: "main",
15
- baseUrl: "/",
14
+ id: 'main',
15
+ baseUrl: '/',
16
16
  },
17
- );
18
- const route = useRoute();
19
- const isLinkActive = (link: NavLink) => {
20
- if (link.to != props.baseUrl) {
21
- if (route.path == link.to || route.path.includes(link.to))
22
- return "fvside-active";
23
- } else {
24
- if (route.path == link.to) {
25
- return "fvside-active";
17
+ )
18
+ const route = useRoute()
19
+ function isLinkActive(link: NavLink) {
20
+ if (link.to !== props.baseUrl) {
21
+ if (route.path === link.to || route.path.includes(link.to)) {
22
+ return 'fvside-active'
26
23
  }
27
24
  }
28
- return "";
29
- };
30
- const isOpen = useStorage(`isOpenSidebar-${props.id}`, true);
25
+ else {
26
+ if (route.path === link.to) {
27
+ return 'fvside-active'
28
+ }
29
+ }
30
+ return ''
31
+ }
32
+ const isOpen = useStorage(`isOpenSidebar-${props.id}`, true)
31
33
  </script>
34
+
32
35
  <template>
33
36
  <aside class="fui-sidebar" :class="isOpen ? '' : 'fui-sidebar__md'">
34
37
  <div class="fui-sidebar__controller">
@@ -42,8 +45,8 @@ const isOpen = useStorage(`isOpenSidebar-${props.id}`, true);
42
45
  <span class="sr-only">{{ $t("sidebar_size_control") }}</span>
43
46
  </button>
44
47
  </div>
45
- <slot name="before"></slot>
46
- <ul role="list" id="side-nav">
48
+ <slot name="before" />
49
+ <ul id="side-nav" role="list">
47
50
  <li v-for="(link, index) of links" :key="`aside_link_${index}`">
48
51
  <RouterLink
49
52
  :to="link.to"
@@ -58,11 +61,12 @@ const isOpen = useStorage(`isOpenSidebar-${props.id}`, true);
58
61
  <span class="sr-only">{{ link.name }}</span>
59
62
  </RouterLink>
60
63
  </li>
61
- <slot name="lis"></slot>
64
+ <slot name="lis" />
62
65
  </ul>
63
- <slot name="after"></slot>
66
+ <slot name="after" />
64
67
  </aside>
65
68
  </template>
69
+
66
70
  <style lang="scss" scoped>
67
71
  .fui-sidebar {
68
72
  @apply w-60 transition-all duration-300 ease-in-out;