@templatical/media-library 0.39.0 → 0.39.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +2 -3
  2. package/dist/MediaEditModal-DltAfTVH.js +311 -0
  3. package/dist/{ca-CGf3MuE2.js → ca-B1Ig3u8O.js} +9 -0
  4. package/dist/cdn/chunks/MediaEditModal-CeKcr-C0.js +3528 -0
  5. package/dist/cdn/chunks/MediaEditModal-CeKcr-C0.js.map +1 -0
  6. package/dist/cdn/chunks/{ca-CGf3MuE2.js → ca-B1Ig3u8O.js} +10 -1
  7. package/dist/cdn/chunks/{ca-CGf3MuE2.js.map → ca-B1Ig3u8O.js.map} +1 -1
  8. package/dist/cdn/chunks/{de-D5ebAV5i.js → de-BNbyJubD.js} +10 -1
  9. package/dist/cdn/chunks/{de-D5ebAV5i.js.map → de-BNbyJubD.js.map} +1 -1
  10. package/dist/cdn/chunks/en-CQxhpwqd.js +101 -0
  11. package/dist/cdn/chunks/en-CQxhpwqd.js.map +1 -0
  12. package/dist/cdn/chunks/{es-BG--QNW0.js → es-B2EH-TdJ.js} +10 -1
  13. package/dist/cdn/chunks/{es-BG--QNW0.js.map → es-B2EH-TdJ.js.map} +1 -1
  14. package/dist/cdn/chunks/{fr-Mdi4AlCR.js → fr-9SWy_n9K.js} +10 -1
  15. package/dist/cdn/chunks/{fr-Mdi4AlCR.js.map → fr-9SWy_n9K.js.map} +1 -1
  16. package/dist/cdn/chunks/{icons-DJG-T8pC.js → icons-DWBJnZvW.js} +1132 -1032
  17. package/dist/cdn/chunks/icons-DWBJnZvW.js.map +1 -0
  18. package/dist/{nl-D-6hT8te.js → cdn/chunks/nl-DJasgSvI.js} +11 -0
  19. package/dist/cdn/chunks/{nl-D-6hT8te.js.map → nl-DJasgSvI.js.map} +1 -1
  20. package/dist/cdn/chunks/{pt-BR-DMfAgDWi.js → pt-BR-BtCfbqSj.js} +10 -1
  21. package/dist/cdn/chunks/{pt-BR-DMfAgDWi.js.map → pt-BR-BtCfbqSj.js.map} +1 -1
  22. package/dist/cdn/chunks/useFocusTrap-tWtljvAm.js +535 -0
  23. package/dist/cdn/chunks/useFocusTrap-tWtljvAm.js.map +1 -0
  24. package/dist/cdn/media-library.css +1 -1
  25. package/dist/cdn/media-library.js +1422 -5258
  26. package/dist/cdn/media-library.js.map +1 -1
  27. package/dist/{de-D5ebAV5i.js → de-BNbyJubD.js} +9 -0
  28. package/dist/en-CQxhpwqd.js +99 -0
  29. package/dist/{es-BG--QNW0.js → es-B2EH-TdJ.js} +9 -0
  30. package/dist/{fr-Mdi4AlCR.js → fr-9SWy_n9K.js} +9 -0
  31. package/dist/index.d.ts +9 -0
  32. package/dist/{cdn/chunks/nl-D-6hT8te.js → nl-DJasgSvI.js} +9 -2
  33. package/dist/{pt-BR-DMfAgDWi.js → pt-BR-BtCfbqSj.js} +9 -0
  34. package/dist/templatical-media-library.css +1 -1
  35. package/dist/templatical-media-library.js +1320 -1931
  36. package/dist/useFocusTrap-6eIRXtCA.js +111 -0
  37. package/package.json +9 -9
  38. package/dist/cdn/chunks/icons-DJG-T8pC.js.map +0 -1
package/README.md CHANGED
@@ -15,7 +15,7 @@ npm install @templatical/media-library
15
15
 
16
16
  Peer dep: `vue@^3.5`. Not needed next to `@templatical/editor` — that package already contains the modal.
17
17
 
18
- > **Storage.** The library is storage-agnostic. Pass a `MediaProvider` — Cloud's adapter is `createCloudMediaProvider` from `@templatical/core/cloud`. See the [media contract](https://docs.templatical.com/backend/media) and the [Cloud adapter](https://docs.templatical.com/cloud/media-library).
18
+ > **Storage.** The library is storage-agnostic. Pass a `MediaProvider` — Cloud's adapter is `createCloudMediaProvider` from `@templatical/core/cloud`. See the [media contract](https://docs.templatical.com/backend/media).
19
19
 
20
20
  ## Usage
21
21
 
@@ -42,7 +42,7 @@ media.unmount();
42
42
 
43
43
  ### Vue component
44
44
 
45
- Use `MediaLibraryModal` inside a Vue 3 app. See [docs](https://docs.templatical.com/cloud/media-library) for the full prop reference.
45
+ Use `MediaLibraryModal` inside a Vue 3 app. See the [media contract](https://docs.templatical.com/backend/media) for the provider the modal sits on.
46
46
 
47
47
  ```ts
48
48
  import { MediaLibraryModal } from '@templatical/media-library';
@@ -105,7 +105,6 @@ If you embed `MediaLibraryModal` manually inside another shadow-DOM-mounted UI,
105
105
  ## Documentation
106
106
 
107
107
  - [Media contract](https://docs.templatical.com/backend/media)
108
- - [Cloud media library](https://docs.templatical.com/cloud/media-library)
109
108
  - [Shadow DOM (editor)](https://docs.templatical.com/guide/shadow-dom)
110
109
 
111
110
  Full reference at **[docs.templatical.com](https://docs.templatical.com)**.
@@ -0,0 +1,311 @@
1
+ import { i as e, l as t, n, o as r, r as i, t as a } from "./useFocusTrap-6eIRXtCA.js";
2
+ import { Fragment as o, Teleport as s, Transition as c, computed as l, createBlock as ee, createCommentVNode as u, createElementBlock as d, createElementVNode as f, createTextVNode as p, createVNode as m, defineComponent as h, inject as g, normalizeClass as _, normalizeStyle as te, openBlock as v, ref as y, renderList as ne, toDisplayString as b, unref as x, vModelText as S, watch as re, withCtx as ie, withDirectives as C, withModifiers as ae } from "vue";
3
+ import { Cropper as oe } from "vue-advanced-cropper";
4
+ //#region src/composables/useImageCrop.ts
5
+ var se = {
6
+ free: void 0,
7
+ square: 1,
8
+ landscape43: 4 / 3,
9
+ landscape169: 16 / 9,
10
+ original: void 0
11
+ };
12
+ function ce(e) {
13
+ return e === "image/png" || e === "image/gif" ? {
14
+ mimeType: "image/png",
15
+ quality: 1
16
+ } : e === "image/webp" ? {
17
+ mimeType: "image/webp",
18
+ quality: .92
19
+ } : {
20
+ mimeType: "image/jpeg",
21
+ quality: .92
22
+ };
23
+ }
24
+ function le(e, t, n) {
25
+ let r = e.width, i = e.height;
26
+ if (!t && !n) return e;
27
+ let a = r, o = i;
28
+ if (t && r > t && (a = t, o = Math.round(t / r * i)), n && o > n) {
29
+ let e = n / o;
30
+ a = Math.round(a * e), o = n;
31
+ }
32
+ if (a === r && o === i) return e;
33
+ let s = document.createElement("canvas");
34
+ s.width = a, s.height = o;
35
+ let c = s.getContext("2d");
36
+ return c && (c.imageSmoothingEnabled = !0, c.imageSmoothingQuality = "high", c.drawImage(e, 0, 0, a, o)), s;
37
+ }
38
+ function ue(e, t, n) {
39
+ return new Promise((r, i) => {
40
+ e.toBlob((e) => {
41
+ if (!e) {
42
+ i(/* @__PURE__ */ Error("Failed to create blob from canvas"));
43
+ return;
44
+ }
45
+ let a = n.mimeType.split("/")[1], o = `${t.replace(/\.[^.]+$/, "")}.${a}`;
46
+ r(new File([e], o, { type: n.mimeType }));
47
+ }, n.mimeType, n.quality);
48
+ });
49
+ }
50
+ function de(e, t, n, r) {
51
+ let i = e, a = t;
52
+ if (n && i > n) {
53
+ let e = n / i;
54
+ i = n, a = Math.round(a * e);
55
+ }
56
+ if (r && a > r) {
57
+ let e = r / a;
58
+ a = r, i = Math.round(i * e);
59
+ }
60
+ return {
61
+ width: i,
62
+ height: a
63
+ };
64
+ }
65
+ //#endregion
66
+ //#region src/components/media/MediaEditModal.vue?vue&type=script&setup=true&lang.ts
67
+ var fe = ["data-tpl-theme"], pe = { class: "tpl:shrink-0 tpl:p-5 tpl:pb-4" }, me = {
68
+ id: "tpl-media-edit-title",
69
+ class: "tpl:text-sm tpl:font-semibold",
70
+ style: { color: "var(--tpl-text)" }
71
+ }, he = { class: "tpl:min-h-0 tpl:flex-1 tpl:overflow-y-auto tpl:px-5" }, ge = {
72
+ key: 0,
73
+ class: "tpl:mb-4"
74
+ }, _e = {
75
+ class: "tpl:relative tpl:mb-3 tpl:overflow-hidden tpl:rounded-md tpl:border",
76
+ style: {
77
+ "border-color": "var(--tpl-border)",
78
+ height: "300px",
79
+ "background-color": "var(--tpl-bg)"
80
+ }
81
+ }, ve = { class: "tpl:space-y-3" }, ye = {
82
+ class: "tpl:mb-1.5 tpl:block tpl:text-xs tpl:font-medium",
83
+ style: { color: "var(--tpl-text-muted)" }
84
+ }, be = { class: "tpl:flex tpl:flex-wrap tpl:gap-1.5" }, xe = ["onClick"], Se = { class: "tpl:flex tpl:gap-3" }, Ce = { class: "tpl:flex-1" }, w = {
85
+ class: "tpl:mb-1 tpl:block tpl:text-xs tpl:font-medium",
86
+ style: { color: "var(--tpl-text-muted)" }
87
+ }, T = {
88
+ class: "tpl:font-normal",
89
+ style: { color: "var(--tpl-text-dim)" }
90
+ }, E = { class: "tpl:relative" }, D = ["value", "placeholder"], O = {
91
+ class: "tpl:absolute tpl:top-1/2 tpl:right-2.5 tpl:-translate-y-1/2 tpl:text-xs",
92
+ style: { color: "var(--tpl-text-dim)" }
93
+ }, k = { class: "tpl:flex-1" }, A = {
94
+ class: "tpl:mb-1 tpl:block tpl:text-xs tpl:font-medium",
95
+ style: { color: "var(--tpl-text-muted)" }
96
+ }, we = {
97
+ class: "tpl:font-normal",
98
+ style: { color: "var(--tpl-text-dim)" }
99
+ }, Te = { class: "tpl:relative" }, Ee = ["value", "placeholder"], De = {
100
+ class: "tpl:absolute tpl:top-1/2 tpl:right-2.5 tpl:-translate-y-1/2 tpl:text-xs",
101
+ style: { color: "var(--tpl-text-dim)" }
102
+ }, Oe = {
103
+ key: 0,
104
+ class: "tpl:flex tpl:items-center tpl:gap-1 tpl:text-xs",
105
+ style: { color: "var(--tpl-text-muted)" }
106
+ }, ke = {
107
+ class: "tpl:font-medium",
108
+ style: { color: "var(--tpl-text)" }
109
+ }, Ae = { class: "tpl:mb-3" }, je = {
110
+ for: "tpl-media-filename",
111
+ class: "tpl:mb-1 tpl:block tpl:text-xs tpl:font-medium",
112
+ style: { color: "var(--tpl-text-muted)" }
113
+ }, Me = ["autofocus"], Ne = {
114
+ key: 1,
115
+ class: "tpl:mb-4"
116
+ }, Pe = {
117
+ for: "tpl-media-alt",
118
+ class: "tpl:mb-1 tpl:block tpl:text-xs tpl:font-medium",
119
+ style: { color: "var(--tpl-text-muted)" }
120
+ }, j = ["placeholder"], Fe = { class: "tpl:flex tpl:shrink-0 tpl:justify-end tpl:gap-2 tpl:p-5 tpl:pt-4" }, Ie = ["disabled"], M = /*#__PURE__*/ n(/* @__PURE__ */ h({
121
+ __name: "MediaEditModal",
122
+ props: {
123
+ visible: { type: Boolean },
124
+ item: {}
125
+ },
126
+ emits: ["save", "close"],
127
+ setup(n, { emit: h }) {
128
+ let M = n, N = h, { t: P } = e(), Le = g(t, null), F = g(r, y(null)), Re = P.mediaLibrary, { isImageMimeType: I } = i(), L = y(""), R = y(""), z = y(null), B = y("free"), V = y(void 0), H = y(void 0), U = y(""), W = y(""), G = y(void 0), K = y(null), q = y(!1), J = y(!1), Y = y(!1), X = l(() => M.item ? [
129
+ "image/jpeg",
130
+ "image/png",
131
+ "image/webp",
132
+ "image/gif"
133
+ ].includes(M.item.mimeType ?? "") : !1), ze = l(() => B.value === "original" ? G.value : se[B.value]), Z = l(() => K.value ? de(K.value.width, K.value.height, V.value, H.value) : null);
134
+ re(() => M.visible, (e) => {
135
+ e && M.item && (L.value = M.item.filename ?? "", R.value = M.item.alt ?? "", B.value = "free", V.value = void 0, H.value = void 0, U.value = "", W.value = "", G.value = void 0, K.value = null, q.value = !1, Y.value = !1, M.item.width && M.item.height && (G.value = M.item.width / M.item.height));
136
+ });
137
+ function Be(e) {
138
+ e.coordinates && (K.value = {
139
+ width: Math.round(e.coordinates.width),
140
+ height: Math.round(e.coordinates.height)
141
+ }, Y.value = !0);
142
+ }
143
+ function Ve() {
144
+ q.value = !0, !G.value && M.item?.width && M.item?.height && (G.value = M.item.width / M.item.height);
145
+ }
146
+ function He(e) {
147
+ let t = e.target.value;
148
+ U.value = t, V.value = t && parseInt(t, 10) || void 0;
149
+ }
150
+ function Ue(e) {
151
+ let t = e.target.value;
152
+ W.value = t, H.value = t && parseInt(t, 10) || void 0;
153
+ }
154
+ async function Q() {
155
+ let e = L.value.trim();
156
+ if (!e || !M.item || J.value) return;
157
+ let t = I(M.item.mimeType ?? ""), n;
158
+ if (X.value && z.value && Y.value) {
159
+ J.value = !0;
160
+ try {
161
+ let { canvas: e } = z.value.getResult();
162
+ if (e) {
163
+ let t = le(e, V.value, H.value), r = ce(M.item.mimeType ?? "");
164
+ n = { file: await ue(t, M.item.filename ?? "image", r) };
165
+ }
166
+ } catch {
167
+ J.value = !1;
168
+ return;
169
+ }
170
+ J.value = !1;
171
+ }
172
+ N("save", M.item.id, e, t ? R.value : void 0, n), N("close");
173
+ }
174
+ let $ = y(null), We = l(() => M.visible && M.item !== null);
175
+ a($, We);
176
+ function Ge(e) {
177
+ if (e.stopPropagation(), e.key === "Enter" && !J.value) {
178
+ if (e.target?.closest("textarea, [contenteditable]")) return;
179
+ e.preventDefault(), Q();
180
+ }
181
+ e.key === "Escape" && N("close");
182
+ }
183
+ return (e, t) => (v(), ee(s, { to: x(F) || "body" }, [m(c, {
184
+ "enter-active-class": "tpl:transition tpl:ease-out tpl:duration-150",
185
+ "enter-from-class": "tpl:opacity-0",
186
+ "enter-to-class": "tpl:opacity-100",
187
+ "leave-active-class": "tpl:transition tpl:ease-in tpl:duration-100",
188
+ "leave-from-class": "tpl:opacity-100",
189
+ "leave-to-class": "tpl:opacity-0"
190
+ }, {
191
+ default: ie(() => [n.visible && n.item ? (v(), d("div", {
192
+ key: 0,
193
+ "data-tpl-theme": x(Le),
194
+ class: _([x(F) ? void 0 : "tpl", "tpl:fixed tpl:inset-0 tpl:z-10 tpl:flex tpl:items-center tpl:justify-center tpl:p-4"]),
195
+ style: { "background-color": "var(--tpl-overlay)" },
196
+ onClick: t[3] ||= ae((e) => N("close"), ["self"]),
197
+ onKeydown: Ge
198
+ }, [f("div", {
199
+ ref_key: "dialogRef",
200
+ ref: $,
201
+ role: "dialog",
202
+ "aria-modal": "true",
203
+ "aria-labelledby": "tpl-media-edit-title",
204
+ class: _(["tpl:flex tpl:max-h-[90%] tpl:w-full tpl:flex-col tpl:overflow-hidden tpl:rounded-lg tpl:shadow-xl", X.value ? "tpl:max-w-2xl" : "tpl:max-w-sm"]),
205
+ style: { "background-color": "var(--tpl-bg-elevated)" }
206
+ }, [
207
+ f("div", pe, [f("h3", me, b(x(P).mediaLibrary.editFile), 1)]),
208
+ f("div", he, [
209
+ X.value ? (v(), d("div", ge, [f("div", _e, [m(x(oe), {
210
+ ref_key: "cropperRef",
211
+ ref: z,
212
+ src: n.item.url,
213
+ "stencil-props": { aspectRatio: ze.value },
214
+ class: "tpl:h-full tpl:w-full",
215
+ "background-class": "tpl-cropper-background",
216
+ onChange: Be,
217
+ onReady: Ve
218
+ }, null, 8, ["src", "stencil-props"])]), f("div", ve, [
219
+ f("div", null, [f("label", ye, b(x(P).mediaLibrary.cropAspectRatio), 1), f("div", be, [(v(), d(o, null, ne([
220
+ "free",
221
+ "square",
222
+ "landscape43",
223
+ "landscape169",
224
+ "original"
225
+ ], (e) => f("button", {
226
+ key: e,
227
+ type: "button",
228
+ class: "tpl:cursor-pointer tpl:rounded-md tpl:border tpl:px-2.5 tpl:py-1 tpl:text-xs tpl:font-medium tpl:transition-all tpl:duration-150",
229
+ style: te({
230
+ borderColor: B.value === e ? "var(--tpl-primary)" : "var(--tpl-border)",
231
+ backgroundColor: B.value === e ? "var(--tpl-primary-light)" : "var(--tpl-bg)",
232
+ color: B.value === e ? "var(--tpl-primary)" : "var(--tpl-text)"
233
+ }),
234
+ onClick: (t) => B.value = e
235
+ }, b(x(Re)[`crop${e.charAt(0).toUpperCase()}${e.slice(1)}`]), 13, xe)), 64))])]),
236
+ f("div", Se, [f("div", Ce, [f("label", w, [p(b(x(P).mediaLibrary.cropMaxWidth) + " ", 1), f("span", T, b(x(P).mediaLibrary.cropOptional), 1)]), f("div", E, [f("input", {
237
+ value: U.value,
238
+ type: "number",
239
+ min: "1",
240
+ class: "tpl:w-full tpl:rounded-md tpl:border tpl:py-1.5 tpl:pr-8 tpl:pl-3 tpl:text-xs tpl:outline-none",
241
+ style: {
242
+ "border-color": "var(--tpl-border)",
243
+ "background-color": "var(--tpl-bg)",
244
+ color: "var(--tpl-text)"
245
+ },
246
+ placeholder: K.value?.width?.toString() || "",
247
+ onInput: He
248
+ }, null, 40, D), f("span", O, b(x(P).mediaLibrary.cropPixels), 1)])]), f("div", k, [f("label", A, [p(b(x(P).mediaLibrary.cropMaxHeight) + " ", 1), f("span", we, b(x(P).mediaLibrary.cropOptional), 1)]), f("div", Te, [f("input", {
249
+ value: W.value,
250
+ type: "number",
251
+ min: "1",
252
+ class: "tpl:w-full tpl:rounded-md tpl:border tpl:py-1.5 tpl:pr-8 tpl:pl-3 tpl:text-xs tpl:outline-none",
253
+ style: {
254
+ "border-color": "var(--tpl-border)",
255
+ "background-color": "var(--tpl-bg)",
256
+ color: "var(--tpl-text)"
257
+ },
258
+ placeholder: K.value?.height?.toString() || "",
259
+ onInput: Ue
260
+ }, null, 40, Ee), f("span", De, b(x(P).mediaLibrary.cropPixels), 1)])])]),
261
+ Z.value ? (v(), d("div", Oe, [f("span", null, b(x(P).mediaLibrary.cropOutputSize) + ": ", 1), f("span", ke, b(Z.value.width) + " x " + b(Z.value.height) + " " + b(x(P).mediaLibrary.cropPixels), 1)])) : u("", !0)
262
+ ])])) : u("", !0),
263
+ f("div", Ae, [f("label", je, b(x(P).mediaLibrary.fileName), 1), C(f("input", {
264
+ id: "tpl-media-filename",
265
+ "onUpdate:modelValue": t[0] ||= (e) => L.value = e,
266
+ type: "text",
267
+ class: "tpl:w-full tpl:rounded-md tpl:border tpl:px-3 tpl:py-1.5 tpl:text-xs tpl:outline-none",
268
+ style: {
269
+ "border-color": "var(--tpl-border)",
270
+ "background-color": "var(--tpl-bg)",
271
+ color: "var(--tpl-text)"
272
+ },
273
+ autofocus: !X.value
274
+ }, null, 8, Me), [[S, L.value]])]),
275
+ x(I)(n.item.mimeType ?? "") ? (v(), d("div", Ne, [f("label", Pe, b(x(P).mediaLibrary.altText), 1), C(f("input", {
276
+ id: "tpl-media-alt",
277
+ "onUpdate:modelValue": t[1] ||= (e) => R.value = e,
278
+ type: "text",
279
+ class: "tpl:w-full tpl:rounded-md tpl:border tpl:px-3 tpl:py-1.5 tpl:text-xs tpl:outline-none",
280
+ style: {
281
+ "border-color": "var(--tpl-border)",
282
+ "background-color": "var(--tpl-bg)",
283
+ color: "var(--tpl-text)"
284
+ },
285
+ placeholder: x(P).mediaLibrary.altTextPlaceholder
286
+ }, null, 8, j), [[S, R.value]])])) : u("", !0)
287
+ ]),
288
+ f("div", Fe, [f("button", {
289
+ class: "tpl:cursor-pointer tpl:rounded-md tpl:border tpl:px-3 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:transition-all tpl:duration-150",
290
+ style: {
291
+ "border-color": "var(--tpl-border)",
292
+ color: "var(--tpl-text)",
293
+ "background-color": "var(--tpl-bg)"
294
+ },
295
+ onClick: t[2] ||= (e) => N("close")
296
+ }, b(x(P).mediaLibrary.cancel), 1), f("button", {
297
+ class: "tpl:cursor-pointer tpl:rounded-md tpl:px-3 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:transition-all tpl:duration-150 tpl:hover:bg-[var(--tpl-primary-hover)] tpl:disabled:cursor-not-allowed tpl:disabled:opacity-50",
298
+ style: {
299
+ "background-color": "var(--tpl-primary)",
300
+ color: "var(--tpl-on-primary)"
301
+ },
302
+ disabled: J.value,
303
+ onClick: Q
304
+ }, b(J.value ? x(P).mediaLibrary.saving : x(P).mediaLibrary.saveChanges), 9, Ie)])
305
+ ], 2)], 42, fe)) : u("", !0)]),
306
+ _: 1
307
+ })], 8, ["to"]));
308
+ }
309
+ }), [["__scopeId", "data-v-6bdfafa4"]]);
310
+ //#endregion
311
+ export { M as default };
@@ -77,6 +77,15 @@ var e = { mediaLibrary: {
77
77
  cropOutputSize: "Mida de sortida",
78
78
  cropPixels: "px",
79
79
  cropOptional: "(opcional)",
80
+ close: "Tanca",
81
+ searchAriaLabel: "Cerca fitxers",
82
+ filterAriaLabel: "Filtra per tipus",
83
+ filesListAriaLabel: "Fitxers",
84
+ loading: "S'està carregant",
85
+ expandFolder: "Expandeix la carpeta",
86
+ collapseFolder: "Redueix la carpeta",
87
+ deleteFolder: "Suprimeix la carpeta",
88
+ deleteFolderConfirm: "Confirma la supressió",
80
89
  storageTooltip: "{used} de {total} utilitzats ({remaining} restants)"
81
90
  } };
82
91
  //#endregion