@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.
- package/dist/module.json +1 -1
- package/dist/runtime/components/GlobalHeader.vue +45 -13
- package/dist/runtime/components/GlobalHeader.vue.d.ts +10 -0
- package/dist/runtime/components/GlobalHeaderAnnouncement.vue +1 -1
- package/dist/runtime/components/ImageTiler.vue +193 -0
- package/dist/runtime/components/ImageTiler.vue.d.ts +31 -0
- package/dist/runtime/components/InlineStatsList.vue +33 -0
- package/dist/runtime/components/InlineStatsList.vue.d.ts +15 -0
- package/dist/runtime/components/InlineStatsListItem.vue +39 -0
- package/dist/runtime/components/InlineStatsListItem.vue.d.ts +19 -0
- package/dist/runtime/components/TableOfContents.vue +56 -0
- package/dist/runtime/components/TableOfContents.vue.d.ts +15 -0
- package/dist/runtime/components/form/Form.vue +4 -2
- package/dist/runtime/components/form/FormField.vue +7 -7
- package/dist/runtime/components/form/FormFieldTurnstile.vue +2 -1
- package/dist/runtime/components/form/element/FormElementTurnstile.vue +2 -1
- package/dist/runtime/components/form/element/FormElementTurnstile.vue.d.ts +1 -0
- package/dist/runtime/composables/use-global-header-state.d.ts +52 -1
- package/dist/runtime/composables/use-global-header-state.js +22 -2
- package/dist/runtime/composables/use-resee-window-scroll.d.ts +18 -0
- package/dist/runtime/composables/use-resee-window-scroll.js +65 -0
- package/dist/runtime/composables/use-settings-for-breakpoint.d.ts +11 -0
- package/dist/runtime/composables/use-settings-for-breakpoint.js +25 -0
- package/dist/runtime/composables/use-url-hash.d.ts +43 -0
- package/dist/runtime/composables/use-url-hash.js +25 -0
- package/dist/runtime/theme/css/brand/application.css +1 -1
- package/dist/runtime/theme/css/brand/image.css +1 -0
- package/dist/runtime/theme/css/brand/typography.css +1 -1
- package/dist/runtime/theme/css/styles.css +1 -1
- package/dist/runtime/types/form.d.ts +1 -0
- package/dist/runtime/utils/form.d.ts +3 -3
- package/dist/runtime/utils/form.js +6 -5
- package/dist/runtime/utils/routing.d.ts +14 -0
- package/dist/runtime/utils/routing.js +14 -0
- package/package.json +10 -10
package/dist/module.json
CHANGED
|
@@ -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="
|
|
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 {
|
|
36
|
-
import {
|
|
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 {
|
|
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
|
|
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
|
|
46
|
-
:on-change = "$field.props
|
|
47
|
-
:on-input = "$field.props
|
|
48
|
-
:on-invalid = "$field.props
|
|
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 =
|
|
91
|
-
const labelId = `${
|
|
92
|
-
const messageId = `${
|
|
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
|
-
|
|
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
|
|
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";
|
|
@@ -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.
|
|
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 --
|
|
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.
|
|
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.
|
|
81
|
-
"@primevue/nuxt-module": "^4.5.
|
|
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.
|
|
84
|
-
"@tailwindcss/vite": "^4.1.
|
|
83
|
+
"@tailwindcss/postcss": "^4.1.18",
|
|
84
|
+
"@tailwindcss/vite": "^4.1.18",
|
|
85
85
|
"@vueuse/core": "^14.1.0",
|
|
86
|
-
"primevue": "^4.5.
|
|
87
|
-
"tailwindcss": "^4.1.
|
|
88
|
-
"zod": "^4.
|
|
86
|
+
"primevue": "^4.5.4",
|
|
87
|
+
"tailwindcss": "^4.1.18",
|
|
88
|
+
"zod": "^4.3.5"
|
|
89
89
|
}
|
|
90
90
|
}
|