@resee-movies/nuxt-ux 0.16.0 → 0.18.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 (35) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/runtime/components/GlobalHeader.vue +45 -13
  3. package/dist/runtime/components/GlobalHeader.vue.d.ts +10 -0
  4. package/dist/runtime/components/GlobalHeaderAnnouncement.vue +1 -1
  5. package/dist/runtime/components/ImageTiler.vue +193 -0
  6. package/dist/runtime/components/ImageTiler.vue.d.ts +31 -0
  7. package/dist/runtime/components/InlineStatsList.vue +33 -0
  8. package/dist/runtime/components/InlineStatsList.vue.d.ts +15 -0
  9. package/dist/runtime/components/InlineStatsListItem.vue +39 -0
  10. package/dist/runtime/components/InlineStatsListItem.vue.d.ts +19 -0
  11. package/dist/runtime/components/TableOfContents.vue +56 -0
  12. package/dist/runtime/components/TableOfContents.vue.d.ts +15 -0
  13. package/dist/runtime/components/form/Form.vue +4 -2
  14. package/dist/runtime/components/form/FormField.vue +7 -7
  15. package/dist/runtime/components/form/FormFieldTurnstile.vue +2 -1
  16. package/dist/runtime/components/form/element/FormElementTurnstile.vue +2 -1
  17. package/dist/runtime/components/form/element/FormElementTurnstile.vue.d.ts +1 -0
  18. package/dist/runtime/composables/use-global-header-state.d.ts +52 -1
  19. package/dist/runtime/composables/use-global-header-state.js +22 -2
  20. package/dist/runtime/composables/use-resee-window-scroll.d.ts +18 -0
  21. package/dist/runtime/composables/use-resee-window-scroll.js +65 -0
  22. package/dist/runtime/composables/use-settings-for-breakpoint.d.ts +11 -0
  23. package/dist/runtime/composables/use-settings-for-breakpoint.js +25 -0
  24. package/dist/runtime/composables/use-url-hash.d.ts +43 -0
  25. package/dist/runtime/composables/use-url-hash.js +25 -0
  26. package/dist/runtime/theme/css/brand/application.css +1 -1
  27. package/dist/runtime/theme/css/brand/image.css +1 -0
  28. package/dist/runtime/theme/css/brand/typography.css +1 -1
  29. package/dist/runtime/theme/css/styles.css +1 -1
  30. package/dist/runtime/types/form.d.ts +1 -0
  31. package/dist/runtime/utils/form.d.ts +3 -3
  32. package/dist/runtime/utils/form.js +6 -5
  33. package/dist/runtime/utils/routing.d.ts +14 -0
  34. package/dist/runtime/utils/routing.js +14 -0
  35. package/package.json +10 -10
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@resee-movies/nuxt-ux",
3
3
  "configKey": "ux",
4
- "version": "0.16.0",
4
+ "version": "0.18.0",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.0"
@@ -10,18 +10,28 @@
10
10
  'header-hidden': hideDrawerContent
11
11
  }"
12
12
  >
13
- <div
14
- ref = "drawerElement"
15
- :class = "slots.subheader ? 'border-b border-b-global-background-accent' : void 0"
16
- >
13
+ <div ref="drawerElement">
17
14
  <LayoutPageColumn>
18
15
  <slot name="default" />
19
16
  </LayoutPageColumn>
17
+
18
+ <div
19
+ v-if = "renderSubheader"
20
+ class = "border-b border-b-global-background-accent"
21
+ />
20
22
  </div>
21
23
 
22
- <div v-if="slots.subheader" ref="subheadElement">
23
- <LayoutPageColumn>
24
- <slot name="subheader" />
24
+ <div v-if="renderSubheader" ref="subheadElement" class="subheader">
25
+ <LayoutPageColumn class="overflow-x-auto styled-scroll">
26
+ <slot name="subheader">
27
+ <TableOfContents
28
+ :toc = "props.subheaderToc ?? headerState.subheaderToc.value"
29
+ class = "flex items-center flex-nowrap"
30
+ link-class = "btn small borderless text-nowrap"
31
+ :min-depth = "2"
32
+ :max-depth = "2"
33
+ />
34
+ </slot>
25
35
  </LayoutPageColumn>
26
36
  </div>
27
37
  </header>
@@ -32,16 +42,20 @@
32
42
  </script>
33
43
 
34
44
  <script setup>
35
- import { ref, useSlots, watch } from "vue";
36
- import { useElementSize, useWindowScroll } from "@vueuse/core";
45
+ import { useHead } from "#imports";
46
+ import { computed, ref, useSlots, watch } from "vue";
47
+ import { useElementSize } from "@vueuse/core";
37
48
  import { useGlobalHeaderState } from "../composables/use-global-header-state";
49
+ import { useReseeWindowScroll } from "../composables/use-resee-window-scroll";
38
50
  import { useTwoFrameRefToggle } from "../composables/use-two-frame-ref-toggle";
39
51
  import LayoutPageColumn from "./LayoutPageColumn.vue";
52
+ import TableOfContents from "./TableOfContents.vue";
40
53
  defineOptions({
41
54
  inheritAttrs: false
42
55
  });
43
56
  const props = defineProps({
44
- drawer: { type: Boolean, required: false, default: true }
57
+ drawer: { type: Boolean, required: false, default: true },
58
+ subheaderToc: { type: Array, required: false }
45
59
  });
46
60
  const slots = useSlots();
47
61
  const rulerElement = ref();
@@ -51,9 +65,23 @@ const subheadElement = ref();
51
65
  const { height: headerHeight } = useElementSize(headerElement);
52
66
  const { height: drawerHeight } = useElementSize(drawerElement);
53
67
  const { height: subheadHeight } = useElementSize(subheadElement);
54
- const { y: windowScrollY } = useWindowScroll();
68
+ const {
69
+ y: windowScrollY,
70
+ source: windowScrollSource
71
+ } = useReseeWindowScroll();
55
72
  const [isHeaderAffixed, doTransitions, updateAffixState] = useTwoFrameRefToggle();
56
73
  const hideDrawerContent = ref(false);
74
+ const headerState = useGlobalHeaderState();
75
+ const renderSubheader = computed(() => {
76
+ return !!(slots.subheader || props.subheaderToc?.length || headerState.subheaderToc.value?.length);
77
+ });
78
+ useHead({
79
+ bodyAttrs: {
80
+ style: () => ({
81
+ "--extra-scroll-margin": subheadHeight.value ? `${subheadHeight.value}px` : ""
82
+ })
83
+ }
84
+ });
57
85
  let backscrollCounter = 0;
58
86
  function disableAffix() {
59
87
  updateAffixState(false);
@@ -73,6 +101,11 @@ const { pause, resume } = watch(windowScrollY, (newScrollY, oldScrollY) => {
73
101
  if (!isHeaderAffixed.value && newScrollY > scrollCeiling + rawDrawerHeight) {
74
102
  return enableAffix();
75
103
  }
104
+ if (!windowScrollSource.value) {
105
+ hideDrawerContent.value = true;
106
+ backscrollCounter = 0;
107
+ return;
108
+ }
76
109
  const scrollDelta = newScrollY - oldScrollY;
77
110
  const isScrollDown = scrollDelta > 0;
78
111
  const negDrawerHeight = rawDrawerHeight * -1;
@@ -83,7 +116,6 @@ const { pause, resume } = watch(windowScrollY, (newScrollY, oldScrollY) => {
83
116
  hideDrawerContent.value = false;
84
117
  }
85
118
  });
86
- const headerState = useGlobalHeaderState();
87
119
  watch(
88
120
  [() => props.drawer, headerHeight, subheadHeight, hideDrawerContent, isHeaderAffixed],
89
121
  () => {
@@ -103,5 +135,5 @@ watch(
103
135
  </script>
104
136
 
105
137
  <style scoped>
106
- .placeholder{height:calc(v-bind(headerHeight)*1px)}.header-affixed{box-shadow:var(--shadow-heavy);left:0;position:fixed;right:0;top:0;transform:translateY(0);z-index:100}.header-affixed.header-transit{transition-duration:calc(var(--default-transition-duration)*2);transition-property:transform,box-shadow;transition-timing-function:var(--default-transition-timing-function)}.header-affixed.header-hidden{box-shadow:none;transform:translateY(calc(v-bind(drawerHeight)*-1px))}
138
+ .placeholder{height:calc(v-bind(headerHeight)*1px)}.header-affixed{box-shadow:var(--shadow-heavy);left:0;position:fixed;right:0;top:0;transform:translateY(0);z-index:100}.header-affixed.header-transit{transition-duration:calc(var(--default-transition-duration)*2);transition-property:transform,box-shadow;transition-timing-function:var(--default-transition-timing-function)}.header-affixed.header-hidden{box-shadow:none;transform:translateY(calc(v-bind(drawerHeight)*-1px))}.subheader :deep(.btn){background:transparent;transition:background-color;transition-duration:var(--default-transition-duration);transition-timing-function:var(--default-transition-timing-function)}.subheader :deep(.btn).active{background:var(--color-global-background-accent)}
107
139
  </style>
@@ -1,5 +1,15 @@
1
+ import type { TableOfContentsItem } from './TableOfContents.vue.js';
1
2
  export interface GlobalHeaderProps {
3
+ /**
4
+ * Whether the header will act like a flyout drawer when
5
+ * scrolling upward on the page.
6
+ */
2
7
  drawer?: boolean;
8
+ /**
9
+ * Table of contents objects for the global subheader which
10
+ * will be turned into anchor links.
11
+ */
12
+ subheaderToc?: TableOfContentsItem[];
3
13
  }
4
14
  declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<GlobalHeaderProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<GlobalHeaderProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, {
5
15
  default?: (props: {}) => any;
@@ -45,5 +45,5 @@ function dismissAnnouncement() {
45
45
  </script>
46
46
 
47
47
  <style scoped>
48
- @reference "tailwindcss";.announcement{--announcement-bg-color:#fff;@variant dark{--announcement-bg-color:#000}background-image:linear-gradient(to bottom,var(--announcement-bg-color) 0 calc(100% - 10px),transparent),linear-gradient(to right,var(--colorscale-resee-linear));padding-bottom:6px}.announcement.dismissable>div{padding-right:12rem}
48
+ @reference "tailwindcss";.announcement{--announcement-bg-color:#fff;@variant dark{--announcement-bg-color:#000}background-image:linear-gradient(to bottom,var(--announcement-bg-color) 0 calc(100% - 10px),transparent),linear-gradient(to right,var(--colorscale-resee-linear));padding-bottom:6px}.announcement.dismissable>div{padding-right:--spacing(12)}
49
49
  </style>
@@ -0,0 +1,193 @@
1
+ <template>
2
+ <div :class="['tiler', props.maskPreset]">
3
+ <div v-for="(entry, idx) of displayArray" :key="idx">
4
+ <ImageBase
5
+ :src = "entry.source"
6
+ aspect = "poster"
7
+ :class = "[props.imageClass, { 'opacity-0': entry.switching || entry.loading }]"
8
+ :style = "{ '--duration': `${entry.switchTime}ms`, '--delay': `${entry.switchDelay}ms` }"
9
+ @loading = "entry.loading = true"
10
+ @load = "entry.loading = false"
11
+ />
12
+ </div>
13
+ </div>
14
+ </template>
15
+
16
+ <style scoped>
17
+ @reference "tailwindcss";@layer components{.tiler{-moz-column-gap:--spacing(v-bind(grid.gapY));column-gap:--spacing(v-bind(grid.gapY));display:grid;grid-template-columns:repeat(v-bind(grid.cols),1fr);row-gap:--spacing(v-bind(grid.gapX))}.tiler>div{justify-self:center}img{--duration:200ms;--delay:0ms;transition:opacity;transition-delay:var(--delay);transition-duration:var(--duration);transition-timing-function:ease-out}}
18
+ </style>
19
+
20
+ <script>
21
+ export const DefaultImageTilerGridSizeFallback = {
22
+ cols: 5,
23
+ rows: 8,
24
+ gap: 3
25
+ };
26
+ export const DefaultImageTilerGridSizeDefinition = {
27
+ md: {
28
+ cols: 7,
29
+ rows: 5
30
+ },
31
+ lg: {
32
+ cols: 10,
33
+ rows: 5
34
+ }
35
+ };
36
+ </script>
37
+
38
+ <script setup>
39
+ import { useState } from "#imports";
40
+ import { getRandomEntry } from "@resee-movies/utilities/arrays/get-random-entry";
41
+ import { normalizeImageFileDescriptor } from "@resee-movies/utilities/images/normalize-image-file-descriptor";
42
+ import { getRandomInteger } from "@resee-movies/utilities/numbers/get-random-integer";
43
+ import { toInteger } from "@resee-movies/utilities/numbers/to-integer";
44
+ import { sleep } from "@resee-movies/utilities/timers/sleep";
45
+ import { computed, onMounted, shallowReactive, useId, watch } from "vue";
46
+ import { useSettingsForBreakpoint } from "../composables/use-settings-for-breakpoint";
47
+ import ImageBase from "./ImageBase.vue";
48
+ const props = defineProps({
49
+ images: { type: Array, required: true },
50
+ play: { type: Boolean, required: false, default: true },
51
+ gridSettings: { type: Object, required: false, default: () => DefaultImageTilerGridSizeDefinition },
52
+ turnoverRate: { type: [String, Number, Array], required: false, default: () => [2e3, 6e3] },
53
+ switchTime: { type: [String, Number, Array], required: false, default: () => [1200, 1800] },
54
+ switchDelay: { type: [String, Number, Array], required: false, default: () => [0, 500] },
55
+ imageClass: { type: null, required: false, default: void 0 },
56
+ maskPreset: { type: [String, Array], required: false }
57
+ });
58
+ const gridSettingsForBreakpoint = useSettingsForBreakpoint(() => props.gridSettings);
59
+ const grid = computed(() => {
60
+ const settings = gridSettingsForBreakpoint.value;
61
+ const rows = settings?.rows ?? DefaultImageTilerGridSizeFallback.rows;
62
+ const cols = settings?.cols ?? DefaultImageTilerGridSizeFallback.cols;
63
+ const cells = rows * cols;
64
+ const gapX = settings?.gapX ?? settings?.gap ?? DefaultImageTilerGridSizeFallback.gap;
65
+ const gapY = settings?.gapY ?? settings?.gap ?? DefaultImageTilerGridSizeFallback.gap;
66
+ return { rows, cols, cells, gapX, gapY };
67
+ });
68
+ const componentId = useId();
69
+ const displayArray = useState(componentId, () => {
70
+ const arr = [];
71
+ for (let i = 0; i < grid.value.cells; i += 1) {
72
+ arr.push(generateImageDisplayInfo(i, arr));
73
+ }
74
+ return arr;
75
+ });
76
+ onMounted(() => {
77
+ showAll();
78
+ queueNextChange();
79
+ });
80
+ watch(() => grid.value.cells, (newCount, oldCount) => {
81
+ if (newCount < oldCount) {
82
+ displayArray.value.splice(newCount, Number.POSITIVE_INFINITY);
83
+ return;
84
+ }
85
+ if (newCount > oldCount) {
86
+ while (displayArray.value.length < newCount) {
87
+ const info = generateImageDisplayInfo(displayArray.value.length, displayArray.value);
88
+ displayArray.value.push(info);
89
+ showImageCellContent(info);
90
+ }
91
+ }
92
+ });
93
+ function queueNextChange() {
94
+ setTimeout(async () => {
95
+ if (props.play) {
96
+ const idx = getValueFromRange([0, displayArray.value.length - 1]);
97
+ const info = displayArray.value[idx];
98
+ if (info) {
99
+ await switchImageCellContent(info, idx);
100
+ }
101
+ }
102
+ queueNextChange();
103
+ }, getValueFromRange(props.turnoverRate));
104
+ }
105
+ function getValueFromRange(value) {
106
+ return Array.isArray(value) ? getRandomInteger(value[0], value[1]) : toInteger(value);
107
+ }
108
+ function pickImage(forIdx, forArray) {
109
+ let candidate = normalizeImageFileDescriptor(getRandomEntry(props.images));
110
+ if (props.images.length > 5) {
111
+ const neighbors = getNeighborIndexes(
112
+ forIdx,
113
+ grid.value.cols,
114
+ grid.value.rows,
115
+ props.images.length > 9 ? "8-edge" : "4-edge"
116
+ );
117
+ neighbors.push(forIdx);
118
+ for (let maxAttempts = 0; maxAttempts < 3; maxAttempts += 1) {
119
+ if (isImageInUse(candidate, forArray, neighbors)) {
120
+ candidate = normalizeImageFileDescriptor(getRandomEntry(props.images));
121
+ } else {
122
+ break;
123
+ }
124
+ }
125
+ }
126
+ return candidate;
127
+ }
128
+ function getNeighborIndexes(centerIdx, columnCount, rowCount, distance = "8-edge") {
129
+ const rowOffset = Math.floor(centerIdx / columnCount);
130
+ const colOffset = centerIdx % columnCount;
131
+ const top = rowOffset > 0 ? centerIdx - columnCount : -1;
132
+ const right = colOffset < columnCount ? centerIdx + 1 : -1;
133
+ const bottom = rowOffset < rowCount ? centerIdx + columnCount : -1;
134
+ const left = colOffset > 0 ? centerIdx - 1 : -1;
135
+ if (distance === "4-edge") {
136
+ return [top, right, bottom, left];
137
+ }
138
+ const topRight = top > -1 && right > -1 ? top + 1 : -1;
139
+ const bottomRight = bottom > -1 && right > -1 ? bottom + 1 : -1;
140
+ const bottomLeft = bottom > -1 && left > -1 ? bottom - 1 : -1;
141
+ const topLeft = top > -1 && left > -1 ? top - 1 : -1;
142
+ return [top, topRight, right, bottomRight, bottom, bottomLeft, left, topLeft];
143
+ }
144
+ function isImageInUse(candidate, sourceArray, indicesToCheck) {
145
+ for (const idx of indicesToCheck) {
146
+ if (idx < 0 || idx > sourceArray.length) {
147
+ continue;
148
+ }
149
+ if (sourceArray.at(idx)?.source.identifier === candidate.identifier) {
150
+ return true;
151
+ }
152
+ }
153
+ return false;
154
+ }
155
+ function generateImageDisplayInfo(forIdx, forArray) {
156
+ return shallowReactive({
157
+ source: pickImage(forIdx, forArray),
158
+ loading: true,
159
+ switching: true,
160
+ switchTime: getValueFromRange(props.switchTime),
161
+ switchDelay: getValueFromRange(props.switchDelay)
162
+ });
163
+ }
164
+ async function hideImageCellContent(info) {
165
+ if (info.switching) {
166
+ return;
167
+ }
168
+ info.switching = true;
169
+ await sleep(info.switchTime + info.switchDelay);
170
+ }
171
+ async function showImageCellContent(info) {
172
+ if (!info.switching) {
173
+ return;
174
+ }
175
+ info.switching = false;
176
+ await sleep(info.switchTime + info.switchDelay);
177
+ }
178
+ async function switchImageCellContent(info, idx) {
179
+ await hideImageCellContent(info);
180
+ info.source = pickImage(idx, displayArray.value);
181
+ await showImageCellContent(info);
182
+ }
183
+ async function showAll() {
184
+ return Promise.allSettled(
185
+ displayArray.value.map((entry) => showImageCellContent(entry))
186
+ );
187
+ }
188
+ async function hideAll() {
189
+ return Promise.allSettled(
190
+ displayArray.value.map((entry) => hideImageCellContent(entry))
191
+ );
192
+ }
193
+ </script>
@@ -0,0 +1,31 @@
1
+ import type { ImageFileDescriptor } from '@resee-movies/utilities/images/normalize-image-file-descriptor';
2
+ import type { BreakpointSettings } from '../composables/use-settings-for-breakpoint.js';
3
+ import type { HTMLElementClassNames } from '../types/index.js';
4
+ export type ValueOrRange = string | number | [min: number, max: number];
5
+ export type ImageTilerGridSizeDefinition = {
6
+ cols: number;
7
+ rows: number;
8
+ gap?: number;
9
+ gapX?: number;
10
+ gapY?: number;
11
+ };
12
+ export type ImageMaskPreset = 'image-mask-washout' | 'image-mask-gradient-washout' | 'image-mask-gradient-washout-lite' | 'image-mask-gradient-opacity' | 'image-mask-hero';
13
+ export declare const DefaultImageTilerGridSizeFallback: {
14
+ cols: number;
15
+ rows: number;
16
+ gap: number;
17
+ };
18
+ export declare const DefaultImageTilerGridSizeDefinition: BreakpointSettings<ImageTilerGridSizeDefinition>;
19
+ export interface ImageTilerProps {
20
+ images: ImageFileDescriptor[];
21
+ play?: boolean;
22
+ gridSettings?: BreakpointSettings<ImageTilerGridSizeDefinition>;
23
+ turnoverRate?: ValueOrRange;
24
+ switchTime?: ValueOrRange;
25
+ switchDelay?: ValueOrRange;
26
+ imageClass?: HTMLElementClassNames;
27
+ maskPreset?: ImageMaskPreset | ImageMaskPreset[];
28
+ }
29
+ declare const __VLS_export: import("vue").DefineComponent<ImageTilerProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ImageTilerProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
30
+ declare const _default: typeof __VLS_export;
31
+ export default _default;
@@ -0,0 +1,33 @@
1
+ <template>
2
+ <div :class="['stats', { responsive: props.responsive }]">
3
+ <dl>
4
+ <slot name="default">
5
+ <template v-if="props.items?.length">
6
+ <InlineStatsListItem
7
+ v-for = "item of props.items"
8
+ :key = "item.label"
9
+ :label = "item.label"
10
+ :description = "item.description"
11
+ :icon = "item.icon"
12
+ />
13
+ </template>
14
+ </slot>
15
+ </dl>
16
+ </div>
17
+ </template>
18
+
19
+ <script>
20
+
21
+ </script>
22
+
23
+ <script setup>
24
+ import InlineStatsListItem from "./InlineStatsListItem.vue";
25
+ const props = defineProps({
26
+ responsive: { type: Boolean, required: false, default: false },
27
+ items: { type: Array, required: false, default: void 0 }
28
+ });
29
+ </script>
30
+
31
+ <style scoped>
32
+ @reference "tailwindcss";.stats{--stats-list-spacer-width:1.2rem;overflow:clip}.stats dl{display:flex;flex-wrap:wrap;margin-inline-start:calc(var(--stats-list-spacer-width)*-1)}.stats.responsive dl{@variant max-sm{flex-direction:column}}
33
+ </style>
@@ -0,0 +1,15 @@
1
+ import type { InlineStatsListItemProps } from './InlineStatsListItem.vue.js';
2
+ export interface InlineStatsListProps {
3
+ responsive?: boolean;
4
+ items?: InlineStatsListItemProps[];
5
+ }
6
+ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<InlineStatsListProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<InlineStatsListProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, {
7
+ default?: (props: {}) => any;
8
+ }>;
9
+ declare const _default: typeof __VLS_export;
10
+ export default _default;
11
+ type __VLS_WithSlots<T, S> = T & {
12
+ new (): {
13
+ $slots: S;
14
+ };
15
+ };
@@ -0,0 +1,39 @@
1
+ <template>
2
+ <dt class="sr-only">
3
+ <slot name="label">
4
+ {{ props.label }}
5
+ </slot>
6
+ </dt>
7
+
8
+ <dd>
9
+ <slot name="default">
10
+ <IconTextPair :icon="props.icon" :text="props.description">
11
+ <template #default v-if="slots.description">
12
+ <slot name="description" />
13
+ </template>
14
+ </IconTextPair>
15
+ </slot>
16
+ </dd>
17
+ </template>
18
+
19
+ <script>
20
+
21
+ </script>
22
+
23
+ <script setup>
24
+ import IconTextPair from "./IconTextPair.vue";
25
+ import { useSlots } from "vue";
26
+ defineOptions({
27
+ inheritAttrs: false
28
+ });
29
+ const props = defineProps({
30
+ label: { type: String, required: true },
31
+ description: { type: String, required: true },
32
+ icon: { type: String, required: false, default: void 0 }
33
+ });
34
+ const slots = useSlots();
35
+ </script>
36
+
37
+ <style scoped>
38
+ @reference "tailwindcss";dd{padding-inline-start:var(--stats-list-spacer-width);position:relative}dd:before{color:var(--color-global-foreground-accent);content:"|";inset-inline-start:0;margin-inline:--spacing(2);position:absolute}
39
+ </style>
@@ -0,0 +1,19 @@
1
+ export interface InlineStatsListItemProps {
2
+ label: string;
3
+ description: string;
4
+ icon?: string;
5
+ }
6
+ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<InlineStatsListItemProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<InlineStatsListItemProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, {
7
+ label?: (props: {}) => any;
8
+ } & {
9
+ default?: (props: {}) => any;
10
+ } & {
11
+ description?: (props: {}) => any;
12
+ }>;
13
+ declare const _default: typeof __VLS_export;
14
+ export default _default;
15
+ type __VLS_WithSlots<T, S> = T & {
16
+ new (): {
17
+ $slots: S;
18
+ };
19
+ };
@@ -0,0 +1,56 @@
1
+ <template>
2
+ <ol v-if="props.toc?.length">
3
+ <template v-for="entry of props.toc" :key="entry.slug">
4
+ <li v-if="shouldRenderLevel(entry.level)">
5
+ <NuxtLink
6
+ v-slot = "config"
7
+ :href = "`#${entry.slug}`"
8
+ :custom = "true"
9
+ >
10
+ <a
11
+ v-html = "entry.text"
12
+ :class = "[props.linkClass, { active: mounted && areRoutesStrictEqual(config.route, route) }]"
13
+ :href = "config.href"
14
+ />
15
+ </NuxtLink>
16
+
17
+ <TableOfContents
18
+ v-if = "entry.children?.length && shouldRenderLevel((entry.level ?? 1) + 1)"
19
+ :toc = "entry.children"
20
+ :link-class = "props.linkClass"
21
+ :min-depth = "props.minDepth"
22
+ :max-depth = "props.maxDepth"
23
+ />
24
+ </li>
25
+ </template>
26
+ </ol>
27
+ </template>
28
+
29
+ <script>
30
+
31
+ </script>
32
+
33
+ <script setup>
34
+ import { NuxtLink } from "#components";
35
+ import { useRoute } from "#imports";
36
+ import { onMounted, ref } from "vue";
37
+ import { areRoutesStrictEqual } from "../utils/routing";
38
+ import TableOfContents from "./TableOfContents.vue";
39
+ const props = defineProps({
40
+ toc: { type: null, required: true },
41
+ minDepth: { type: Number, required: false },
42
+ maxDepth: { type: Number, required: false },
43
+ linkClass: { type: null, required: false }
44
+ });
45
+ const route = useRoute();
46
+ const mounted = ref(false);
47
+ onMounted(() => {
48
+ mounted.value = true;
49
+ });
50
+ function shouldRenderLevel(level) {
51
+ if (!level) {
52
+ return true;
53
+ }
54
+ return (!props.minDepth || props.minDepth <= level) && (!props.maxDepth || props.maxDepth >= level);
55
+ }
56
+ </script>
@@ -0,0 +1,15 @@
1
+ import type { TableOfContents as TableOfContentsOptions } from '@resee-movies/utilities/dom/generate-table-of-contents';
2
+ import type { HTMLElementClassNames } from '../types/index.js';
3
+ export type TableOfContentsItem = Partial<TableOfContentsOptions> & {
4
+ text: string;
5
+ slug: string;
6
+ };
7
+ export type UiTableOfContentsProps = {
8
+ toc: TableOfContentsItem[] | null | undefined;
9
+ minDepth?: number;
10
+ maxDepth?: number;
11
+ linkClass?: HTMLElementClassNames;
12
+ };
13
+ declare const __VLS_export: import("vue").DefineComponent<UiTableOfContentsProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<UiTableOfContentsProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
14
+ declare const _default: typeof __VLS_export;
15
+ export default _default;
@@ -23,6 +23,7 @@
23
23
  <PrimeForm
24
24
  v-slot = "$form"
25
25
  v-bind = "$attrs"
26
+ :id = "formUid"
26
27
  ref = "form"
27
28
  novalidate = "true"
28
29
  :validate-on-mount = "true"
@@ -54,7 +55,7 @@ import PrimeForm, {} from "@primevue/forms/form";
54
55
  import { toNonNullableArray } from "@resee-movies/utilities/arrays/to-non-nullable-array";
55
56
  import { isPromiseLike } from "@resee-movies/utilities/objects/is-promise-like";
56
57
  import { syncRefs } from "@vueuse/core";
57
- import { ref, useTemplateRef } from "vue";
58
+ import { ref, useId, useTemplateRef } from "vue";
58
59
  import FormFieldBuilder from "./FormFieldBuilder.vue";
59
60
  import LazySuccessSplash from "../SuccessSplash.vue";
60
61
  import LazyMessage from "../Message.vue";
@@ -76,8 +77,9 @@ const form = useTemplateRef("form");
76
77
  const values = defineModel("values", { type: null, ...{ default: void 0 } });
77
78
  const success = ref(false);
78
79
  const errors = ref();
80
+ const formUid = useId();
79
81
  defineEmits(["submit", "change"]);
80
- const formInstance = provideFormInstance();
82
+ const formInstance = provideFormInstance(formUid);
81
83
  syncRefs(() => props.disabled, formInstance.isDisabled);
82
84
  useReactiveObjectsSync({
83
85
  left: () => form.value?.states,
@@ -42,10 +42,10 @@
42
42
  :readonly = "isReadonly"
43
43
  :value = "$field.value"
44
44
  :invalid = "$field.invalid"
45
- :on-blur = "$field.props.onBlur"
46
- :on-change = "$field.props.onChange"
47
- :on-input = "$field.props.onInput"
48
- :on-invalid = "$field.props.onInvalid"
45
+ :on-blur = "$field.props?.onBlur"
46
+ :on-change = "$field.props?.onChange"
47
+ :on-input = "$field.props?.onInput"
48
+ :on-invalid = "$field.props?.onInvalid"
49
49
  />
50
50
  </template>
51
51
  </FormLabelInputPair>
@@ -87,9 +87,9 @@ const props = defineProps({
87
87
  class: { type: null, required: false }
88
88
  });
89
89
  const formState = injectFormInstance();
90
- const inputId = useId();
91
- const labelId = `${inputId}_label`;
92
- const messageId = `${inputId}_message`;
90
+ const inputId = computed(() => `${formState.formUid}_${props.name}_field`);
91
+ const labelId = computed(() => `${formState.formUid}_${props.name}_label`);
92
+ const messageId = computed(() => `${formState.formUid}_${props.name}_message`);
93
93
  const labelText = computed(() => props.label ?? humanize(props.name));
94
94
  const isDisabled = computed(() => props.disabled || formState.isDisabled.value);
95
95
  const isReadonly = computed(() => props.readonly || formState.isSubmitting.value);
@@ -4,8 +4,9 @@
4
4
  <slot name="label" />
5
5
  </template>
6
6
 
7
- <template #default="{ inputName, onChange }">
7
+ <template #default="{ inputId, inputName, onChange }">
8
8
  <FormElementTurnstile
9
+ :id = "inputId"
9
10
  :sitekey = "props.sitekey"
10
11
  :response-field-name = "inputName"
11
12
  :callback = "(token) => onChange({ value: token })"
@@ -16,6 +16,7 @@
16
16
  import { onUnmounted, useId } from "#imports";
17
17
  import { useCloudflareTurnstile } from "../../../composables/use-cloudflare-turnstile";
18
18
  const props = defineProps({
19
+ id: { type: String, required: false },
19
20
  sitekey: { type: String, required: true },
20
21
  action: { type: String, required: false },
21
22
  cData: { type: String, required: false },
@@ -40,7 +41,7 @@ const props = defineProps({
40
41
  appearance: { type: String, required: false, default: "always" },
41
42
  "feedback-enabled": { type: Boolean, required: false }
42
43
  });
43
- const widgetId = useId();
44
+ const widgetId = props.id ?? useId();
44
45
  const { onReady } = useCloudflareTurnstile();
45
46
  let turnstile = void 0;
46
47
  onReady((ts) => {
@@ -1,5 +1,6 @@
1
1
  import type { TurnstileRenderOptions } from '../../../composables/use-cloudflare-turnstile.js';
2
2
  export interface FormElementTurnstileProps extends TurnstileRenderOptions {
3
+ id?: string;
3
4
  }
4
5
  declare const __VLS_export: import("vue").DefineComponent<FormElementTurnstileProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<FormElementTurnstileProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
5
6
  declare const _default: typeof __VLS_export;
@@ -1,10 +1,61 @@
1
+ import { type MaybeRefOrGetter } from 'vue';
2
+ import type { TableOfContentsItem } from '../components/TableOfContents.vue.js';
3
+ /**
4
+ *
5
+ */
6
+ declare function tableOfContents(toc: UseGlobalHeaderStateOptions['tableOfContents']): void;
7
+ /**
8
+ * Configuration for the {@link useGlobalHeaderState} composable.
9
+ */
10
+ export type UseGlobalHeaderStateOptions = {
11
+ tableOfContents?: MaybeRefOrGetter<(TableOfContentsItem | undefined)[] | undefined>;
12
+ };
1
13
  /**
2
14
  * Stateful information about the GlobalHeader component.
3
15
  */
4
- export declare function useGlobalHeaderState(): {
16
+ export declare function useGlobalHeaderState(options?: UseGlobalHeaderStateOptions): {
5
17
  headerHeight: import("vue").Ref<number, number>;
6
18
  subheaderHeight: import("vue").Ref<number, number>;
19
+ subheaderToc: import("vue").Ref<{
20
+ level?: number | undefined;
21
+ text: string;
22
+ slug: string;
23
+ parent?: {
24
+ level: number;
25
+ text: string;
26
+ slug: string;
27
+ parent: /*elided*/ any | undefined;
28
+ children: /*elided*/ any[];
29
+ } | undefined;
30
+ children?: {
31
+ level: number;
32
+ text: string;
33
+ slug: string;
34
+ parent: /*elided*/ any | undefined;
35
+ children: /*elided*/ any[];
36
+ }[] | undefined;
37
+ }[], TableOfContentsItem[] | {
38
+ level?: number | undefined;
39
+ text: string;
40
+ slug: string;
41
+ parent?: {
42
+ level: number;
43
+ text: string;
44
+ slug: string;
45
+ parent: /*elided*/ any | undefined;
46
+ children: /*elided*/ any[];
47
+ } | undefined;
48
+ children?: {
49
+ level: number;
50
+ text: string;
51
+ slug: string;
52
+ parent: /*elided*/ any | undefined;
53
+ children: /*elided*/ any[];
54
+ }[] | undefined;
55
+ }[]>;
56
+ tableOfContents: typeof tableOfContents;
7
57
  isHeaderDrawerEnabled: import("vue").Ref<boolean, boolean>;
8
58
  isHeaderPulledDown: import("vue").Ref<boolean, boolean>;
9
59
  offsetFromHeaderStyles: import("vue").ComputedRef<string[]>;
10
60
  };
61
+ export {};
@@ -1,4 +1,4 @@
1
- import { computed, ref } from "vue";
1
+ import { computed, onScopeDispose, ref, toValue, watch } from "vue";
2
2
  const headerHeight = ref(0);
3
3
  const subheaderHeight = ref(0);
4
4
  const isHeaderDrawerEnabled = ref(true);
@@ -9,10 +9,30 @@ const offsetFromHeaderStyles = computed(() => {
9
9
  `padding-top: ${headerHeight.value}px;`
10
10
  ];
11
11
  });
12
- export function useGlobalHeaderState() {
12
+ const subheaderToc = ref([]);
13
+ function tableOfContents(toc) {
14
+ onScopeDispose(() => {
15
+ subheaderToc.value.length = 0;
16
+ }, true);
17
+ watch(
18
+ () => toValue(toc),
19
+ (entries) => {
20
+ subheaderToc.value.push(
21
+ ...entries?.filter((entry) => !!entry) ?? []
22
+ );
23
+ },
24
+ { immediate: true }
25
+ );
26
+ }
27
+ export function useGlobalHeaderState(options) {
28
+ if (options?.tableOfContents) {
29
+ tableOfContents(options.tableOfContents);
30
+ }
13
31
  return {
14
32
  headerHeight,
15
33
  subheaderHeight,
34
+ subheaderToc,
35
+ tableOfContents,
16
36
  isHeaderDrawerEnabled,
17
37
  isHeaderPulledDown,
18
38
  offsetFromHeaderStyles
@@ -0,0 +1,18 @@
1
+ import { type UseWindowScrollOptions, type UseWindowScrollReturn } from '@vueuse/core';
2
+ import { type Ref } from 'vue';
3
+ export type UseReseeWindowScrollReturn = UseWindowScrollReturn & {
4
+ source: Ref<Event | undefined>;
5
+ };
6
+ /**
7
+ * A specialized implementation of the Vueuse {@link useWindowScroll} composable, which adds
8
+ * the new property `source` to the returned object.
9
+ *
10
+ * The purpose of `source` is to provide a best-effort attempt at identifying _why_ the scroll
11
+ * was initiated. To do this, a series of common user interaction events - _wheel_, _touchmove_,
12
+ * etc. are listened to and correlated with the scroll event.
13
+ *
14
+ * In the case of a scroll **not** being initiated by direct user interaction - e.g. invocation of
15
+ * `window.scrollTo` or the user agent scrolling the page in response to a URL hash change - then
16
+ * `source` will be undefined.
17
+ */
18
+ export declare function useReseeWindowScroll(options?: UseWindowScrollOptions): UseReseeWindowScrollReturn;
@@ -0,0 +1,65 @@
1
+ import {
2
+ useEventListener,
3
+ useWindowScroll
4
+ } from "@vueuse/core";
5
+ import { ref } from "vue";
6
+ const NavigationKeys = [
7
+ "ArrowUp",
8
+ "ArrowDown",
9
+ " ",
10
+ "Spacebar",
11
+ "ArrowRight",
12
+ "ArrowLeft",
13
+ "End",
14
+ "Home",
15
+ "PageDown",
16
+ "PageUp"
17
+ ];
18
+ export function useReseeWindowScroll(options) {
19
+ const scrollSource = ref();
20
+ let scrollEndTimeoutId = void 0;
21
+ function clearScrollEndTimeout() {
22
+ if (scrollEndTimeoutId) {
23
+ clearTimeout(scrollEndTimeoutId);
24
+ scrollEndTimeoutId = void 0;
25
+ }
26
+ }
27
+ function setScrollEndTimeout() {
28
+ clearScrollEndTimeout();
29
+ scrollEndTimeoutId = setTimeout(
30
+ () => {
31
+ scrollSource.value = void 0;
32
+ scrollEndTimeoutId = void 0;
33
+ },
34
+ 250
35
+ );
36
+ }
37
+ useEventListener(["wheel", "touchmove", "keydown", "keyup", "mousedown", "mouseup"], (e) => {
38
+ if (e instanceof KeyboardEvent) {
39
+ if (NavigationKeys.includes(e.key)) {
40
+ setScrollEndTimeout();
41
+ scrollSource.value = e;
42
+ }
43
+ } else if (e.type === "mouseup") {
44
+ clearScrollEndTimeout();
45
+ scrollSource.value = void 0;
46
+ } else {
47
+ setScrollEndTimeout();
48
+ scrollSource.value = e;
49
+ }
50
+ });
51
+ const scrollProps = useWindowScroll({
52
+ ...options,
53
+ onScroll(e) {
54
+ options?.onScroll?.(e);
55
+ clearScrollEndTimeout();
56
+ },
57
+ onStop(e) {
58
+ options?.onStop?.(e);
59
+ if (scrollSource.value?.type !== "mousedown") {
60
+ setScrollEndTimeout();
61
+ }
62
+ }
63
+ });
64
+ return { ...scrollProps, source: scrollSource };
65
+ }
@@ -0,0 +1,11 @@
1
+ import type { breakpointsTailwind } from '@vueuse/core';
2
+ import { type ComputedRef, type MaybeRefOrGetter } from 'vue';
3
+ export type BreakpointSettingName = (keyof typeof breakpointsTailwind) | 'default';
4
+ export type BreakpointSettings<T> = Partial<Record<BreakpointSettingName, T>>;
5
+ /**
6
+ * Given an object whose properties are Tailwind breakpoint names, this will return
7
+ * the value of the property that matches the active breakpoint. If an exact match
8
+ * is not available, a mobile-first approach is taken - the first value of a smaller
9
+ * breakpoint, or finally the `default`, will be returned.
10
+ */
11
+ export declare function useSettingsForBreakpoint<T>(settings: MaybeRefOrGetter<BreakpointSettings<T> | null | undefined>): ComputedRef<T | undefined>;
@@ -0,0 +1,25 @@
1
+ import { computed, toValue } from "vue";
2
+ import { useReseeBreakpoints } from "./use-resee-breakpoints.js";
3
+ export function useSettingsForBreakpoint(settings) {
4
+ const ordering = ["default", "sm", "md", "lg", "xl", "2xl"];
5
+ const activeBreak = useReseeBreakpoints().active();
6
+ return computed(() => {
7
+ const breakpoint = activeBreak.value || "default";
8
+ const rawSettings = toValue(settings);
9
+ if (!rawSettings) {
10
+ return void 0;
11
+ }
12
+ if (breakpoint in rawSettings) {
13
+ return rawSettings[breakpoint];
14
+ }
15
+ let idx = ordering.indexOf(breakpoint);
16
+ while (idx > 0) {
17
+ idx -= 1;
18
+ const name = ordering[idx];
19
+ if (name && name in rawSettings) {
20
+ return rawSettings[name];
21
+ }
22
+ }
23
+ return rawSettings["default"];
24
+ });
25
+ }
@@ -0,0 +1,43 @@
1
+ import { type Ref } from 'vue';
2
+ import type { RouteLocationResolvedGeneric } from 'vue-router';
3
+ /**
4
+ * Vue Router's `resolve` method creates a RouteLocationResolvedGeneric object,
5
+ * while Vue Router's `currentRoute` ref expects a RouteLocationNormalizedLoadedGeneric
6
+ * object (because of course). There is an inconsistency between the two in that the
7
+ * former's `name` property can be null, while the latter's cannot. This means you
8
+ * cannot directly assign the former to the latter without TS complaining.
9
+ *
10
+ * The exceptionally long name here is a nod to the 50+ other _Location_ types that
11
+ * Vue Route exposes.
12
+ */
13
+ export type RouteLocationResolvedGenericWithNonNullableName = Omit<RouteLocationResolvedGeneric, 'name'> & {
14
+ name: string | undefined;
15
+ };
16
+ /**
17
+ * Options for the `update` method returned by the {@link useUrlHash} composable.
18
+ */
19
+ export type UseUrlHashUpdateOptions = {
20
+ /**
21
+ * Whether to update the hash in a way that will cause the browser
22
+ * to scroll to the identified element (default: false).
23
+ */
24
+ scrollTo?: boolean;
25
+ /**
26
+ * Whether to create a new history entry for the hash - push - or to replace the
27
+ * current (default: replace).
28
+ */
29
+ mode?: 'push' | 'replace';
30
+ };
31
+ /**
32
+ * The return type of the {@link useUrlHash} composable.
33
+ */
34
+ export type UseUrlHashReturn = {
35
+ value: Readonly<Ref<string | undefined>>;
36
+ update: (newHash: string | undefined, options?: UseUrlHashUpdateOptions) => boolean;
37
+ };
38
+ /**
39
+ * Read/Write the current URL hash value. By default, this will be done in a way that does
40
+ * not cause browser scroll to behavior to occur - very useful when updating the hash
41
+ * based on the scroll position of the page.
42
+ */
43
+ export declare function useUrlHash(): UseUrlHashReturn;
@@ -0,0 +1,25 @@
1
+ import { useRouter } from "#imports";
2
+ import { isString } from "@resee-movies/utilities/strings/is-string";
3
+ import { computed } from "vue";
4
+ export function useUrlHash() {
5
+ const router = useRouter();
6
+ const value = computed(() => {
7
+ return router.currentRoute.value.hash || void 0;
8
+ });
9
+ const update = (newHash, options) => {
10
+ const normalizedHash = isString(newHash, { withContent: true }) ? !newHash.startsWith("#") ? `#${newHash}` : newHash : void 0;
11
+ const { path, query, hash } = router.currentRoute.value;
12
+ if (normalizedHash && hash && normalizedHash === hash) {
13
+ return false;
14
+ }
15
+ if (options?.scrollTo === true) {
16
+ (options?.mode === "push" ? router.push : router.replace)({ path, query, hash: normalizedHash });
17
+ return true;
18
+ }
19
+ const newRoute = router.resolve({ path, query, hash: normalizedHash });
20
+ router.currentRoute.value = newRoute;
21
+ window.history[options?.mode === "push" ? "pushState" : "replaceState"](null, "", normalizedHash);
22
+ return true;
23
+ };
24
+ return { value, update };
25
+ }
@@ -1 +1 @@
1
- @layer base{:root{--p-scrollbar-width:0px}html:has(body.p-overflow-hidden){scrollbar-color:transparent var(--color-global-background)}body{background-color:var(--color-global-background);color:var(--color-global-foreground);min-height:100vh;transition:color,background-color;transition-duration:var(--default-transition-duration);@variant dark{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}}@property --background-grid-line-color{syntax:"<color>";inherits:false;initial-value:transparent}#app-root{min-height:100vh;@variant sm{background-position:top;background-size:160px 80px;transition:--background-grid-line-color;transition-duration:var(--default-transition-duration);--background-grid-line-color:var(--color-global-background-accent);background-image:linear-gradient(to bottom,transparent 0 45px,var(--background-grid-line-color) 45px 46px,transparent 46px 59px,var(--background-grid-line-color) 59px 60px,transparent 60px),linear-gradient(to right,transparent 0 80px,var(--background-grid-line-color) 80px 81px,transparent 81px)}}.app-main{min-height:100vh}.app-footer{position:sticky;top:100vh}}
1
+ @layer base{:root{--p-scrollbar-width:0px}html{scroll-behavior:smooth}@media screen and (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}html:has(body.p-overflow-hidden){scrollbar-color:transparent var(--color-global-background)}body{background-color:var(--color-global-background);color:var(--color-global-foreground);min-height:100vh;transition:color,background-color;transition-duration:var(--default-transition-duration);@variant dark{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}}@property --background-grid-line-color{syntax:"<color>";inherits:false;initial-value:transparent}#app-root{min-height:100vh;@variant sm{background-position:top;background-size:160px 74px;transition:--background-grid-line-color;transition-duration:var(--default-transition-duration);--background-grid-line-color:var(--color-global-background-accent);background-image:linear-gradient(to bottom,transparent 0 45px,var(--background-grid-line-color) 45px 46px,transparent 46px 59px,var(--background-grid-line-color) 59px 60px,transparent 60px),linear-gradient(to right,transparent 0 80px,var(--background-grid-line-color) 80px 81px,transparent 81px)}}.app-main{min-height:100vh}.app-footer{position:sticky;top:100vh}}
@@ -0,0 +1 @@
1
+ @layer base{:root{--image-mask-gradient-opacity-dir:to bottom;--image-mask-gradient-opacity-stop:85%;--image-mask-gradient-dir:to bottom;--image-mask-gradient-stop:80%;--image-mask-color:var(--color-global-background);--image-mask-alpha-percent:85%}}@utility image-mask-washout{@apply relative before:z-1 before:absolute before:inset-0;&:before{background:--alpha(var(--image-mask-color)/var(--image-mask-alpha-percent))}}@utility image-mask-gradient-washout{@apply relative before:z-1 before:absolute before:inset-0;&:before{background:linear-gradient(var(--image-mask-gradient-dir),--alpha(var(--image-mask-color)/var(--image-mask-alpha-percent)) var(--image-mask-gradient-stop),var(--image-mask-color))}}@utility image-mask-gradient-washout-lite{@apply relative before:z-1 before:absolute before:inset-0;--image-mask-alpha-percent:10%;--image-mask-gradient-stop:30%;&:before{background:linear-gradient(var(--image-mask-gradient-dir),--alpha(var(--image-mask-color)/var(--image-mask-alpha-percent)) var(--image-mask-gradient-stop),var(--image-mask-color))}}@utility image-mask-gradient-opacity{-webkit-mask-image:linear-gradient(var(--image-mask-gradient-opacity-dir),#000 var(--image-mask-gradient-opacity-stop),transparent);mask-image:linear-gradient(var(--image-mask-gradient-opacity-dir),#000 var(--image-mask-gradient-opacity-stop),transparent)}@utility image-mask-hero{@apply relative before:z-1 before:absolute before:inset-0;--image-mask-color:#fff;@variant dark{--image-mask-color:#000}&:before{background:--alpha(var(--image-mask-color)/75%);@variant sm{background:linear-gradient(to right,--alpha(var(--image-mask-color)/90%) 35%,--alpha(var(--image-mask-color)/15%))}}}
@@ -1 +1 @@
1
- @utility prose-layout-container{margin-left:auto;margin-right:auto;max-width:var(--container-3xl);width:100%;&.sm{max-width:var(--container-md)}}@layer components{:root{--typo-h6:clamp(var(--text-base),2.500vw,1.2rem);--typo-h5:clamp(var(--typo-h6),3.000vw,1.44rem);--typo-h4:clamp(var(--typo-h5),3.600vw,1.728rem);--typo-h3:clamp(var(--typo-h4),4.320vw,2.0736rem);--typo-h2:clamp(var(--typo-h3),5.184vw,2.4883rem);--typo-h1:clamp(var(--typo-h2),6.221vw,2.986rem);--typo-h1-hero:clamp(var(--typo-h1),9.331vw,4.479rem);--typo-p-hero:clamp(1.25rem,3.125vw,1.5rem)}.font-variant-small-caps{font-variant:small-caps}.icon-inline{align-items:center;display:inline-flex}.icon-inline:before{content:"​";display:block}.prose-container{@apply prose-layout-container}.prose-container:where(:not(.prose+.prose-container,.prose-container+.prose-container))>:first-child,.prose-container:where(:not(.prose+.prose-container,.prose-container+.prose-container))>:first-child>:first-child,.prose:where(:not(.prose+.prose,.prose-container+.prose))>:first-child,.prose:where(:not(.prose+.prose,.prose-container+.prose))>:first-child>:first-child{margin-block-start:0}.prose-container>:last-child,.prose-container>:last-child>:last-child,.prose>:last-child,.prose>:last-child>:last-child{margin-block-end:0}:where(.h1,.h2,.h3,.h4,.h5,.h6).prose,:where(.prose-container,.prose) :where(h1,h2,h3,h4,h5,h6){margin-block-end:.4lh;margin-block-start:.9lh;text-wrap:pretty}:where(.p,.pre,.table,.ol,.ul,.img,.figure,.blockquote).prose,:where(.prose-container,.prose) :where(p,pre,table,ol,ul,img,figure,blockquote){margin-block-end:1lh;text-wrap:pretty}:where(.prose-container,.prose) hr+*{margin-block-start:0}:where(.prose-container,.prose) :has(+hr){margin-block-end:0}.hr,.prose hr,.prose-container hr{border-color:var(--color-global-background-accent);margin-block-end:1lh;margin-block-start:1lh}.h1,.prose h1,.prose-container h1{color:color-mix(in srgb-linear,var(--custom-accent-color) 40%,currentColor);font-size:var(--typo-h1);letter-spacing:.0025em;line-height:1.125}.h1.hero,.prose h1.hero,.prose-container h1.hero{font-size:var(--typo-h1-hero);line-height:1}.h2,.prose h2,.prose-container h2{font-size:var(--typo-h2);font-weight:var(--font-weight-extralight);letter-spacing:.0108em;line-height:1.1765}.h3,.prose h3,.prose-container h3{font-size:var(--typo-h3);font-weight:var(--font-weight-extralight);letter-spacing:.022em;line-height:1.2}.h4,.prose h4,.prose-container h4{font-size:var(--typo-h4);letter-spacing:.035em;line-height:1.25}.h5,.prose h5,.prose-container h5{font-size:var(--typo-h5);letter-spacing:.0532em;line-height:1.28}.h6,.prose h6,.prose-container h6{font-size:var(--typo-h6);letter-spacing:.0532em;line-height:1.28}.p,.prose p,.prose-container p{font-size:1rem;letter-spacing:.03em;line-height:1.5}.p.hero,.prose p.hero,.prose-container p.hero{font-size:var(--typo-p-hero);line-height:1.3}.note{color:var(--color-foreground-scale-g);font-size:.95rem!important;letter-spacing:.05rem!important;line-height:1.5!important}.code,.pre,.prose code,.prose pre,.prose-container code,.prose-container pre{border-radius:.25rem;color:var(--color-foreground-scale-e);font-family:monospace;font-size:.9rem;font-weight:bolder;outline:dashed 2px var(--color-background-scale-g);outline-offset:-2px;padding:.2rem .25rem;transition:color,outline-color;transition-duration:.15s}.code:hover,.pre:hover,.prose code:hover,.prose pre:hover,.prose-container code:hover,.prose-container pre:hover{color:var(--color-global-foreground)}.pre,.prose pre,.prose-container pre{padding:.5rem .75rem}.prose table,.prose-container table,.table{border-collapse:collapse}.prose table td,.prose table th,.prose-container table td,.prose-container table th,.table td,.table th{border:1px solid var(--color-background-scale-f);padding:.5rem;vertical-align:top}.prose table tr:nth-child(2n),.prose-container table tr:nth-child(2n),.table tr:nth-child(2n){background-color:var(--color-background-scale-a)}.prose table th,.prose-container table th,.table th{background-color:var(--color-background-scale-c);font-weight:var(--font-weight-normal);letter-spacing:.1em;text-align:start}.prose table td>:last-child,.prose-container table td>:last-child,.table td>:last-child{margin-block-end:0}.ol,.prose ol,.prose ul,.prose-container ol,.prose-container ul,.ul{list-style-type:disc;padding-inline-start:1.25rem}.ol li ol,.ol li ul,.prose ol li ol,.prose ol li ul,.prose ul li ol,.prose ul li ul,.prose-container ol li ol,.prose-container ol li ul,.prose-container ul li ol,.prose-container ul li ul,.ul li ol,.ul li ul{padding-inline-start:2rem}.ol li:not(:last-child) ol:not(p+ol),.ol li:not(:last-child) ul:not(p+ul),.prose ol li:not(:last-child) ol:not(p+ol),.prose ol li:not(:last-child) ul:not(p+ul),.prose ul li:not(:last-child) ol:not(p+ol),.prose ul li:not(:last-child) ul:not(p+ul),.prose-container ol li:not(:last-child) ol:not(p+ol),.prose-container ol li:not(:last-child) ul:not(p+ul),.prose-container ul li:not(:last-child) ol:not(p+ol),.prose-container ul li:not(:last-child) ul:not(p+ul),.ul li:not(:last-child) ol:not(p+ol),.ul li:not(:last-child) ul:not(p+ul){margin-block-end:0}.ol,.prose ol,.prose-container ol{counter-reset:item;list-style-type:none}.ol>li,.prose ol>li,.prose-container ol>li{counter-increment:item}.ol>li::marker,.prose ol>li::marker,.prose-container ol>li::marker{content:counters(item,".") ". "}.img,.prose img,.prose-container img{border:2px solid var(--color-background-scale-e);border-radius:.25rem;margin-left:auto;margin-right:auto;max-height:450px;width:auto}.figure,.prose figure,.prose-container figure{display:table;margin-left:auto;margin-right:auto}.figure img,.prose figure img,.prose-container figure img{display:block;margin:0}.figure img:has(+figcaption),.prose figure img:has(+figcaption),.prose-container figure img:has(+figcaption){border-bottom-left-radius:0;border-bottom-right-radius:0}.figure figcaption,.prose figure figcaption,.prose-container figure figcaption{background-color:var(--color-background-scale-e);border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem;caption-side:bottom;display:table-caption;font-size:.85rem;padding:.5rem;text-align:center}.figure figcaption>*,.prose figure figcaption>*,.prose-container figure figcaption>*{font-size:.85rem}.figure figcaption>:last-child,.prose figure figcaption>:last-child,.prose-container figure figcaption>:last-child{margin-block-end:0}.blockquote,.prose blockquote,.prose-container blockquote{background-color:var(--color-background-scale-b);border-radius:.25rem;font-family:serif;font-size:1.1rem;padding:.25rem .75rem}.prose-numbering-2,.prose-numbering-3,.prose-numbering-4,.prose-numbering-5,.prose-numbering-6{counter-reset:l1}:where(.prose-numbering-2,.prose-numbering-3,.prose-numbering-4,.prose-numbering-5,.prose-numbering-6) h2{counter-reset:l2}:where(.prose-numbering-2,.prose-numbering-3,.prose-numbering-4,.prose-numbering-5,.prose-numbering-6) h2:before{content:counter(l1) ". ";counter-increment:l1}:where(.prose-numbering-3,.prose-numbering-4,.prose-numbering-5,.prose-numbering-6) h3{counter-reset:l3}:where(.prose-numbering-3,.prose-numbering-4,.prose-numbering-5,.prose-numbering-6) h3:before{content:counter(l1) "." counter(l2) ". ";counter-increment:l2}:where(.prose-numbering-4,.prose-numbering-5,.prose-numbering-6) h4{counter-reset:l4}:where(.prose-numbering-4,.prose-numbering-5,.prose-numbering-6) h4:before{content:counter(l1) "." counter(l2) "." counter(l3) ". ";counter-increment:l3}:where(.prose-numbering-5,.prose-numbering-6) h5{counter-reset:l5}:where(.prose-numbering-5,.prose-numbering-6) h5:before{content:counter(l1) "." counter(l2) "." counter(l3) "." counter(l4) ". ";counter-increment:l4}.prose-numbering-6 h6{counter-reset:l6}.prose-numbering-6 h6:before{content:counter(l1) "." counter(l2) "." counter(l3) "." counter(l4) "." counter(l5) ". ";counter-increment:l5}}
1
+ @utility prose-layout-container{margin-left:auto;margin-right:auto;max-width:var(--container-3xl);width:100%;&.sm{max-width:var(--container-md)}}@layer components{:root{--typo-h6:clamp(var(--text-base),2.500vw,1.2rem);--typo-h5:clamp(var(--typo-h6),3.000vw,1.44rem);--typo-h4:clamp(var(--typo-h5),3.600vw,1.728rem);--typo-h3:clamp(var(--typo-h4),4.320vw,2.0736rem);--typo-h2:clamp(var(--typo-h3),5.184vw,2.4883rem);--typo-h1:clamp(var(--typo-h2),6.221vw,2.986rem);--typo-h1-hero:clamp(var(--typo-h1),9.331vw,4.479rem);--typo-p-hero:clamp(1.25rem,3.125vw,1.5rem);--extra-scroll-margin:0px}.font-variant-small-caps{font-variant:small-caps}.icon-inline{align-items:center;display:inline-flex}.icon-inline:before{content:"​";display:block}.prose-container{@apply prose-layout-container}.prose-container:where(:not(.prose+.prose-container,.prose-container+.prose-container))>:first-child,.prose-container:where(:not(.prose+.prose-container,.prose-container+.prose-container))>:first-child>:first-child,.prose:where(:not(.prose+.prose,.prose-container+.prose))>:first-child,.prose:where(:not(.prose+.prose,.prose-container+.prose))>:first-child>:first-child{margin-block-start:0}.prose-container>:last-child,.prose-container>:last-child>:last-child,.prose>:last-child,.prose>:last-child>:last-child{margin-block-end:0}:where(.h1,.h2,.h3,.h4,.h5,.h6).prose,:where(.prose-container,.prose) :where(h1,h2,h3,h4,h5,h6){margin-block-end:.4lh;margin-block-start:.9lh;scroll-margin-block-start:calc(--spacing(6) + var(--extra-scroll-margin, 0px));text-wrap:pretty}:where(.p,.pre,.table,.ol,.ul,.img,.figure,.blockquote).prose,:where(.prose-container,.prose) :where(p,pre,table,ol,ul,img,figure,blockquote){margin-block-end:1lh;text-wrap:pretty}:where(.prose-container,.prose) hr+*{margin-block-start:0}:where(.prose-container,.prose) :has(+hr){margin-block-end:0}.hr,.prose hr,.prose-container hr{border-color:var(--color-global-background-accent);margin-block-end:1lh;margin-block-start:1lh}.h1,.prose h1,.prose-container h1{color:color-mix(in srgb-linear,var(--custom-accent-color) 40%,currentColor);font-size:var(--typo-h1);letter-spacing:.0025em;line-height:1.125}.h1.hero,.prose h1.hero,.prose-container h1.hero{font-size:var(--typo-h1-hero);line-height:1}.h2,.prose h2,.prose-container h2{font-size:var(--typo-h2);font-weight:var(--font-weight-extralight);letter-spacing:.0108em;line-height:1.1765}.h3,.prose h3,.prose-container h3{font-size:var(--typo-h3);font-weight:var(--font-weight-extralight);letter-spacing:.022em;line-height:1.2}.h4,.prose h4,.prose-container h4{font-size:var(--typo-h4);letter-spacing:.035em;line-height:1.25}.h5,.prose h5,.prose-container h5{font-size:var(--typo-h5);letter-spacing:.0532em;line-height:1.28}.h6,.prose h6,.prose-container h6{font-size:var(--typo-h6);letter-spacing:.0532em;line-height:1.28}.p,.prose p,.prose-container p{font-size:1rem;letter-spacing:.03em;line-height:1.5}.p.hero,.prose p.hero,.prose-container p.hero{font-size:var(--typo-p-hero);line-height:1.3}.note{color:var(--color-foreground-scale-g);font-size:.95rem!important;letter-spacing:.05rem!important;line-height:1.5!important}.code,.pre,.prose code,.prose pre,.prose-container code,.prose-container pre{border-radius:.25rem;color:var(--color-foreground-scale-e);font-family:monospace;font-size:.9rem;font-weight:bolder;outline:dashed 2px var(--color-background-scale-g);outline-offset:-2px;padding:.2rem .25rem;transition:color,outline-color;transition-duration:.15s}.code:hover,.pre:hover,.prose code:hover,.prose pre:hover,.prose-container code:hover,.prose-container pre:hover{color:var(--color-global-foreground)}.pre,.prose pre,.prose-container pre{padding:.5rem .75rem}.prose table,.prose-container table,.table{border-collapse:collapse}.prose table td,.prose table th,.prose-container table td,.prose-container table th,.table td,.table th{border:1px solid var(--color-background-scale-f);padding:.5rem;vertical-align:top}.prose table tr:nth-child(2n),.prose-container table tr:nth-child(2n),.table tr:nth-child(2n){background-color:var(--color-background-scale-a)}.prose table th,.prose-container table th,.table th{background-color:var(--color-background-scale-c);font-weight:var(--font-weight-normal);letter-spacing:.1em;text-align:start}.prose table td>:last-child,.prose-container table td>:last-child,.table td>:last-child{margin-block-end:0}.ol,.prose ol,.prose ul,.prose-container ol,.prose-container ul,.ul{list-style-type:disc;padding-inline-start:1.25rem}.ol li ol,.ol li ul,.prose ol li ol,.prose ol li ul,.prose ul li ol,.prose ul li ul,.prose-container ol li ol,.prose-container ol li ul,.prose-container ul li ol,.prose-container ul li ul,.ul li ol,.ul li ul{padding-inline-start:2rem}.ol li:not(:last-child) ol:not(p+ol),.ol li:not(:last-child) ul:not(p+ul),.prose ol li:not(:last-child) ol:not(p+ol),.prose ol li:not(:last-child) ul:not(p+ul),.prose ul li:not(:last-child) ol:not(p+ol),.prose ul li:not(:last-child) ul:not(p+ul),.prose-container ol li:not(:last-child) ol:not(p+ol),.prose-container ol li:not(:last-child) ul:not(p+ul),.prose-container ul li:not(:last-child) ol:not(p+ol),.prose-container ul li:not(:last-child) ul:not(p+ul),.ul li:not(:last-child) ol:not(p+ol),.ul li:not(:last-child) ul:not(p+ul){margin-block-end:0}.ol,.prose ol,.prose-container ol{counter-reset:item;list-style-type:none}.ol>li,.prose ol>li,.prose-container ol>li{counter-increment:item}.ol>li::marker,.prose ol>li::marker,.prose-container ol>li::marker{content:counters(item,".") ". "}.img,.prose img,.prose-container img{border:2px solid var(--color-background-scale-e);border-radius:.25rem;margin-left:auto;margin-right:auto;max-height:450px;width:auto}.figure,.prose figure,.prose-container figure{display:table;margin-left:auto;margin-right:auto}.figure img,.prose figure img,.prose-container figure img{display:block;margin:0}.figure img:has(+figcaption),.prose figure img:has(+figcaption),.prose-container figure img:has(+figcaption){border-bottom-left-radius:0;border-bottom-right-radius:0}.figure figcaption,.prose figure figcaption,.prose-container figure figcaption{background-color:var(--color-background-scale-e);border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem;caption-side:bottom;display:table-caption;font-size:.85rem;padding:.5rem;text-align:center}.figure figcaption>*,.prose figure figcaption>*,.prose-container figure figcaption>*{font-size:.85rem}.figure figcaption>:last-child,.prose figure figcaption>:last-child,.prose-container figure figcaption>:last-child{margin-block-end:0}.blockquote,.prose blockquote,.prose-container blockquote{background-color:var(--color-background-scale-b);border-radius:.25rem;font-family:serif;font-size:1.1rem;padding:.25rem .75rem}.prose-numbering-2,.prose-numbering-3,.prose-numbering-4,.prose-numbering-5,.prose-numbering-6{counter-reset:l1}:where(.prose-numbering-2,.prose-numbering-3,.prose-numbering-4,.prose-numbering-5,.prose-numbering-6) h2{counter-reset:l2}:where(.prose-numbering-2,.prose-numbering-3,.prose-numbering-4,.prose-numbering-5,.prose-numbering-6) h2:before{content:counter(l1) ". ";counter-increment:l1}:where(.prose-numbering-3,.prose-numbering-4,.prose-numbering-5,.prose-numbering-6) h3{counter-reset:l3}:where(.prose-numbering-3,.prose-numbering-4,.prose-numbering-5,.prose-numbering-6) h3:before{content:counter(l1) "." counter(l2) ". ";counter-increment:l2}:where(.prose-numbering-4,.prose-numbering-5,.prose-numbering-6) h4{counter-reset:l4}:where(.prose-numbering-4,.prose-numbering-5,.prose-numbering-6) h4:before{content:counter(l1) "." counter(l2) "." counter(l3) ". ";counter-increment:l3}:where(.prose-numbering-5,.prose-numbering-6) h5{counter-reset:l5}:where(.prose-numbering-5,.prose-numbering-6) h5:before{content:counter(l1) "." counter(l2) "." counter(l3) "." counter(l4) ". ";counter-increment:l4}.prose-numbering-6 h6{counter-reset:l6}.prose-numbering-6 h6:before{content:counter(l1) "." counter(l2) "." counter(l3) "." counter(l4) "." counter(l5) ". ";counter-increment:l5}}
@@ -1 +1 @@
1
- @import "./brand/anchor.css";@import "./brand/application.css";@import "./brand/button.css";@import "./brand/form.css";@import "./brand/gradient.css";@import "./brand/menu.css";@import "./brand/mobile.css";@import "./brand/status.css";@import "./brand/theme.css";@import "./brand/tooltip.css";@import "./brand/transition.css";@import "./brand/typography.css";@import "./brand/utilities.css";
1
+ @import "./brand/anchor.css";@import "./brand/application.css";@import "./brand/button.css";@import "./brand/form.css";@import "./brand/gradient.css";@import "./brand/image.css";@import "./brand/menu.css";@import "./brand/mobile.css";@import "./brand/status.css";@import "./brand/theme.css";@import "./brand/tooltip.css";@import "./brand/transition.css";@import "./brand/typography.css";@import "./brand/utilities.css";
@@ -9,6 +9,7 @@ export type FormValues = Record<string, any>;
9
9
  * injected into descendent components.
10
10
  */
11
11
  export interface FormInstance {
12
+ formUid: string | undefined;
12
13
  hasSubmitted: Ref<boolean>;
13
14
  isSubmitting: Ref<boolean>;
14
15
  isDisabled: Ref<boolean>;
@@ -13,21 +13,21 @@ export declare const FormSymbol: InjectionKey<FormInstance>;
13
13
  *
14
14
  * @private
15
15
  */
16
- export declare function createFormInstance(): FormInstance;
16
+ export declare function createFormInstance(uid?: string): FormInstance;
17
17
  /**
18
18
  * Provides the object that a Form uses to convey stateful information to the
19
19
  * DI registry. You shouldn't ever need to use this directly.
20
20
  *
21
21
  * @private
22
22
  */
23
- export declare function provideFormInstance(): FormInstance;
23
+ export declare function provideFormInstance(uid?: string): FormInstance;
24
24
  /**
25
25
  * Injects the stateful object provided by an ancestor Form instance. If not
26
26
  * available, a dummy state object is generated.
27
27
  *
28
28
  * @private
29
29
  */
30
- export declare function injectFormInstance(): FormInstance;
30
+ export declare function injectFormInstance(uid?: string): FormInstance;
31
31
  /**
32
32
  * Takes a Primevue Form's `states` object, and extracts the current values
33
33
  * of each named property. In doing so, it will deref proxies, and create
@@ -4,20 +4,21 @@ import { isObjectLike } from "@resee-movies/utilities/objects/is-object-like";
4
4
  import { isString } from "@resee-movies/utilities/strings/is-string";
5
5
  import { computed, inject, provide, ref, toRaw, toValue } from "vue";
6
6
  export const FormSymbol = Symbol("form");
7
- export function createFormInstance() {
7
+ export function createFormInstance(uid) {
8
8
  return {
9
+ formUid: uid,
9
10
  hasSubmitted: ref(false),
10
11
  isSubmitting: ref(false),
11
12
  isDisabled: ref(false)
12
13
  };
13
14
  }
14
- export function provideFormInstance() {
15
- const instance = createFormInstance();
15
+ export function provideFormInstance(uid) {
16
+ const instance = createFormInstance(uid);
16
17
  provide(FormSymbol, instance);
17
18
  return instance;
18
19
  }
19
- export function injectFormInstance() {
20
- return inject(FormSymbol, () => createFormInstance(), true);
20
+ export function injectFormInstance(uid) {
21
+ return inject(FormSymbol, () => createFormInstance(uid), true);
21
22
  }
22
23
  export function getValuesFromFormState(state) {
23
24
  const result = {};
@@ -0,0 +1,14 @@
1
+ import type { RouteLocationGeneric } from 'vue-router';
2
+ /**
3
+ * Strictly compare the entirety of two URLs, including their hashes.
4
+ *
5
+ * This is required for two reasons:
6
+ *
7
+ * 1) NuxtLink does not provide equivalent results when parsing `:to` and `:href`
8
+ * props (the value of a URL's `hash` will appear in the `fullPath` of the former,
9
+ * but not the latter).
10
+ * 2) NuxtLink does not take into account the value of `hash` when computing whether
11
+ * a link is active. This makes sense for a lot of circumstances, but in some cases
12
+ * is required.
13
+ */
14
+ export declare function areRoutesStrictEqual(routeA: RouteLocationGeneric | undefined, routeB: RouteLocationGeneric | undefined): boolean;
@@ -0,0 +1,14 @@
1
+ export function areRoutesStrictEqual(routeA, routeB) {
2
+ if (!(routeA && routeB)) {
3
+ return false;
4
+ }
5
+ let fullPathA = routeA.fullPath;
6
+ let fullPathB = routeB.fullPath;
7
+ if (routeA.hash && !fullPathA.endsWith(routeA.hash)) {
8
+ fullPathA += routeA.hash;
9
+ }
10
+ if (routeB.hash && !fullPathB.endsWith(routeB.hash)) {
11
+ fullPathB += routeB.hash;
12
+ }
13
+ return fullPathA === fullPathB;
14
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@resee-movies/nuxt-ux",
3
- "version": "0.16.0",
3
+ "version": "0.18.0",
4
4
  "description": "The next-gen user experience library for ReSee Movies - currently in development. ",
5
5
  "repository": {
6
6
  "url": "https://github.com/ReSee-Movies/nuxt-ux.git"
@@ -35,7 +35,7 @@
35
35
  "dist"
36
36
  ],
37
37
  "scripts": {
38
- "dev": "npm run dev:prepare && nuxi dev playground --local --port 3003",
38
+ "dev": "npm run dev:prepare && nuxi dev playground --port 3003 --public",
39
39
  "dev:preview": "npm run dev:build && nuxi preview playground --port 3003",
40
40
  "dev:build": "nuxi build playground",
41
41
  "dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
@@ -72,19 +72,19 @@
72
72
  "dependencies": {
73
73
  "@egoist/tailwindcss-icons": "^1.9.0",
74
74
  "@iconify-json/ph": "^1.2.2",
75
- "@iconify-json/simple-icons": "^1.2.61",
75
+ "@iconify-json/simple-icons": "^1.2.65",
76
76
  "@iconify-json/solar": "^1.2.5",
77
77
  "@nuxt/fonts": "^0.12.1",
78
78
  "@nuxtjs/device": "^4.0.0",
79
79
  "@primeuix/utils": "^0.6.1",
80
- "@primevue/forms": "^4.5.1",
81
- "@primevue/nuxt-module": "^4.5.1",
80
+ "@primevue/forms": "^4.5.4",
81
+ "@primevue/nuxt-module": "^4.5.4",
82
82
  "@resee-movies/utilities": "^0.11.0",
83
- "@tailwindcss/postcss": "^4.1.17",
84
- "@tailwindcss/vite": "^4.1.17",
83
+ "@tailwindcss/postcss": "^4.1.18",
84
+ "@tailwindcss/vite": "^4.1.18",
85
85
  "@vueuse/core": "^14.1.0",
86
- "primevue": "^4.5.1",
87
- "tailwindcss": "^4.1.17",
88
- "zod": "^4.1.13"
86
+ "primevue": "^4.5.4",
87
+ "tailwindcss": "^4.1.18",
88
+ "zod": "^4.3.5"
89
89
  }
90
90
  }