@jjlmoya/utils-creative 1.7.0 → 1.9.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 +2 -1
- package/src/category/i18n/de.ts +9 -0
- package/src/category/i18n/id.ts +9 -0
- package/src/category/i18n/it.ts +9 -0
- package/src/category/i18n/ja.ts +9 -0
- package/src/category/i18n/ko.ts +9 -0
- package/src/category/i18n/nl.ts +9 -0
- package/src/category/i18n/pl.ts +9 -0
- package/src/category/i18n/pt.ts +9 -0
- package/src/category/i18n/ru.ts +9 -0
- package/src/category/i18n/sv.ts +9 -0
- package/src/category/i18n/tr.ts +9 -0
- package/src/category/i18n/zh.ts +9 -0
- package/src/category/index.ts +12 -0
- package/src/tests/faq_count.test.ts +1 -1
- package/src/tests/i18n_coverage.test.ts +36 -0
- package/src/tests/locale_completeness.test.ts +2 -2
- package/src/tests/slug_uniqueness.test.ts +81 -0
- package/src/tests/title_quality.test.ts +3 -3
- package/src/tool/bead-pattern-generator/i18n/de.ts +115 -0
- package/src/tool/bead-pattern-generator/i18n/en.ts +1 -1
- package/src/tool/bead-pattern-generator/i18n/es.ts +1 -1
- package/src/tool/bead-pattern-generator/i18n/fr.ts +1 -1
- package/src/tool/bead-pattern-generator/i18n/id.ts +115 -0
- package/src/tool/bead-pattern-generator/i18n/it.ts +115 -0
- package/src/tool/bead-pattern-generator/i18n/ja.ts +115 -0
- package/src/tool/bead-pattern-generator/i18n/ko.ts +115 -0
- package/src/tool/bead-pattern-generator/i18n/nl.ts +115 -0
- package/src/tool/bead-pattern-generator/i18n/pl.ts +115 -0
- package/src/tool/bead-pattern-generator/i18n/pt.ts +115 -0
- package/src/tool/bead-pattern-generator/i18n/ru.ts +115 -0
- package/src/tool/bead-pattern-generator/i18n/sv.ts +115 -0
- package/src/tool/bead-pattern-generator/i18n/tr.ts +115 -0
- package/src/tool/bead-pattern-generator/i18n/zh.ts +115 -0
- package/src/tool/bead-pattern-generator/index.ts +12 -0
- package/src/tool/dice-roller/i18n/de.ts +138 -0
- package/src/tool/dice-roller/i18n/id.ts +138 -0
- package/src/tool/dice-roller/i18n/it.ts +138 -0
- package/src/tool/dice-roller/i18n/ja.ts +138 -0
- package/src/tool/dice-roller/i18n/ko.ts +138 -0
- package/src/tool/dice-roller/i18n/nl.ts +138 -0
- package/src/tool/dice-roller/i18n/pl.ts +138 -0
- package/src/tool/dice-roller/i18n/pt.ts +138 -0
- package/src/tool/dice-roller/i18n/ru.ts +138 -0
- package/src/tool/dice-roller/i18n/sv.ts +138 -0
- package/src/tool/dice-roller/i18n/tr.ts +138 -0
- package/src/tool/dice-roller/i18n/zh.ts +138 -0
- package/src/tool/dice-roller/index.ts +12 -0
- package/src/tool/excuse-generator/i18n/de.ts +122 -0
- package/src/tool/excuse-generator/i18n/id.ts +122 -0
- package/src/tool/excuse-generator/i18n/it.ts +122 -0
- package/src/tool/excuse-generator/i18n/ja.ts +122 -0
- package/src/tool/excuse-generator/i18n/ko.ts +122 -0
- package/src/tool/excuse-generator/i18n/nl.ts +122 -0
- package/src/tool/excuse-generator/i18n/pl.ts +122 -0
- package/src/tool/excuse-generator/i18n/pt.ts +122 -0
- package/src/tool/excuse-generator/i18n/ru.ts +122 -0
- package/src/tool/excuse-generator/i18n/sv.ts +122 -0
- package/src/tool/excuse-generator/i18n/tr.ts +122 -0
- package/src/tool/excuse-generator/i18n/zh.ts +122 -0
- package/src/tool/excuse-generator/index.ts +12 -0
- package/src/tool/fortune-cookie/i18n/de.ts +127 -0
- package/src/tool/fortune-cookie/i18n/id.ts +127 -0
- package/src/tool/fortune-cookie/i18n/it.ts +127 -0
- package/src/tool/fortune-cookie/i18n/ja.ts +127 -0
- package/src/tool/fortune-cookie/i18n/ko.ts +127 -0
- package/src/tool/fortune-cookie/i18n/nl.ts +127 -0
- package/src/tool/fortune-cookie/i18n/pl.ts +127 -0
- package/src/tool/fortune-cookie/i18n/pt.ts +127 -0
- package/src/tool/fortune-cookie/i18n/ru.ts +127 -0
- package/src/tool/fortune-cookie/i18n/sv.ts +127 -0
- package/src/tool/fortune-cookie/i18n/tr.ts +127 -0
- package/src/tool/fortune-cookie/i18n/zh.ts +127 -0
- package/src/tool/fortune-cookie/index.ts +12 -0
- package/src/tool/synesthesia-painter/i18n/de.ts +122 -0
- package/src/tool/synesthesia-painter/i18n/fr.ts +2 -2
- package/src/tool/synesthesia-painter/i18n/id.ts +122 -0
- package/src/tool/synesthesia-painter/i18n/it.ts +122 -0
- package/src/tool/synesthesia-painter/i18n/ja.ts +122 -0
- package/src/tool/synesthesia-painter/i18n/ko.ts +122 -0
- package/src/tool/synesthesia-painter/i18n/nl.ts +122 -0
- package/src/tool/synesthesia-painter/i18n/pl.ts +122 -0
- package/src/tool/synesthesia-painter/i18n/pt.ts +122 -0
- package/src/tool/synesthesia-painter/i18n/ru.ts +122 -0
- package/src/tool/synesthesia-painter/i18n/sv.ts +122 -0
- package/src/tool/synesthesia-painter/i18n/tr.ts +122 -0
- package/src/tool/synesthesia-painter/i18n/zh.ts +122 -0
- package/src/tool/synesthesia-painter/index.ts +12 -0
- package/src/tool/zalgo-generator/i18n/de.ts +113 -0
- package/src/tool/zalgo-generator/i18n/id.ts +113 -0
- package/src/tool/zalgo-generator/i18n/it.ts +113 -0
- package/src/tool/zalgo-generator/i18n/ja.ts +113 -0
- package/src/tool/zalgo-generator/i18n/ko.ts +113 -0
- package/src/tool/zalgo-generator/i18n/nl.ts +113 -0
- package/src/tool/zalgo-generator/i18n/pl.ts +113 -0
- package/src/tool/zalgo-generator/i18n/pt.ts +113 -0
- package/src/tool/zalgo-generator/i18n/ru.ts +113 -0
- package/src/tool/zalgo-generator/i18n/sv.ts +113 -0
- package/src/tool/zalgo-generator/i18n/tr.ts +113 -0
- package/src/tool/zalgo-generator/i18n/zh.ts +113 -0
- package/src/tool/zalgo-generator/index.ts +12 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jjlmoya/utils-creative",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@iconify-json/mdi": "^1.2.3",
|
|
40
|
+
"@jjlmoya/prompagate": "^1.1.0",
|
|
40
41
|
"@jjlmoya/utils-shared": "1.2.0",
|
|
41
42
|
"astro": "^6.1.2",
|
|
42
43
|
"astro-icon": "^1.1.0"
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const content = {
|
|
2
|
+
slug: 'kreativitaet-freizeit',
|
|
3
|
+
title: 'Kreativität und Freizeit',
|
|
4
|
+
description: 'Werkzeuge, die inspirieren, amüsieren und kreativ machen.',
|
|
5
|
+
seo: [
|
|
6
|
+
{ type: 'title', text: 'Tägliche kreative Hilfsmittel', level: 2 },
|
|
7
|
+
{ type: 'paragraph', html: 'Von Ausredengeneratoren bis hin zu Bastelmustern – unsere Sammlung kreativer Werkzeuge ist für Unterhaltung und praktischen Gebrauch konzipiert.' }
|
|
8
|
+
]
|
|
9
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const content = {
|
|
2
|
+
slug: 'kreativitas-hiburan',
|
|
3
|
+
title: 'Kreativitas dan Hiburan',
|
|
4
|
+
description: 'Alat yang dirancang untuk menginspirasi, menghibur, dan berkreasi.',
|
|
5
|
+
seo: [
|
|
6
|
+
{ type: 'title', text: 'Utilitas Kreatif Harian', level: 2 },
|
|
7
|
+
{ type: 'paragraph', html: 'Dari pembuat alasan hingga pola kerajinan, koleksi alat kreatif kami dirancang untuk hiburan dan penggunaan praktis.' }
|
|
8
|
+
]
|
|
9
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const content = {
|
|
2
|
+
slug: 'creativita-tempo-libero',
|
|
3
|
+
title: 'Creatività e Tempo Libero',
|
|
4
|
+
description: 'Strumenti progettati per ispirare, divertire e creare.',
|
|
5
|
+
seo: [
|
|
6
|
+
{ type: 'title', text: 'Utility Creative Quotidiane', level: 2 },
|
|
7
|
+
{ type: 'paragraph', html: 'Dai generatori di scuse ai modelli per il fai-da-te, la nostra collezione di strumenti creativi è pensata per l\'intrattenimento e l\'uso pratico.' }
|
|
8
|
+
]
|
|
9
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const content = {
|
|
2
|
+
slug: 'creativity-leisure-ja',
|
|
3
|
+
title: 'クリエイティビティとレジャー',
|
|
4
|
+
description: 'インスピレーションを与え、楽しみ、創造するためのツール。',
|
|
5
|
+
seo: [
|
|
6
|
+
{ type: 'title', text: '毎日のクリエイティブ・ユーティリティ', level: 2 },
|
|
7
|
+
{ type: 'paragraph', html: '言訳ジェネレーターから手芸パターンまで、私たちのクリエイティブツールコレクションは、エンターテインメントと実用性のために設計されています。' }
|
|
8
|
+
]
|
|
9
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const content = {
|
|
2
|
+
slug: 'creativity-leisure-ko',
|
|
3
|
+
title: '창의성과 여가',
|
|
4
|
+
description: '영감을 주고, 즐거움을 선사하며, 창작을 돕기 위해 설계된 도구들입니다.',
|
|
5
|
+
seo: [
|
|
6
|
+
{ type: 'title', text: '일상의 창의적인 유틸리티', level: 2 },
|
|
7
|
+
{ type: 'paragraph', html: '변명 생성기부터 공예 패턴까지, 당사의 창의적인 도구 컬렉션은 즐거움과 실용적인 사용을 위해 제작되었습니다.' }
|
|
8
|
+
]
|
|
9
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const content = {
|
|
2
|
+
slug: 'creativiteit-vrije-tijd',
|
|
3
|
+
title: 'Creativiteit en Vrije Tijd',
|
|
4
|
+
description: 'Hulpmiddelen ontworpen om te inspireren, te vermaken en te creëren.',
|
|
5
|
+
seo: [
|
|
6
|
+
{ type: 'title', text: 'Dagelijkse Creatieve Hulpmiddelen', level: 2 },
|
|
7
|
+
{ type: 'paragraph', html: 'Van smoesjesgeneratoren tot knutselpatronen, onze collectie creatieve hulpmiddelen is ontworpen voor entertainment en praktisch gebruik.' }
|
|
8
|
+
]
|
|
9
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const content = {
|
|
2
|
+
slug: 'kreatywnosc-i-rozrywka',
|
|
3
|
+
title: 'Kreatywność i Rozrywka',
|
|
4
|
+
description: 'Narzędzia zaprojektowane, aby inspirować, bawić i tworzyć.',
|
|
5
|
+
seo: [
|
|
6
|
+
{ type: 'title', text: 'Codzienne Narzędzia Kreatywne', level: 2 },
|
|
7
|
+
{ type: 'paragraph', html: 'Od generatorów wymówek po wzory do rękodzieła, nasza kolekcja narzędzi kreatywnych została stworzona z myślą o rozrywce i praktycznym zastosowaniu.' }
|
|
8
|
+
]
|
|
9
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const content = {
|
|
2
|
+
slug: 'criatividade-lazer',
|
|
3
|
+
title: 'Criatividade e Lazer',
|
|
4
|
+
description: 'Ferramentas concebidas para inspirar, divertir e criar.',
|
|
5
|
+
seo: [
|
|
6
|
+
{ type: 'title', text: 'Utilitários Criativos Diários', level: 2 },
|
|
7
|
+
{ type: 'paragraph', html: 'Desde geradores de desculpas a padrões de artesanato, a nossa coleção de ferramentas criativas foi desenhada para entretenimento e uso prático.' }
|
|
8
|
+
]
|
|
9
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const content = {
|
|
2
|
+
slug: 'creativity-leisure-ru',
|
|
3
|
+
title: 'Творчество и досуг',
|
|
4
|
+
description: 'Инструменты, созданные для того, чтобы вдохновлять, развлекать и создавать.',
|
|
5
|
+
seo: [
|
|
6
|
+
{ type: 'title', text: 'Ежедневные творческие утилиты', level: 2 },
|
|
7
|
+
{ type: 'paragraph', html: 'От генераторов оправданий до шаблонов для рукоделия — наша коллекция творческих инструментов создана для развлечения и практического использования.' }
|
|
8
|
+
]
|
|
9
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const content = {
|
|
2
|
+
slug: 'kreativitet-fritid',
|
|
3
|
+
title: 'Kreativitet och Fritid',
|
|
4
|
+
description: 'Verktyg designade för att inspirera, roa och skapa.',
|
|
5
|
+
seo: [
|
|
6
|
+
{ type: 'title', text: 'Dagliga Kreativa Verktyg', level: 2 },
|
|
7
|
+
{ type: 'paragraph', html: 'Från ursäktsgeneratorer till hantverksmönster, vår samling av kreativa verktyg är designad för underhållning och praktisk användning.' }
|
|
8
|
+
]
|
|
9
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const content = {
|
|
2
|
+
slug: 'yaraticilik-bos-zaman',
|
|
3
|
+
title: 'Yaratıcılık ve Boş Zaman',
|
|
4
|
+
description: 'İlham vermek, eğlendirmek ve yaratmak için tasarlanmış araçlar.',
|
|
5
|
+
seo: [
|
|
6
|
+
{ type: 'title', text: 'Günlük Yaratıcı Araçlar', level: 2 },
|
|
7
|
+
{ type: 'paragraph', html: 'Mazeret üreteçlerinden el işi desenlerine kadar yaratıcı araç koleksiyonumuz eğlence ve pratik kullanım için tasarlanmıştır.' }
|
|
8
|
+
]
|
|
9
|
+
};
|
package/src/category/index.ts
CHANGED
|
@@ -30,5 +30,17 @@ export const creativeCategory: {
|
|
|
30
30
|
es: () => import('./i18n/es').then((m) => m.content),
|
|
31
31
|
en: () => import('./i18n/en').then((m) => m.content),
|
|
32
32
|
fr: () => import('./i18n/fr').then((m) => m.content),
|
|
33
|
+
de: () => import('./i18n/de').then((m) => m.content),
|
|
34
|
+
id: () => import('./i18n/id').then((m) => m.content),
|
|
35
|
+
it: () => import('./i18n/it').then((m) => m.content),
|
|
36
|
+
ja: () => import('./i18n/ja').then((m) => m.content),
|
|
37
|
+
ko: () => import('./i18n/ko').then((m) => m.content),
|
|
38
|
+
nl: () => import('./i18n/nl').then((m) => m.content),
|
|
39
|
+
pl: () => import('./i18n/pl').then((m) => m.content),
|
|
40
|
+
pt: () => import('./i18n/pt').then((m) => m.content),
|
|
41
|
+
ru: () => import('./i18n/ru').then((m) => m.content),
|
|
42
|
+
sv: () => import('./i18n/sv').then((m) => m.content),
|
|
43
|
+
tr: () => import('./i18n/tr').then((m) => m.content),
|
|
44
|
+
zh: () => import('./i18n/zh').then((m) => m.content),
|
|
33
45
|
},
|
|
34
46
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
2
|
import type * as DATA from '../data';
|
|
3
3
|
|
|
4
|
-
const TOOLS: typeof DATA.
|
|
4
|
+
const TOOLS: typeof DATA.audiovisualCategory[] = [];
|
|
5
5
|
|
|
6
6
|
describe('FAQ Content Validation', () => {
|
|
7
7
|
TOOLS.forEach((entry) => {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { ALL_TOOLS } from '../tools';
|
|
3
|
+
|
|
4
|
+
const EXPECTED_LOCALES = [
|
|
5
|
+
'de', 'en', 'es', 'fr', 'id', 'it', 'ja', 'ko', 'nl', 'pl', 'pt', 'ru', 'sv', 'tr', 'zh'
|
|
6
|
+
];
|
|
7
|
+
|
|
8
|
+
describe('I18n Coverage Validation', () => {
|
|
9
|
+
it('all tools should be registered', () => {
|
|
10
|
+
expect(ALL_TOOLS.length).toBeGreaterThan(0);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
ALL_TOOLS.forEach(({ entry }: { entry: any }) => {
|
|
14
|
+
describe(`Tool: ${entry.id}`, () => {
|
|
15
|
+
it('should have all 15 required locales', () => {
|
|
16
|
+
const registeredLocales = Object.keys(entry.i18n);
|
|
17
|
+
EXPECTED_LOCALES.forEach((locale) => {
|
|
18
|
+
expect(
|
|
19
|
+
registeredLocales,
|
|
20
|
+
`Tool "${entry.id}" is missing locale "${locale}"`,
|
|
21
|
+
).toContain(locale);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('all locale loaders should be functions', () => {
|
|
26
|
+
EXPECTED_LOCALES.forEach((locale) => {
|
|
27
|
+
const loader = entry.i18n[locale as keyof typeof entry.i18n];
|
|
28
|
+
expect(
|
|
29
|
+
typeof loader,
|
|
30
|
+
`Tool "${entry.id}" locale "${locale}" loader is not a function`,
|
|
31
|
+
).toBe('function');
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
});
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { ALL_TOOLS } from '../tools';
|
|
3
|
+
import type { ToolLocaleContent } from '../types';
|
|
4
|
+
|
|
5
|
+
const sharingLocales = ['ja', 'ko', 'zh'];
|
|
6
|
+
|
|
7
|
+
interface ValidateParams {
|
|
8
|
+
toolId: string;
|
|
9
|
+
locale: string;
|
|
10
|
+
content: ToolLocaleContent;
|
|
11
|
+
enSlug: string;
|
|
12
|
+
slugs: Map<string, string>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const validateLocaleSlug = ({
|
|
16
|
+
toolId,
|
|
17
|
+
locale,
|
|
18
|
+
content,
|
|
19
|
+
enSlug,
|
|
20
|
+
slugs,
|
|
21
|
+
}: ValidateParams) => {
|
|
22
|
+
expect(
|
|
23
|
+
content.slug,
|
|
24
|
+
`Tool "${toolId}" locale "${locale}" has an invalid slug ("${content.slug}"). Slugs must be transliterated (only a-z, 0-9, and -).`,
|
|
25
|
+
).toMatch(/^[a-z0-9-]+$/);
|
|
26
|
+
|
|
27
|
+
if (locale === 'en') {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (sharingLocales.includes(locale)) {
|
|
32
|
+
expect(
|
|
33
|
+
content.slug,
|
|
34
|
+
`Tool "${toolId}" locale "${locale}" must use the same slug as "en" ("${enSlug}").`,
|
|
35
|
+
).toBe(enSlug);
|
|
36
|
+
} else {
|
|
37
|
+
expect(
|
|
38
|
+
content.slug,
|
|
39
|
+
`Tool "${toolId}" locale "${locale}" has the same slug as "en" ("${enSlug}"). Cada slug tiene que estar en su propia idioma`,
|
|
40
|
+
).not.toBe(enSlug);
|
|
41
|
+
|
|
42
|
+
if (slugs.has(content.slug)) {
|
|
43
|
+
const previousLocale = slugs.get(content.slug);
|
|
44
|
+
expect(
|
|
45
|
+
false,
|
|
46
|
+
`Tool "${toolId}" locales "${locale}" and "${previousLocale}" share the same slug ("${content.slug}"). Cada slug tiene que estar en su propia idioma`,
|
|
47
|
+
).toBe(true);
|
|
48
|
+
}
|
|
49
|
+
slugs.set(content.slug, locale);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
describe('Slug Localization and Uniqueness Validation', () => {
|
|
54
|
+
ALL_TOOLS.forEach((tool) => {
|
|
55
|
+
describe(`Tool: ${tool.entry.id}`, () => {
|
|
56
|
+
it('every locale should have a unique, translated slug', async () => {
|
|
57
|
+
const slugs = new Map<string, string>();
|
|
58
|
+
const locales = Object.keys(tool.entry.i18n);
|
|
59
|
+
|
|
60
|
+
let enSlug = '';
|
|
61
|
+
if (locales.includes('en')) {
|
|
62
|
+
const enLoader = tool.entry.i18n['en' as keyof typeof tool.entry.i18n];
|
|
63
|
+
const enContent = (await enLoader?.()) as ToolLocaleContent;
|
|
64
|
+
enSlug = enContent.slug;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
for (const locale of locales) {
|
|
68
|
+
const loader = tool.entry.i18n[locale as keyof typeof tool.entry.i18n];
|
|
69
|
+
const content = (await loader?.()) as ToolLocaleContent;
|
|
70
|
+
validateLocaleSlug({
|
|
71
|
+
toolId: tool.entry.id,
|
|
72
|
+
locale,
|
|
73
|
+
content,
|
|
74
|
+
enSlug,
|
|
75
|
+
slugs,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -26,7 +26,7 @@ describe('Project Titles - Separator Validation', () => {
|
|
|
26
26
|
...getFiles(path.join(SRC_DIR, 'category'), ['.ts']),
|
|
27
27
|
].filter(f => f.includes('i18n'));
|
|
28
28
|
|
|
29
|
-
it.each(files)('Verify that titles in %s do not contain | or
|
|
29
|
+
it.each(files)('Verify that titles in %s do not contain | or -', (filePath) => {
|
|
30
30
|
const content = fs.readFileSync(filePath, 'utf-8');
|
|
31
31
|
const relativePath = path.relative(process.cwd(), filePath);
|
|
32
32
|
|
|
@@ -41,7 +41,7 @@ describe('Project Titles - Separator Validation', () => {
|
|
|
41
41
|
let match;
|
|
42
42
|
while ((match = pattern.exec(content)) !== null) {
|
|
43
43
|
const title = match[1];
|
|
44
|
-
if (title.includes('|') ||
|
|
44
|
+
if (title.includes('|') || title.includes('-')) {
|
|
45
45
|
findings.push(title);
|
|
46
46
|
}
|
|
47
47
|
}
|
|
@@ -49,7 +49,7 @@ describe('Project Titles - Separator Validation', () => {
|
|
|
49
49
|
|
|
50
50
|
if (findings.length > 0) {
|
|
51
51
|
const list = findings.map((f) => ` - "${f}"`).join('\n');
|
|
52
|
-
throw new Error(`Forbidden separators (| or
|
|
52
|
+
throw new Error(`Forbidden separators (| or -) found in titles in ${relativePath}:\n${list}`);
|
|
53
53
|
}
|
|
54
54
|
});
|
|
55
55
|
});
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
|
|
2
|
+
import type { BeadPatternGeneratorLocaleContent } from '../index';
|
|
3
|
+
|
|
4
|
+
const slug = 'perlenmuster-generator';
|
|
5
|
+
const title = 'Muster Generator';
|
|
6
|
+
const description = 'Erstellen Sie Pixelkunst und Perlenschemata für Miyuki oder Hama aus Ihren Fotos. Farbauantierungsalgorithmus, Tunnelblick-Modus und ZIP-Export.';
|
|
7
|
+
|
|
8
|
+
const faq: BeadPatternGeneratorLocaleContent['faq'] = [
|
|
9
|
+
{ question: 'Was ist Farbauantierung bei Mustern?', answer: 'Dabei werden die Tausenden von Farben in einem Foto auf einige wenige reduziert, die den tatsächlich verfügbaren Perlenfarben entsprechen (z. B. Miyuki oder Hama). Wir verwenden intelligente Algorithmen, um die visuelle Ähnlichkeit mit einer minimalen Palette beizubehalten.' },
|
|
10
|
+
{ question: 'Kann ich dieses Muster für Kreuzstich verwenden?', answer: 'Ja, der Generator erstellt ein Rasterdiagramm, das perfekt für Kreuzstich geeignet ist. Sie müssen lediglich eine Rastergröße wählen, die zu Ihrem Stoff passt (Aida 14, 18 usw.).' },
|
|
11
|
+
{ question: 'Was ist der Unterschied zwischen Miyuki- und Hama-Perlen?', answer: 'Miyuki Delica-Perlen sind sehr kleine, präzise Glasperlen für Schmuck. Hama-Perlen sind aus Kunststoff und werden mit einem Bügeleisen verschmolzen. Unser Werkzeug ermöglicht es Ihnen, das Seitenverhältnis anzupassen, damit sich das Muster je nach verwendetem Material nicht verzerrt.' },
|
|
12
|
+
{ question: 'Wie funktioniert der Dithering-Algorithmus?', answer: 'Dithering erzeugt die Illusion von mehr Farben, indem Pixel verschiedener Farben in Abständen gemischt werden. Dies hilft dabei, Farbübergänge auch mit einer begrenzten Perlenpalette glatter erscheinen zu lassen.' },
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
const howTo: BeadPatternGeneratorLocaleContent['howTo'] = [
|
|
16
|
+
{ name: 'Ein klares Bild hochladen', text: 'Wählen Sie ein Foto mit gutem Kontrast und wenigen kleinen Details, damit das Muster einfacher zu befolgen ist.' },
|
|
17
|
+
{ name: 'Die Rastergröße anpassen', text: 'Legen Sie fest, wie viele Perlen breit und hoch Ihr fertiges Stück sein soll. Mehr Perlen = mehr Details, aber auch höherer Schwierigkeitsgrad.' },
|
|
18
|
+
{ name: 'Die Farbpalette optimieren', text: 'Reduzieren Sie die Anzahl der Farben, bis sie mit den Perlen übereinstimmen, die Sie in Ihrem Bastelset zur Verfügung haben.' },
|
|
19
|
+
{ name: 'Das Musterschema exportieren', text: 'Generieren Sie das endgültige Muster mit Farbcodes, um es als Referenz beim Zusammensetzen Ihrer Perlen auf der Platte oder dem Faden zu verwenden.' },
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
const faqSchema: WithContext<FAQPage> = {
|
|
23
|
+
'@context': 'https://schema.org',
|
|
24
|
+
'@type': 'FAQPage',
|
|
25
|
+
mainEntity: faq.map((item) => ({
|
|
26
|
+
'@type': 'Question',
|
|
27
|
+
name: item.question,
|
|
28
|
+
acceptedAnswer: { '@type': 'Answer', text: item.answer },
|
|
29
|
+
})),
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const howToSchema: WithContext<HowTo> = {
|
|
33
|
+
'@context': 'https://schema.org',
|
|
34
|
+
'@type': 'HowTo',
|
|
35
|
+
name: title,
|
|
36
|
+
description,
|
|
37
|
+
step: howTo.map((step) => ({
|
|
38
|
+
'@type': 'HowToStep',
|
|
39
|
+
name: step.name,
|
|
40
|
+
text: step.text,
|
|
41
|
+
})),
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const appSchema: WithContext<SoftwareApplication> = {
|
|
45
|
+
'@context': 'https://schema.org',
|
|
46
|
+
'@type': 'SoftwareApplication',
|
|
47
|
+
name: title,
|
|
48
|
+
description,
|
|
49
|
+
applicationCategory: 'UtilitiesApplication',
|
|
50
|
+
operatingSystem: 'Web',
|
|
51
|
+
offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
|
|
52
|
+
inLanguage: 'de',
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const content: BeadPatternGeneratorLocaleContent = {
|
|
56
|
+
slug,
|
|
57
|
+
title,
|
|
58
|
+
description,
|
|
59
|
+
faqTitle: 'Häufig gestellte Fragen',
|
|
60
|
+
bibliographyTitle: 'Handwerks-Bibliographie',
|
|
61
|
+
ui: {
|
|
62
|
+
title: 'Muster Labor',
|
|
63
|
+
subtitle: 'Farbtechnik für Ihre Hände',
|
|
64
|
+
description: 'Vom Foto zum Perlenschema.',
|
|
65
|
+
gridSizeLabel: 'Größe (Breite)',
|
|
66
|
+
colorCountLabel: 'Farben',
|
|
67
|
+
optionsLabel: 'Optionen',
|
|
68
|
+
rulersLabel: 'Lineale',
|
|
69
|
+
symbolsTooltip: 'Überraschungsmuster',
|
|
70
|
+
symbolsLabel: 'Symbole',
|
|
71
|
+
downloadBtn: 'Herunterladen',
|
|
72
|
+
uploadTitle: 'Laden Sie Ihre Vision hoch',
|
|
73
|
+
uploadSubtitle: 'und lassen Sie die digitale Magie wirken',
|
|
74
|
+
paletteTitle: 'Chromatische DNA',
|
|
75
|
+
reuploadBtn: 'Bild ändern',
|
|
76
|
+
tunnelVisionTitle: 'Tunnelblick',
|
|
77
|
+
tunnelVisionSubtitle: 'Ihr Präzisionsassistent Reihe für Reihe.',
|
|
78
|
+
uploadLabel: 'Laden Sie Ihr Foto hoch',
|
|
79
|
+
pixelateBtn: 'Muster generieren',
|
|
80
|
+
faqTitle: 'FAQ',
|
|
81
|
+
bibliographyTitle: 'Referenzen'
|
|
82
|
+
},
|
|
83
|
+
seo: [
|
|
84
|
+
{ type: 'title', text: 'Digitale Alchemie: Pixel in greifbare Kunst verwandeln', level: 2 },
|
|
85
|
+
{ type: 'paragraph', html: 'Willkommen im <strong>Ultimativen Musterstudio</strong>. Ein <em>chromatisches Intelligenzsystem</em>, entwickelt für Pixel-Art-Architekten, Miyuki-Meister und Kreuzstich-Visionäre. Ihre Brücke zwischen Digitalem und Handwerk.' },
|
|
86
|
+
{ type: 'card', icon: 'mdi:grid', title: 'Das intelligente Raster', html: 'Unser Algorithmus für <strong>räumliches Subsampling</strong> "schrumpft" Ihr Bild nicht einfach nur. Er analysiert die visuelle Struktur, um komplexe Pixelgruppen auf einzelne Zellen abzubilden und so die Integrität von Silhouetten und Kanten wie ein erfahrener Illustrator zu bewahren.' },
|
|
87
|
+
{ type: 'card', icon: 'mdi:palette', title: 'K Means Farbquantisierung', html: 'Wir implementieren eine Variante des <strong>K-Means-Clustering</strong>-Algorithmus, der mathematisch die "Zentroid"-Töne Ihres Bildes findet. Erstaunliche visuelle Treue mit einer minimalistischen Palette von 12, 24 oder 32 Farben.' },
|
|
88
|
+
{ type: 'title', text: 'Meisterschaft in 3 Schritten', level: 3 },
|
|
89
|
+
{ type: 'card', icon: 'mdi:image-search', title: 'Die perfekte Auswahl', html: 'Suchen Sie nach <strong>hohem Kontrast</strong>, dramatischer Beleuchtung und ikonischen Formen. Porträts mit klarem Hintergrund, Logos und Vektorgrafiken lassen sich wunderbar umsetzen.' },
|
|
90
|
+
{ type: 'card', icon: 'mdi:ruler', title: 'Dimensionale Kalibrierung', html: '<strong>Miyuki Delica:</strong> 50 Perlen ≈ 8 cm · <strong>Hama Midi:</strong> 50 Perlen ≈ 25 cm · <strong>Kreuzstich:</strong> 1 Zelle = 1 Stich.' },
|
|
91
|
+
{ type: 'card', icon: 'mdi:eye-check', title: 'Zen Ausführung (Tunnelblick Modus)', html: 'Unser <strong>Tunnelblick</strong>-System fungiert als Ihr persönlicher Assistent, der visuelles Rauschen ausblendet und chirurgisch nur die aktive Reihe hervorhebt. Absolute Konzentration.' },
|
|
92
|
+
{ type: 'title', text: 'Unendliche Leinwände', level: 3 },
|
|
93
|
+
{ type: 'list', items: [
|
|
94
|
+
'<strong>Textiler Schmuck:</strong> Komplizierte Muster für Webstühle und geometrische Armbänder.',
|
|
95
|
+
'<strong>Kreuzstich:</strong> Moderne Schemata, bereit, Pixel für Pixel gestickt zu werden.',
|
|
96
|
+
'<strong>Mosaike:</strong> Großformatige Wandbilder aus vereinfachten Keramikmosaiksteinen.',
|
|
97
|
+
'<strong>Retro-Gaming:</strong> Authentische 8-Bit-Assets und Sprites in Sekunden.',
|
|
98
|
+
]},
|
|
99
|
+
{ type: 'stats', items: [
|
|
100
|
+
{ value: '10–100', label: 'Perlenbreite', icon: 'mdi:arrow-expand-horizontal' },
|
|
101
|
+
{ value: '2–32', label: 'Farbpalettenplätze', icon: 'mdi:palette-swatch' },
|
|
102
|
+
{ value: 'K-Means', label: 'Quantisierungsalgorithmus', icon: 'mdi:function-variant' },
|
|
103
|
+
{ value: 'ZIP', label: 'Exportformat (Muster + Anleitung)', icon: 'mdi:zip-box' },
|
|
104
|
+
], columns: 4 },
|
|
105
|
+
{ type: 'paragraph', html: 'In einer Ära flüchtiger Bildschirme ist das Erschaffen von etwas Physischem ein revolutionärer Akt. Dieses Werkzeug versucht nicht, Kunst zu automatisieren, sondern den <strong>Handwerker zu stärken</strong>. Wir geben Ihnen rechnerische Präzision, damit Ihre Hände bleibende Vermächtnisse schaffen können.' },
|
|
106
|
+
],
|
|
107
|
+
faq,
|
|
108
|
+
bibliography: [
|
|
109
|
+
{ name: 'Scikit-Image: Color Quantization using K-Means', url: 'https://scikit-learn.org/0.23/auto_examples/cluster/plot_color_quantization.html' },
|
|
110
|
+
{ name: 'Miyuki Delica Beads Specification', url: 'https://www.miyuki-beads.co.jp/english/seedbeads/delica.html' },
|
|
111
|
+
{ name: 'Visgraf Lab: Dithering Algorithms', url: 'https://www.visgraf.impa.br/Courses/ip00/proj/Dithering1/floyd_steinberg_dithering.html' },
|
|
112
|
+
],
|
|
113
|
+
howTo,
|
|
114
|
+
schemas: [faqSchema as any, howToSchema as any, appSchema],
|
|
115
|
+
};
|
|
@@ -84,7 +84,7 @@ export const content: BeadPatternGeneratorLocaleContent = {
|
|
|
84
84
|
{ type: 'title', text: 'Digital Alchemy: Transmute Pixels into Tangible Art', level: 2 },
|
|
85
85
|
{ type: 'paragraph', html: 'Welcome to the <strong>Ultimate Pattern Studio</strong>. A <em>chromatic intelligence engine</em> designed for Pixel Art architects, Miyuki masters, and cross-stitch visionaries. Your bridge between the digital and the handmade.' },
|
|
86
86
|
{ type: 'card', icon: 'mdi:grid', title: 'The Intelligent Grid', html: 'Our <strong>spatial subsampling</strong> algorithm does not just "shrink" your image. It analyzes the visual structure to map complex pixel groups to individual cells, preserving the integrity of silhouettes and edges like an expert illustrator.' },
|
|
87
|
-
{ type: 'card', icon: 'mdi:palette', title: 'K
|
|
87
|
+
{ type: 'card', icon: 'mdi:palette', title: 'K Means Color Quantization', html: 'We implement a variant of the <strong>K-Means Clustering</strong> algorithm that mathematically finds the "centroid" tones of your image. Astonishing visual fidelity with a minimalist palette of 12, 24 or 32 colors.' },
|
|
88
88
|
{ type: 'title', text: 'Mastery in 3 Steps', level: 3 },
|
|
89
89
|
{ type: 'card', icon: 'mdi:image-search', title: 'The Perfect Selection', html: 'Look for <strong>high contrast</strong>, dramatic lighting and iconic shapes. Portraits with clean backgrounds, logos, and vector art translate beautifully.' },
|
|
90
90
|
{ type: 'card', icon: 'mdi:ruler', title: 'Dimensional Calibration', html: '<strong>Miyuki Delica:</strong> 50 beads ≈ 8cm · <strong>Hama Midi:</strong> 50 beads ≈ 25cm · <strong>Cross-Stitch:</strong> 1 cell = 1 stitch.' },
|
|
@@ -84,7 +84,7 @@ export const content: BeadPatternGeneratorLocaleContent = {
|
|
|
84
84
|
{ type: 'title', text: 'Alquimia Digital: Transmuta Píxeles en Arte Tangible', level: 2 },
|
|
85
85
|
{ type: 'paragraph', html: 'Bienvenido al <strong>Estudio Definitivo de Patrones</strong>. Un motor de <em>inteligencia cromática</em> diseñado para arquitectos del Pixel Art, maestros del Miyuki y visionarios del punto de cruz. Tu puente entre lo digital y lo artesanal.' },
|
|
86
86
|
{ type: 'card', icon: 'mdi:grid', title: 'La Retícula Inteligente', html: 'Nuestro algoritmo de <strong>submuestreo espacial</strong> no solo "encoge" tu imagen. Analiza la estructura visual para mapear grupos de píxeles complejos a celdas individuales, preservando la integridad de siluetas y bordes como un dibujante experto.' },
|
|
87
|
-
{ type: 'card', icon: 'mdi:palette', title: 'Cuantización K
|
|
87
|
+
{ type: 'card', icon: 'mdi:palette', title: 'Cuantización de Color K Means', html: 'Implementamos una variante del algoritmo <strong>K-Means Clustering</strong> que encuentra matemáticamente los tonos "centroides" de tu imagen. Fidelidad visual asombrosa con una paleta minimalista de 12, 24 o 32 colores.' },
|
|
88
88
|
{ type: 'title', text: 'Maestría en 3 Pasos', level: 3 },
|
|
89
89
|
{ type: 'card', icon: 'mdi:image-search', title: 'La Selección Perfecta', html: 'Busca <strong>alto contraste</strong>, iluminación dramática y formas icónicas. Los retratos con fondo limpio, logotipos y arte vectorial se traducen maravillosamente.' },
|
|
90
90
|
{ type: 'card', icon: 'mdi:ruler', title: 'Calibración Dimensional', html: '<strong>Miyuki Delica:</strong> 50 cuentas ≈ 8cm · <strong>Hama Midi:</strong> 50 cuentas ≈ 25cm · <strong>Punto de Cruz:</strong> 1 celda = 1 puntada.' },
|
|
@@ -84,7 +84,7 @@ export const content: BeadPatternGeneratorLocaleContent = {
|
|
|
84
84
|
{ type: 'title', text: 'Alchimie Numérique : Transmutez les Pixels en Art Tangible', level: 2 },
|
|
85
85
|
{ type: 'paragraph', html: 'Bienvenue dans le <strong>Studio de Modèles Ultime</strong>. Un <em>moteur d\'intelligence chromatique</em> conçu pour les architectes du Pixel Art, les maîtres de la Miyuki et les visionnaires du point de croix. Votre pont entre le numérique et le fait-main.' },
|
|
86
86
|
{ type: 'card', icon: 'mdi:grid', title: 'La Grille Intelligente', html: 'Notre algorithme de <strong>sous-échantillonnage spatial</strong> ne se contente pas de "réduire" votre image. Il analyse la structure visuelle pour mapper des groupes de pixels complexes sur des cellules individuelles, préservant l\'intégrité des silhouettes et des contours comme le ferait un illustrateur expert.' },
|
|
87
|
-
{ type: 'card', icon: 'mdi:palette', title: 'Quantification de Couleurs K
|
|
87
|
+
{ type: 'card', icon: 'mdi:palette', title: 'Quantification de Couleurs K Means', html: 'Nous implémentons une variante de l\'algorithme <strong>K-Means Clustering</strong> qui trouve mathématiquement les tons "centroïdes" de votre image. Une fidélité visuelle étonnante avec une palette minimaliste de 12, 24 ou 32 couleurs.' },
|
|
88
88
|
{ type: 'title', text: 'La Maîtrise en 3 Étapes', level: 3 },
|
|
89
89
|
{ type: 'card', icon: 'mdi:image-search', title: 'La Sélection Parfaite', html: 'Recherchez un <strong>contraste élevé</strong>, un éclairage dramatique et des formes iconiques. Les portraits avec des fonds épurés, les logos et l\'art vectoriel se traduisent magnifiquement.' },
|
|
90
90
|
{ type: 'card', icon: 'mdi:ruler', title: 'Calibration Dimensionnelle', html: '<strong>Miyuki Delica :</strong> 50 perles ≈ 8 cm · <strong>Hama Midi :</strong> 50 perles ≈ 25 cm · <strong>Point de Croix :</strong> 1 cellule = 1 point.' },
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
|
|
2
|
+
import type { BeadPatternGeneratorLocaleContent } from '../index';
|
|
3
|
+
|
|
4
|
+
const slug = 'pembuat-pola-manik';
|
|
5
|
+
const title = 'Pembuat Pola';
|
|
6
|
+
const description = 'Buat pixel art dan skema manik-manik untuk Miyuki atau Hama dari foto Anda. Algoritma kuantisasi warna, mode pandangan terowongan, dan ekspor ZIP.';
|
|
7
|
+
|
|
8
|
+
const faq: BeadPatternGeneratorLocaleContent['faq'] = [
|
|
9
|
+
{ question: 'Apa itu kuantisasi warna dalam pola?', answer: 'Ini adalah proses pengurangan ribuan warna dalam foto menjadi hanya beberapa yang sesuai dengan warna manik-manik asli yang tersedia (misalnya, Miyuki atau Hama). Kami menggunakan algoritma cerdas untuk menjaga kemiripan visual dengan palet seminimal mungkin.' },
|
|
10
|
+
{ question: 'Bisakah saya menggunakan pola ini untuk sulam silang (cross-stitch)?', answer: 'Ya, generator ini membuat grafik kisi yang sangat kompatibel dengan sulam silang. Anda hanya perlu memilih ukuran kisi yang sesuai dengan kain Anda (Aida 14, 18, dsb.).' },
|
|
11
|
+
{ question: 'Apa perbedaan antara Manik Miyuki dan Hama?', answer: 'Manik Miyuki Delica adalah manik-manik kaca yang sangat kecil dan presisi untuk perhiasan. Manik Hama berbahan plastik dan disatukan dengan setrika. Alat kami memungkinkan Anda menyesuaikan rasio aspek agar pola tidak terdistorsi tergantung pada bahan yang digunakan.' },
|
|
12
|
+
{ question: 'Bagaimana cara kerja algoritma dithering?', answer: 'Dithering menciptakan ilusi warna yang lebih banyak dengan mencampurkan piksel dari warna yang berbeda dalam pola berjarak. Ini membantu gradasi warna tampak lebih halus meskipun dengan palet manik-manik yang terbatas.' },
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
const howTo: BeadPatternGeneratorLocaleContent['howTo'] = [
|
|
16
|
+
{ name: 'Unggah gambar yang jelas', text: 'Pilih foto dengan kontras yang baik dan sedikit detail kecil agar pola lebih mudah diikuti.' },
|
|
17
|
+
{ name: 'Sesuaikan ukuran kisi', text: 'Tentukan berapa banyak manik lebar dan tinggi untuk karya akhir Anda. Lebih banyak manik = lebih banyak detail tetapi lebih sulit.' },
|
|
18
|
+
{ name: 'Optimalkan palet warna', text: 'Kurangi jumlah warna hingga sesuai dengan manik-manik yang tersedia dalam kit kerajinan Anda.' },
|
|
19
|
+
{ name: 'Ekspor skema panduan', text: 'Hasilkan pola akhir dengan kode warna untuk digunakan sebagai referensi saat merangkai manik-manik Anda pada papan atau benang.' },
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
const faqSchema: WithContext<FAQPage> = {
|
|
23
|
+
'@context': 'https://schema.org',
|
|
24
|
+
'@type': 'FAQPage',
|
|
25
|
+
mainEntity: faq.map((item) => ({
|
|
26
|
+
'@type': 'Question',
|
|
27
|
+
name: item.question,
|
|
28
|
+
acceptedAnswer: { '@type': 'Answer', text: item.answer },
|
|
29
|
+
})),
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const howToSchema: WithContext<HowTo> = {
|
|
33
|
+
'@context': 'https://schema.org',
|
|
34
|
+
'@type': 'HowTo',
|
|
35
|
+
name: title,
|
|
36
|
+
description,
|
|
37
|
+
step: howTo.map((step) => ({
|
|
38
|
+
'@type': 'HowToStep',
|
|
39
|
+
name: step.name,
|
|
40
|
+
text: step.text,
|
|
41
|
+
})),
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const appSchema: WithContext<SoftwareApplication> = {
|
|
45
|
+
'@context': 'https://schema.org',
|
|
46
|
+
'@type': 'SoftwareApplication',
|
|
47
|
+
name: title,
|
|
48
|
+
description,
|
|
49
|
+
applicationCategory: 'UtilitiesApplication',
|
|
50
|
+
operatingSystem: 'Web',
|
|
51
|
+
offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
|
|
52
|
+
inLanguage: 'id',
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const content: BeadPatternGeneratorLocaleContent = {
|
|
56
|
+
slug,
|
|
57
|
+
title,
|
|
58
|
+
description,
|
|
59
|
+
faqTitle: 'Pertanyaan yang Sering Diajukan',
|
|
60
|
+
bibliographyTitle: 'Bibliografi Artisan',
|
|
61
|
+
ui: {
|
|
62
|
+
title: 'Laboratorium Pola',
|
|
63
|
+
subtitle: 'Rekayasa warna untuk tangan Anda',
|
|
64
|
+
description: 'Dari foto ke skema manik-manik.',
|
|
65
|
+
gridSizeLabel: 'Ukuran (Lebar)',
|
|
66
|
+
colorCountLabel: 'Warna',
|
|
67
|
+
optionsLabel: 'Opsi',
|
|
68
|
+
rulersLabel: 'Penggaris',
|
|
69
|
+
symbolsTooltip: 'Pola Kejutan',
|
|
70
|
+
symbolsLabel: 'Simbol',
|
|
71
|
+
downloadBtn: 'Unduh',
|
|
72
|
+
uploadTitle: 'Unggah Visi Anda',
|
|
73
|
+
uploadSubtitle: 'dan biarkan keajaiban digital terjadi',
|
|
74
|
+
paletteTitle: 'DNA Kromatik',
|
|
75
|
+
reuploadBtn: 'Ubah Gambar',
|
|
76
|
+
tunnelVisionTitle: 'Pandangan Terowongan',
|
|
77
|
+
tunnelVisionSubtitle: 'Asisten presisi Anda baris demi baris.',
|
|
78
|
+
uploadLabel: 'Unggah foto Anda',
|
|
79
|
+
pixelateBtn: 'Hasilkan Pola',
|
|
80
|
+
faqTitle: 'FAQ',
|
|
81
|
+
bibliographyTitle: 'Referensi'
|
|
82
|
+
},
|
|
83
|
+
seo: [
|
|
84
|
+
{ type: 'title', text: 'Alkimia Digital: Mengubah Piksel Menjadi Seni Nyata', level: 2 },
|
|
85
|
+
{ type: 'paragraph', html: 'Selamat datang di <strong>Studio Pola Utama</strong>. Sebuah <em>mesin kecerdasan kromatik</em> yang dirancang untuk arsitek Pixel Art, master Miyuki, dan visioner sulam silang. Jembatan Anda antara dunia digital dan buatan tangan.' },
|
|
86
|
+
{ type: 'card', icon: 'mdi:grid', title: 'Kisi Cerdas', html: 'Algoritma <strong>subsampling spasial</strong> kami tidak sekadar "menyusutkan" gambar Anda. Ia menganalisis struktur visual untuk memetakan kelompok piksel yang kompleks ke sel individu, menjaga integritas siluet dan tepi layaknya ilustrator ahli.' },
|
|
87
|
+
{ type: 'card', icon: 'mdi:palette', title: 'Kuantisasi Warna K Means', html: 'Kami menerapkan varian algoritma <strong>K-Means Clustering</strong> yang secara matematis menemukan nada "centroid" dari gambar Anda. Kesetiaan visual yang mengagumkan dengan palet minimalis 12, 24, atau 32 warna.' },
|
|
88
|
+
{ type: 'title', text: 'Penguasaan dalam 3 Langkah', level: 3 },
|
|
89
|
+
{ type: 'card', icon: 'mdi:image-search', title: 'Pilihan Sempurna', html: 'Cari <strong>kontras tinggi</strong>, pencahayaan dramatis, dan bentuk ikonik. Potret dengan latar belakang bersih, logo, dan seni vektor dapat diterjemahkan dengan indah.' },
|
|
90
|
+
{ type: 'card', icon: 'mdi:ruler', title: 'Kalibrasi Dimensi', html: '<strong>Miyuki Delica:</strong> 50 manik ≈ 8cm · <strong>Hama Midi:</strong> 50 manik ≈ 25cm · <strong>Sulam Silang:</strong> 1 sel = 1 jahitan.' },
|
|
91
|
+
{ type: 'card', icon: 'mdi:eye-check', title: 'Eksekusi Zen (Mode Pandangan Terowongan)', html: 'Sistem <strong>Pandangan Terowongan</strong> kami bertindak sebagai asisten pribadi Anda, meredupkan kebisingan visual dan menyoroti secara bedah hanya baris yang aktif. Konsentrasi mutlak.' },
|
|
92
|
+
{ type: 'title', text: 'Kanvas Tak Terbatas', level: 3 },
|
|
93
|
+
{ type: 'list', items: [
|
|
94
|
+
'<strong>Perhiasan Tekstil:</strong> Pola rumit untuk alat tenun dan gelang geometris.',
|
|
95
|
+
'<strong>Sulam Silang:</strong> Skema modern yang siap disulam piksel demi piksel.',
|
|
96
|
+
'<strong>Mosaik:</strong> Mural skala besar menggunakan tesserae keramik yang disederhanakan.',
|
|
97
|
+
'<strong>Retro Gaming:</strong> Aset dan sprite 8-bit otentik dalam hitungan detik.',
|
|
98
|
+
]},
|
|
99
|
+
{ type: 'stats', items: [
|
|
100
|
+
{ value: '10–100', label: 'Rentang lebar manik', icon: 'mdi:arrow-expand-horizontal' },
|
|
101
|
+
{ value: '2–32', label: 'Slot palet warna', icon: 'mdi:palette-swatch' },
|
|
102
|
+
{ value: 'K-Means', label: 'Algoritma kuantisasi', icon: 'mdi:function-variant' },
|
|
103
|
+
{ value: 'ZIP', label: 'Format ekspor (pola + panduan)', icon: 'mdi:zip-box' },
|
|
104
|
+
], columns: 4 },
|
|
105
|
+
{ type: 'paragraph', html: 'Di era layar yang fana, menciptakan sesuatu yang fisik adalah tindakan revolusioner. Alat ini tidak berusaha mengotomatisasi seni, tetapi untuk <strong>memberdayakan artisan</strong>. Kami memberi Anda presisi komputasi sehingga tangan Anda dapat membangun warisan yang langgeng.' },
|
|
106
|
+
],
|
|
107
|
+
faq,
|
|
108
|
+
bibliography: [
|
|
109
|
+
{ name: 'Scikit-Image: Color Quantization using K-Means', url: 'https://scikit-learn.org/0.23/auto_examples/cluster/plot_color_quantization.html' },
|
|
110
|
+
{ name: 'Miyuki Delica Beads Specification', url: 'https://www.miyuki-beads.co.jp/english/seedbeads/delica.html' },
|
|
111
|
+
{ name: 'Visgraf Lab: Dithering Algorithms', url: 'https://www.visgraf.impa.br/Courses/ip00/proj/Dithering1/floyd_steinberg_dithering.html' },
|
|
112
|
+
],
|
|
113
|
+
howTo,
|
|
114
|
+
schemas: [faqSchema as any, howToSchema as any, appSchema],
|
|
115
|
+
};
|