@jjlmoya/utils-audiovisual 1.17.0 → 1.18.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/package.json +1 -1
- package/src/category/index.ts +2 -0
- package/src/entries.ts +4 -1
- package/src/index.ts +1 -0
- package/src/pages/[locale]/[slug].astro +28 -12
- package/src/tests/locale_completeness.test.ts +2 -36
- package/src/tests/shared-test-helpers.ts +56 -0
- package/src/tests/tool_exports.test.ts +34 -0
- package/src/tests/tool_validation.test.ts +2 -2
- package/src/tool/chromaticLens/bibliography.ts +12 -0
- package/src/tool/chromaticLens/entry.ts +2 -0
- package/src/tool/chromaticLens/i18n/de.ts +1 -15
- package/src/tool/chromaticLens/i18n/en.ts +1 -15
- package/src/tool/chromaticLens/i18n/es.ts +1 -13
- package/src/tool/chromaticLens/i18n/fr.ts +1 -13
- package/src/tool/chromaticLens/i18n/id.ts +1 -15
- package/src/tool/chromaticLens/i18n/it.ts +1 -15
- package/src/tool/chromaticLens/i18n/ja.ts +1 -15
- package/src/tool/chromaticLens/i18n/ko.ts +1 -15
- package/src/tool/chromaticLens/i18n/nl.ts +1 -15
- package/src/tool/chromaticLens/i18n/pl.ts +1 -15
- package/src/tool/chromaticLens/i18n/pt.ts +1 -15
- package/src/tool/chromaticLens/i18n/ru.ts +1 -15
- package/src/tool/chromaticLens/i18n/sv.ts +1 -15
- package/src/tool/chromaticLens/i18n/tr.ts +1 -15
- package/src/tool/chromaticLens/i18n/zh.ts +1 -15
- package/src/tool/chromaticLens/seo.astro +1 -1
- package/src/tool/collageMaker/bibliography.ts +8 -0
- package/src/tool/collageMaker/entry.ts +2 -0
- package/src/tool/collageMaker/i18n/de.ts +1 -11
- package/src/tool/collageMaker/i18n/en.ts +1 -11
- package/src/tool/collageMaker/i18n/es.ts +1 -9
- package/src/tool/collageMaker/i18n/fr.ts +1 -9
- package/src/tool/collageMaker/i18n/id.ts +1 -11
- package/src/tool/collageMaker/i18n/it.ts +1 -11
- package/src/tool/collageMaker/i18n/ja.ts +1 -11
- package/src/tool/collageMaker/i18n/ko.ts +1 -11
- package/src/tool/collageMaker/i18n/nl.ts +1 -11
- package/src/tool/collageMaker/i18n/pl.ts +1 -11
- package/src/tool/collageMaker/i18n/pt.ts +1 -11
- package/src/tool/collageMaker/i18n/ru.ts +1 -11
- package/src/tool/collageMaker/i18n/sv.ts +1 -11
- package/src/tool/collageMaker/i18n/tr.ts +1 -11
- package/src/tool/collageMaker/i18n/zh.ts +1 -11
- package/src/tool/collageMaker/seo.astro +1 -1
- package/src/tool/depthOfFieldCalculator/bibliography.astro +15 -0
- package/src/tool/depthOfFieldCalculator/bibliography.ts +20 -0
- package/src/tool/depthOfFieldCalculator/component.astro +341 -0
- package/src/tool/depthOfFieldCalculator/depth-of-field-calculator.css +417 -0
- package/src/tool/depthOfFieldCalculator/entry.ts +52 -0
- package/src/tool/depthOfFieldCalculator/i18n/de.ts +141 -0
- package/src/tool/depthOfFieldCalculator/i18n/en.ts +141 -0
- package/src/tool/depthOfFieldCalculator/i18n/es.ts +141 -0
- package/src/tool/depthOfFieldCalculator/i18n/fr.ts +141 -0
- package/src/tool/depthOfFieldCalculator/i18n/id.ts +141 -0
- package/src/tool/depthOfFieldCalculator/i18n/it.ts +141 -0
- package/src/tool/depthOfFieldCalculator/i18n/ja.ts +141 -0
- package/src/tool/depthOfFieldCalculator/i18n/ko.ts +141 -0
- package/src/tool/depthOfFieldCalculator/i18n/nl.ts +141 -0
- package/src/tool/depthOfFieldCalculator/i18n/pl.ts +141 -0
- package/src/tool/depthOfFieldCalculator/i18n/pt.ts +141 -0
- package/src/tool/depthOfFieldCalculator/i18n/ru.ts +141 -0
- package/src/tool/depthOfFieldCalculator/i18n/sv.ts +141 -0
- package/src/tool/depthOfFieldCalculator/i18n/tr.ts +141 -0
- package/src/tool/depthOfFieldCalculator/i18n/zh.ts +141 -0
- package/src/tool/depthOfFieldCalculator/index.ts +10 -0
- package/src/tool/depthOfFieldCalculator/logic.ts +91 -0
- package/src/tool/depthOfFieldCalculator/seo.astro +15 -0
- package/src/tool/exifCleaner/bibliography.ts +12 -0
- package/src/tool/exifCleaner/entry.ts +2 -0
- package/src/tool/exifCleaner/i18n/de.ts +1 -15
- package/src/tool/exifCleaner/i18n/en.ts +1 -15
- package/src/tool/exifCleaner/i18n/es.ts +1 -15
- package/src/tool/exifCleaner/i18n/fr.ts +1 -15
- package/src/tool/exifCleaner/i18n/id.ts +1 -15
- package/src/tool/exifCleaner/i18n/it.ts +1 -15
- package/src/tool/exifCleaner/i18n/ja.ts +1 -15
- package/src/tool/exifCleaner/i18n/ko.ts +1 -15
- package/src/tool/exifCleaner/i18n/nl.ts +1 -15
- package/src/tool/exifCleaner/i18n/pl.ts +1 -15
- package/src/tool/exifCleaner/i18n/pt.ts +1 -15
- package/src/tool/exifCleaner/i18n/ru.ts +1 -15
- package/src/tool/exifCleaner/i18n/sv.ts +1 -15
- package/src/tool/exifCleaner/i18n/tr.ts +1 -15
- package/src/tool/exifCleaner/i18n/zh.ts +1 -15
- package/src/tool/exifCleaner/seo.astro +2 -5
- package/src/tool/imageCompressor/bibliography.ts +12 -0
- package/src/tool/imageCompressor/entry.ts +2 -0
- package/src/tool/imageCompressor/i18n/de.ts +1 -15
- package/src/tool/imageCompressor/i18n/en.ts +1 -15
- package/src/tool/imageCompressor/i18n/es.ts +1 -13
- package/src/tool/imageCompressor/i18n/fr.ts +1 -13
- package/src/tool/imageCompressor/i18n/id.ts +1 -15
- package/src/tool/imageCompressor/i18n/it.ts +1 -15
- package/src/tool/imageCompressor/i18n/ja.ts +1 -15
- package/src/tool/imageCompressor/i18n/ko.ts +1 -15
- package/src/tool/imageCompressor/i18n/nl.ts +1 -15
- package/src/tool/imageCompressor/i18n/pl.ts +1 -15
- package/src/tool/imageCompressor/i18n/pt.ts +1 -15
- package/src/tool/imageCompressor/i18n/ru.ts +1 -15
- package/src/tool/imageCompressor/i18n/sv.ts +1 -15
- package/src/tool/imageCompressor/i18n/tr.ts +1 -15
- package/src/tool/imageCompressor/i18n/zh.ts +1 -15
- package/src/tool/imageCompressor/seo.astro +1 -1
- package/src/tool/printQualityCalculator/bibliography.ts +12 -0
- package/src/tool/printQualityCalculator/entry.ts +2 -0
- package/src/tool/printQualityCalculator/i18n/de.ts +1 -15
- package/src/tool/printQualityCalculator/i18n/en.ts +1 -15
- package/src/tool/printQualityCalculator/i18n/es.ts +1 -13
- package/src/tool/printQualityCalculator/i18n/fr.ts +1 -13
- package/src/tool/printQualityCalculator/i18n/id.ts +1 -15
- package/src/tool/printQualityCalculator/i18n/it.ts +1 -15
- package/src/tool/printQualityCalculator/i18n/ja.ts +1 -15
- package/src/tool/printQualityCalculator/i18n/ko.ts +1 -15
- package/src/tool/printQualityCalculator/i18n/nl.ts +1 -15
- package/src/tool/printQualityCalculator/i18n/pl.ts +1 -15
- package/src/tool/printQualityCalculator/i18n/pt.ts +1 -15
- package/src/tool/printQualityCalculator/i18n/ru.ts +1 -15
- package/src/tool/printQualityCalculator/i18n/sv.ts +1 -15
- package/src/tool/printQualityCalculator/i18n/tr.ts +1 -15
- package/src/tool/printQualityCalculator/i18n/zh.ts +1 -15
- package/src/tool/printQualityCalculator/seo.astro +2 -5
- package/src/tool/privacyBlur/bibliography.ts +8 -0
- package/src/tool/privacyBlur/entry.ts +2 -0
- package/src/tool/privacyBlur/i18n/de.ts +1 -11
- package/src/tool/privacyBlur/i18n/en.ts +1 -11
- package/src/tool/privacyBlur/i18n/es.ts +1 -9
- package/src/tool/privacyBlur/i18n/fr.ts +1 -9
- package/src/tool/privacyBlur/i18n/id.ts +1 -11
- package/src/tool/privacyBlur/i18n/it.ts +1 -11
- package/src/tool/privacyBlur/i18n/ja.ts +1 -11
- package/src/tool/privacyBlur/i18n/ko.ts +1 -11
- package/src/tool/privacyBlur/i18n/nl.ts +1 -11
- package/src/tool/privacyBlur/i18n/pl.ts +1 -11
- package/src/tool/privacyBlur/i18n/pt.ts +1 -11
- package/src/tool/privacyBlur/i18n/ru.ts +1 -11
- package/src/tool/privacyBlur/i18n/sv.ts +1 -11
- package/src/tool/privacyBlur/i18n/tr.ts +1 -11
- package/src/tool/privacyBlur/i18n/zh.ts +1 -11
- package/src/tool/privacyBlur/seo.astro +1 -1
- package/src/tool/subtitleSync/bibliography.ts +12 -0
- package/src/tool/subtitleSync/entry.ts +2 -0
- package/src/tool/subtitleSync/i18n/de.ts +1 -13
- package/src/tool/subtitleSync/i18n/en.ts +1 -13
- package/src/tool/subtitleSync/i18n/es.ts +1 -13
- package/src/tool/subtitleSync/i18n/fr.ts +1 -13
- package/src/tool/subtitleSync/i18n/id.ts +1 -13
- package/src/tool/subtitleSync/i18n/it.ts +1 -13
- package/src/tool/subtitleSync/i18n/ja.ts +1 -13
- package/src/tool/subtitleSync/i18n/ko.ts +1 -13
- package/src/tool/subtitleSync/i18n/nl.ts +1 -13
- package/src/tool/subtitleSync/i18n/pl.ts +1 -13
- package/src/tool/subtitleSync/i18n/pt.ts +1 -13
- package/src/tool/subtitleSync/i18n/ru.ts +1 -13
- package/src/tool/subtitleSync/i18n/sv.ts +1 -13
- package/src/tool/subtitleSync/i18n/tr.ts +1 -13
- package/src/tool/subtitleSync/i18n/zh.ts +1 -13
- package/src/tool/subtitleSync/seo.astro +1 -1
- package/src/tool/timelapseCalculator/bibliography.ts +20 -0
- package/src/tool/timelapseCalculator/entry.ts +2 -0
- package/src/tool/timelapseCalculator/i18n/de.ts +1 -21
- package/src/tool/timelapseCalculator/i18n/en.ts +1 -21
- package/src/tool/timelapseCalculator/i18n/es.ts +1 -21
- package/src/tool/timelapseCalculator/i18n/fr.ts +1 -21
- package/src/tool/timelapseCalculator/i18n/id.ts +1 -21
- package/src/tool/timelapseCalculator/i18n/it.ts +1 -21
- package/src/tool/timelapseCalculator/i18n/ja.ts +1 -21
- package/src/tool/timelapseCalculator/i18n/ko.ts +1 -21
- package/src/tool/timelapseCalculator/i18n/nl.ts +1 -21
- package/src/tool/timelapseCalculator/i18n/pl.ts +1 -21
- package/src/tool/timelapseCalculator/i18n/pt.ts +1 -21
- package/src/tool/timelapseCalculator/i18n/ru.ts +1 -21
- package/src/tool/timelapseCalculator/i18n/sv.ts +1 -21
- package/src/tool/timelapseCalculator/i18n/tr.ts +1 -21
- package/src/tool/timelapseCalculator/i18n/zh.ts +1 -21
- package/src/tool/timelapseCalculator/seo.astro +2 -5
- package/src/tool/tvDistance/bibliography.ts +12 -0
- package/src/tool/tvDistance/entry.ts +2 -0
- package/src/tool/tvDistance/i18n/de.ts +1 -13
- package/src/tool/tvDistance/i18n/en.ts +1 -13
- package/src/tool/tvDistance/i18n/es.ts +1 -13
- package/src/tool/tvDistance/i18n/fr.ts +1 -13
- package/src/tool/tvDistance/i18n/id.ts +1 -13
- package/src/tool/tvDistance/i18n/it.ts +1 -13
- package/src/tool/tvDistance/i18n/ja.ts +1 -13
- package/src/tool/tvDistance/i18n/ko.ts +1 -13
- package/src/tool/tvDistance/i18n/nl.ts +1 -13
- package/src/tool/tvDistance/i18n/pl.ts +1 -13
- package/src/tool/tvDistance/i18n/pt.ts +1 -13
- package/src/tool/tvDistance/i18n/ru.ts +1 -13
- package/src/tool/tvDistance/i18n/sv.ts +1 -13
- package/src/tool/tvDistance/i18n/tr.ts +1 -13
- package/src/tool/tvDistance/i18n/zh.ts +1 -13
- package/src/tool/tvDistance/seo.astro +1 -1
- package/src/tool/videoFrameExtractor/bibliography.ts +8 -0
- package/src/tool/videoFrameExtractor/entry.ts +2 -0
- package/src/tool/videoFrameExtractor/i18n/de.ts +1 -9
- package/src/tool/videoFrameExtractor/i18n/en.ts +1 -9
- package/src/tool/videoFrameExtractor/i18n/es.ts +1 -9
- package/src/tool/videoFrameExtractor/i18n/fr.ts +1 -8
- package/src/tool/videoFrameExtractor/i18n/id.ts +1 -9
- package/src/tool/videoFrameExtractor/i18n/it.ts +1 -8
- package/src/tool/videoFrameExtractor/i18n/ja.ts +1 -9
- package/src/tool/videoFrameExtractor/i18n/ko.ts +1 -9
- package/src/tool/videoFrameExtractor/i18n/nl.ts +1 -9
- package/src/tool/videoFrameExtractor/i18n/pl.ts +1 -9
- package/src/tool/videoFrameExtractor/i18n/pt.ts +1 -9
- package/src/tool/videoFrameExtractor/i18n/ru.ts +1 -9
- package/src/tool/videoFrameExtractor/i18n/sv.ts +1 -9
- package/src/tool/videoFrameExtractor/i18n/tr.ts +1 -9
- package/src/tool/videoFrameExtractor/i18n/zh.ts +1 -9
- package/src/tool/videoFrameExtractor/seo.astro +1 -1
- package/src/tools.ts +2 -0
- package/src/types.ts +0 -2
package/package.json
CHANGED
package/src/category/index.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { tvDistance } from '../tool/tvDistance/index';
|
|
|
9
9
|
import { imageCompressor } from '../tool/imageCompressor/index';
|
|
10
10
|
import { collageMaker } from '../tool/collageMaker/index';
|
|
11
11
|
import { videoFrameExtractor } from '../tool/videoFrameExtractor/index';
|
|
12
|
+
import { depthOfFieldCalculator } from '../tool/depthOfFieldCalculator/index';
|
|
12
13
|
|
|
13
14
|
export const audiovisualCategory: AudiovisualCategoryEntry = {
|
|
14
15
|
icon: 'mdi:camera-iris',
|
|
@@ -23,6 +24,7 @@ export const audiovisualCategory: AudiovisualCategoryEntry = {
|
|
|
23
24
|
imageCompressor as AudiovisualToolEntry,
|
|
24
25
|
collageMaker as AudiovisualToolEntry,
|
|
25
26
|
videoFrameExtractor as AudiovisualToolEntry,
|
|
27
|
+
depthOfFieldCalculator as AudiovisualToolEntry,
|
|
26
28
|
],
|
|
27
29
|
i18n: {
|
|
28
30
|
es: async () => (await import('./i18n/es')).content,
|
package/src/entries.ts
CHANGED
|
@@ -18,6 +18,8 @@ export { tvDistance } from './tool/tvDistance/entry';
|
|
|
18
18
|
export type { TvDistanceUI, TvDistanceLocaleContent } from './tool/tvDistance/entry';
|
|
19
19
|
export { videoFrameExtractor } from './tool/videoFrameExtractor/entry';
|
|
20
20
|
export type { VideoFrameExtractorUI, VideoFrameExtractorLocaleContent } from './tool/videoFrameExtractor/entry';
|
|
21
|
+
export { depthOfFieldCalculator } from './tool/depthOfFieldCalculator/entry';
|
|
22
|
+
export type { DepthOfFieldUI, DepthOfFieldLocaleContent } from './tool/depthOfFieldCalculator/entry';
|
|
21
23
|
export { audiovisualCategory, toolsCategory } from './category';
|
|
22
24
|
import { chromaticLens } from './tool/chromaticLens/entry';
|
|
23
25
|
import { collageMaker } from './tool/collageMaker/entry';
|
|
@@ -29,4 +31,5 @@ import { subtitleSync } from './tool/subtitleSync/entry';
|
|
|
29
31
|
import { timelapseCalculator } from './tool/timelapseCalculator/entry';
|
|
30
32
|
import { tvDistance } from './tool/tvDistance/entry';
|
|
31
33
|
import { videoFrameExtractor } from './tool/videoFrameExtractor/entry';
|
|
32
|
-
|
|
34
|
+
import { depthOfFieldCalculator } from './tool/depthOfFieldCalculator/entry';
|
|
35
|
+
export const ALL_ENTRIES = [chromaticLens, collageMaker, exifCleaner, imageCompressor, printQualityCalculator, privacyBlur, subtitleSync, timelapseCalculator, tvDistance, videoFrameExtractor, depthOfFieldCalculator];
|
package/src/index.ts
CHANGED
|
@@ -34,18 +34,28 @@ export async function getStaticPaths() {
|
|
|
34
34
|
]),
|
|
35
35
|
) as Partial<Record<KnownLocale, string>>;
|
|
36
36
|
|
|
37
|
+
const firstLoader = entry.i18n.en ?? Object.values(entry.i18n)[0];
|
|
38
|
+
const englishSlug = firstLoader ? (await firstLoader()).slug : entry.id;
|
|
39
|
+
|
|
37
40
|
for (const { locale, content } of localeContents) {
|
|
38
|
-
const allToolsNav =
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
const allToolsNav = (
|
|
42
|
+
await Promise.all(
|
|
43
|
+
ALL_TOOLS.map(async ({ entry: navEntry }) => {
|
|
44
|
+
const loader = navEntry.i18n[locale] ?? navEntry.i18n.en;
|
|
45
|
+
if (!loader) return null;
|
|
46
|
+
const navContent = await loader();
|
|
47
|
+
return {
|
|
48
|
+
id: navEntry.id,
|
|
49
|
+
title: navContent.title,
|
|
50
|
+
href: `/${locale}/${navContent.slug}`,
|
|
51
|
+
isActive: navEntry.id === entry.id,
|
|
52
|
+
};
|
|
53
|
+
}),
|
|
54
|
+
)
|
|
55
|
+
).filter(Boolean) as NavItem[];
|
|
46
56
|
paths.push({
|
|
47
57
|
params: { locale, slug: content.slug },
|
|
48
|
-
props: { Component, locale, content, localeUrls, allToolsNav },
|
|
58
|
+
props: { Component, locale, content, localeUrls, allToolsNav, englishSlug },
|
|
49
59
|
});
|
|
50
60
|
}
|
|
51
61
|
}
|
|
@@ -66,11 +76,16 @@ interface Props {
|
|
|
66
76
|
content: ToolLocaleContent;
|
|
67
77
|
localeUrls: Partial<Record<KnownLocale, string>>;
|
|
68
78
|
allToolsNav: NavItem[];
|
|
79
|
+
englishSlug: string;
|
|
69
80
|
}
|
|
70
81
|
|
|
71
|
-
const { Component, locale, content, localeUrls, allToolsNav } = Astro.props;
|
|
82
|
+
const { Component, locale, content, localeUrls, allToolsNav, englishSlug } = Astro.props;
|
|
83
|
+
|
|
84
|
+
const cssFiles = import.meta.glob("../../tool/*/*.css", { query: "?raw", import: "default" });
|
|
85
|
+
const cssKey = Object.keys(cssFiles).find((k) => k.endsWith(`/${englishSlug}.css`));
|
|
86
|
+
const toolCss = cssKey ? await cssFiles[cssKey]() as string : "";
|
|
72
87
|
|
|
73
|
-
const seoContent: UtilitySEOContent = { locale, sections: content.seo };
|
|
88
|
+
const seoContent: UtilitySEOContent = { locale, sections: content.seo ?? [] };
|
|
74
89
|
|
|
75
90
|
const words = content.title.split(" ");
|
|
76
91
|
const titleHighlight = words[0] || "";
|
|
@@ -89,8 +104,9 @@ const titleBase = words.slice(1).join(" ") || "";
|
|
|
89
104
|
tools={allToolsNav}
|
|
90
105
|
/>
|
|
91
106
|
<Fragment slot="head">
|
|
107
|
+
<Fragment set:html={toolCss ? `<style>${toolCss}</style>` : ''} />
|
|
92
108
|
{
|
|
93
|
-
content.schemas.map((schema: unknown) => (
|
|
109
|
+
( content.schemas ?? []).map((schema: unknown) => (
|
|
94
110
|
<script
|
|
95
111
|
is:inline
|
|
96
112
|
type="application/ld+json"
|
|
@@ -1,42 +1,8 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
2
|
import { ALL_TOOLS } from '../tools';
|
|
3
|
-
import type { ToolLocaleContent } from '../types';
|
|
4
3
|
|
|
5
4
|
describe('Locale Completeness Validation', () => {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
Object.keys(tool.entry.i18n).forEach((locale) => {
|
|
9
|
-
describe(`Locale: ${locale}`, () => {
|
|
10
|
-
it('faqTitle should be defined when faq items exist', async () => {
|
|
11
|
-
const loader = tool.entry.i18n[locale as keyof typeof tool.entry.i18n];
|
|
12
|
-
const content = (await loader?.()) as ToolLocaleContent;
|
|
13
|
-
|
|
14
|
-
if (content.faq.length > 0) {
|
|
15
|
-
expect(
|
|
16
|
-
content.faqTitle,
|
|
17
|
-
`Tool "${tool.entry.id}" locale "${locale}" has ${content.faq.length} FAQ items but is missing faqTitle`,
|
|
18
|
-
).toBeTruthy();
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it('bibliographyTitle should be defined when bibliography items exist', async () => {
|
|
23
|
-
const loader = tool.entry.i18n[locale as keyof typeof tool.entry.i18n];
|
|
24
|
-
const content = (await loader?.()) as ToolLocaleContent;
|
|
25
|
-
|
|
26
|
-
if (content.bibliography.length > 0) {
|
|
27
|
-
expect(
|
|
28
|
-
content.bibliographyTitle,
|
|
29
|
-
`Tool "${tool.entry.id}" locale "${locale}" has ${content.bibliography.length} bibliography items but is missing bibliographyTitle`,
|
|
30
|
-
).toBeTruthy();
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('all 10 tools registered', () => {
|
|
39
|
-
expect(ALL_TOOLS.length).toBe(10);
|
|
5
|
+
it('all 11 tools registered', () => {
|
|
6
|
+
expect(ALL_TOOLS.length).toBe(11);
|
|
40
7
|
});
|
|
41
8
|
});
|
|
42
|
-
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { ToolDefinition } from '../types';
|
|
2
|
+
|
|
3
|
+
export interface ToolExportValidationResult {
|
|
4
|
+
passed: boolean;
|
|
5
|
+
failures: string[];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function validateComponentType(
|
|
9
|
+
toolId: string,
|
|
10
|
+
componentName: string,
|
|
11
|
+
component: unknown,
|
|
12
|
+
failures: string[],
|
|
13
|
+
): void {
|
|
14
|
+
if (typeof component !== 'function') {
|
|
15
|
+
failures.push(`${toolId}: ${componentName} is not a function (${typeof component})`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async function validateComponentExecution(
|
|
20
|
+
toolId: string,
|
|
21
|
+
componentName: string,
|
|
22
|
+
fn: () => Promise<unknown>,
|
|
23
|
+
failures: string[],
|
|
24
|
+
): Promise<void> {
|
|
25
|
+
try {
|
|
26
|
+
const result = await fn();
|
|
27
|
+
if (!result || typeof result !== 'object') {
|
|
28
|
+
failures.push(`${toolId}: ${componentName} import returned invalid result`);
|
|
29
|
+
}
|
|
30
|
+
} catch (error) {
|
|
31
|
+
failures.push(`${toolId}: ${componentName} execution error - ${error instanceof Error ? error.message : 'unknown'}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function validateToolExports(tools: ToolDefinition[]): Promise<ToolExportValidationResult> {
|
|
36
|
+
const failures: string[] = [];
|
|
37
|
+
|
|
38
|
+
for (const tool of tools) {
|
|
39
|
+
validateComponentType(tool.entry.id, 'Component', tool.Component, failures);
|
|
40
|
+
validateComponentType(tool.entry.id, 'SEOComponent', tool.SEOComponent, failures);
|
|
41
|
+
validateComponentType(tool.entry.id, 'BibliographyComponent', tool.BibliographyComponent, failures);
|
|
42
|
+
|
|
43
|
+
const componentFn = tool.Component as () => Promise<unknown>;
|
|
44
|
+
const seoFn = tool.SEOComponent as () => Promise<unknown>;
|
|
45
|
+
const bibFn = tool.BibliographyComponent as () => Promise<unknown>;
|
|
46
|
+
|
|
47
|
+
await validateComponentExecution(tool.entry.id, 'Component', componentFn, failures);
|
|
48
|
+
await validateComponentExecution(tool.entry.id, 'SEOComponent', seoFn, failures);
|
|
49
|
+
await validateComponentExecution(tool.entry.id, 'BibliographyComponent', bibFn, failures);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
passed: failures.length === 0,
|
|
54
|
+
failures,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { ALL_TOOLS } from '../tools';
|
|
3
|
+
import { validateToolExports } from './shared-test-helpers';
|
|
4
|
+
|
|
5
|
+
describe('Tool Exports Pattern Validation', () => {
|
|
6
|
+
describe('Component Exports Format', () => {
|
|
7
|
+
ALL_TOOLS.forEach((tool) => {
|
|
8
|
+
it(`${tool.entry.id}: Component should be a lazy-loaded function`, () => {
|
|
9
|
+
expect(typeof tool.Component).toBe('function');
|
|
10
|
+
expect(tool.Component).toBeInstanceOf(Function);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it(`${tool.entry.id}: SEOComponent should be a lazy-loaded function`, () => {
|
|
14
|
+
expect(typeof tool.SEOComponent).toBe('function');
|
|
15
|
+
expect(tool.SEOComponent).toBeInstanceOf(Function);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it(`${tool.entry.id}: BibliographyComponent should be a lazy-loaded function`, () => {
|
|
19
|
+
expect(typeof tool.BibliographyComponent).toBe('function');
|
|
20
|
+
expect(tool.BibliographyComponent).toBeInstanceOf(Function);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe('Dynamic Import Validation', () => {
|
|
26
|
+
it('all tools must have functional dynamic imports', async () => {
|
|
27
|
+
const result = await validateToolExports(ALL_TOOLS);
|
|
28
|
+
if (!result.passed) {
|
|
29
|
+
throw new Error(`Tool export validation failed:\n${result.failures.join('\n')}`);
|
|
30
|
+
}
|
|
31
|
+
expect(result.passed).toBe(true);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -4,8 +4,8 @@ import { audiovisualCategory } from '../data';
|
|
|
4
4
|
|
|
5
5
|
describe('Tool Validation Suite', () => {
|
|
6
6
|
describe('Library Registration', () => {
|
|
7
|
-
it('should have
|
|
8
|
-
expect(ALL_TOOLS.length).toBe(
|
|
7
|
+
it('should have 11 tools in ALL_TOOLS', () => {
|
|
8
|
+
expect(ALL_TOOLS.length).toBe(11);
|
|
9
9
|
});
|
|
10
10
|
|
|
11
11
|
it('audiovisualCategory should be defined', () => {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { BibliographyEntry } from '../../types';
|
|
2
|
+
|
|
3
|
+
export const bibliography: BibliographyEntry[] = [
|
|
4
|
+
{
|
|
5
|
+
name: "Median Cut Algorithm - Wikipedia",
|
|
6
|
+
url: "https://en.wikipedia.org/wiki/Median_cut",
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
name: "Farblehre für Designer",
|
|
10
|
+
url: "https://www.smashingmagazine.com/2010/01/color-theory-for-designers-part-1-the-meaning-of-color/",
|
|
11
|
+
},
|
|
12
|
+
];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { bibliography } from '../bibliography';
|
|
1
2
|
import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
|
|
2
3
|
import type { ChromaticLensUI, ChromaticLensLocaleContent } from '../index';
|
|
3
4
|
|
|
@@ -14,8 +15,6 @@ const ui: ChromaticLensUI = {
|
|
|
14
15
|
copiedLabel: "Kopiert!",
|
|
15
16
|
colorCountLabel: "Anzahl der Farben",
|
|
16
17
|
changeImage: "Bild ändern",
|
|
17
|
-
faqTitle: "Häufig gestellte Fragen zur Farbetraktion",
|
|
18
|
-
bibliographyTitle: "Ressourcen und technische Dokumentation"
|
|
19
18
|
};
|
|
20
19
|
|
|
21
20
|
const faq: ChromaticLensLocaleContent['faq'] = [
|
|
@@ -52,17 +51,6 @@ const howTo: ChromaticLensLocaleContent['howTo'] = [
|
|
|
52
51
|
},
|
|
53
52
|
];
|
|
54
53
|
|
|
55
|
-
const bibliography: ChromaticLensLocaleContent['bibliography'] = [
|
|
56
|
-
{
|
|
57
|
-
name: "Median Cut Algorithm - Wikipedia",
|
|
58
|
-
url: "https://en.wikipedia.org/wiki/Median_cut",
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
name: "Farblehre für Designer",
|
|
62
|
-
url: "https://www.smashingmagazine.com/2010/01/color-theory-for-designers-part-1-the-meaning-of-color/",
|
|
63
|
-
},
|
|
64
|
-
];
|
|
65
|
-
|
|
66
54
|
const seo: ChromaticLensLocaleContent['seo'] = [
|
|
67
55
|
{
|
|
68
56
|
type: 'summary',
|
|
@@ -237,9 +225,7 @@ export const content: ChromaticLensLocaleContent = {
|
|
|
237
225
|
description,
|
|
238
226
|
ui,
|
|
239
227
|
seo,
|
|
240
|
-
faqTitle: "Häufig gestellte Fragen",
|
|
241
228
|
faq,
|
|
242
|
-
bibliographyTitle: "Referenzen",
|
|
243
229
|
bibliography,
|
|
244
230
|
howTo,
|
|
245
231
|
schemas: [faqSchema as any, howToSchema as any, appSchema],
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { bibliography } from '../bibliography';
|
|
1
2
|
import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
|
|
2
3
|
import type { ChromaticLensUI, ChromaticLensLocaleContent } from '../index';
|
|
3
4
|
|
|
@@ -14,8 +15,6 @@ const ui: ChromaticLensUI = {
|
|
|
14
15
|
copiedLabel: "Copied!",
|
|
15
16
|
colorCountLabel: "Number of colors",
|
|
16
17
|
changeImage: "Change image",
|
|
17
|
-
faqTitle: "Frequently asked questions about color extraction",
|
|
18
|
-
bibliographyTitle: "Resources and technical documentation"
|
|
19
18
|
};
|
|
20
19
|
|
|
21
20
|
const faq: ChromaticLensLocaleContent['faq'] = [
|
|
@@ -52,17 +51,6 @@ const howTo: ChromaticLensLocaleContent['howTo'] = [
|
|
|
52
51
|
},
|
|
53
52
|
];
|
|
54
53
|
|
|
55
|
-
const bibliography: ChromaticLensLocaleContent['bibliography'] = [
|
|
56
|
-
{
|
|
57
|
-
name: "Median Cut Algorithm - Wikipedia",
|
|
58
|
-
url: "https://en.wikipedia.org/wiki/Median_cut",
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
name: "Color Theory for Designers",
|
|
62
|
-
url: "https://www.smashingmagazine.com/2010/01/color-theory-for-designers-part-1-the-meaning-of-color/",
|
|
63
|
-
},
|
|
64
|
-
];
|
|
65
|
-
|
|
66
54
|
const seo: ChromaticLensLocaleContent['seo'] = [
|
|
67
55
|
{
|
|
68
56
|
type: 'summary',
|
|
@@ -237,9 +225,7 @@ export const content: ChromaticLensLocaleContent = {
|
|
|
237
225
|
description,
|
|
238
226
|
ui,
|
|
239
227
|
seo,
|
|
240
|
-
faqTitle: "Frequently Asked Questions",
|
|
241
228
|
faq,
|
|
242
|
-
bibliographyTitle: "References",
|
|
243
229
|
bibliography,
|
|
244
230
|
howTo,
|
|
245
231
|
schemas: [faqSchema as any, howToSchema as any, appSchema],
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { bibliography } from '../bibliography';
|
|
1
2
|
import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
|
|
2
3
|
import type { ChromaticLensUI, ChromaticLensLocaleContent } from '../index';
|
|
3
4
|
|
|
@@ -50,17 +51,6 @@ const howTo: ChromaticLensLocaleContent['howTo'] = [
|
|
|
50
51
|
},
|
|
51
52
|
];
|
|
52
53
|
|
|
53
|
-
const bibliography: ChromaticLensLocaleContent['bibliography'] = [
|
|
54
|
-
{
|
|
55
|
-
name: "Median Cut Algorithm - Wikipedia",
|
|
56
|
-
url: "https://en.wikipedia.org/wiki/Median_cut",
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
name: "Color Theory for Designers",
|
|
60
|
-
url: "https://www.smashingmagazine.com/2010/01/color-theory-for-designers-part-1-the-meaning-of-color/",
|
|
61
|
-
},
|
|
62
|
-
];
|
|
63
|
-
|
|
64
54
|
const seo: ChromaticLensLocaleContent['seo'] = [
|
|
65
55
|
{
|
|
66
56
|
type: 'summary',
|
|
@@ -236,9 +226,7 @@ export const content: ChromaticLensLocaleContent = {
|
|
|
236
226
|
ui,
|
|
237
227
|
seo,
|
|
238
228
|
faq,
|
|
239
|
-
faqTitle: 'Preguntas frecuentes sobre paletas de color',
|
|
240
229
|
bibliography,
|
|
241
|
-
bibliographyTitle: 'Recursos técnicos sobre teoría del color',
|
|
242
230
|
howTo,
|
|
243
231
|
schemas: [faqSchema as any, howToSchema as any, appSchema],
|
|
244
232
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { bibliography } from '../bibliography';
|
|
1
2
|
import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
|
|
2
3
|
import type { ChromaticLensUI, ChromaticLensLocaleContent } from '../index';
|
|
3
4
|
|
|
@@ -50,17 +51,6 @@ const howTo: ChromaticLensLocaleContent['howTo'] = [
|
|
|
50
51
|
},
|
|
51
52
|
];
|
|
52
53
|
|
|
53
|
-
const bibliography: ChromaticLensLocaleContent['bibliography'] = [
|
|
54
|
-
{
|
|
55
|
-
name: "Median Cut Algorithm - Wikipédia",
|
|
56
|
-
url: "https://fr.wikipedia.org/wiki/Coupure_m%C3%A9diane",
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
name: "Théorie des couleurs pour les designers",
|
|
60
|
-
url: "https://www.smashingmagazine.com/2010/01/color-theory-for-designers-part-1-the-meaning-of-color/",
|
|
61
|
-
},
|
|
62
|
-
];
|
|
63
|
-
|
|
64
54
|
const seo: ChromaticLensLocaleContent['seo'] = [
|
|
65
55
|
{
|
|
66
56
|
type: 'summary',
|
|
@@ -235,10 +225,8 @@ export const content: ChromaticLensLocaleContent = {
|
|
|
235
225
|
description,
|
|
236
226
|
ui,
|
|
237
227
|
seo,
|
|
238
|
-
faqTitle: "Frequently Asked Questions",
|
|
239
228
|
faq,
|
|
240
229
|
bibliography,
|
|
241
|
-
bibliographyTitle: "References",
|
|
242
230
|
howTo,
|
|
243
231
|
schemas: [faqSchema as any, howToSchema as any, appSchema],
|
|
244
232
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { bibliography } from '../bibliography';
|
|
1
2
|
import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
|
|
2
3
|
import type { ChromaticLensUI, ChromaticLensLocaleContent } from '../index';
|
|
3
4
|
|
|
@@ -14,8 +15,6 @@ const ui: ChromaticLensUI = {
|
|
|
14
15
|
copiedLabel: "Tersalin!",
|
|
15
16
|
colorCountLabel: "Jumlah warna",
|
|
16
17
|
changeImage: "Ganti gambar",
|
|
17
|
-
faqTitle: "Pertanyaan umum tentang ekstraksi warna",
|
|
18
|
-
bibliographyTitle: "Sumber daya dan dokumentasi teknis"
|
|
19
18
|
};
|
|
20
19
|
|
|
21
20
|
const faq: ChromaticLensLocaleContent['faq'] = [
|
|
@@ -52,17 +51,6 @@ const howTo: ChromaticLensLocaleContent['howTo'] = [
|
|
|
52
51
|
},
|
|
53
52
|
];
|
|
54
53
|
|
|
55
|
-
const bibliography: ChromaticLensLocaleContent['bibliography'] = [
|
|
56
|
-
{
|
|
57
|
-
name: "Median Cut Algorithm - Wikipedia",
|
|
58
|
-
url: "https://en.wikipedia.org/wiki/Median_cut",
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
name: "Teori Warna untuk Desainer",
|
|
62
|
-
url: "https://www.smashingmagazine.com/2010/01/color-theory-for-designers-part-1-the-meaning-of-color/",
|
|
63
|
-
},
|
|
64
|
-
];
|
|
65
|
-
|
|
66
54
|
const seo: ChromaticLensLocaleContent['seo'] = [
|
|
67
55
|
{
|
|
68
56
|
type: 'summary',
|
|
@@ -237,9 +225,7 @@ export const content: ChromaticLensLocaleContent = {
|
|
|
237
225
|
description,
|
|
238
226
|
ui,
|
|
239
227
|
seo,
|
|
240
|
-
faqTitle: "Pertanyaan yang Sering Diajukan",
|
|
241
228
|
faq,
|
|
242
|
-
bibliographyTitle: "Referensi",
|
|
243
229
|
bibliography,
|
|
244
230
|
howTo,
|
|
245
231
|
schemas: [faqSchema as any, howToSchema as any, appSchema],
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { bibliography } from '../bibliography';
|
|
1
2
|
import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
|
|
2
3
|
import type { ChromaticLensUI, ChromaticLensLocaleContent } from '../index';
|
|
3
4
|
|
|
@@ -14,8 +15,6 @@ const ui: ChromaticLensUI = {
|
|
|
14
15
|
copiedLabel: "Copiato!",
|
|
15
16
|
colorCountLabel: "Numero di colori",
|
|
16
17
|
changeImage: "Cambia immagine",
|
|
17
|
-
faqTitle: "Domande frequenti sull'estrazione del colore",
|
|
18
|
-
bibliographyTitle: "Risorse e documentazione tecnica"
|
|
19
18
|
};
|
|
20
19
|
|
|
21
20
|
const faq: ChromaticLensLocaleContent['faq'] = [
|
|
@@ -52,17 +51,6 @@ const howTo: ChromaticLensLocaleContent['howTo'] = [
|
|
|
52
51
|
},
|
|
53
52
|
];
|
|
54
53
|
|
|
55
|
-
const bibliography: ChromaticLensLocaleContent['bibliography'] = [
|
|
56
|
-
{
|
|
57
|
-
name: "Median Cut Algorithm - Wikipedia",
|
|
58
|
-
url: "https://en.wikipedia.org/wiki/Median_cut",
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
name: "Teoria del Colore per Designer",
|
|
62
|
-
url: "https://www.smashingmagazine.com/2010/01/color-theory-for-designers-part-1-the-meaning-of-color/",
|
|
63
|
-
},
|
|
64
|
-
];
|
|
65
|
-
|
|
66
54
|
const seo: ChromaticLensLocaleContent['seo'] = [
|
|
67
55
|
{
|
|
68
56
|
type: 'summary',
|
|
@@ -237,9 +225,7 @@ export const content: ChromaticLensLocaleContent = {
|
|
|
237
225
|
description,
|
|
238
226
|
ui,
|
|
239
227
|
seo,
|
|
240
|
-
faqTitle: "Domande Frequenti",
|
|
241
228
|
faq,
|
|
242
|
-
bibliographyTitle: "Riferimenti",
|
|
243
229
|
bibliography,
|
|
244
230
|
howTo,
|
|
245
231
|
schemas: [faqSchema as any, howToSchema as any, appSchema],
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { bibliography } from '../bibliography';
|
|
1
2
|
import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
|
|
2
3
|
import type { ChromaticLensUI, ChromaticLensLocaleContent } from '../index';
|
|
3
4
|
|
|
@@ -14,8 +15,6 @@ const ui: ChromaticLensUI = {
|
|
|
14
15
|
copiedLabel: "コピーしました!",
|
|
15
16
|
colorCountLabel: "色の数",
|
|
16
17
|
changeImage: "画像を変更",
|
|
17
|
-
faqTitle: "カラー抽出に関するよくある質問",
|
|
18
|
-
bibliographyTitle: "リソースと技術ドキュメント"
|
|
19
18
|
};
|
|
20
19
|
|
|
21
20
|
const faq: ChromaticLensLocaleContent['faq'] = [
|
|
@@ -52,17 +51,6 @@ const howTo: ChromaticLensLocaleContent['howTo'] = [
|
|
|
52
51
|
},
|
|
53
52
|
];
|
|
54
53
|
|
|
55
|
-
const bibliography: ChromaticLensLocaleContent['bibliography'] = [
|
|
56
|
-
{
|
|
57
|
-
name: "メディアンカット・アルゴリズム - Wikipedia",
|
|
58
|
-
url: "https://ja.wikipedia.org/wiki/%E3%83%A1%E3%83%87%E3%82%A3%E3%82%A2%E3%83%B3%E3%82%AB%E3%83%83%E3%83%88",
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
name: "デザイナーのための色彩理論",
|
|
62
|
-
url: "https://www.smashingmagazine.com/2010/01/color-theory-for-designers-part-1-the-meaning-of-color/",
|
|
63
|
-
},
|
|
64
|
-
];
|
|
65
|
-
|
|
66
54
|
const seo: ChromaticLensLocaleContent['seo'] = [
|
|
67
55
|
{
|
|
68
56
|
type: 'summary',
|
|
@@ -237,9 +225,7 @@ export const content: ChromaticLensLocaleContent = {
|
|
|
237
225
|
description,
|
|
238
226
|
ui,
|
|
239
227
|
seo,
|
|
240
|
-
faqTitle: "よくある質問",
|
|
241
228
|
faq,
|
|
242
|
-
bibliographyTitle: "リファレンス",
|
|
243
229
|
bibliography,
|
|
244
230
|
howTo,
|
|
245
231
|
schemas: [faqSchema as any, howToSchema as any, appSchema],
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { bibliography } from '../bibliography';
|
|
1
2
|
import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
|
|
2
3
|
import type { ChromaticLensUI, ChromaticLensLocaleContent } from '../index';
|
|
3
4
|
|
|
@@ -14,8 +15,6 @@ const ui: ChromaticLensUI = {
|
|
|
14
15
|
copiedLabel: "복사 완료!",
|
|
15
16
|
colorCountLabel: "색상 수",
|
|
16
17
|
changeImage: "이미지 변경",
|
|
17
|
-
faqTitle: "색상 추출에 관한 자주 묻는 질문",
|
|
18
|
-
bibliographyTitle: "리소스 및 기술 문서"
|
|
19
18
|
};
|
|
20
19
|
|
|
21
20
|
const faq: ChromaticLensLocaleContent['faq'] = [
|
|
@@ -52,17 +51,6 @@ const howTo: ChromaticLensLocaleContent['howTo'] = [
|
|
|
52
51
|
},
|
|
53
52
|
];
|
|
54
53
|
|
|
55
|
-
const bibliography: ChromaticLensLocaleContent['bibliography'] = [
|
|
56
|
-
{
|
|
57
|
-
name: "메디안 컷 알고리즘 - 위키백과",
|
|
58
|
-
url: "https://ko.wikipedia.org/wiki/%EB%A9%94%EB%94%94%EC%95%88_%EC%BB%B7_%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98",
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
name: "디자이너를 위한 색채 이론",
|
|
62
|
-
url: "https://www.smashingmagazine.com/2010/01/color-theory-for-designers-part-1-the-meaning-of-color/",
|
|
63
|
-
},
|
|
64
|
-
];
|
|
65
|
-
|
|
66
54
|
const seo: ChromaticLensLocaleContent['seo'] = [
|
|
67
55
|
{
|
|
68
56
|
type: 'summary',
|
|
@@ -237,9 +225,7 @@ export const content: ChromaticLensLocaleContent = {
|
|
|
237
225
|
description,
|
|
238
226
|
ui,
|
|
239
227
|
seo,
|
|
240
|
-
faqTitle: "자주 묻는 질문",
|
|
241
228
|
faq,
|
|
242
|
-
bibliographyTitle: "참고 문헌",
|
|
243
229
|
bibliography,
|
|
244
230
|
howTo,
|
|
245
231
|
schemas: [faqSchema as any, howToSchema as any, appSchema],
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { bibliography } from '../bibliography';
|
|
1
2
|
import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
|
|
2
3
|
import type { ChromaticLensUI, ChromaticLensLocaleContent } from '../index';
|
|
3
4
|
|
|
@@ -14,8 +15,6 @@ const ui: ChromaticLensUI = {
|
|
|
14
15
|
copiedLabel: "Gekopieerd!",
|
|
15
16
|
colorCountLabel: "Aantal kleuren",
|
|
16
17
|
changeImage: "Afbeelding wijzigen",
|
|
17
|
-
faqTitle: "Veelgestelde vragen over kleurextractie",
|
|
18
|
-
bibliographyTitle: "Hulpmiddelen en technische documentatie"
|
|
19
18
|
};
|
|
20
19
|
|
|
21
20
|
const faq: ChromaticLensLocaleContent['faq'] = [
|
|
@@ -52,17 +51,6 @@ const howTo: ChromaticLensLocaleContent['howTo'] = [
|
|
|
52
51
|
},
|
|
53
52
|
];
|
|
54
53
|
|
|
55
|
-
const bibliography: ChromaticLensLocaleContent['bibliography'] = [
|
|
56
|
-
{
|
|
57
|
-
name: "Median Cut Algorithm - Wikipedia",
|
|
58
|
-
url: "https://en.wikipedia.org/wiki/Median_cut",
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
name: "Kleurentheorie voor Ontwerpers",
|
|
62
|
-
url: "https://www.smashingmagazine.com/2010/01/color-theory-for-designers-part-1-the-meaning-of-color/",
|
|
63
|
-
},
|
|
64
|
-
];
|
|
65
|
-
|
|
66
54
|
const seo: ChromaticLensLocaleContent['seo'] = [
|
|
67
55
|
{
|
|
68
56
|
type: 'summary',
|
|
@@ -237,9 +225,7 @@ export const content: ChromaticLensLocaleContent = {
|
|
|
237
225
|
description,
|
|
238
226
|
ui,
|
|
239
227
|
seo,
|
|
240
|
-
faqTitle: "Veelgestelde Vragen",
|
|
241
228
|
faq,
|
|
242
|
-
bibliographyTitle: "Referenties",
|
|
243
229
|
bibliography,
|
|
244
230
|
howTo,
|
|
245
231
|
schemas: [faqSchema as any, howToSchema as any, appSchema],
|