@leavepulse/ui 0.93.1 → 0.93.3
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/assets/{LpTable-gpdZSVMX.css → LpTable-DxnthVz4.css} +30 -30
- package/dist/chunks/{LpMediaGallery-B7DOV_aL.js → LpMediaGallery-CtWA5Uab.js} +35 -14
- package/dist/components/LpMediaGallery.vue.d.ts +2 -0
- package/dist/components/LpMediaGallery.vue.js +1 -1
- package/dist/components/LpTable.vue.js +22 -5
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/components/LpMediaGallery.vue +44 -11
- package/src/components/LpTable.vue +15 -1
|
@@ -6,28 +6,28 @@
|
|
|
6
6
|
* outside and only the dots between facts are seen. A cell whose slot drew
|
|
7
7
|
* nothing (a v-if that failed, an empty value) is left out, dot and all.
|
|
8
8
|
*/
|
|
9
|
-
.lp-line[data-v-
|
|
9
|
+
.lp-line[data-v-a346ca36] {
|
|
10
10
|
--lp-line-sep: 1rem;
|
|
11
11
|
}
|
|
12
|
-
.lp-line-row[data-v-
|
|
12
|
+
.lp-line-row[data-v-a346ca36] {
|
|
13
13
|
margin-left: calc(-1 * var(--lp-line-sep));
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
/* The dot lives in the field's own left padding, so whatever the cell draws,
|
|
17
17
|
a word or a block of two lines, starts after it and never in the clipped
|
|
18
18
|
strip. */
|
|
19
|
-
.lp-line-field[data-v-
|
|
19
|
+
.lp-line-field[data-v-a346ca36] {
|
|
20
20
|
position: relative;
|
|
21
21
|
padding-left: var(--lp-line-sep);
|
|
22
22
|
}
|
|
23
|
-
.lp-line-field[data-v-
|
|
23
|
+
.lp-line-field[data-v-a346ca36]::before {
|
|
24
24
|
content: "·" / "";
|
|
25
25
|
position: absolute;
|
|
26
26
|
left: 0;
|
|
27
27
|
width: var(--lp-line-sep);
|
|
28
28
|
text-align: center;
|
|
29
29
|
}
|
|
30
|
-
.lp-line-field[data-v-
|
|
30
|
+
.lp-line-field[data-v-a346ca36]:has(> .lp-line-value:empty) {
|
|
31
31
|
display: none;
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -43,17 +43,17 @@
|
|
|
43
43
|
* fade before closing the gap and the whole list lurches at the end instead of
|
|
44
44
|
* gliding.
|
|
45
45
|
*/
|
|
46
|
-
.lp-row-enter-active[data-v-
|
|
47
|
-
.lp-row-leave-active[data-v-
|
|
46
|
+
.lp-row-enter-active[data-v-a346ca36],
|
|
47
|
+
.lp-row-leave-active[data-v-a346ca36] {
|
|
48
48
|
transition:
|
|
49
49
|
opacity var(--duration-fast) var(--ease-emphasized),
|
|
50
50
|
transform var(--duration-fast) var(--ease-emphasized);
|
|
51
51
|
}
|
|
52
|
-
.lp-row-move[data-v-
|
|
52
|
+
.lp-row-move[data-v-a346ca36] {
|
|
53
53
|
transition: transform var(--duration-medium) var(--ease-emphasized);
|
|
54
54
|
}
|
|
55
|
-
.lp-row-enter-from[data-v-
|
|
56
|
-
.lp-row-leave-to[data-v-
|
|
55
|
+
.lp-row-enter-from[data-v-a346ca36],
|
|
56
|
+
.lp-row-leave-to[data-v-a346ca36] {
|
|
57
57
|
opacity: 0;
|
|
58
58
|
transform: translateX(-0.5rem);
|
|
59
59
|
}
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
* drops out of the table layout entirely. Nothing sits below this row to be
|
|
68
68
|
* dragged around, so simply not animating its exit costs nothing.
|
|
69
69
|
*/
|
|
70
|
-
.lp-row-empty.lp-row-leave-active[data-v-
|
|
70
|
+
.lp-row-empty.lp-row-leave-active[data-v-a346ca36] {
|
|
71
71
|
display: none;
|
|
72
72
|
}
|
|
73
73
|
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
* once anything is selected. An earlier version collapsed the column to nothing
|
|
87
87
|
* and floated the hover box over the first cell, where it sat on the text.
|
|
88
88
|
*/
|
|
89
|
-
.lp-tick[data-v-
|
|
89
|
+
.lp-tick[data-v-a346ca36] {
|
|
90
90
|
display: flex;
|
|
91
91
|
align-items: center;
|
|
92
92
|
max-width: 0;
|
|
@@ -98,17 +98,17 @@
|
|
|
98
98
|
padding var(--duration-medium) var(--ease-emphasized),
|
|
99
99
|
opacity var(--duration-fast) ease;
|
|
100
100
|
}
|
|
101
|
-
.lp-tick-open[data-v-
|
|
101
|
+
.lp-tick-open[data-v-a346ca36] {
|
|
102
102
|
max-width: 3.25rem;
|
|
103
103
|
padding-inline: 1rem;
|
|
104
104
|
opacity: 1;
|
|
105
105
|
}
|
|
106
|
-
.lp-tick-hidden[data-v-
|
|
107
|
-
.lp-tick-cue[data-v-
|
|
106
|
+
.lp-tick-hidden[data-v-a346ca36],
|
|
107
|
+
.lp-tick-cue[data-v-a346ca36] {
|
|
108
108
|
opacity: 0;
|
|
109
109
|
}
|
|
110
|
-
tr:hover .lp-tick-cue[data-v-
|
|
111
|
-
.lp-tick-cue[data-v-
|
|
110
|
+
tr:hover .lp-tick-cue[data-v-a346ca36],
|
|
111
|
+
.lp-tick-cue[data-v-a346ca36]:focus-within {
|
|
112
112
|
opacity: 1;
|
|
113
113
|
}
|
|
114
114
|
|
|
@@ -116,15 +116,15 @@ tr:hover .lp-tick-cue[data-v-5ac91b9e],
|
|
|
116
116
|
turned down the rows change without animating rather than not changing. */
|
|
117
117
|
/* Only where there is a hover to reveal it; a finger long-presses instead. */
|
|
118
118
|
@media (hover: none) {
|
|
119
|
-
tr:hover .lp-tick-cue[data-v-
|
|
119
|
+
tr:hover .lp-tick-cue[data-v-a346ca36] {
|
|
120
120
|
opacity: 0;
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
/* Nor is there anything for the column's width to hold until then: on a
|
|
124
124
|
touch screen it stays closed until a long press starts selecting, and
|
|
125
125
|
eases open like the rest of the column. */
|
|
126
|
-
.lp-tick-hidden[data-v-
|
|
127
|
-
.lp-tick-cue[data-v-
|
|
126
|
+
.lp-tick-hidden[data-v-a346ca36],
|
|
127
|
+
.lp-tick-cue[data-v-a346ca36] {
|
|
128
128
|
max-width: 0;
|
|
129
129
|
padding-inline: 0;
|
|
130
130
|
}
|
|
@@ -134,7 +134,7 @@ tr:hover .lp-tick-cue[data-v-5ac91b9e] {
|
|
|
134
134
|
* A list line's tick opens from nothing, as the table's column does, so lines
|
|
135
135
|
* do not carry an empty gap until selection starts.
|
|
136
136
|
*/
|
|
137
|
-
.lp-tick-line[data-v-
|
|
137
|
+
.lp-tick-line[data-v-a346ca36] {
|
|
138
138
|
max-width: 2rem;
|
|
139
139
|
opacity: 1;
|
|
140
140
|
}
|
|
@@ -144,28 +144,28 @@ tr:hover .lp-tick-cue[data-v-5ac91b9e] {
|
|
|
144
144
|
* open; a cue shows it only while
|
|
145
145
|
* the card is pointed at or holds focus, the same rule as a row's.
|
|
146
146
|
*/
|
|
147
|
-
.lp-tick-card[data-v-
|
|
147
|
+
.lp-tick-card[data-v-a346ca36] {
|
|
148
148
|
max-width: none;
|
|
149
149
|
padding-inline: 0;
|
|
150
150
|
opacity: 1;
|
|
151
151
|
}
|
|
152
|
-
.lp-tick[data-cue][data-v-
|
|
152
|
+
.lp-tick[data-cue][data-v-a346ca36] {
|
|
153
153
|
opacity: 0;
|
|
154
154
|
}
|
|
155
|
-
.lp-item:hover .lp-tick[data-cue][data-v-
|
|
156
|
-
.lp-tick[data-cue][data-v-
|
|
155
|
+
.lp-item:hover .lp-tick[data-cue][data-v-a346ca36],
|
|
156
|
+
.lp-tick[data-cue][data-v-a346ca36]:focus-within {
|
|
157
157
|
opacity: 1;
|
|
158
158
|
}
|
|
159
159
|
@media (hover: none) {
|
|
160
|
-
.lp-item:hover .lp-tick[data-cue][data-v-
|
|
160
|
+
.lp-item:hover .lp-tick[data-cue][data-v-a346ca36] {
|
|
161
161
|
opacity: 0;
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
164
|
@media (prefers-reduced-motion: reduce) {
|
|
165
|
-
.lp-row-enter-active[data-v-
|
|
166
|
-
.lp-row-leave-active[data-v-
|
|
167
|
-
.lp-row-move[data-v-
|
|
168
|
-
.lp-tick[data-v-
|
|
165
|
+
.lp-row-enter-active[data-v-a346ca36],
|
|
166
|
+
.lp-row-leave-active[data-v-a346ca36],
|
|
167
|
+
.lp-row-move[data-v-a346ca36],
|
|
168
|
+
.lp-tick[data-v-a346ca36] {
|
|
169
169
|
transition: none;
|
|
170
170
|
}
|
|
171
171
|
}
|
|
@@ -9,7 +9,7 @@ import { _ as _sfc_main$2 } from "./VideoThumb-BfDkIXqE.js";
|
|
|
9
9
|
const _hoisted_1 = { key: 0 };
|
|
10
10
|
const _hoisted_2 = ["aria-label"];
|
|
11
11
|
const _hoisted_3 = ["aria-label", "onClick"];
|
|
12
|
-
const _hoisted_4 = ["src", "alt"];
|
|
12
|
+
const _hoisted_4 = ["src", "alt", "onError"];
|
|
13
13
|
const _hoisted_5 = {
|
|
14
14
|
key: 0,
|
|
15
15
|
class: "pointer-events-none absolute inset-0 flex items-center justify-center"
|
|
@@ -39,7 +39,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
39
39
|
itemMenu: {},
|
|
40
40
|
labels: {}
|
|
41
41
|
},
|
|
42
|
-
emits: ["select", "reveal", "update:open"],
|
|
42
|
+
emits: ["select", "reveal", "broken", "update:open"],
|
|
43
43
|
setup(__props, { expose: __expose, emit: __emit }) {
|
|
44
44
|
const DEFAULT_LABELS = {
|
|
45
45
|
/** Accessible name of the grid. */
|
|
@@ -60,7 +60,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
60
60
|
}
|
|
61
61
|
function menuTitle(item, i) {
|
|
62
62
|
if (isHidden(item)) return text.value.spoiler;
|
|
63
|
-
return item.title || fill(text.value.image, i + 1,
|
|
63
|
+
return item.title || fill(text.value.image, i + 1, shown.value.length);
|
|
64
64
|
}
|
|
65
65
|
const emit = __emit;
|
|
66
66
|
const open = ref(false);
|
|
@@ -68,10 +68,27 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
68
68
|
watch(open, (value, was) => {
|
|
69
69
|
if (!value && was) emit("update:open", false);
|
|
70
70
|
});
|
|
71
|
+
const fellBack = ref(/* @__PURE__ */ new Set());
|
|
72
|
+
const broken = ref(/* @__PURE__ */ new Set());
|
|
73
|
+
const shown = computed(
|
|
74
|
+
() => broken.value.size ? props.items.filter((item) => !broken.value.has(item.src)) : props.items
|
|
75
|
+
);
|
|
76
|
+
function thumbOf(item) {
|
|
77
|
+
return item.thumb && !fellBack.value.has(item.src) ? item.thumb : item.src;
|
|
78
|
+
}
|
|
79
|
+
function onImageError(item) {
|
|
80
|
+
if (item.thumb && item.thumb !== item.src && !fellBack.value.has(item.src)) {
|
|
81
|
+
fellBack.value = new Set(fellBack.value).add(item.src);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (broken.value.has(item.src)) return;
|
|
85
|
+
broken.value = new Set(broken.value).add(item.src);
|
|
86
|
+
emit("broken", item);
|
|
87
|
+
}
|
|
71
88
|
const visible = computed(
|
|
72
|
-
() => props.max &&
|
|
89
|
+
() => props.max && shown.value.length > props.max ? shown.value.slice(0, props.max) : shown.value
|
|
73
90
|
);
|
|
74
|
-
const hiddenCount = computed(() => Math.max(
|
|
91
|
+
const hiddenCount = computed(() => Math.max(shown.value.length - visible.value.length, 0));
|
|
75
92
|
const COLS = {
|
|
76
93
|
1: "grid-cols-1",
|
|
77
94
|
2: "grid-cols-2",
|
|
@@ -141,9 +158,9 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
141
158
|
() => ["grid", columnClass.value, GAPS[props.gap] ?? GAPS[2]].join(" ")
|
|
142
159
|
);
|
|
143
160
|
function activate(i) {
|
|
144
|
-
const item =
|
|
161
|
+
const item = shown.value[i];
|
|
145
162
|
if (!item) return;
|
|
146
|
-
emit("select", item,
|
|
163
|
+
emit("select", item, props.items.indexOf(item));
|
|
147
164
|
if (!props.openable) return;
|
|
148
165
|
const at = openIndexOf(i);
|
|
149
166
|
if (at === -1) return;
|
|
@@ -162,14 +179,17 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
162
179
|
revealed.value = new Set(revealed.value).add(item.src);
|
|
163
180
|
emit("reveal", item);
|
|
164
181
|
}
|
|
165
|
-
const openItems = computed(() =>
|
|
182
|
+
const openItems = computed(() => shown.value.filter((item) => !isHidden(item)));
|
|
166
183
|
function openIndexOf(i) {
|
|
167
|
-
const item =
|
|
184
|
+
const item = shown.value[i];
|
|
168
185
|
return item ? openItems.value.indexOf(item) : -1;
|
|
169
186
|
}
|
|
170
187
|
__expose({
|
|
171
188
|
/** Open the lightbox at an index — for a "view all" button outside the grid. */
|
|
172
|
-
openAt: (i) =>
|
|
189
|
+
openAt: (i) => {
|
|
190
|
+
const item = props.items[i];
|
|
191
|
+
if (item) activate(shown.value.indexOf(item));
|
|
192
|
+
},
|
|
173
193
|
/** Uncover every spoiler in the set. */
|
|
174
194
|
revealAll: () => {
|
|
175
195
|
const next = new Set(revealed.value);
|
|
@@ -178,7 +198,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
178
198
|
}
|
|
179
199
|
});
|
|
180
200
|
return (_ctx, _cache) => {
|
|
181
|
-
return !
|
|
201
|
+
return !shown.value.length ? (openBlock(), createElementBlock("div", _hoisted_1, [
|
|
182
202
|
renderSlot(_ctx.$slots, "empty")
|
|
183
203
|
])) : (openBlock(), createElementBlock("div", mergeProps({
|
|
184
204
|
key: 1,
|
|
@@ -191,7 +211,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
191
211
|
key: item.src + i,
|
|
192
212
|
items: __props.itemMenu?.(item, i) ?? [],
|
|
193
213
|
title: menuTitle(item, i),
|
|
194
|
-
"title-image": isHidden(item) ? void 0 : unref(isVideoItem)(item) ? item.poster ?? item.thumb : item
|
|
214
|
+
"title-image": isHidden(item) ? void 0 : unref(isVideoItem)(item) ? item.poster ?? item.thumb : thumbOf(item),
|
|
195
215
|
subtitle: isHidden(item) ? void 0 : item.description
|
|
196
216
|
}, {
|
|
197
217
|
default: withCtx(() => [
|
|
@@ -221,15 +241,16 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
221
241
|
]
|
|
222
242
|
}, null, 8, ["item", "alt", "media-class"])) : (openBlock(), createElementBlock("img", {
|
|
223
243
|
key: 1,
|
|
224
|
-
src: item
|
|
244
|
+
src: thumbOf(item),
|
|
225
245
|
alt: isHidden(item) ? "" : item.title || "",
|
|
226
246
|
loading: "lazy",
|
|
227
247
|
decoding: "async",
|
|
248
|
+
onError: ($event) => onImageError(item),
|
|
228
249
|
class: normalizeClass(["size-full object-cover transition-transform duration-[var(--duration-medium)] ease-[var(--ease-emphasized)] group-hover:scale-[1.03] motion-reduce:transition-none motion-reduce:group-hover:scale-100", [
|
|
229
250
|
isHidden(item) ? "scale-[1.12] blur-[18px] brightness-[0.6] saturate-[1.1] group-hover:scale-[1.12]" : "",
|
|
230
251
|
!isHidden(item) && hiddenCount.value && i === visible.value.length - 1 ? "scale-[1.06] blur-[2px] brightness-[0.45] group-hover:scale-[1.06]" : ""
|
|
231
252
|
]])
|
|
232
|
-
}, null,
|
|
253
|
+
}, null, 42, _hoisted_4))
|
|
233
254
|
]),
|
|
234
255
|
isHidden(item) ? (openBlock(), createElementBlock("span", _hoisted_5, [
|
|
235
256
|
createElementVNode("span", _hoisted_6, toDisplayString(unref(text).spoiler), 1)
|
|
@@ -67,10 +67,12 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
|
|
|
67
67
|
select: (item: LightboxItem, index: number) => any;
|
|
68
68
|
reveal: (item: LightboxItem) => any;
|
|
69
69
|
"update:open": (value: boolean) => any;
|
|
70
|
+
broken: (item: LightboxItem) => any;
|
|
70
71
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
71
72
|
onSelect?: ((item: LightboxItem, index: number) => any) | undefined;
|
|
72
73
|
onReveal?: ((item: LightboxItem) => any) | undefined;
|
|
73
74
|
"onUpdate:open"?: ((value: boolean) => any) | undefined;
|
|
75
|
+
onBroken?: ((item: LightboxItem) => any) | undefined;
|
|
74
76
|
}>, {
|
|
75
77
|
columns: number | {
|
|
76
78
|
base?: number;
|
|
@@ -34,7 +34,7 @@ import { toCsv, downloadFile, fileStem } from "./exportData.js";
|
|
|
34
34
|
import { toHiddenSets, sameHidden, summarizeShown, parseTableState, mergeRestored, serializeTableState, fromHiddenSets } from "./tableFilter.js";
|
|
35
35
|
import { resolveRowMenu } from "./tableRowMenu.js";
|
|
36
36
|
import { _ as _export_sfc } from "../chunks/_plugin-vue_export-helper-1tPrXgE0.js";
|
|
37
|
-
import '../assets/LpTable-
|
|
37
|
+
import '../assets/LpTable-DxnthVz4.css';const _hoisted_1 = {
|
|
38
38
|
key: 0,
|
|
39
39
|
class: "flex min-h-8 flex-wrap items-center gap-x-3 gap-y-2 pb-3 text-xs"
|
|
40
40
|
};
|
|
@@ -141,6 +141,7 @@ const _hoisted_48 = {
|
|
|
141
141
|
class: "lp-line-label"
|
|
142
142
|
};
|
|
143
143
|
const _hoisted_49 = { class: "lp-line-value" };
|
|
144
|
+
const _hoisted_50 = ["aria-expanded", "aria-label", "onClick"];
|
|
144
145
|
const __default__ = { inheritAttrs: false };
|
|
145
146
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
146
147
|
...__default__,
|
|
@@ -232,7 +233,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
232
233
|
noMatches: "No rows match the filters",
|
|
233
234
|
resetFilters: "Reset filters",
|
|
234
235
|
rowCount: "{shown} of {total}",
|
|
235
|
-
rowsTotal: "{total}
|
|
236
|
+
rowsTotal: "Rows: {total}",
|
|
236
237
|
selectedCount: "{count} selected",
|
|
237
238
|
clearSelection: "Clear selection",
|
|
238
239
|
pageSelected: "All {count} on this page are selected.",
|
|
@@ -1873,7 +1874,23 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1873
1874
|
])
|
|
1874
1875
|
])) : createCommentVNode("", true)
|
|
1875
1876
|
], true)
|
|
1876
|
-
]))
|
|
1877
|
+
])),
|
|
1878
|
+
expansionOn.value && canExpand(entry.row) ? (openBlock(), createElementBlock("button", {
|
|
1879
|
+
key: 3,
|
|
1880
|
+
type: "button",
|
|
1881
|
+
class: normalizeClass(["inline-grid size-6 shrink-0 place-items-center rounded-small text-muted outline-none transition-colors duration-fast hover:text-ink focus-visible:ring-2 focus-visible:ring-ring", activeLayout.value === "cards" ? "absolute right-2 bottom-2" : ""]),
|
|
1882
|
+
"aria-expanded": expandedKeys.value.has(keyFor(entry.row, entry.index)),
|
|
1883
|
+
"aria-label": expandedKeys.value.has(keyFor(entry.row, entry.index)) ? text.value.collapseRow : text.value.expandRow,
|
|
1884
|
+
onClick: withModifiers(($event) => toggleExpanded(keyFor(entry.row, entry.index)), ["stop"]),
|
|
1885
|
+
onPointerdown: _cache[10] || (_cache[10] = withModifiers(() => {
|
|
1886
|
+
}, ["stop"]))
|
|
1887
|
+
}, [
|
|
1888
|
+
createVNode(_sfc_main$5, {
|
|
1889
|
+
name: "lucide:chevron-right",
|
|
1890
|
+
size: 14,
|
|
1891
|
+
class: normalizeClass(["transition-transform duration-fast motion-reduce:transition-none", expandedKeys.value.has(keyFor(entry.row, entry.index)) ? "rotate-90" : ""])
|
|
1892
|
+
}, null, 8, ["class"])
|
|
1893
|
+
], 42, _hoisted_50)) : createCommentVNode("", true)
|
|
1877
1894
|
], 16, _hoisted_35))
|
|
1878
1895
|
], 64);
|
|
1879
1896
|
}), 128))
|
|
@@ -1889,7 +1906,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1889
1906
|
__props.load && total.value > __props.pageSize ? (openBlock(), createBlock(_sfc_main$h, {
|
|
1890
1907
|
key: 0,
|
|
1891
1908
|
page: page.value,
|
|
1892
|
-
"onUpdate:page": _cache[
|
|
1909
|
+
"onUpdate:page": _cache[11] || (_cache[11] = ($event) => page.value = $event),
|
|
1893
1910
|
total: total.value,
|
|
1894
1911
|
"page-size": __props.pageSize,
|
|
1895
1912
|
disabled: busy.value
|
|
@@ -1898,7 +1915,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1898
1915
|
};
|
|
1899
1916
|
}
|
|
1900
1917
|
});
|
|
1901
|
-
const LpTable = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-
|
|
1918
|
+
const LpTable = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-a346ca36"]]);
|
|
1902
1919
|
export {
|
|
1903
1920
|
LpTable as default
|
|
1904
1921
|
};
|
package/dist/index.js
CHANGED
|
@@ -63,7 +63,7 @@ import { _ as _37 } from "./chunks/LpLogViewer-BuIzr_6h.js";
|
|
|
63
63
|
import { _ as _38 } from "./chunks/LpLogInspector-BhJTJIst.js";
|
|
64
64
|
import { compilePattern, findIds, messageShape, structuredPayload, timeMs } from "./components/logTools.js";
|
|
65
65
|
import { countLevels, matchPositions, matchesTerm, ringWindow, stepMatch } from "./components/logSearch.js";
|
|
66
|
-
import { _ as _39 } from "./chunks/LpMediaGallery-
|
|
66
|
+
import { _ as _39 } from "./chunks/LpMediaGallery-CtWA5Uab.js";
|
|
67
67
|
import { _ as _40 } from "./chunks/LpModal-D1E7rQzw.js";
|
|
68
68
|
import { _ as _41 } from "./chunks/LpModalNav-DivqT1NV.js";
|
|
69
69
|
import { _ as _42 } from "./chunks/LpNotificationBell-KRgdRZs-.js";
|
package/package.json
CHANGED
|
@@ -115,7 +115,7 @@ function fill(template: string, n: number, total = 0): string {
|
|
|
115
115
|
*/
|
|
116
116
|
function menuTitle(item: LightboxItem, i: number): string {
|
|
117
117
|
if (isHidden(item)) return text.value.spoiler
|
|
118
|
-
return item.title || fill(text.value.image, i + 1,
|
|
118
|
+
return item.title || fill(text.value.image, i + 1, shown.value.length)
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
const emit = defineEmits<{
|
|
@@ -123,6 +123,8 @@ const emit = defineEmits<{
|
|
|
123
123
|
(e: "select", item: LightboxItem, index: number): void
|
|
124
124
|
/** A spoiler was uncovered. */
|
|
125
125
|
(e: "reveal", item: LightboxItem): void
|
|
126
|
+
/** An image failed to load from both its thumbnail and its source and left the grid. */
|
|
127
|
+
(e: "broken", item: LightboxItem): void
|
|
126
128
|
(e: "update:open", value: boolean): void
|
|
127
129
|
}>()
|
|
128
130
|
|
|
@@ -142,12 +144,39 @@ watch(open, (value, was) => {
|
|
|
142
144
|
if (!value && was) emit("update:open", false)
|
|
143
145
|
})
|
|
144
146
|
|
|
147
|
+
/*
|
|
148
|
+
* Images that failed to load. A thumbnail that fails falls back to the full
|
|
149
|
+
* source once; when that fails too the image leaves the grid and the lightbox
|
|
150
|
+
* and `broken` says so. A cell of grey with a broken-picture glyph tells the
|
|
151
|
+
* viewer nothing they can act on, and paging the lightbox onto it is worse.
|
|
152
|
+
* Keyed by `src`, like `revealed`, so a reordered set keeps the right ones out.
|
|
153
|
+
*/
|
|
154
|
+
const fellBack = ref(new Set<string>())
|
|
155
|
+
const broken = ref(new Set<string>())
|
|
156
|
+
const shown = computed(() =>
|
|
157
|
+
broken.value.size ? props.items.filter((item) => !broken.value.has(item.src)) : props.items,
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
function thumbOf(item: LightboxItem): string {
|
|
161
|
+
return item.thumb && !fellBack.value.has(item.src) ? item.thumb : item.src
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function onImageError(item: LightboxItem) {
|
|
165
|
+
if (item.thumb && item.thumb !== item.src && !fellBack.value.has(item.src)) {
|
|
166
|
+
fellBack.value = new Set(fellBack.value).add(item.src)
|
|
167
|
+
return
|
|
168
|
+
}
|
|
169
|
+
if (broken.value.has(item.src)) return
|
|
170
|
+
broken.value = new Set(broken.value).add(item.src)
|
|
171
|
+
emit("broken", item)
|
|
172
|
+
}
|
|
173
|
+
|
|
145
174
|
// `max` counts what is SHOWN, so the badge reads "+N more" rather than "N
|
|
146
175
|
// total". A set of 7 capped at 4 shows 4 cells, the last one badged +3.
|
|
147
176
|
const visible = computed(() =>
|
|
148
|
-
props.max &&
|
|
177
|
+
props.max && shown.value.length > props.max ? shown.value.slice(0, props.max) : shown.value,
|
|
149
178
|
)
|
|
150
|
-
const hiddenCount = computed(() => Math.max(
|
|
179
|
+
const hiddenCount = computed(() => Math.max(shown.value.length - visible.value.length, 0))
|
|
151
180
|
|
|
152
181
|
/*
|
|
153
182
|
* Column classes are written out rather than interpolated. Tailwind scans
|
|
@@ -231,11 +260,11 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(() =>
|
|
|
231
260
|
)
|
|
232
261
|
|
|
233
262
|
function activate(i: number) {
|
|
234
|
-
const item =
|
|
263
|
+
const item = shown.value[i]
|
|
235
264
|
if (!item) return
|
|
236
265
|
// `select` reports the position in the caller's own array, which is the one
|
|
237
266
|
// they can do anything with — the lightbox's filtered index is internal.
|
|
238
|
-
emit("select", item,
|
|
267
|
+
emit("select", item, props.items.indexOf(item))
|
|
239
268
|
if (!props.openable) return
|
|
240
269
|
// Covered images are not in the lightbox's list, so the index has to be
|
|
241
270
|
// translated into it.
|
|
@@ -285,17 +314,20 @@ function reveal(item: LightboxItem) {
|
|
|
285
314
|
* pass through untouched, so opening the one you just uncovered still lands on
|
|
286
315
|
* it.
|
|
287
316
|
*/
|
|
288
|
-
const openItems = computed(() =>
|
|
317
|
+
const openItems = computed(() => shown.value.filter((item) => !isHidden(item)))
|
|
289
318
|
|
|
290
319
|
/** Index within `openItems` of the grid item at `i`, or -1 when it is covered. */
|
|
291
320
|
function openIndexOf(i: number): number {
|
|
292
|
-
const item =
|
|
321
|
+
const item = shown.value[i]
|
|
293
322
|
return item ? openItems.value.indexOf(item) : -1
|
|
294
323
|
}
|
|
295
324
|
|
|
296
325
|
defineExpose({
|
|
297
326
|
/** Open the lightbox at an index — for a "view all" button outside the grid. */
|
|
298
|
-
openAt: (i: number) =>
|
|
327
|
+
openAt: (i: number) => {
|
|
328
|
+
const item = props.items[i]
|
|
329
|
+
if (item) activate(shown.value.indexOf(item))
|
|
330
|
+
},
|
|
299
331
|
/** Uncover every spoiler in the set. */
|
|
300
332
|
revealAll: () => {
|
|
301
333
|
const next = new Set(revealed.value)
|
|
@@ -306,7 +338,7 @@ defineExpose({
|
|
|
306
338
|
</script>
|
|
307
339
|
|
|
308
340
|
<template>
|
|
309
|
-
<div v-if="!
|
|
341
|
+
<div v-if="!shown.length">
|
|
310
342
|
<slot name="empty" />
|
|
311
343
|
</div>
|
|
312
344
|
|
|
@@ -316,7 +348,7 @@ defineExpose({
|
|
|
316
348
|
:key="item.src + i"
|
|
317
349
|
:items="itemMenu?.(item, i) ?? []"
|
|
318
350
|
:title="menuTitle(item, i)"
|
|
319
|
-
:title-image="isHidden(item) ? undefined : isVideoItem(item) ? item.poster ?? item.thumb : item
|
|
351
|
+
:title-image="isHidden(item) ? undefined : isVideoItem(item) ? item.poster ?? item.thumb : thumbOf(item)"
|
|
320
352
|
:subtitle="isHidden(item) ? undefined : item.description"
|
|
321
353
|
>
|
|
322
354
|
<button
|
|
@@ -370,10 +402,11 @@ defineExpose({
|
|
|
370
402
|
/>
|
|
371
403
|
<img
|
|
372
404
|
v-else
|
|
373
|
-
:src="item
|
|
405
|
+
:src="thumbOf(item)"
|
|
374
406
|
:alt="isHidden(item) ? '' : item.title || ''"
|
|
375
407
|
loading="lazy"
|
|
376
408
|
decoding="async"
|
|
409
|
+
@error="onImageError(item)"
|
|
377
410
|
class="size-full object-cover transition-transform duration-[var(--duration-medium)] ease-[var(--ease-emphasized)] group-hover:scale-[1.03] motion-reduce:transition-none motion-reduce:group-hover:scale-100"
|
|
378
411
|
:class="[
|
|
379
412
|
isHidden(item)
|
|
@@ -523,7 +523,7 @@ const labelSet = useLabels<TableLabels>(
|
|
|
523
523
|
noMatches: "No rows match the filters",
|
|
524
524
|
resetFilters: "Reset filters",
|
|
525
525
|
rowCount: "{shown} of {total}",
|
|
526
|
-
rowsTotal: "{total}
|
|
526
|
+
rowsTotal: "Rows: {total}",
|
|
527
527
|
selectedCount: "{count} selected",
|
|
528
528
|
clearSelection: "Clear selection",
|
|
529
529
|
pageSelected: "All {count} on this page are selected.",
|
|
@@ -2413,6 +2413,20 @@ usePaletteCommands(() => {
|
|
|
2413
2413
|
</div>
|
|
2414
2414
|
</slot>
|
|
2415
2415
|
</div>
|
|
2416
|
+
<!-- The table's chevron, in a line and a card too: without it an
|
|
2417
|
+
expandable row drew its detail panel but nothing opened it. -->
|
|
2418
|
+
<button
|
|
2419
|
+
v-if="expansionOn && canExpand(entry.row)"
|
|
2420
|
+
type="button"
|
|
2421
|
+
class="inline-grid size-6 shrink-0 place-items-center rounded-small text-muted outline-none transition-colors duration-fast hover:text-ink focus-visible:ring-2 focus-visible:ring-ring"
|
|
2422
|
+
:class="activeLayout === 'cards' ? 'absolute right-2 bottom-2' : ''"
|
|
2423
|
+
:aria-expanded="expandedKeys.has(keyFor(entry.row, entry.index))"
|
|
2424
|
+
:aria-label="expandedKeys.has(keyFor(entry.row, entry.index)) ? text.collapseRow : text.expandRow"
|
|
2425
|
+
@click.stop="toggleExpanded(keyFor(entry.row, entry.index))"
|
|
2426
|
+
@pointerdown.stop
|
|
2427
|
+
>
|
|
2428
|
+
<LpIcon name="lucide:chevron-right" :size="14" class="transition-transform duration-fast motion-reduce:transition-none" :class="expandedKeys.has(keyFor(entry.row, entry.index)) ? 'rotate-90' : ''" />
|
|
2429
|
+
</button>
|
|
2416
2430
|
</div>
|
|
2417
2431
|
</template>
|
|
2418
2432
|
</TransitionGroup>
|