@cloudron/pankow 4.2.2 → 4.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/types/utils.d.ts CHANGED
@@ -26,35 +26,195 @@ declare namespace _default {
26
26
  export { uuidv4 };
27
27
  }
28
28
  export default _default;
29
- export function getFileTypeGroup(item: any): any;
30
- export function translation(id: any): any;
31
- export function useDebouncedRef(value: any, delay?: number): import("vue").Ref<any, any>;
32
- export function isValidDomain(domain: any): boolean;
33
- export function isValidDomainOrURL(domain: any): boolean;
34
- export function isValidEmail(email: any): boolean;
35
- export function prettyBinarySize(size: any, fallback: any): any;
36
- export function prettyDecimalSize(size: any, fallback: any): any;
37
- export function prettyDate(value: any): string;
38
- export function prettyShortDate(value: any): string;
39
- export function formatDate(format: any, value: any): any;
40
- export function prettyLongDate(value: any): string;
41
- export function prettyFileSize(value: any): string;
42
- export function prettyEmailAddresses(addresses: any): any;
43
- export function prettyDuration(ms: any): string;
44
- export function sanitize(path: any): any;
45
- export function pathJoin(...args: any[]): any;
46
- export function download(entries: any, name: any): void;
47
- export function getExtension(entry: any): any;
48
- export function copyToClipboard(value: any): void;
49
- export function urlSearchQuery(): {};
50
- export function parseResourcePath(resourcePath: any): {
29
+ /**
30
+ * Extracts the MIME type group from an item (e.g. "image" from "image/png").
31
+ * @param {{ mimeType: string }} item
32
+ * @returns {string}
33
+ * @throws {string} If item has no mimeType string property
34
+ */
35
+ export function getFileTypeGroup(item: {
36
+ mimeType: string;
37
+ }): string;
38
+ /**
39
+ * Looks up a translation string by dot-separated key (e.g. "filemanager.title").
40
+ * Falls back to the key itself if the translation is not found.
41
+ * @param {string} id - Dot-separated translation key
42
+ * @returns {string}
43
+ */
44
+ export function translation(id: string): string;
45
+ /**
46
+ * Creates a debounced reactive ref that delays value updates.
47
+ * @see https://vuejs.org/api/reactivity-advanced.html#customref
48
+ * @param {any} value
49
+ * @param {number} [delay=300] - Debounce delay in milliseconds
50
+ * @returns {import('vue').Ref}
51
+ */
52
+ export function useDebouncedRef(value: any, delay?: number): import("vue").Ref;
53
+ /**
54
+ * Validates whether a string is a valid domain name.
55
+ * @param {string} domain
56
+ * @returns {boolean}
57
+ */
58
+ export function isValidDomain(domain: string): boolean;
59
+ /**
60
+ * Validates whether a string is a valid domain or URL (extracts hostname from URLs first).
61
+ * @param {string} domain
62
+ * @returns {boolean}
63
+ */
64
+ export function isValidDomainOrURL(domain: string): boolean;
65
+ /**
66
+ * Validates whether a string is a valid email address.
67
+ * Does not match: quoted local-parts, IP-literal domains, comments, or internationalized addresses.
68
+ * @param {string} email
69
+ * @returns {boolean}
70
+ */
71
+ export function isValidEmail(email: string): boolean;
72
+ /**
73
+ * Formats a byte count into human-readable IEC binary units (KiB, MiB, GiB, TiB).
74
+ * @see https://en.wikipedia.org/wiki/Binary_prefix
75
+ * @param {number} size - Byte count; -1 returns "Unlimited"
76
+ * @param {string|number} [fallback] - Value returned when size is falsy (0, null, undefined)
77
+ * @returns {string|number}
78
+ */
79
+ export function prettyBinarySize(size: number, fallback?: string | number): string | number;
80
+ /**
81
+ * Formats a byte count into human-readable SI decimal units (kB, MB, GB, TB).
82
+ * @param {number} size - Byte count
83
+ * @param {string|number} [fallback] - Value returned when size is falsy
84
+ * @returns {string|number}
85
+ */
86
+ export function prettyDecimalSize(size: number, fallback?: string | number): string | number;
87
+ /**
88
+ * Formats a value as a human-friendly relative time offset from now (e.g. "2 days ago").
89
+ * @param {string|number} value - Date string or timestamp; falsy returns "never"
90
+ * @returns {string}
91
+ */
92
+ export function prettyDate(value: string | number): string;
93
+ /**
94
+ * Formats a value as a short time string (medium time style via Intl.DateTimeFormat).
95
+ * @param {string|number} value - Date string or timestamp; falsy returns "unknown"
96
+ * @returns {string}
97
+ */
98
+ export function prettyShortDate(value: string | number): string;
99
+ /**
100
+ * Formats a date using a named format preset.
101
+ * @param {'hh:mm A'|'hh:mm:ss A'|'DD MMM'|'DD MMM hh:mm A'} format - Preset format key
102
+ * @param {string|number} value - Date string or timestamp
103
+ * @returns {string}
104
+ */
105
+ export function formatDate(format: "hh:mm A" | "hh:mm:ss A" | "DD MMM" | "DD MMM hh:mm A", value: string | number): string;
106
+ /**
107
+ * Formats a value as a long date string (day, month, year, time).
108
+ * @param {string|number} value - Date string or timestamp; falsy returns "unknown"
109
+ * @returns {string}
110
+ */
111
+ export function prettyLongDate(value: string | number): string;
112
+ /**
113
+ * Formats a numeric value as a human-readable file size string (uses the `filesize` library).
114
+ * @param {number} value - Byte count
115
+ * @returns {string}
116
+ */
117
+ export function prettyFileSize(value: number): string;
118
+ /**
119
+ * Strips angle brackets from email address strings or arrays.
120
+ * @param {string|string[]} addresses - Format: "<name@example.com>"; returns empty string if falsy
121
+ * @returns {string}
122
+ */
123
+ export function prettyEmailAddresses(addresses: string | string[]): string;
124
+ /**
125
+ * Formats milliseconds as a human-readable duration string using Intl.DurationFormat.
126
+ * @param {number} ms - Duration in milliseconds
127
+ * @returns {string}
128
+ */
129
+ export function prettyDuration(ms: number): string;
130
+ /**
131
+ * Normalizes a file path: ensures leading slash and collapses consecutive slashes.
132
+ * @param {string} path
133
+ * @returns {string}
134
+ */
135
+ export function sanitize(path: string): string;
136
+ /**
137
+ * Joins path segments and normalizes the result (via sanitize).
138
+ * @param {...string} args - Path segments to join
139
+ * @returns {string}
140
+ */
141
+ export function pathJoin(...args: string[]): string;
142
+ /**
143
+ * Triggers a file download via the browser. Single entry: direct download.
144
+ * Multiple entries: zipped archive download via /api/v1/download.
145
+ * @param {Array<{ filePath: string, share?: { id: string } }>} entries - File entries to download
146
+ * @param {string} [name] - Archive name for multi-file downloads
147
+ * @returns {void}
148
+ */
149
+ export function download(entries: Array<{
150
+ filePath: string;
151
+ share?: {
152
+ id: string;
153
+ };
154
+ }>, name?: string): void;
155
+ /**
156
+ * Extracts the file extension from a file entry. Does not detect double extensions (e.g. .tar.gz).
157
+ * @param {{ isFile: boolean, fileName: string }} entry
158
+ * @returns {string} Extension without leading dot (empty string for directories or files without extension)
159
+ */
160
+ export function getExtension(entry: {
161
+ isFile: boolean;
162
+ fileName: string;
163
+ }): string;
164
+ /**
165
+ * Copies a string to the system clipboard using a temporary input element.
166
+ * @param {string} value
167
+ * @returns {void}
168
+ * @deprecated Prefer the native `navigator.clipboard.writeText()` API.
169
+ */
170
+ export function copyToClipboard(value: string): void;
171
+ /**
172
+ * Parses the current page's URL query string into a key/value object.
173
+ * @returns {Object<string, string>}
174
+ */
175
+ export function urlSearchQuery(): {
176
+ [x: string]: string;
177
+ };
178
+ /**
179
+ * Parses a Cloudron resource path into its components (type, path, shareId, apiPath).
180
+ * Handles paths like "files/folder/filename" or "shares/:shareId/folder/filename".
181
+ * @param {string} resourcePath
182
+ * @returns {{ type: string, path: string, shareId: string, apiPath: string, resourcePath: string }}
183
+ */
184
+ export function parseResourcePath(resourcePath: string): {
51
185
  type: string;
52
186
  path: string;
53
187
  shareId: string;
54
188
  apiPath: string;
55
189
  resourcePath: string;
56
190
  };
57
- export function getEntryIdentifier(entry: any): string;
58
- export function entryListSort(list: any, prop: any, desc: any): any;
59
- export function sleep(ms: any): Promise<any>;
191
+ /**
192
+ * Generates a unique identifier for a file entry, including its share ID if present.
193
+ * @param {{ share?: { id: string }, filePath: string }} entry
194
+ * @returns {string}
195
+ */
196
+ export function getEntryIdentifier(entry: {
197
+ share?: {
198
+ id: string;
199
+ };
200
+ filePath: string;
201
+ }): string;
202
+ /**
203
+ * Sorts an array of objects by a given property, case-insensitive for strings.
204
+ * @param {Array<Object>} list - Array of objects to sort
205
+ * @param {string} prop - Property name to sort by
206
+ * @param {boolean} desc - If falsey, reverses the sort (descending order)
207
+ * @returns {Array<Object>}
208
+ */
209
+ export function entryListSort(list: Array<Object>, prop: string, desc: boolean): Array<Object>;
210
+ /**
211
+ * Returns a promise that resolves after the specified number of milliseconds.
212
+ * @param {number} ms
213
+ * @returns {Promise<void>}
214
+ */
215
+ export function sleep(ms: number): Promise<void>;
216
+ /**
217
+ * Generates a random UUID v4 string using crypto.getRandomValues.
218
+ * @returns {string}
219
+ */
60
220
  export function uuidv4(): string;
package/utils.js CHANGED
@@ -2,7 +2,13 @@
2
2
  import { filesize } from 'filesize';
3
3
  import { customRef } from 'vue';
4
4
 
5
- // https://vuejs.org/api/reactivity-advanced.html#customref
5
+ /**
6
+ * Creates a debounced reactive ref that delays value updates.
7
+ * @see https://vuejs.org/api/reactivity-advanced.html#customref
8
+ * @param {any} value
9
+ * @param {number} [delay=300] - Debounce delay in milliseconds
10
+ * @returns {import('vue').Ref}
11
+ */
6
12
  function useDebouncedRef(value, delay = 300) {
7
13
  let timeout;
8
14
  return customRef((track, trigger) => {
@@ -22,25 +28,46 @@ function useDebouncedRef(value, delay = 300) {
22
28
  })
23
29
  }
24
30
 
31
+ /**
32
+ * Extracts the MIME type group from an item (e.g. "image" from "image/png").
33
+ * @param {{ mimeType: string }} item
34
+ * @returns {string}
35
+ * @throws {string} If item has no mimeType string property
36
+ */
25
37
  function getFileTypeGroup(item) {
26
38
  if (typeof item.mimeType !== 'string') throw 'item must have mimeType string property';
27
39
  return item.mimeType.split('/')[0];
28
40
  }
29
41
 
42
+ /**
43
+ * Validates whether a string is a valid domain or URL (extracts hostname from URLs first).
44
+ * @param {string} domain
45
+ * @returns {boolean}
46
+ */
30
47
  function isValidDomainOrURL(domain) {
31
48
  try {
32
- domain = new URL(input).hostname;
49
+ domain = new URL(domain).hostname;
33
50
  } catch (e) {}
34
51
 
35
52
  return isValidDomain(domain);
36
53
  }
37
54
 
55
+ /**
56
+ * Validates whether a string is a valid domain name.
57
+ * @param {string} domain
58
+ * @returns {boolean}
59
+ */
38
60
  function isValidDomain(domain) {
39
61
  const domainRegex = /^([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/;
40
62
  return domainRegex.test(domain);
41
63
  }
42
64
 
43
- // this currently does not match: "john.doe"@example.com, user@[192.168.1.1], john.doe(comment)@example.com or 用户@例子.世界
65
+ /**
66
+ * Validates whether a string is a valid email address.
67
+ * Does not match: quoted local-parts, IP-literal domains, comments, or internationalized addresses.
68
+ * @param {string} email
69
+ * @returns {boolean}
70
+ */
44
71
  function isValidEmail(email) {
45
72
  if (!email || typeof email !== 'string') return false;
46
73
 
@@ -49,8 +76,13 @@ function isValidEmail(email) {
49
76
  }
50
77
 
51
78
 
52
- // https://en.wikipedia.org/wiki/Binary_prefix
53
- // binary units (IEC) 1024 based
79
+ /**
80
+ * Formats a byte count into human-readable IEC binary units (KiB, MiB, GiB, TiB).
81
+ * @see https://en.wikipedia.org/wiki/Binary_prefix
82
+ * @param {number} size - Byte count; -1 returns "Unlimited"
83
+ * @param {string|number} [fallback] - Value returned when size is falsy (0, null, undefined)
84
+ * @returns {string|number}
85
+ */
54
86
  function prettyBinarySize(size, fallback) {
55
87
  if (!size) return fallback || 0;
56
88
  if (size === -1) return 'Unlimited';
@@ -60,7 +92,12 @@ function prettyBinarySize(size, fallback) {
60
92
  return (size / Math.pow(1024, i)).toFixed(3) * 1 + ' ' + ['B', 'KiB', 'MiB', 'GiB', 'TiB'][i];
61
93
  }
62
94
 
63
- // decimal units (SI) 1000 based
95
+ /**
96
+ * Formats a byte count into human-readable SI decimal units (kB, MB, GB, TB).
97
+ * @param {number} size - Byte count
98
+ * @param {string|number} [fallback] - Value returned when size is falsy
99
+ * @returns {string|number}
100
+ */
64
101
  function prettyDecimalSize(size, fallback) {
65
102
  if (!size) return fallback || 0;
66
103
 
@@ -68,6 +105,11 @@ function prettyDecimalSize(size, fallback) {
68
105
  return (size / Math.pow(1000, i)).toFixed(2) * 1 + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][i];
69
106
  }
70
107
 
108
+ /**
109
+ * Formats a date as a relative time string using Intl.RelativeTimeFormat.
110
+ * @param {Date} date
111
+ * @returns {string}
112
+ */
71
113
  function fromNow(date) {
72
114
  const rtf = new Intl.RelativeTimeFormat(undefined, { numeric: 'auto' });
73
115
 
@@ -93,7 +135,11 @@ function fromNow(date) {
93
135
  return rtf.format(years, 'year');
94
136
  }
95
137
 
96
- // this will print a human friendly datetime offset from now
138
+ /**
139
+ * Formats a value as a human-friendly relative time offset from now (e.g. "2 days ago").
140
+ * @param {string|number} value - Date string or timestamp; falsy returns "never"
141
+ * @returns {string}
142
+ */
97
143
  function prettyDate(value) {
98
144
  if (!value) return 'never';
99
145
 
@@ -103,6 +149,12 @@ function prettyDate(value) {
103
149
  return fromNow(date);
104
150
  }
105
151
 
152
+ /**
153
+ * Formats a date using a named format preset.
154
+ * @param {'hh:mm A'|'hh:mm:ss A'|'DD MMM'|'DD MMM hh:mm A'} format - Preset format key
155
+ * @param {string|number} value - Date string or timestamp
156
+ * @returns {string}
157
+ */
106
158
  function formatDate(format, value) {
107
159
  const formatters = {
108
160
  'hh:mm A': new Intl.DateTimeFormat(undefined, {
@@ -126,16 +178,17 @@ function formatDate(format, value) {
126
178
  hour: '2-digit',
127
179
  minute: '2-digit',
128
180
  hour12: true
129
- }),
130
- 'DD MMM': new Intl.DateTimeFormat(undefined, { // force this to get month first
131
- day: '2-digit',
132
- month: 'short'
133
181
  })
134
182
  };
135
183
 
136
184
  return formatters[format].format(new Date(value));
137
185
  }
138
186
 
187
+ /**
188
+ * Formats a value as a short time string (medium time style via Intl.DateTimeFormat).
189
+ * @param {string|number} value - Date string or timestamp; falsy returns "unknown"
190
+ * @returns {string}
191
+ */
139
192
  function prettyShortDate(value) {
140
193
  if (!value) return 'unknown';
141
194
 
@@ -151,6 +204,11 @@ function prettyShortDate(value) {
151
204
  return formattedDate;
152
205
  }
153
206
 
207
+ /**
208
+ * Formats a value as a long date string (day, month, year, time).
209
+ * @param {string|number} value - Date string or timestamp; falsy returns "unknown"
210
+ * @returns {string}
211
+ */
154
212
  function prettyLongDate(value) {
155
213
  if (!value) return 'unknown';
156
214
 
@@ -170,12 +228,22 @@ function prettyLongDate(value) {
170
228
  return formattedDate;
171
229
  }
172
230
 
231
+ /**
232
+ * Formats a numeric value as a human-readable file size string (uses the `filesize` library).
233
+ * @param {number} value - Byte count
234
+ * @returns {string}
235
+ */
173
236
  function prettyFileSize(value) {
174
237
  if (typeof value !== 'number') return 'unknown';
175
238
 
176
239
  return filesize(value);
177
240
  }
178
241
 
242
+ /**
243
+ * Strips angle brackets from email address strings or arrays.
244
+ * @param {string|string[]} addresses - Format: "<name@example.com>"; returns empty string if falsy
245
+ * @returns {string}
246
+ */
179
247
  function prettyEmailAddresses(addresses) {
180
248
  if (!addresses) return '';
181
249
  if (addresses === '<>') return '<>';
@@ -183,6 +251,11 @@ function prettyEmailAddresses(addresses) {
183
251
  return addresses.slice(1, -1);
184
252
  }
185
253
 
254
+ /**
255
+ * Formats milliseconds as a human-readable duration string using Intl.DurationFormat.
256
+ * @param {number} ms - Duration in milliseconds
257
+ * @returns {string}
258
+ */
186
259
  function prettyDuration(ms) {
187
260
  const totalSeconds = Math.floor(ms / 1000);
188
261
  const days = Math.floor(totalSeconds / 86400);
@@ -194,15 +267,32 @@ function prettyDuration(ms) {
194
267
  return df.format({ days, hours, minutes, seconds });
195
268
  }
196
269
 
270
+ /**
271
+ * Normalizes a file path: ensures leading slash and collapses consecutive slashes.
272
+ * @param {string} path
273
+ * @returns {string}
274
+ */
197
275
  function sanitize(path) {
198
276
  path = '/' + path;
199
277
  return path.replace(/\/+/g, '/');
200
278
  }
201
279
 
280
+ /**
281
+ * Joins path segments and normalizes the result (via sanitize).
282
+ * @param {...string} args - Path segments to join
283
+ * @returns {string}
284
+ */
202
285
  function pathJoin() {
203
286
  return sanitize(Array.from(arguments).join('/'));
204
287
  }
205
288
 
289
+ /**
290
+ * Triggers a file download via the browser. Single entry: direct download.
291
+ * Multiple entries: zipped archive download via /api/v1/download.
292
+ * @param {Array<{ filePath: string, share?: { id: string } }>} entries - File entries to download
293
+ * @param {string} [name] - Archive name for multi-file downloads
294
+ * @returns {void}
295
+ */
206
296
  function download(entries, name) {
207
297
  if (!entries.length) return;
208
298
 
@@ -231,12 +321,22 @@ function download(entries, name) {
231
321
  window.location.href = '/api/v1/download?' + params.toString();
232
322
  }
233
323
 
234
- // simple extension detection, does not work with double extension like .tar.gz
324
+ /**
325
+ * Extracts the file extension from a file entry. Does not detect double extensions (e.g. .tar.gz).
326
+ * @param {{ isFile: boolean, fileName: string }} entry
327
+ * @returns {string} Extension without leading dot (empty string for directories or files without extension)
328
+ */
235
329
  function getExtension(entry) {
236
330
  if (entry.isFile) return entry.fileName.slice(entry.fileName.lastIndexOf('.') + 1);
237
331
  return '';
238
332
  }
239
333
 
334
+ /**
335
+ * Copies a string to the system clipboard using a temporary input element.
336
+ * @param {string} value
337
+ * @returns {void}
338
+ * @deprecated Prefer the native `navigator.clipboard.writeText()` API.
339
+ */
240
340
  function copyToClipboard(value) {
241
341
  var elem = document.createElement('input');
242
342
  elem.value = value;
@@ -246,11 +346,20 @@ function copyToClipboard(value) {
246
346
  elem.remove();
247
347
  }
248
348
 
349
+ /**
350
+ * Parses the current page's URL query string into a key/value object.
351
+ * @returns {Object<string, string>}
352
+ */
249
353
  function urlSearchQuery() {
250
354
  return decodeURIComponent(window.location.search).slice(1).split('&').map(function (item) { return item.split('='); }).reduce(function (o, k) { o[k[0]] = k[1]; return o; }, {});
251
355
  }
252
356
 
253
- // those paths contain the internal type and path reference eg. shares/:shareId/folder/filename or files/folder/filename
357
+ /**
358
+ * Parses a Cloudron resource path into its components (type, path, shareId, apiPath).
359
+ * Handles paths like "files/folder/filename" or "shares/:shareId/folder/filename".
360
+ * @param {string} resourcePath
361
+ * @returns {{ type: string, path: string, shareId: string, apiPath: string, resourcePath: string }}
362
+ */
254
363
  function parseResourcePath(resourcePath) {
255
364
  var result = {
256
365
  type: '',
@@ -279,10 +388,22 @@ function parseResourcePath(resourcePath) {
279
388
  return result;
280
389
  }
281
390
 
391
+ /**
392
+ * Generates a unique identifier for a file entry, including its share ID if present.
393
+ * @param {{ share?: { id: string }, filePath: string }} entry
394
+ * @returns {string}
395
+ */
282
396
  function getEntryIdentifier(entry) {
283
397
  return (entry.share ? (entry.share.id + '/') : '') + entry.filePath;
284
398
  }
285
399
 
400
+ /**
401
+ * Sorts an array of objects by a given property, case-insensitive for strings.
402
+ * @param {Array<Object>} list - Array of objects to sort
403
+ * @param {string} prop - Property name to sort by
404
+ * @param {boolean} desc - If falsey, reverses the sort (descending order)
405
+ * @returns {Array<Object>}
406
+ */
286
407
  function entryListSort(list, prop, desc) {
287
408
  var tmp = list.sort(function (a, b) {
288
409
  var av = a[prop];
@@ -296,11 +417,20 @@ function entryListSort(list, prop, desc) {
296
417
  return tmp.reverse();
297
418
  }
298
419
 
420
+ /**
421
+ * Returns a promise that resolves after the specified number of milliseconds.
422
+ * @param {number} ms
423
+ * @returns {Promise<void>}
424
+ */
299
425
  function sleep(ms) {
300
426
  return new Promise(resolve => setTimeout(resolve, ms));
301
427
  }
302
428
 
303
- // this is from the Cloudron dashboard translation project en.json
429
+ /**
430
+ * Fallback English translations from the Cloudron dashboard translation project.
431
+ * Used when the app does not provide its own i18n strings.
432
+ * @type {Object<string, Object<string, string>>}
433
+ */
304
434
  const fallbackTranslations = {
305
435
  "main": {
306
436
  "dialog": {
@@ -410,6 +540,12 @@ const fallbackTranslations = {
410
540
  }
411
541
  };
412
542
 
543
+ /**
544
+ * Looks up a translation string by dot-separated key (e.g. "filemanager.title").
545
+ * Falls back to the key itself if the translation is not found.
546
+ * @param {string} id - Dot-separated translation key
547
+ * @returns {string}
548
+ */
413
549
  function translation(id) {
414
550
  let value;
415
551
  try {
@@ -422,6 +558,10 @@ function translation(id) {
422
558
  return value;
423
559
  }
424
560
 
561
+ /**
562
+ * Generates a random UUID v4 string using crypto.getRandomValues.
563
+ * @returns {string}
564
+ */
425
565
  function uuidv4() {
426
566
  return '10000000-1000-4000-8000-100000000000'.replace(/[018]/g, c =>
427
567
  (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
@@ -22,45 +22,33 @@
22
22
  </MainLayout>
23
23
  </template>
24
24
 
25
- <script>
25
+ <script setup>
26
26
 
27
+ import { reactive } from 'vue';
27
28
  import Button from '../components/Button.vue';
28
29
  import MainLayout from '../components/MainLayout.vue';
29
30
  import TopBar from '../components/TopBar.vue';
30
31
  import utils from '../utils.js';
31
32
 
32
- export default {
33
- name: 'GenericViewer',
34
- components: {
35
- Button,
36
- TopBar,
37
- MainLayout
38
- },
39
- props: {
40
- tr: {
41
- type: Function,
42
- default(id) { console.warn('Missing tr for GenericViewer'); return utils.translation(id); }
43
- }
44
- },
45
- emits: [ 'close' ],
46
- data() {
47
- return {
48
- entry: {}
49
- };
50
- },
51
- methods: {
52
- async open(entry) {
53
- if (!entry) return;
33
+ const props = defineProps({
34
+ tr: {
35
+ type: Function,
36
+ default(id) { console.warn('Missing tr for GenericViewer'); return utils.translation(id); }
37
+ }
38
+ });
54
39
 
55
- this.entry = entry;
56
- },
57
- onClose() {
58
- this.$emit('close');
59
- }
60
- },
61
- mounted() {
62
- }
63
- };
40
+ const emit = defineEmits([ 'close' ]);
41
+
42
+ const entry = reactive({});
43
+
44
+ async function open(e) {
45
+ if (!e) return;
46
+ Object.assign(entry, e);
47
+ }
48
+
49
+ function onClose() {
50
+ emit('close');
51
+ }
64
52
 
65
53
  </script>
66
54