@resee-movies/nuxt-ux 0.13.1 → 0.15.0

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 (39) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/runtime/components/Card.vue +23 -15
  3. package/dist/runtime/components/Card.vue.d.ts +8 -5
  4. package/dist/runtime/components/CardScroller.vue +189 -0
  5. package/dist/runtime/components/CardScroller.vue.d.ts +36 -0
  6. package/dist/runtime/components/GlobalHeader.vue +107 -0
  7. package/dist/runtime/components/GlobalHeader.vue.d.ts +15 -0
  8. package/dist/runtime/components/GlobalHeaderAnnouncement.vue +49 -0
  9. package/dist/runtime/components/GlobalHeaderAnnouncement.vue.d.ts +14 -0
  10. package/dist/runtime/components/Image.vue +70 -127
  11. package/dist/runtime/components/Image.vue.d.ts +4 -35
  12. package/dist/runtime/components/ImageBase.vue +114 -0
  13. package/dist/runtime/components/ImageBase.vue.d.ts +41 -0
  14. package/dist/runtime/components/LayoutPageRoot.vue +55 -0
  15. package/dist/runtime/components/LayoutPageRoot.vue.d.ts +21 -0
  16. package/dist/runtime/components/Message.vue +31 -11
  17. package/dist/runtime/components/Message.vue.d.ts +4 -3
  18. package/dist/runtime/components/NotificationContainer.vue +2 -2
  19. package/dist/runtime/components/ReseeWordLogo.vue +53 -0
  20. package/dist/runtime/components/ReseeWordLogo.vue.d.ts +12 -0
  21. package/dist/runtime/components/ScrollPinnedContainer.vue +33 -0
  22. package/dist/runtime/components/ScrollPinnedContainer.vue.d.ts +14 -0
  23. package/dist/runtime/components/SuccessSplash.vue +47 -0
  24. package/dist/runtime/components/SuccessSplash.vue.d.ts +6 -0
  25. package/dist/runtime/components/form/Form.vue +55 -21
  26. package/dist/runtime/components/form/Form.vue.d.ts +5 -0
  27. package/dist/runtime/composables/use-global-header-state.d.ts +10 -0
  28. package/dist/runtime/composables/use-global-header-state.js +20 -0
  29. package/dist/runtime/composables/use-load-image.d.ts +3 -0
  30. package/dist/runtime/composables/use-load-image.js +26 -44
  31. package/dist/runtime/composables/use-mutable-intersection-observer.d.ts +44 -0
  32. package/dist/runtime/composables/use-mutable-intersection-observer.js +68 -0
  33. package/dist/runtime/composables/use-resee-ux.d.ts +5 -0
  34. package/dist/runtime/composables/use-resee-ux.js +11 -1
  35. package/dist/runtime/composables/use-two-frame-ref-toggle.d.ts +25 -0
  36. package/dist/runtime/composables/use-two-frame-ref-toggle.js +24 -0
  37. package/dist/runtime/utils/validation.d.ts +2 -2
  38. package/dist/runtime/utils/validation.js +2 -2
  39. package/package.json +1 -1
@@ -1,149 +1,92 @@
1
1
  <template>
2
- <div
3
- ref = "container"
4
- :class = "['image', {
5
- loading: imgLoading || imgBgLoading || props.showLoading,
6
- glass: props.glassy,
7
- bordered: props.bordered,
8
- beveled: props.beveled,
9
- raised: props.raised
10
- }]"
2
+ <Card
3
+ :is = "props.is"
4
+ :loading = "isImgLoading || props.loading"
5
+ :interactive = "props.interactive"
6
+ :colorful = "props.colorful"
7
+ :beveled = "props.beveled"
8
+ :raised = "props.raised"
9
+ :bordered = "props.bordered"
10
+ :class = "[
11
+ 'image',
12
+ {
13
+ glass: props.glassy && !(imgHasError || isImgLoading || props.loading),
14
+ scale: props.scaleToParent
15
+ }
16
+ ]"
11
17
  >
12
18
  <Icon
13
- v-if = "props.defaultIcon && (!imgSrc || imgError || imgLoading || props.showLoading)"
14
- :name = "props.defaultIcon"
15
- :size = "props.iconSize"
16
- :color-cycle = "imgLoading || props.showLoading"
19
+ v-if = "props.defaultIcon && imgHasError"
20
+ :name = "props.defaultIcon"
21
+ :size = "props.iconSize"
22
+ class = "transition-opacity duration-300"
23
+ :class = "{ 'opacity-0': isImgLoading || props.loading }"
17
24
  />
18
25
 
19
- <img
20
- :src = "imgSrc"
21
- :alt = "altText"
22
- :width = "dimensions.width"
23
- :height = "dimensions.height"
24
- :loading = "props.loading"
25
- class = "transition-opacity duration-300"
26
- :class = "[aspectRatioClass, objectFitClass, {
27
- 'opacity-0': !imgSrc || imgLoading
28
- }]"
29
- >
30
- </div>
26
+ <ImageBase
27
+ :src = "props.src"
28
+ :type = "props.type"
29
+ :alt = "props.alt"
30
+ :width = "props.width"
31
+ :height = "props.height"
32
+ :aspect = "props.aspect"
33
+ :fit = "props.fit"
34
+ :loadStyle = "props.loadStyle"
35
+ class = "transition-opacity duration-300"
36
+ :class = "{ 'opacity-0': isImgLoading || props.loading || imgHasError }"
37
+ :aria-hidden = "imgHasError ? 'true' : 'false'"
38
+ @loading = "handleLoading"
39
+ @load = "handleLoaded"
40
+ @error = "handleError"
41
+ />
42
+ </Card>
31
43
  </template>
32
44
 
33
45
  <script>
34
- export const AspectRatioClassNames = {
35
- "1/1": "aspect-square",
36
- "square": "aspect-square",
37
- "2/3": "aspect-poster",
38
- "poster": "aspect-poster",
39
- "4/5": "aspect-tall",
40
- "16/9": "aspect-video",
41
- "video": "aspect-video"
42
- };
43
- export const ObjectFitClassNames = {
44
- cover: "object-cover",
45
- outside: "object-cover",
46
- contain: "object-contain",
47
- inside: "object-contain"
48
- };
46
+
49
47
  </script>
50
48
 
51
49
  <script setup>
52
- import { normalizeImageFileDescriptor } from "@resee-movies/utilities/images/normalize-image-file-descriptor";
53
- import { getAspectRatio } from "@resee-movies/utilities/numbers/get-aspect-ratio";
54
- import { fromTmdbImageSize } from "@resee-movies/utilities/tmdb/from-tmdb-image-size";
55
- import { computed, ref } from "vue";
56
- import { useLoadImage } from "../composables/use-load-image";
57
- import { useSharedIntersectionObserver } from "../composables/use-shared-intersection-observer";
50
+ import { ref } from "vue";
51
+ import Card from "./Card.vue";
58
52
  import Icon from "./Icon.vue";
53
+ import ImageBase from "./ImageBase.vue";
59
54
  const props = defineProps({
60
- src: { type: null, required: true },
61
- alt: { type: [String, null, Function], required: false, default: "" },
62
- type: { type: String, required: false, default: void 0 },
63
- width: { type: null, required: false, default: "w185" },
64
- height: { type: [String, Number], required: false, default: void 0 },
65
- aspect: { type: String, required: false, default: void 0 },
66
- fit: { type: String, required: false, default: "cover" },
67
- showLoading: { type: Boolean, required: false, default: false },
68
55
  defaultIcon: { type: String, required: false, default: "i-ph-image-thin" },
69
56
  iconSize: { type: String, required: false, default: "xl" },
70
- loading: { type: String, required: false, default: "lazy" },
71
57
  glassy: { type: Boolean, required: false, default: false },
72
- bordered: { type: Boolean, required: false, default: false },
73
- beveled: { type: Boolean, required: false, default: false },
74
- raised: { type: Boolean, required: false, default: false },
75
- overlayClasses: { type: null, required: false, default: void 0 }
76
- });
77
- const deferLoad = ref(props.loading === "lazy");
78
- const container = ref();
79
- const normalizedSource = computed(() => {
80
- const result = normalizeImageFileDescriptor(props.src);
81
- if (props.type) {
82
- result.sourceType = props.type;
83
- }
84
- return result;
85
- });
86
- const dimensions = computed(() => {
87
- let intWidth = normalizedSource.value.width;
88
- let intHeight = normalizedSource.value.height;
89
- if (props.width || props.height) {
90
- intWidth = fromTmdbImageSize(props.width);
91
- intHeight = fromTmdbImageSize(props.height);
92
- }
93
- if (!props.aspect || props.aspect === "auto" || intWidth && intHeight) {
94
- return { width: intWidth, height: intHeight };
95
- }
96
- if (intHeight) {
97
- const aspect = getAspectRatio(intHeight, "y", props.aspect);
98
- return { width: aspect.x, height: aspect.y };
99
- }
100
- if (intWidth) {
101
- const aspect = getAspectRatio(intWidth, "x", props.aspect);
102
- return { width: aspect.x, height: aspect.y };
103
- }
104
- return { width: void 0, height: void 0 };
58
+ scaleToParent: { type: Boolean, required: false, default: true },
59
+ src: { type: null, required: true },
60
+ alt: { type: [String, null, Function], required: false },
61
+ type: { type: String, required: false },
62
+ width: { type: null, required: false },
63
+ height: { type: [String, Number], required: false },
64
+ aspect: { type: String, required: false },
65
+ fit: { type: String, required: false },
66
+ loadStyle: { type: String, required: false },
67
+ is: { type: null, required: false },
68
+ loading: { type: Boolean, required: false },
69
+ interactive: { type: Boolean, required: false },
70
+ colorful: { type: Boolean, required: false },
71
+ bordered: { type: Boolean, required: false },
72
+ beveled: { type: Boolean, required: false },
73
+ raised: { type: Boolean, required: false }
105
74
  });
106
- const imgLoadInfo = useLoadImage(
107
- () => normalizedSource.value.identifier,
108
- {
109
- deferLoad,
110
- type: () => normalizedSource.value.sourceType,
111
- width: () => props.width,
112
- friendlyName: () => normalizedSource.value.friendlyName,
113
- reseeConfig: () => ({
114
- width: dimensions.value.width,
115
- height: dimensions.value.height,
116
- fit: props.fit
117
- })
118
- }
119
- );
120
- const {
121
- src: imgSrc,
122
- loading: imgLoading,
123
- bgLoading: imgBgLoading,
124
- error: imgError
125
- } = imgLoadInfo;
126
- if (deferLoad.value) {
127
- useSharedIntersectionObserver(container, {
128
- once: true,
129
- onChange(isIntersecting) {
130
- if (isIntersecting) {
131
- deferLoad.value = false;
132
- }
133
- }
134
- });
75
+ const isImgLoading = ref(true);
76
+ const imgHasError = ref(null);
77
+ function handleLoading() {
78
+ isImgLoading.value = true;
79
+ }
80
+ function handleLoaded(src) {
81
+ isImgLoading.value = false;
82
+ imgHasError.value = null;
83
+ }
84
+ function handleError(err) {
85
+ isImgLoading.value = false;
86
+ imgHasError.value = err;
135
87
  }
136
- const aspectRatioClass = computed(() => {
137
- return !props.aspect || props.aspect === "auto" ? void 0 : AspectRatioClassNames[props.aspect];
138
- });
139
- const objectFitClass = computed(() => {
140
- return !props.fit ? void 0 : ObjectFitClassNames[props.fit];
141
- });
142
- const altText = computed(() => {
143
- return typeof props.alt === "function" ? props.alt(imgError.value) : props.alt ?? normalizedSource.value.description ?? "";
144
- });
145
88
  </script>
146
89
 
147
90
  <style scoped>
148
- @reference "tailwindcss";@layer components{.image{background-color:#fff;max-width:-moz-fit-content;max-width:fit-content;overflow:clip;position:relative;width:100%;@variant dark{background-color:#000}}.image.bordered{border:2px solid var(--color-global-background-accent)}.image.beveled{border-bottom-left-radius:var(--radius-xl);border-top-right-radius:var(--radius-xl)}.image.raised{box-shadow:var(--shadow-heavy)}.image.glass:after{background-image:linear-gradient(110deg,transparent 25%,hsla(0,0%,100%,.15) 80%,transparent);content:var(--zero-width-space);inset:0;position:absolute}.image :deep(.icon){color:var(--color-global-background-accent);left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%)}}
91
+ @layer components{.image{display:block;max-width:-moz-fit-content;max-width:fit-content;overflow:clip;position:relative}.image.glass:after{background-image:linear-gradient(110deg,transparent 25%,hsla(0,0%,100%,.15) 80%,transparent);content:var(--zero-width-space);inset:0;position:absolute}.image :deep(.icon){color:var(--color-global-background-accent);left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%)}.image.scale{max-width:unset}.image.scale :deep(img){min-width:100%}}
149
92
  </style>
@@ -1,43 +1,12 @@
1
- import type { ImageFileDescriptor } from '@resee-movies/utilities/images/normalize-image-file-descriptor';
2
- import type { AspectRatio } from '@resee-movies/utilities/numbers/get-aspect-ratio';
3
- import type { MediaAssetTransformConfig } from '@resee-movies/utilities/resee/get-media-asset-url';
4
- import type { TmdbImageSize } from '@resee-movies/utilities/tmdb/get-tmdb-image-url';
5
- import type { LoadImageType } from '../composables/use-load-image.js';
6
- import type { HTMLElementClassNames } from '../types/index.js';
1
+ import type { CardProps } from './Card.vue.js';
7
2
  import type { IconProps } from './Icon.vue.js';
8
- export interface ImageProps {
9
- src: ImageFileDescriptor | null | undefined;
10
- alt?: string | null | ((error: unknown) => string);
11
- type?: LoadImageType;
12
- width?: TmdbImageSize | string | number;
13
- height?: string | number;
14
- aspect?: AspectRatio | 'auto';
15
- fit?: MediaAssetTransformConfig['fit'];
16
- showLoading?: boolean;
3
+ import type { ImageBaseProps } from './ImageBase.vue.js';
4
+ export interface ImageProps extends ImageBaseProps, CardProps {
17
5
  defaultIcon?: string;
18
6
  iconSize?: IconProps['size'];
19
- loading?: 'lazy' | 'eager';
20
7
  glassy?: boolean;
21
- bordered?: boolean;
22
- beveled?: boolean;
23
- raised?: boolean;
24
- overlayClasses?: HTMLElementClassNames;
8
+ scaleToParent?: boolean;
25
9
  }
26
- export declare const AspectRatioClassNames: {
27
- readonly '1/1': "aspect-square";
28
- readonly square: "aspect-square";
29
- readonly '2/3': "aspect-poster";
30
- readonly poster: "aspect-poster";
31
- readonly '4/5': "aspect-tall";
32
- readonly '16/9': "aspect-video";
33
- readonly video: "aspect-video";
34
- };
35
- export declare const ObjectFitClassNames: {
36
- readonly cover: "object-cover";
37
- readonly outside: "object-cover";
38
- readonly contain: "object-contain";
39
- readonly inside: "object-contain";
40
- };
41
10
  declare const __VLS_export: import("vue").DefineComponent<ImageProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ImageProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
42
11
  declare const _default: typeof __VLS_export;
43
12
  export default _default;
@@ -0,0 +1,114 @@
1
+ <template>
2
+ <img
3
+ ref = "container"
4
+ :src = "imgSrc"
5
+ :alt = "altText"
6
+ :width = "dimensions.width"
7
+ :height = "dimensions.height"
8
+ :loading = "props.loadStyle"
9
+ :class = "[aspectRatioClass, objectFitClass]"
10
+ >
11
+ </template>
12
+
13
+ <script>
14
+ export const AspectRatioClassNames = {
15
+ "1/1": "aspect-square",
16
+ "square": "aspect-square",
17
+ "2/3": "aspect-poster",
18
+ "poster": "aspect-poster",
19
+ "4/5": "aspect-tall",
20
+ "16/9": "aspect-video",
21
+ "video": "aspect-video"
22
+ };
23
+ export const ObjectFitClassNames = {
24
+ cover: "object-cover",
25
+ outside: "object-cover",
26
+ contain: "object-contain",
27
+ inside: "object-contain"
28
+ };
29
+ </script>
30
+
31
+ <script setup>
32
+ import { normalizeImageFileDescriptor } from "@resee-movies/utilities/images/normalize-image-file-descriptor";
33
+ import { getAspectRatio } from "@resee-movies/utilities/numbers/get-aspect-ratio";
34
+ import { fromTmdbImageSize } from "@resee-movies/utilities/tmdb/from-tmdb-image-size";
35
+ import { computed, ref } from "vue";
36
+ import { useLoadImage } from "../composables/use-load-image";
37
+ import { useSharedIntersectionObserver } from "../composables/use-shared-intersection-observer";
38
+ const props = defineProps({
39
+ src: { type: null, required: true },
40
+ alt: { type: [String, null, Function], required: false, default: "" },
41
+ type: { type: String, required: false, default: void 0 },
42
+ width: { type: null, required: false, default: "w185" },
43
+ height: { type: [String, Number], required: false, default: void 0 },
44
+ aspect: { type: String, required: false, default: void 0 },
45
+ fit: { type: String, required: false, default: "cover" },
46
+ loadStyle: { type: String, required: false }
47
+ });
48
+ const emits = defineEmits(["loading", "load", "error"]);
49
+ const deferLoad = ref(props.loadStyle === "lazy");
50
+ const container = ref();
51
+ const normalizedSource = computed(() => {
52
+ const result = normalizeImageFileDescriptor(props.src);
53
+ if (props.type) {
54
+ result.sourceType = props.type;
55
+ }
56
+ return result;
57
+ });
58
+ const dimensions = computed(() => {
59
+ let intWidth = normalizedSource.value.width;
60
+ let intHeight = normalizedSource.value.height;
61
+ if (props.width || props.height) {
62
+ intWidth = fromTmdbImageSize(props.width);
63
+ intHeight = fromTmdbImageSize(props.height);
64
+ }
65
+ if (!props.aspect || props.aspect === "auto" || intWidth && intHeight) {
66
+ return { width: intWidth, height: intHeight };
67
+ }
68
+ if (intHeight) {
69
+ const aspect = getAspectRatio(intHeight, "y", props.aspect);
70
+ return { width: aspect.x, height: aspect.y };
71
+ }
72
+ if (intWidth) {
73
+ const aspect = getAspectRatio(intWidth, "x", props.aspect);
74
+ return { width: aspect.x, height: aspect.y };
75
+ }
76
+ return { width: void 0, height: void 0 };
77
+ });
78
+ const { src: imgSrc, error: imgError } = useLoadImage(
79
+ () => normalizedSource.value.identifier,
80
+ {
81
+ deferLoad,
82
+ type: () => normalizedSource.value.sourceType,
83
+ width: () => props.width,
84
+ friendlyName: () => normalizedSource.value.friendlyName,
85
+ onLoading: () => emits("loading"),
86
+ onLoad: (src) => emits("load", src),
87
+ onError: (err) => emits("error", err),
88
+ reseeConfig: () => ({
89
+ width: dimensions.value.width,
90
+ height: dimensions.value.height,
91
+ fit: props.fit
92
+ })
93
+ }
94
+ );
95
+ if (deferLoad.value) {
96
+ useSharedIntersectionObserver(container, {
97
+ once: true,
98
+ onChange(isIntersecting) {
99
+ if (isIntersecting) {
100
+ deferLoad.value = false;
101
+ }
102
+ }
103
+ });
104
+ }
105
+ const aspectRatioClass = computed(() => {
106
+ return !props.aspect || props.aspect === "auto" ? void 0 : AspectRatioClassNames[props.aspect];
107
+ });
108
+ const objectFitClass = computed(() => {
109
+ return !props.fit ? void 0 : ObjectFitClassNames[props.fit];
110
+ });
111
+ const altText = computed(() => {
112
+ return typeof props.alt === "function" ? props.alt(imgError.value) : props.alt ?? normalizedSource.value.description ?? "";
113
+ });
114
+ </script>
@@ -0,0 +1,41 @@
1
+ import type { ImageFileDescriptor } from '@resee-movies/utilities/images/normalize-image-file-descriptor';
2
+ import type { AspectRatio } from '@resee-movies/utilities/numbers/get-aspect-ratio';
3
+ import type { MediaAssetTransformConfig } from '@resee-movies/utilities/resee/get-media-asset-url';
4
+ import type { TmdbImageSize } from '@resee-movies/utilities/tmdb/get-tmdb-image-url';
5
+ import type { LoadImageType } from '../composables/use-load-image.js';
6
+ export interface ImageBaseProps {
7
+ src: ImageFileDescriptor | null | undefined;
8
+ alt?: string | null | ((error: unknown) => string);
9
+ type?: LoadImageType;
10
+ width?: TmdbImageSize | string | number;
11
+ height?: string | number;
12
+ aspect?: AspectRatio | 'auto';
13
+ fit?: MediaAssetTransformConfig['fit'];
14
+ loadStyle?: 'lazy' | 'eager';
15
+ }
16
+ export declare const AspectRatioClassNames: {
17
+ readonly '1/1': "aspect-square";
18
+ readonly square: "aspect-square";
19
+ readonly '2/3': "aspect-poster";
20
+ readonly poster: "aspect-poster";
21
+ readonly '4/5': "aspect-tall";
22
+ readonly '16/9': "aspect-video";
23
+ readonly video: "aspect-video";
24
+ };
25
+ export declare const ObjectFitClassNames: {
26
+ readonly cover: "object-cover";
27
+ readonly outside: "object-cover";
28
+ readonly contain: "object-contain";
29
+ readonly inside: "object-contain";
30
+ };
31
+ declare const __VLS_export: import("vue").DefineComponent<ImageBaseProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
32
+ error: (err: unknown) => any;
33
+ load: (src: string | undefined) => any;
34
+ loading: () => any;
35
+ }, string, import("vue").PublicProps, Readonly<ImageBaseProps> & Readonly<{
36
+ onError?: ((err: unknown) => any) | undefined;
37
+ onLoad?: ((src: string | undefined) => any) | undefined;
38
+ onLoading?: (() => any) | undefined;
39
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
40
+ declare const _default: typeof __VLS_export;
41
+ export default _default;
@@ -0,0 +1,55 @@
1
+ <template>
2
+ <div class="app-main">
3
+ <ClientOnly>
4
+ <LazyNuxtRouteAnnouncer />
5
+ <LazyNuxtLoadingIndicator :color="false" class="resee-bg-linear-to-r" />
6
+ </ClientOnly>
7
+
8
+ <GlobalHeaderAnnouncement v-if="slots.announcement" :announcement-id="props.announcementId">
9
+ <slot name="announcement" />
10
+ </GlobalHeaderAnnouncement>
11
+
12
+ <GlobalHeader v-if="slots.header || slots.subheader" class="app-header">
13
+ <template #default v-if="slots.header">
14
+ <slot name="header" />
15
+ </template>
16
+
17
+ <template #subheader v-if="slots.subheader">
18
+ <slot name="subheader" />
19
+ </template>
20
+ </GlobalHeader>
21
+
22
+ <slot name="default" />
23
+
24
+ <footer v-if="slots.footer" class="app-footer">
25
+ <LayoutPageColumn>
26
+ <slot name="footer" />
27
+ </LayoutPageColumn>
28
+ </footer>
29
+
30
+ <ClientOnly>
31
+ <LazyNotificationContainer />
32
+ </ClientOnly>
33
+ </div>
34
+ </template>
35
+
36
+ <script>
37
+
38
+ </script>
39
+
40
+ <script setup>
41
+ import { LazyNuxtLoadingIndicator, LazyNuxtRouteAnnouncer } from "#components";
42
+ import { useSlots } from "vue";
43
+ import GlobalHeaderAnnouncement from "./GlobalHeaderAnnouncement.vue";
44
+ import LayoutPageColumn from "./LayoutPageColumn.vue";
45
+ import LazyNotificationContainer from "./NotificationContainer.vue";
46
+ import GlobalHeader from "./GlobalHeader.vue";
47
+ const props = defineProps({
48
+ announcementId: { type: String, required: false, default: void 0 }
49
+ });
50
+ const slots = useSlots();
51
+ </script>
52
+
53
+ <style>
54
+ @reference "tailwindcss";.app-footer,.app-header{backdrop-filter:blur(var(--blur-md));background-color:--alpha(var(--color-global-background)/60%)}.app-header{border-bottom:1px solid var(--color-global-foreground-accent)}.app-footer{border-top:1px solid var(--color-global-foreground-accent)}
55
+ </style>
@@ -0,0 +1,21 @@
1
+ export interface LayoutPageRootProps {
2
+ announcementId?: string;
3
+ }
4
+ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<LayoutPageRootProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<LayoutPageRootProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, {
5
+ announcement?: (props: {}) => any;
6
+ } & {
7
+ header?: (props: {}) => any;
8
+ } & {
9
+ subheader?: (props: {}) => any;
10
+ } & {
11
+ default?: (props: {}) => any;
12
+ } & {
13
+ footer?: (props: {}) => any;
14
+ }>;
15
+ declare const _default: typeof __VLS_export;
16
+ export default _default;
17
+ type __VLS_WithSlots<T, S> = T & {
18
+ new (): {
19
+ $slots: S;
20
+ };
21
+ };
@@ -1,7 +1,11 @@
1
1
  <template>
2
- <PrimeMessage :severity="props.severity" class="message" :pt="passthroughProps">
3
- <template #icon>
4
- <Icon :name="props.icon" :size="props.iconSize" />
2
+ <PrimeMessage
3
+ class = "message"
4
+ :severity = "props.severity"
5
+ :pt = "passthroughProps"
6
+ >
7
+ <template #icon v-if="displayIcon">
8
+ <Icon :name="displayIcon" :size="props.iconSize" />
5
9
  </template>
6
10
 
7
11
  <template #default>
@@ -11,20 +15,30 @@
11
15
  </template>
12
16
 
13
17
  <script>
14
- import { computed } from "vue";
18
+
15
19
  </script>
16
20
 
17
21
  <script setup>
22
+ import { useCurrentElement } from "@vueuse/core";
18
23
  import PrimeMessage from "primevue/message";
24
+ import { computed, onMounted } from "vue";
19
25
  import Icon from "./Icon.vue";
26
+ import { StatusLevelIcons } from "../constants";
20
27
  const props = defineProps({
21
- severity: { type: String, required: false },
22
- text: { type: String, required: false },
23
- class: { type: String, required: false },
24
- style: { type: String, required: false },
25
- accented: { type: Boolean, required: false },
26
- icon: { type: String, required: false },
27
- iconSize: { type: String, required: false }
28
+ severity: { type: String, required: false, default: "default" },
29
+ text: { type: String, required: false, default: void 0 },
30
+ class: { type: null, required: false, default: void 0 },
31
+ style: { type: String, required: false, default: void 0 },
32
+ accented: { type: Boolean, required: false, default: false },
33
+ icon: { type: [String, Boolean], required: false, default: void 0 },
34
+ iconSize: { type: String, required: false, default: void 0 },
35
+ scrollIntoView: { type: Boolean, required: false, default: false }
36
+ });
37
+ const element = useCurrentElement();
38
+ onMounted(() => {
39
+ if (props.scrollIntoView && element.value instanceof HTMLElement) {
40
+ element.value.scrollIntoView({ behavior: "smooth", block: "start" });
41
+ }
28
42
  });
29
43
  const passthroughProps = computed(() => {
30
44
  return {
@@ -47,6 +61,12 @@ const passthroughProps = computed(() => {
47
61
  }
48
62
  };
49
63
  });
64
+ const displayIcon = computed(() => {
65
+ if (props.icon === false) {
66
+ return void 0;
67
+ }
68
+ return props.icon ?? StatusLevelIcons[props.severity];
69
+ });
50
70
  </script>
51
71
 
52
72
  <style scoped>
@@ -1,13 +1,14 @@
1
- import type { StyleStatusLevel } from '../types/index.js';
1
+ import type { HTMLElementClassNames, StyleStatusLevel } from '../types/index.js';
2
2
  import type { IconProps } from './Icon.vue.js';
3
3
  export interface MessageProps {
4
4
  severity?: StyleStatusLevel;
5
5
  text?: string;
6
- class?: string;
6
+ class?: HTMLElementClassNames;
7
7
  style?: string;
8
8
  accented?: boolean;
9
- icon?: IconProps['name'];
9
+ icon?: IconProps['name'] | false;
10
10
  iconSize?: IconProps['size'];
11
+ scrollIntoView?: boolean;
11
12
  }
12
13
  declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<MessageProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<MessageProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, {
13
14
  default?: (props: {}) => any;
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <PrimeToast :pt="passthroughProps">
2
+ <PrimeToast :pt="passthroughProps" position="bottom-center">
3
3
  <template #messageicon="iconProps">
4
4
  <span v-bind="iconProps" />
5
5
  </template>
@@ -41,5 +41,5 @@ const passthroughProps = {
41
41
  </script>
42
42
 
43
43
  <style>
44
- @reference "tailwindcss";@layer components{.notification-container>div{display:flex;flex-direction:column;gap:--spacing(2);width:min(calc(100vw - 40px),--spacing(92))}.notification-container>div .notification .content{align-items:center;display:flex;gap:--spacing(2.5);padding:--spacing(2) --spacing(2.5)}.notification-container>div .notification .icon{flex-shrink:0;font-size:1.25rem}.notification-container>div .notification.has-summary .icon{align-self:start;margin-top:--spacing(.25)}.notification-container>div .notification .text{flex-grow:1}.notification-container>div .notification .close-wrapper{align-self:start}}
44
+ @reference "tailwindcss";@layer components{.notification-container>div{display:flex;flex-direction:column;gap:--spacing(2);transform:translateX(-50%);width:min(calc(100vw - 40px),--spacing(92))}.notification-container>div .notification .content{align-items:center;display:flex;gap:--spacing(2.5);padding:--spacing(2) --spacing(2.5)}.notification-container>div .notification .icon{flex-shrink:0;font-size:1.25rem}.notification-container>div .notification.has-summary .icon{align-self:start;margin-top:--spacing(.25)}.notification-container>div .notification .text{flex-grow:1}.notification-container>div .notification .close-wrapper{align-self:start}}
45
45
  </style>