@webx-ui/module-catalog 0.2.0 → 0.3.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/style.css CHANGED
@@ -1 +1 @@
1
- .wx-catalog-categories[data-v-5385c84c]{min-width:0}.wx-catalog-categories__name[data-v-5385c84c]{font-weight:var(--wx-font-weight-medium)}.wx-catalog-categories__name.is-hidden[data-v-5385c84c]{color:var(--wx-text-muted)}.wx-catalog-categories__count[data-v-5385c84c]{color:var(--wx-color-primary);font-variant-numeric:tabular-nums;text-decoration:none}.wx-catalog-categories__count[data-v-5385c84c]:hover{text-decoration:underline}.wx-catalog-category-editor[data-v-45d5817b]{display:flex;flex-direction:column;gap:var(--wx-gap, var(--wx-space-16));container-type:inline-size}.wx-catalog-category-editor__ghost[data-v-45d5817b]{max-width:420px}.wx-catalog-deleted[data-v-1fad643b]{min-width:0}.wx-catalog-deleted__name[data-v-1fad643b]{display:flex;flex-direction:column;min-width:0}.wx-catalog-deleted__title[data-v-1fad643b]{font-weight:var(--wx-font-weight-medium);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wx-catalog-deleted__code[data-v-1fad643b]{font-family:var(--wx-font-family-mono);font-size:var(--wx-font-size-sm);color:var(--wx-text-muted)}.wx-catalog-deleted__ref[data-v-1fad643b]{display:flex;flex-wrap:wrap;align-items:center;gap:var(--wx-space-4) var(--wx-space-8);min-width:0}.wx-catalog-facets[data-v-4ca00a4d]{display:flex;flex-direction:column;gap:var(--wx-space-12)}.wx-catalog-facets__own[data-v-4ca00a4d],.wx-catalog-facets__inherited[data-v-4ca00a4d]{display:flex;flex-direction:column;gap:var(--wx-space-4)}.wx-catalog-facets[data-v-4ca00a4d] .wx-sortable-list__content{display:flex;align-items:center;gap:var(--wx-space-8);min-width:0}.wx-catalog-facets__name[data-v-4ca00a4d]{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wx-catalog-facets__name.is-off[data-v-4ca00a4d]{color:var(--wx-text-muted)}.wx-catalog-gallery[data-v-695c0f5d]{display:flex;flex-direction:column;gap:var(--wx-space-16);container-type:inline-size}.wx-catalog-gallery[data-v-695c0f5d] .wx-sortable-list__content{min-width:0}.wx-catalog-gallery__item[data-v-695c0f5d]{display:grid;grid-template-columns:72px minmax(0,1fr);gap:var(--wx-space-12);align-items:center}.wx-catalog-gallery__thumb[data-v-695c0f5d]{position:relative;display:block;width:72px;aspect-ratio:1;overflow:clip;border-radius:var(--wx-radius-sm);background:var(--wx-bg-subtle);border:1px solid var(--wx-border-default)}.wx-catalog-gallery__thumb img[data-v-695c0f5d]{width:100%;height:100%;min-width:0;object-fit:contain;display:block}.wx-catalog-gallery__main[data-v-695c0f5d]{position:absolute;inset-inline-start:var(--wx-space-2);inset-block-start:var(--wx-space-2)}.wx-catalog-gallery__size[data-v-695c0f5d]{position:absolute;inset-inline:0;inset-block-end:0;padding-block:var(--wx-space-2);background:var(--wx-bg-overlay);color:var(--wx-color-white);font-size:var(--wx-font-size-xs);line-height:1.2;text-align:center;white-space:nowrap;font-variant-numeric:tabular-nums}.wx-catalog-gallery__words[data-v-695c0f5d]{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--wx-space-8)}@container (min-width: 640px){.wx-catalog-gallery__words[data-v-695c0f5d]{grid-template-columns:repeat(2,minmax(0,1fr))}}@container (max-width: 420px){.wx-catalog-gallery__item[data-v-695c0f5d]{grid-template-columns:minmax(0,1fr)}}.wx-catalog-gallery__address[data-v-695c0f5d]{display:flex;gap:var(--wx-space-8);align-items:center;max-width:560px}.wx-catalog-gallery__address[data-v-695c0f5d]>:first-child{flex:1;min-width:0}.wx-catalog-product[data-v-837dd378]{display:flex;flex-direction:column;gap:var(--wx-gap, var(--wx-space-16));container-type:inline-size}.wx-catalog-product__ghost[data-v-837dd378]{max-width:420px}.wx-catalog-bulk-params__field[data-v-b83c3fb0]{margin-top:var(--wx-space-16)}.wx-catalog-bulk[data-v-94557c14]{display:contents}.wx-catalog-bulk__progress[data-v-94557c14]{display:grid;gap:var(--wx-space-4);flex:1 1 240px;min-width:0}.wx-catalog-bulk__refused[data-v-94557c14]{display:flex;flex-wrap:wrap;align-items:baseline;gap:var(--wx-space-8);flex-basis:100%;min-width:0}.wx-catalog-bulk__errors[data-v-94557c14]{flex-basis:100%;font-size:var(--wx-font-size-sm)}.wx-catalog-bulk__errors summary[data-v-94557c14]{cursor:pointer;color:var(--wx-text-muted)}.wx-catalog-bulk__errors ul[data-v-94557c14]{margin:var(--wx-space-8) 0 0;padding-inline-start:var(--wx-space-18);max-height:200px;overflow:auto}.wx-catalog-products[data-v-44965ffc]{min-width:0}.wx-catalog-products__selection[data-v-44965ffc]{display:flex;flex-wrap:wrap;align-items:center;gap:var(--wx-space-12);padding:var(--wx-space-8) var(--wx-space-16);border-bottom:1px solid var(--wx-border-default);background:var(--wx-bg-subtle)}.wx-catalog-products__image[data-v-44965ffc]{display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:var(--wx-radius-sm);overflow:clip;background:var(--wx-bg-subtle);color:var(--wx-text-muted);vertical-align:middle}.wx-catalog-products__image img[data-v-44965ffc]{width:100%;height:100%;min-width:0;object-fit:cover}.wx-catalog-products__name[data-v-44965ffc]{display:flex;flex-direction:column;min-width:0}.wx-catalog-products__title[data-v-44965ffc]{font-weight:var(--wx-font-weight-medium);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wx-catalog-products__sku[data-v-44965ffc]{font-family:var(--wx-font-family-mono);font-size:var(--wx-font-size-sm);color:var(--wx-text-muted);min-height:1em}.wx-catalog-products__price[data-v-44965ffc]{display:inline-flex;flex-direction:column;align-items:flex-end;font-variant-numeric:tabular-nums}.wx-catalog-products__price[data-v-44965ffc]>*{white-space:nowrap}.wx-catalog-products__price small[data-v-44965ffc],.wx-catalog-products__price s[data-v-44965ffc]{font-size:var(--wx-font-size-sm);color:var(--wx-text-muted)}.wx-catalog-products__range[data-v-44965ffc]{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--wx-space-8)}
1
+ .wx-catalog-categories[data-v-5385c84c]{min-width:0}.wx-catalog-categories__name[data-v-5385c84c]{font-weight:var(--wx-font-weight-medium)}.wx-catalog-categories__name.is-hidden[data-v-5385c84c]{color:var(--wx-text-muted)}.wx-catalog-categories__count[data-v-5385c84c]{color:var(--wx-color-primary);font-variant-numeric:tabular-nums;text-decoration:none}.wx-catalog-categories__count[data-v-5385c84c]:hover{text-decoration:underline}.wx-catalog-category-editor[data-v-45d5817b]{display:flex;flex-direction:column;gap:var(--wx-gap, var(--wx-space-16));container-type:inline-size}.wx-catalog-category-editor__ghost[data-v-45d5817b]{max-width:420px}.wx-catalog-deleted[data-v-1fad643b]{min-width:0}.wx-catalog-deleted__name[data-v-1fad643b]{display:flex;flex-direction:column;min-width:0}.wx-catalog-deleted__title[data-v-1fad643b]{font-weight:var(--wx-font-weight-medium);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wx-catalog-deleted__code[data-v-1fad643b]{font-family:var(--wx-font-family-mono);font-size:var(--wx-font-size-sm);color:var(--wx-text-muted)}.wx-catalog-deleted__ref[data-v-1fad643b]{display:flex;flex-wrap:wrap;align-items:center;gap:var(--wx-space-4) var(--wx-space-8);min-width:0}.wx-catalog-facets[data-v-4ca00a4d]{display:flex;flex-direction:column;gap:var(--wx-space-12)}.wx-catalog-facets__own[data-v-4ca00a4d],.wx-catalog-facets__inherited[data-v-4ca00a4d]{display:flex;flex-direction:column;gap:var(--wx-space-4)}.wx-catalog-facets[data-v-4ca00a4d] .wx-sortable-list__content{display:flex;align-items:center;gap:var(--wx-space-8);min-width:0}.wx-catalog-facets__name[data-v-4ca00a4d]{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wx-catalog-facets__name.is-off[data-v-4ca00a4d]{color:var(--wx-text-muted)}.wx-catalog-video-progress[data-v-09fd14bf]{display:flex;flex-direction:column;gap:var(--wx-space-4);min-width:0}.wx-catalog-video-progress__line[data-v-09fd14bf]{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--wx-space-4) var(--wx-space-8);min-width:0}.wx-catalog-video-progress__figures[data-v-09fd14bf]{font-variant-numeric:tabular-nums;min-width:0}.wx-catalog-video-progress__figure[data-v-09fd14bf]{white-space:nowrap}.wx-catalog-video-progress__buttons[data-v-09fd14bf]{display:flex;gap:var(--wx-space-4);margin-inline-start:auto}.wx-catalog-video-progress.is-failed[data-v-09fd14bf]{flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--wx-space-4) var(--wx-space-8)}.wx-catalog-gallery[data-v-fdb59e51]{display:flex;flex-direction:column;gap:var(--wx-space-16);container-type:inline-size}.wx-catalog-gallery[data-v-fdb59e51] .wx-sortable-list__content{min-width:0}.wx-catalog-gallery__item[data-v-fdb59e51]{display:grid;grid-template-columns:72px minmax(0,1fr);gap:var(--wx-space-12);align-items:center}.wx-catalog-gallery__thumb[data-v-fdb59e51]{position:relative;display:block;width:72px;aspect-ratio:1;overflow:clip;border-radius:var(--wx-radius-sm);background:var(--wx-bg-subtle);border:1px solid var(--wx-border-default)}.wx-catalog-gallery__thumb img[data-v-fdb59e51]{width:100%;height:100%;min-width:0;object-fit:contain;display:block}.wx-catalog-gallery__main[data-v-fdb59e51]{position:absolute;inset-inline-start:var(--wx-space-2);inset-block-start:var(--wx-space-2)}.wx-catalog-gallery__size[data-v-fdb59e51],.wx-catalog-gallery__play[data-v-fdb59e51]{position:absolute;background:var(--wx-bg-overlay);color:var(--wx-color-white);font-size:var(--wx-font-size-xs);line-height:1.2;white-space:nowrap;font-variant-numeric:tabular-nums}.wx-catalog-gallery__size[data-v-fdb59e51]{inset-inline:0;inset-block-end:0;padding-block:var(--wx-space-2);text-align:center}.wx-catalog-gallery__play[data-v-fdb59e51]{inset-block-start:50%;inset-inline-start:50%;translate:-50% -50%;padding:var(--wx-space-2) var(--wx-space-4);border-radius:var(--wx-radius-xs)}.wx-catalog-gallery__body[data-v-fdb59e51]{display:flex;flex-direction:column;gap:var(--wx-space-8);min-width:0}.wx-catalog-gallery__words[data-v-fdb59e51]{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--wx-space-8)}@container (min-width: 640px){.wx-catalog-gallery__words[data-v-fdb59e51]{grid-template-columns:repeat(2,minmax(0,1fr))}}@container (max-width: 420px){.wx-catalog-gallery__item[data-v-fdb59e51]{grid-template-columns:minmax(0,1fr)}}.wx-catalog-gallery__pending[data-v-fdb59e51]{display:flex;flex-direction:column;gap:var(--wx-space-8);margin:0;padding:var(--wx-space-8) var(--wx-space-12);list-style:none;border:1px dashed var(--wx-border-default);border-radius:var(--wx-radius-md)}.wx-catalog-gallery__name[data-v-fdb59e51]{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wx-catalog-gallery__picker[data-v-fdb59e51]{display:none}.wx-catalog-gallery__address[data-v-fdb59e51]{display:flex;gap:var(--wx-space-8);align-items:center;max-width:560px}.wx-catalog-gallery__address[data-v-fdb59e51]>:first-child{flex:1;min-width:0}.wx-catalog-gallery__address-hint[data-v-fdb59e51]{display:block;margin-block-start:var(--wx-space-8)}.wx-catalog-product[data-v-923c09f7]{display:flex;flex-direction:column;gap:var(--wx-gap, var(--wx-space-16));container-type:inline-size}.wx-catalog-product__ghost[data-v-923c09f7]{max-width:420px}.wx-catalog-bulk-params__field[data-v-b83c3fb0]{margin-top:var(--wx-space-16)}.wx-catalog-bulk[data-v-94557c14]{display:contents}.wx-catalog-bulk__progress[data-v-94557c14]{display:grid;gap:var(--wx-space-4);flex:1 1 240px;min-width:0}.wx-catalog-bulk__refused[data-v-94557c14]{display:flex;flex-wrap:wrap;align-items:baseline;gap:var(--wx-space-8);flex-basis:100%;min-width:0}.wx-catalog-bulk__errors[data-v-94557c14]{flex-basis:100%;font-size:var(--wx-font-size-sm)}.wx-catalog-bulk__errors summary[data-v-94557c14]{cursor:pointer;color:var(--wx-text-muted)}.wx-catalog-bulk__errors ul[data-v-94557c14]{margin:var(--wx-space-8) 0 0;padding-inline-start:var(--wx-space-18);max-height:200px;overflow:auto}.wx-catalog-products[data-v-44965ffc]{min-width:0}.wx-catalog-products__selection[data-v-44965ffc]{display:flex;flex-wrap:wrap;align-items:center;gap:var(--wx-space-12);padding:var(--wx-space-8) var(--wx-space-16);border-bottom:1px solid var(--wx-border-default);background:var(--wx-bg-subtle)}.wx-catalog-products__image[data-v-44965ffc]{display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:var(--wx-radius-sm);overflow:clip;background:var(--wx-bg-subtle);color:var(--wx-text-muted);vertical-align:middle}.wx-catalog-products__image img[data-v-44965ffc]{width:100%;height:100%;min-width:0;object-fit:cover}.wx-catalog-products__name[data-v-44965ffc]{display:flex;flex-direction:column;min-width:0}.wx-catalog-products__title[data-v-44965ffc]{font-weight:var(--wx-font-weight-medium);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wx-catalog-products__sku[data-v-44965ffc]{font-family:var(--wx-font-family-mono);font-size:var(--wx-font-size-sm);color:var(--wx-text-muted);min-height:1em}.wx-catalog-products__price[data-v-44965ffc]{display:inline-flex;flex-direction:column;align-items:flex-end;font-variant-numeric:tabular-nums}.wx-catalog-products__price[data-v-44965ffc]>*{white-space:nowrap}.wx-catalog-products__price small[data-v-44965ffc],.wx-catalog-products__price s[data-v-44965ffc]{font-size:var(--wx-font-size-sm);color:var(--wx-text-muted)}.wx-catalog-products__range[data-v-44965ffc]{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--wx-space-8)}
package/dist/types.d.ts CHANGED
@@ -117,6 +117,30 @@ export interface ProductImage {
117
117
  height: number | null;
118
118
  size: number | null;
119
119
  position: number;
120
+ /** The video attached to the picture, which is then its poster (the video spec, §1.1). */
121
+ video?: ProductVideo | null;
122
+ }
123
+ /** A video in the gallery: a file on the gallery's disk, or one on a provider's site. */
124
+ export interface ProductVideo {
125
+ /** `file`, or the provider's key (`youtube`). */
126
+ provider: string;
127
+ /** The file, or the provider's page of the video. */
128
+ url: string;
129
+ /** The address for an iframe; `null` for a file. */
130
+ embed: string | null;
131
+ /** Whole seconds, when known. */
132
+ duration: number | null;
133
+ }
134
+ /**
135
+ * The answer to a direct link to a video file: the server downloads it in its queue, and the row
136
+ * appears — or the picture gets its video — when that is done.
137
+ */
138
+ export interface QueuedVideo {
139
+ queued: true;
140
+ product: number;
141
+ url: string;
142
+ /** The picture the video goes onto; `null` for a new row. */
143
+ image: number | null;
120
144
  }
121
145
  /** One product as its editor opens it. */
122
146
  export interface ProductDetail {
@@ -0,0 +1,69 @@
1
+ import { ProductImage } from './types';
2
+ /**
3
+ * The browser half of videos in the gallery (§1.6, §7 of the video spec): the frame that becomes
4
+ * the poster, and the checks made before a byte is sent.
5
+ */
6
+ /** What the panel learns about a video file by opening it in the browser. */
7
+ export interface VideoProbe {
8
+ /** The frame, as a JPEG; `null` when only the length was asked for. */
9
+ frame: Blob | null;
10
+ /** Whole seconds, or `null` when the file does not say. */
11
+ duration: number | null;
12
+ width: number;
13
+ height: number;
14
+ }
15
+ /**
16
+ * The pieces of the DOM the probe needs, handed in so that a test can stand them up: jsdom does
17
+ * not decode video, so a probe against a real `<video>` there never gets past loading.
18
+ */
19
+ export interface ProbeEnvironment {
20
+ createVideo(): HTMLVideoElement;
21
+ createCanvas(): HTMLCanvasElement;
22
+ createUrl(file: Blob): string;
23
+ revokeUrl(url: string): void;
24
+ }
25
+ export interface ProbeOptions {
26
+ /** Take a frame as well as the length. */
27
+ frame?: boolean;
28
+ /** How long to wait for the browser to open the file before giving up on it. */
29
+ timeout?: number;
30
+ environment?: ProbeEnvironment;
31
+ }
32
+ /** The browser could not open the file — mostly a codec it does not play. */
33
+ export declare class VideoUnreadable extends Error {
34
+ constructor(reason: string);
35
+ }
36
+ /** Where the frame is taken: a little in, as the very first frame is so often black. */
37
+ export declare function frameTime(duration: number): number;
38
+ /**
39
+ * Open a video file in the browser and read its length and, if asked, one frame of it.
40
+ *
41
+ * Read off the local file, before the upload, so a poster does not wait on gigabytes going up
42
+ * (decision 6). Rejects with `VideoUnreadable` when the browser cannot open the file, which is
43
+ * what the panel then says in words: add a picture and attach the video to it.
44
+ */
45
+ export declare function probeVideo(file: Blob, options?: ProbeOptions): Promise<VideoProbe>;
46
+ /** The name of the poster: the video's own, as a JPEG. */
47
+ export declare function posterName(file: Pick<File, 'name'>): string;
48
+ /**
49
+ * The id of a YouTube video in any of the forms the server takes (§3), or `null`. The server
50
+ * decides in the end; this only says what the field should call the address.
51
+ */
52
+ export declare function youTubeId(address: string): string | null;
53
+ /** A direct link to an MP4 or WebM file, judged by its name — the server checks the answer. */
54
+ export declare function isVideoFileLink(address: string): boolean;
55
+ /** Anything the gallery treats as a video rather than a picture. */
56
+ export declare function isVideoLink(address: string): boolean;
57
+ /** A file the gallery may take as a video, by the limits the screen gave it. */
58
+ export declare function videoRefusal(file: Pick<File, 'type' | 'size'>, types: readonly string[], maxBytes: number): 'type' | 'size' | null;
59
+ /**
60
+ * The poster the server puts on a video that came by a direct link without a picture: a plain
61
+ * dark PNG, 1280×720 (a single pixel where the server has no GD). Recognised by its shape, as the
62
+ * resource carries no mark of it; a panel-made poster is a JPEG, so a mistake here needs a PNG of
63
+ * exactly that size with a file video on it, and then the hint only says what may be done anyway.
64
+ */
65
+ export declare function hasPlaceholderPoster(image: ProductImage): boolean;
66
+ /** Bytes as the panel says them: "840 KB", "1.2 GB". */
67
+ export declare function formatBytes(bytes: number, locale?: string): string;
68
+ /** A length of time as a clock: "0:42", "12:05", "1:02:03". */
69
+ export declare function formatClock(seconds: number): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webx-ui/module-catalog",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "The catalogue of the WebX UI admin panel: products with a gallery, a tree of categories with their filters, and the deleted ones waiting to come back.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -45,7 +45,7 @@
45
45
  },
46
46
  "dependencies": {
47
47
  "@webx-ui/core": "^0.34.1",
48
- "@webx-ui/module-admin": "^0.19.0",
48
+ "@webx-ui/module-admin": "^0.20.0",
49
49
  "@webx-ui/schema": "^0.6.4"
50
50
  },
51
51
  "devDependencies": {