@jjlmoya/utils-audiovisual 1.2.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.
Files changed (120) hide show
  1. package/package.json +60 -0
  2. package/src/category/i18n/en.ts +198 -0
  3. package/src/category/i18n/es.ts +198 -0
  4. package/src/category/i18n/fr.ts +198 -0
  5. package/src/category/index.ts +17 -0
  6. package/src/category/seo.astro +15 -0
  7. package/src/components/PreviewNavSidebar.astro +116 -0
  8. package/src/components/PreviewToolbar.astro +143 -0
  9. package/src/data.ts +4 -0
  10. package/src/env.d.ts +5 -0
  11. package/src/index.ts +32 -0
  12. package/src/layouts/PreviewLayout.astro +117 -0
  13. package/src/pages/[locale]/[slug].astro +146 -0
  14. package/src/pages/[locale].astro +251 -0
  15. package/src/pages/index.astro +4 -0
  16. package/src/tests/faq_count.test.ts +19 -0
  17. package/src/tests/locale_completeness.test.ts +42 -0
  18. package/src/tests/mocks/astro_mock.js +2 -0
  19. package/src/tests/no_h1_in_components.test.ts +48 -0
  20. package/src/tests/seo_length.test.ts +22 -0
  21. package/src/tests/tool_validation.test.ts +17 -0
  22. package/src/tool/chromaticLens/bibliography.astro +17 -0
  23. package/src/tool/chromaticLens/component.astro +178 -0
  24. package/src/tool/chromaticLens/i18n/en.ts +246 -0
  25. package/src/tool/chromaticLens/i18n/es.ts +244 -0
  26. package/src/tool/chromaticLens/i18n/fr.ts +244 -0
  27. package/src/tool/chromaticLens/index.ts +43 -0
  28. package/src/tool/chromaticLens/logic.ts +87 -0
  29. package/src/tool/chromaticLens/seo.astro +15 -0
  30. package/src/tool/chromaticLens/style.css +308 -0
  31. package/src/tool/chromaticLens/ui.ts +109 -0
  32. package/src/tool/collageMaker/bibliography.astro +17 -0
  33. package/src/tool/collageMaker/component.astro +302 -0
  34. package/src/tool/collageMaker/i18n/en.ts +233 -0
  35. package/src/tool/collageMaker/i18n/es.ts +231 -0
  36. package/src/tool/collageMaker/i18n/fr.ts +231 -0
  37. package/src/tool/collageMaker/index.ts +51 -0
  38. package/src/tool/collageMaker/logic.ts +134 -0
  39. package/src/tool/collageMaker/seo.astro +15 -0
  40. package/src/tool/collageMaker/style.css +386 -0
  41. package/src/tool/exifCleaner/bibliography.astro +18 -0
  42. package/src/tool/exifCleaner/component.astro +162 -0
  43. package/src/tool/exifCleaner/i18n/en.ts +277 -0
  44. package/src/tool/exifCleaner/i18n/es.ts +277 -0
  45. package/src/tool/exifCleaner/i18n/fr.ts +277 -0
  46. package/src/tool/exifCleaner/index.ts +57 -0
  47. package/src/tool/exifCleaner/logic.ts +135 -0
  48. package/src/tool/exifCleaner/seo.astro +18 -0
  49. package/src/tool/exifCleaner/style.css +289 -0
  50. package/src/tool/exifCleaner/ui.ts +117 -0
  51. package/src/tool/imageCompressor/bibliography.astro +17 -0
  52. package/src/tool/imageCompressor/component.astro +262 -0
  53. package/src/tool/imageCompressor/i18n/en.ts +232 -0
  54. package/src/tool/imageCompressor/i18n/es.ts +230 -0
  55. package/src/tool/imageCompressor/i18n/fr.ts +230 -0
  56. package/src/tool/imageCompressor/index.ts +50 -0
  57. package/src/tool/imageCompressor/logic.ts +79 -0
  58. package/src/tool/imageCompressor/seo.astro +15 -0
  59. package/src/tool/imageCompressor/style.css +503 -0
  60. package/src/tool/printQualityCalculator/bibliography.astro +18 -0
  61. package/src/tool/printQualityCalculator/component.astro +318 -0
  62. package/src/tool/printQualityCalculator/i18n/en.ts +247 -0
  63. package/src/tool/printQualityCalculator/i18n/es.ts +245 -0
  64. package/src/tool/printQualityCalculator/i18n/fr.ts +245 -0
  65. package/src/tool/printQualityCalculator/index.ts +56 -0
  66. package/src/tool/printQualityCalculator/logic.ts +53 -0
  67. package/src/tool/printQualityCalculator/seo.astro +18 -0
  68. package/src/tool/printQualityCalculator/style.css +491 -0
  69. package/src/tool/printQualityCalculator/ui.ts +122 -0
  70. package/src/tool/privacyBlur/bibliography.astro +17 -0
  71. package/src/tool/privacyBlur/component.astro +230 -0
  72. package/src/tool/privacyBlur/i18n/en.ts +238 -0
  73. package/src/tool/privacyBlur/i18n/es.ts +236 -0
  74. package/src/tool/privacyBlur/i18n/fr.ts +236 -0
  75. package/src/tool/privacyBlur/index.ts +49 -0
  76. package/src/tool/privacyBlur/logic.ts +249 -0
  77. package/src/tool/privacyBlur/seo.astro +15 -0
  78. package/src/tool/privacyBlur/style.css +332 -0
  79. package/src/tool/privacyBlur/ui.ts +124 -0
  80. package/src/tool/subtitleSync/bibliography.astro +17 -0
  81. package/src/tool/subtitleSync/component.astro +187 -0
  82. package/src/tool/subtitleSync/i18n/en.ts +241 -0
  83. package/src/tool/subtitleSync/i18n/es.ts +241 -0
  84. package/src/tool/subtitleSync/i18n/fr.ts +241 -0
  85. package/src/tool/subtitleSync/index.ts +49 -0
  86. package/src/tool/subtitleSync/logic.ts +91 -0
  87. package/src/tool/subtitleSync/seo.astro +15 -0
  88. package/src/tool/subtitleSync/style.css +325 -0
  89. package/src/tool/subtitleSync/ui.ts +152 -0
  90. package/src/tool/timelapseCalculator/bibliography.astro +15 -0
  91. package/src/tool/timelapseCalculator/component.astro +148 -0
  92. package/src/tool/timelapseCalculator/i18n/en.ts +169 -0
  93. package/src/tool/timelapseCalculator/i18n/es.ts +169 -0
  94. package/src/tool/timelapseCalculator/i18n/fr.ts +169 -0
  95. package/src/tool/timelapseCalculator/index.ts +52 -0
  96. package/src/tool/timelapseCalculator/logic.ts +46 -0
  97. package/src/tool/timelapseCalculator/seo.astro +18 -0
  98. package/src/tool/timelapseCalculator/style.css +285 -0
  99. package/src/tool/tvDistance/bibliography.astro +17 -0
  100. package/src/tool/tvDistance/component.astro +178 -0
  101. package/src/tool/tvDistance/i18n/en.ts +223 -0
  102. package/src/tool/tvDistance/i18n/es.ts +223 -0
  103. package/src/tool/tvDistance/i18n/fr.ts +223 -0
  104. package/src/tool/tvDistance/index.ts +49 -0
  105. package/src/tool/tvDistance/logic.ts +47 -0
  106. package/src/tool/tvDistance/seo.astro +15 -0
  107. package/src/tool/tvDistance/style.css +435 -0
  108. package/src/tool/tvDistance/ui.ts +66 -0
  109. package/src/tool/videoFrameExtractor/bibliography.astro +17 -0
  110. package/src/tool/videoFrameExtractor/component.astro +285 -0
  111. package/src/tool/videoFrameExtractor/i18n/en.ts +235 -0
  112. package/src/tool/videoFrameExtractor/i18n/es.ts +235 -0
  113. package/src/tool/videoFrameExtractor/i18n/fr.ts +235 -0
  114. package/src/tool/videoFrameExtractor/index.ts +53 -0
  115. package/src/tool/videoFrameExtractor/logic.ts +49 -0
  116. package/src/tool/videoFrameExtractor/seo.astro +15 -0
  117. package/src/tool/videoFrameExtractor/style.css +426 -0
  118. package/src/tool/videoFrameExtractor/ui.ts +179 -0
  119. package/src/tools.ts +25 -0
  120. package/src/types.ts +72 -0
@@ -0,0 +1,503 @@
1
+ .ic-dashboard {
2
+ max-width: 900px;
3
+ margin: 0 auto;
4
+ display: flex;
5
+ flex-direction: column;
6
+ gap: 1rem;
7
+ }
8
+
9
+ :root {
10
+ --ic-bg: #fff;
11
+ --ic-bg-muted: #f8fafc;
12
+ --ic-border: #e2e8f0;
13
+ --ic-text: #111827;
14
+ --ic-text-muted: #6b7280;
15
+ --ic-accent: #10b981;
16
+ --ic-accent-dark: #059669;
17
+ --ic-accent-light: #f0fdf4;
18
+ --ic-success: #10b981;
19
+ --ic-error: #ef4444;
20
+ --ic-error-dark: #dc2626;
21
+ --ic-warning: #f59e0b;
22
+ --ic-shadow: rgba(0, 0, 0, 0.03);
23
+ }
24
+
25
+ .theme-dark {
26
+ --ic-bg: #0f172a;
27
+ --ic-bg-muted: #1e293b;
28
+ --ic-border: #334155;
29
+ --ic-text: #f1f5f9;
30
+ --ic-text-muted: #cbd5e1;
31
+ --ic-accent: #10b981;
32
+ --ic-accent-dark: #059669;
33
+ --ic-accent-light: rgba(16, 185, 129, 0.1);
34
+ --ic-shadow: rgba(0, 0, 0, 0.4);
35
+ }
36
+
37
+ .ic-global-settings {
38
+ display: flex;
39
+ justify-content: flex-end;
40
+ gap: 1.5rem;
41
+ background: rgba(255, 255, 255, 0.5);
42
+ backdrop-filter: blur(8px);
43
+ padding: 0.75rem 1.5rem;
44
+ border-radius: 0.75rem;
45
+ border: 1px solid rgba(255, 255, 255, 0.35);
46
+ color: #374151;
47
+ flex-wrap: wrap;
48
+ }
49
+
50
+ .theme-dark .ic-global-settings {
51
+ background: rgba(30, 41, 59, 0.6);
52
+ border-color: rgba(71, 85, 105, 0.5);
53
+ color: var(--ic-text-muted);
54
+ }
55
+
56
+ .ic-toggle-group {
57
+ display: flex;
58
+ align-items: center;
59
+ gap: 0.5rem;
60
+ }
61
+
62
+ .ic-webp-switch {
63
+ position: relative;
64
+ display: inline-block;
65
+ width: 44px;
66
+ height: 24px;
67
+ }
68
+
69
+ .ic-webp-switch input {
70
+ opacity: 0;
71
+ width: 0;
72
+ height: 0;
73
+ }
74
+
75
+ .ic-webp-slider {
76
+ position: absolute;
77
+ cursor: pointer;
78
+ inset: 0;
79
+ background: var(--ic-border);
80
+ border-radius: 24px;
81
+ transition: 0.3s;
82
+ }
83
+
84
+ .ic-webp-slider::before {
85
+ content: '';
86
+ position: absolute;
87
+ width: 18px;
88
+ height: 18px;
89
+ left: 3px;
90
+ bottom: 3px;
91
+ background: var(--ic-bg);
92
+ border-radius: 50%;
93
+ transition: 0.3s;
94
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
95
+ }
96
+
97
+ .ic-webp-switch input:checked + .ic-webp-slider {
98
+ background: var(--ic-accent);
99
+ }
100
+
101
+ .ic-webp-switch input:checked + .ic-webp-slider::before {
102
+ transform: translateX(20px);
103
+ }
104
+
105
+ .ic-toggle-label {
106
+ font-size: 0.9rem;
107
+ font-weight: 600;
108
+ }
109
+
110
+ .ic-settings-group {
111
+ display: flex;
112
+ align-items: center;
113
+ gap: 0.75rem;
114
+ font-size: 0.9rem;
115
+ font-weight: 600;
116
+ }
117
+
118
+ .ic-mini-slider {
119
+ width: 100px;
120
+ accent-color: var(--ic-accent);
121
+ }
122
+
123
+ /* ── Drop zone ── */
124
+ .ic-drop-zone {
125
+ position: relative;
126
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.85) 0%, rgba(255, 255, 255, 0.45) 100%);
127
+ border: 3px dashed var(--ic-accent);
128
+ border-radius: 1.5rem;
129
+ padding: 4rem 2rem;
130
+ text-align: center;
131
+ cursor: pointer;
132
+ transition: all 0.3s ease;
133
+ backdrop-filter: blur(12px);
134
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.04);
135
+ }
136
+
137
+ .theme-dark .ic-drop-zone {
138
+ background: linear-gradient(180deg, rgba(30, 41, 59, 0.85) 0%, rgba(15, 23, 42, 0.6) 100%);
139
+ }
140
+
141
+ .ic-drop-zone.ic-dragover,
142
+ .ic-drop-zone:hover {
143
+ transform: scale(1.01);
144
+ border-color: var(--ic-accent-dark);
145
+ background: linear-gradient(180deg, var(--ic-accent-light) 0%, rgba(255, 255, 255, 0.6) 100%);
146
+ }
147
+
148
+ .theme-dark .ic-drop-zone.ic-dragover,
149
+ .theme-dark .ic-drop-zone:hover {
150
+ background: linear-gradient(180deg, rgba(6, 78, 59, 0.4) 0%, rgba(15, 23, 42, 0.6) 100%);
151
+ }
152
+
153
+ .ic-file-label {
154
+ display: flex;
155
+ flex-direction: column;
156
+ align-items: center;
157
+ gap: 0.5rem;
158
+ cursor: pointer;
159
+ pointer-events: none;
160
+ }
161
+
162
+ .ic-upload-icon {
163
+ color: var(--ic-accent);
164
+ margin-bottom: 0.5rem;
165
+ }
166
+
167
+ .ic-upload-text {
168
+ font-size: 1.5rem;
169
+ font-weight: 700;
170
+ color: var(--ic-text);
171
+ }
172
+
173
+ .ic-upload-subtext {
174
+ color: var(--ic-text-muted);
175
+ font-size: 1rem;
176
+ margin-bottom: 1rem;
177
+ }
178
+
179
+ .ic-upload-btn {
180
+ background: var(--ic-text);
181
+ color: var(--ic-bg);
182
+ padding: 0.75rem 2rem;
183
+ border-radius: 9999px;
184
+ font-weight: 600;
185
+ font-size: 0.95rem;
186
+ pointer-events: auto;
187
+ transition: background 0.2s;
188
+ }
189
+
190
+ .ic-upload-btn:hover {
191
+ background: var(--ic-text-muted);
192
+ }
193
+
194
+ .ic-drop-zone input[type="file"] {
195
+ position: absolute;
196
+ inset: 0;
197
+ width: 100%;
198
+ height: 100%;
199
+ opacity: 0;
200
+ cursor: pointer;
201
+ }
202
+
203
+ /* ── File list ── */
204
+ .ic-file-list-container {
205
+ margin-top: 1.5rem;
206
+ }
207
+
208
+ .ic-list-header {
209
+ display: flex;
210
+ justify-content: space-between;
211
+ align-items: center;
212
+ margin-bottom: 1rem;
213
+ padding: 0 0.5rem;
214
+ }
215
+
216
+ .ic-list-header h3 {
217
+ font-size: 1.25rem;
218
+ font-weight: 700;
219
+ color: var(--ic-text);
220
+ margin: 0;
221
+ }
222
+
223
+ .ic-total-savings {
224
+ font-weight: 700;
225
+ font-size: 1rem;
226
+ }
227
+
228
+ .ic-file-list {
229
+ list-style: none;
230
+ padding: 1rem;
231
+ margin: 0;
232
+ display: flex;
233
+ flex-direction: column;
234
+ gap: 0.75rem;
235
+ background: var(--ic-bg-muted);
236
+ border-radius: 1rem;
237
+ border: 1px solid var(--ic-border);
238
+ }
239
+
240
+ /* ── File item ── */
241
+ .ic-file-item {
242
+ background: var(--ic-bg);
243
+ border-radius: 0.75rem;
244
+ padding: 0.75rem 1.25rem;
245
+ display: grid;
246
+ grid-template-columns: 2fr 2.5rem 2fr;
247
+ align-items: center;
248
+ gap: 1rem;
249
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.03);
250
+ transition: box-shadow 0.2s;
251
+ }
252
+
253
+ .ic-file-item:hover {
254
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
255
+ }
256
+
257
+ .ic-preview-col {
258
+ display: flex;
259
+ align-items: center;
260
+ gap: 1rem;
261
+ overflow: hidden;
262
+ }
263
+
264
+ .ic-preview-wrapper {
265
+ width: 48px;
266
+ height: 48px;
267
+ border-radius: 0.5rem;
268
+ overflow: hidden;
269
+ background: var(--ic-bg-muted);
270
+ flex-shrink: 0;
271
+ }
272
+
273
+ .ic-preview-img {
274
+ width: 100%;
275
+ height: 100%;
276
+ object-fit: cover;
277
+ }
278
+
279
+ .ic-file-info {
280
+ display: flex;
281
+ flex-direction: column;
282
+ overflow: hidden;
283
+ }
284
+
285
+ .ic-filename {
286
+ font-weight: 600;
287
+ color: var(--ic-text);
288
+ white-space: nowrap;
289
+ overflow: hidden;
290
+ text-overflow: ellipsis;
291
+ font-size: 0.9rem;
292
+ }
293
+
294
+ .ic-orig-size {
295
+ color: var(--ic-text-muted);
296
+ font-size: 0.8rem;
297
+ }
298
+
299
+ .ic-arrow-col {
300
+ display: flex;
301
+ justify-content: center;
302
+ }
303
+
304
+ .ic-arrow-circle {
305
+ background: var(--ic-accent-light);
306
+ color: var(--ic-accent);
307
+ width: 36px;
308
+ height: 36px;
309
+ border-radius: 50%;
310
+ display: flex;
311
+ align-items: center;
312
+ justify-content: center;
313
+ flex-shrink: 0;
314
+ }
315
+
316
+ .ic-result-col {
317
+ display: flex;
318
+ align-items: center;
319
+ justify-content: flex-end;
320
+ gap: 1.25rem;
321
+ }
322
+
323
+ .ic-savings-pill {
324
+ display: flex;
325
+ flex-direction: column;
326
+ align-items: center;
327
+ }
328
+
329
+ .ic-new-size {
330
+ font-weight: 700;
331
+ color: var(--ic-text);
332
+ font-size: 0.95rem;
333
+ }
334
+
335
+ .ic-savings-pct {
336
+ color: var(--ic-accent);
337
+ font-weight: 800;
338
+ font-size: 0.85rem;
339
+ }
340
+
341
+ .ic-savings-pill-negative .ic-savings-pct {
342
+ color: var(--ic-error);
343
+ }
344
+
345
+ .ic-item-actions {
346
+ display: flex;
347
+ gap: 0.4rem;
348
+ }
349
+
350
+ .ic-icon-btn {
351
+ background: var(--ic-bg-muted);
352
+ border: none;
353
+ color: var(--ic-text-muted);
354
+ width: 36px;
355
+ height: 36px;
356
+ border-radius: 0.5rem;
357
+ display: flex;
358
+ align-items: center;
359
+ justify-content: center;
360
+ cursor: pointer;
361
+ transition: background 0.2s, color 0.2s;
362
+ text-decoration: none;
363
+ flex-shrink: 0;
364
+ }
365
+
366
+ .ic-icon-btn:hover {
367
+ background: var(--ic-border);
368
+ color: var(--ic-text);
369
+ }
370
+
371
+ .ic-download-btn {
372
+ background: var(--ic-accent);
373
+ color: var(--ic-bg);
374
+ }
375
+
376
+ .ic-download-btn:hover {
377
+ background: var(--ic-accent-dark);
378
+ color: var(--ic-bg);
379
+ }
380
+
381
+ /* ── Inline editor ── */
382
+ .ic-inline-editor {
383
+ grid-column: 1 / -1;
384
+ background: var(--ic-bg-muted);
385
+ border-radius: 0.75rem;
386
+ padding: 1rem 1.25rem;
387
+ margin-top: 0.25rem;
388
+ display: flex;
389
+ justify-content: space-between;
390
+ align-items: center;
391
+ gap: 1rem;
392
+ border: 1px solid var(--ic-border);
393
+ animation: ic-slide-down 0.2s ease-out;
394
+ }
395
+
396
+ @keyframes ic-slide-down {
397
+ from {
398
+ opacity: 0;
399
+ transform: translateY(-4px);
400
+ }
401
+ to {
402
+ opacity: 1;
403
+ transform: translateY(0);
404
+ }
405
+ }
406
+
407
+ .ic-editor-controls {
408
+ display: flex;
409
+ gap: 1.5rem;
410
+ flex-wrap: wrap;
411
+ }
412
+
413
+ .ic-editor-group {
414
+ display: flex;
415
+ flex-direction: column;
416
+ gap: 0.25rem;
417
+ font-size: 0.85rem;
418
+ font-weight: 600;
419
+ color: var(--ic-text-muted);
420
+ }
421
+
422
+ .ic-editor-group input[type="range"] {
423
+ accent-color: var(--ic-accent);
424
+ }
425
+
426
+ .ic-editor-group input[type="number"] {
427
+ padding: 0.25rem 0.5rem;
428
+ border: 1px solid var(--ic-border);
429
+ border-radius: 0.375rem;
430
+ font-size: 0.85rem;
431
+ background: var(--ic-bg);
432
+ color: var(--ic-text);
433
+ }
434
+
435
+ .ic-editor-close {
436
+ background: var(--ic-border);
437
+ border: none;
438
+ padding: 0.4rem 0.875rem;
439
+ border-radius: 0.375rem;
440
+ font-weight: 600;
441
+ font-size: 0.85rem;
442
+ cursor: pointer;
443
+ transition: background 0.2s;
444
+ color: var(--ic-text-muted);
445
+ white-space: nowrap;
446
+ }
447
+
448
+ .ic-editor-close:hover {
449
+ background: var(--ic-border);
450
+ }
451
+
452
+ /* ── Download all ── */
453
+ .ic-global-actions {
454
+ margin-top: 1.5rem;
455
+ display: flex;
456
+ justify-content: center;
457
+ }
458
+
459
+ .ic-primary-btn {
460
+ background: var(--ic-text);
461
+ color: var(--ic-bg);
462
+ border: none;
463
+ padding: 1rem 3rem;
464
+ border-radius: 9999px;
465
+ font-weight: 700;
466
+ font-size: 1.1rem;
467
+ cursor: pointer;
468
+ transition: background 0.2s, transform 0.1s;
469
+ }
470
+
471
+ .ic-primary-btn:hover {
472
+ background: var(--ic-text-muted);
473
+ }
474
+
475
+ .ic-primary-btn:active {
476
+ transform: scale(0.98);
477
+ }
478
+
479
+ @media (max-width: 600px) {
480
+ .ic-file-item {
481
+ grid-template-columns: 1fr;
482
+ justify-items: center;
483
+ text-align: center;
484
+ }
485
+
486
+ .ic-preview-col {
487
+ flex-direction: column;
488
+ }
489
+
490
+ .ic-arrow-col {
491
+ transform: rotate(90deg);
492
+ }
493
+
494
+ .ic-result-col {
495
+ width: 100%;
496
+ justify-content: space-around;
497
+ }
498
+
499
+ .ic-global-settings {
500
+ flex-direction: column;
501
+ align-items: flex-start;
502
+ }
503
+ }
@@ -0,0 +1,18 @@
1
+ ---
2
+ import { Bibliography as SharedBibliography } from '@jjlmoya/utils-shared';
3
+ import { printQualityCalculator, type PrintQualityCalculatorLocaleContent } from './index';
4
+ import type { KnownLocale } from '../../types';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ }
9
+
10
+ const { locale = 'es' } = Astro.props;
11
+ const localeContentLoader = (printQualityCalculator.i18n as Record<string, () => Promise<PrintQualityCalculatorLocaleContent>>)[locale];
12
+ const content = localeContentLoader ? await localeContentLoader() : null;
13
+ if (!content) return null;
14
+
15
+ const { bibliography } = content;
16
+ ---
17
+
18
+ <SharedBibliography links={bibliography} />