@jjlmoya/utils-developer 1.31.0 → 1.33.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 (53) hide show
  1. package/package.json +1 -1
  2. package/src/category/i18n/en.ts +1 -1
  3. package/src/category/i18n/es.ts +1 -1
  4. package/src/category/index.ts +2 -1
  5. package/src/entries.ts +4 -1
  6. package/src/index.ts +1 -0
  7. package/src/pages/[locale]/[slug].astro +3 -3
  8. package/src/tests/bibliography_wellformed_export.test.ts +46 -0
  9. package/src/tests/category_seo_quality.test.ts +76 -0
  10. package/src/tests/locale_completeness.test.ts +1 -1
  11. package/src/tests/seo_translation_completeness.test.ts +69 -0
  12. package/src/tests/seo_wellformed_export.test.ts +65 -0
  13. package/src/tests/tool_validation.test.ts +12 -7
  14. package/src/tool/dualOsIconPreview/assets/day-check.webp +0 -0
  15. package/src/tool/dualOsIconPreview/assets/fast-task.webp +0 -0
  16. package/src/tool/dualOsIconPreview/assets/fortune-cookie.webp +0 -0
  17. package/src/tool/dualOsIconPreview/assets/lexi-crash.webp +0 -0
  18. package/src/tool/dualOsIconPreview/assets/pizzametrics.webp +0 -0
  19. package/src/tool/dualOsIconPreview/assets/sauce-lab.webp +0 -0
  20. package/src/tool/dualOsIconPreview/assets/vesp.webp +0 -0
  21. package/src/tool/dualOsIconPreview/bibliography.astro +6 -0
  22. package/src/tool/dualOsIconPreview/bibliography.ts +7 -0
  23. package/src/tool/dualOsIconPreview/component.astro +117 -0
  24. package/src/tool/dualOsIconPreview/controller.ts +157 -0
  25. package/src/tool/dualOsIconPreview/dom-views.ts +82 -0
  26. package/src/tool/dualOsIconPreview/dual-ios-android-app-icon-preview.css +861 -0
  27. package/src/tool/dualOsIconPreview/entry.ts +31 -0
  28. package/src/tool/dualOsIconPreview/evaluator.ts +20 -0
  29. package/src/tool/dualOsIconPreview/i18n/de.ts +56 -0
  30. package/src/tool/dualOsIconPreview/i18n/en.ts +46 -0
  31. package/src/tool/dualOsIconPreview/i18n/es.ts +56 -0
  32. package/src/tool/dualOsIconPreview/i18n/fr.ts +56 -0
  33. package/src/tool/dualOsIconPreview/i18n/id.ts +56 -0
  34. package/src/tool/dualOsIconPreview/i18n/it.ts +56 -0
  35. package/src/tool/dualOsIconPreview/i18n/ja.ts +56 -0
  36. package/src/tool/dualOsIconPreview/i18n/ko.ts +56 -0
  37. package/src/tool/dualOsIconPreview/i18n/nl.ts +56 -0
  38. package/src/tool/dualOsIconPreview/i18n/pl.ts +56 -0
  39. package/src/tool/dualOsIconPreview/i18n/pt.ts +56 -0
  40. package/src/tool/dualOsIconPreview/i18n/ru.ts +56 -0
  41. package/src/tool/dualOsIconPreview/i18n/sv.ts +56 -0
  42. package/src/tool/dualOsIconPreview/i18n/tr.ts +43 -0
  43. package/src/tool/dualOsIconPreview/i18n/zh.ts +43 -0
  44. package/src/tool/dualOsIconPreview/index.ts +11 -0
  45. package/src/tool/dualOsIconPreview/logic.test.ts +63 -0
  46. package/src/tool/dualOsIconPreview/logic.ts +135 -0
  47. package/src/tool/dualOsIconPreview/seo.astro +15 -0
  48. package/src/tool/dualOsIconPreview/storage.ts +18 -0
  49. package/src/tool/dualOsIconPreview/ui.ts +52 -0
  50. package/src/tool/promoteThisWebsite/i18n/pl.ts +1 -1
  51. package/src/tool/promoteThisWebsite/i18n/ru.ts +1 -1
  52. package/src/tool/promoteThisWebsite/i18n/tr.ts +1 -1
  53. package/src/tools.ts +2 -1
@@ -0,0 +1,56 @@
1
+ import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
2
+ import { bibliography } from '../bibliography';
3
+ import type { ToolLocaleContent, SEOSection } from '../../../types';
4
+ import type { DualOsIconPreviewUI } from '../ui';
5
+
6
+ interface LocalizedCopy {
7
+ locale: string;
8
+ slug: string;
9
+ title: string;
10
+ description: string;
11
+ faqTitle: string;
12
+ bibliographyTitle: string;
13
+ ui: DualOsIconPreviewUI;
14
+ faq: { question: string; answer: string }[];
15
+ howTo: { name: string; text: string }[];
16
+ seo: SEOSection[];
17
+ }
18
+
19
+ function createDualOsIconPreviewContent(copy: LocalizedCopy): ToolLocaleContent<DualOsIconPreviewUI> {
20
+ const faqSchema: WithContext<FAQPage> = { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: copy.faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) };
21
+ const howToSchema: WithContext<HowTo> = { '@context': 'https://schema.org', '@type': 'HowTo', name: copy.title, description: copy.description, step: copy.howTo.map((step, index) => ({ '@type': 'HowToStep', position: index + 1, name: step.name, text: step.text })) };
22
+ const appSchema: WithContext<SoftwareApplication> = { '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: copy.title, description: copy.description, applicationCategory: 'DesignApplication', operatingSystem: 'iOS, Android', offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' }, inLanguage: copy.locale };
23
+ return { slug: copy.slug, title: copy.title, description: copy.description, ui: copy.ui, faqTitle: copy.faqTitle, faq: copy.faq, bibliographyTitle: copy.bibliographyTitle, bibliography, howTo: copy.howTo, schemas: [appSchema, faqSchema, howToSchema], seo: copy.seo };
24
+ }
25
+
26
+ const title = 'Apppictogram audit voor iOS en Android';
27
+ const description = 'Upload een logo en controleer hoe het eruitziet op iPhone en Pixel. Bekijk iOS modi, adaptieve Android maskers, veilige marges en thema pictogrammen direct in de browser.';
28
+ const ui: DualOsIconPreviewUI = {
29
+ labelUpload: 'Logo uploaden', uploadAction: 'Afbeelding kiezen', uploadHint: 'Hetzelfde teken vult beide telefoons', dropHint: 'PNG, JPG, WEBP of SVG', labelAppName: 'Appnaam', appNamePlaceholder: 'Verschijnt onder het pictogram', labelBrandColor: 'Systeemkleur voor accent', labelIosAppearance: 'iOS weergave', iosAppearanceHint: 'Controleer het teken in elke beginschermmodus', iosDefault: 'Standaard', iosDark: 'Donker', iosClear: 'Helder', iosTinted: 'Getint', labelAndroidShape: 'Adaptief Android masker', androidShapeHint: 'De launcher kan de buitenvorm wijzigen', androidCircle: 'Cirkel', androidSquircle: 'Squircle', androidRounded: 'Rond', androidTeardrop: 'Druppel', labelAndroidTheme: 'Themapictogram bekijken', androidThemeHint: 'Geeft elk pictogram één systeemtint en behoudt de omtrek', iosDeviceLabel: 'iPhone', androidDeviceLabel: 'Pixel', iosHomeLabel: 'Beginscherm', androidHomeLabel: 'Launcher', safeZoneLabel: 'iOS masker', adaptiveLayerLabel: 'Adaptief pictogram', monochromeLabel: 'Thema laag', nameFallback: 'Je app', emptyLogo: 'Je logo', fileError: 'Kies een afbeeldingsbestand om verder te gaan.', statusReady: 'Gereed', statusNeedsReview: 'Logo toevoegen', stageKicker: 'Twee apparaatcontexten, één audit', stageNote: 'Bekijk elke behandeling in context', auditTitle: 'Logo audit', auditHint: 'Lokaal gemeten op basis van de geladen afbeelding', auditWaiting: 'Upload een logo', auditNotChecked: 'Niet gecontroleerd', auditFile: 'Canvas', auditAspect: 'Beeldverhouding', auditResolution: 'Resolutie', auditIosMask: 'iOS masker marge', auditAndroidZone: 'Android veilige zone', auditMargin: 'Minimale rand', auditTransparency: 'Alfa rand', auditTransparent: 'Transparant', auditFullBleed: 'Volledig gevuld', statusPass: 'GESLAAGD', statusReview: 'CONTROLEREN',
30
+ };
31
+ const faq = [
32
+ { question: 'Wat controleert deze audit van het apppictogram?', answer: 'De audit controleert afmetingen, beeldverhouding, resolutie, transparante rand, iOS masker marge en de adaptieve Android veilige zone. Je kunt ook de appnaam op launcher formaat bekijken.' },
33
+ { question: 'Kan ik iPhone en Android tegelijk zien?', answer: 'Ja. Hetzelfde logo en dezelfde appnaam verschijnen tegelijk in een iPhone beginscherm en een Pixel launcher, zodat de context van beide apparaten zichtbaar blijft.' },
34
+ { question: 'Wat doet de modus voor Android themapictogrammen?', answer: 'De modus past één systeemtint en een monochrome behandeling toe op elk Android pictogram in de scène, inclusief het geüploade pictogram, omliggende apps en het dock. Zo zie je of de vorm zonder de oorspronkelijke kleuren leesbaar blijft.' },
35
+ { question: 'Verlaat het logo mijn browser?', answer: 'Nee. De afbeelding wordt lokaal in je browser gelezen en gemeten. Deze tool uploadt haar niet naar een server.' },
36
+ { question: 'Is het resultaat klaar voor publicatie in een app store?', answer: 'Nee. Dit is een lokale ontwerp en asset audit. Gebruik Apple en Android platformtools plus een echt apparaat of emulator voor de definitieve export, launcherwerking en storegoedkeuring.' },
37
+ ];
38
+ const howTo = [
39
+ { name: 'Upload het logo', text: 'Kies een PNG, JPG, WEBP of SVG logo. Dezelfde lokale afbeelding verschijnt in beide apparaatcontexten.' },
40
+ { name: 'Voer de appnaam in', text: 'Typ het launcherlabel en controleer of het leesbaar blijft naast de echte labels van omliggende apps.' },
41
+ { name: 'Bekijk iOS weergaven', text: 'Wissel tussen Standaard, Donker, Helder en Getint en let op zwak contrast of verdwijnende details.' },
42
+ { name: 'Bekijk Android maskers', text: 'Probeer cirkel, squircle, rond en druppel. Schakel daarna themapictogrammen in om de monochrome versie overal in de launcher te beoordelen.' },
43
+ { name: 'Handel op basis van de audit', text: 'Voeg ademruimte toe, vereenvoudig kleine details of verbeter het contrast voordat je de definitieve platformassets maakt.' },
44
+ ];
45
+
46
+ export const content = createDualOsIconPreviewContent({ locale: 'nl', slug: 'appicoon-audit-ios-android', title, description, faqTitle: 'Veelgestelde vragen', bibliographyTitle: 'Bronnen', ui, faq, howTo, seo: [
47
+ { type: 'title', text: 'Controleer je apppictogram vóór publicatie', level: 2 },
48
+ { type: 'paragraph', html: 'Upload één logo en bekijk het tegelijk in een iPhone beginscherm en een Pixel launcher. Deze audit van het apppictogram meet het canvas, de beeldverhouding, de resolutie, de transparante rand, de iOS masker marge en de adaptieve Android veilige zone. Voer ook de echte appnaam in, want een teken kan de pictogramcontrole doorstaan en toch mislukken wanneer het launcherlabel onleesbaar wordt.' },
49
+ { type: 'title', text: 'Wat deze audit van het apppictogram controleert', level: 3 },
50
+ { type: 'list', items: ['Canvas en beeldverhouding: controleer of de bron vierkant is voordat platformtools hun eigen behandeling toevoegen.', 'Resolutie: vind kleine bronbestanden voordat ze zacht of onbruikbaar worden in grotere launchers.', 'Randmarge: controleer of belangrijke vormen of letters te dicht bij het iOS masker of de Android veilige zone staan.', 'Launcherlabel: bekijk de appnaam op dezelfde schaal als pictogrammen ernaast en ontdek onhandige afbrekingen.', 'Android themabehandeling: pas één monochrome systeemtint toe op doel, omliggende pictogrammen en dock zodat kleur geen zwakke omtrek verbergt.'] },
51
+ { type: 'title', text: 'Bekijk beide apparaatcontexten tegelijk', level: 3 },
52
+ { type: 'paragraph', html: 'Gebruik de twee telefoonweergaven als één auditoppervlak. Doorloop iOS Standaard, Donker, Helder en Getint en probeer daarna Android cirkel, squircle, rond en druppel. Het doel is informatie verzamelen over hetzelfde asset op verschillende launcheroppervlakken, niet bepalen welk platform beter is.' },
53
+ { type: 'title', text: 'Wat de audit niet kan garanderen', level: 3 },
54
+ { type: 'paragraph', html: 'Dit is een browsergebaseerde ontwerp en assetcontrole en geen vervanging voor Xcode, Android Studio, een echt apparaat of een emulator. Launchers, besturingssysteemversies en fabrikanten kunnen maskers, tussenruimtes, contrast en regels voor themapictogrammen anders toepassen. Gebruik de audit om risico s vroeg te vinden en valideer daarna de definitieve platformassets in de omgevingen die je ondersteunt.' },
55
+ { type: 'tip', title: 'Praktische audit routine', html: 'Bekijk het logo in elke behandeling op de kleinste praktische grootte. Als het alleen werkt met één achtergrond, masker of de oorspronkelijke kleuren, vereenvoudig het ontwerp of voeg ruimte toe voordat je publiceert.' },
56
+ ] });
@@ -0,0 +1,56 @@
1
+ import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
2
+ import { bibliography } from '../bibliography';
3
+ import type { ToolLocaleContent, SEOSection } from '../../../types';
4
+ import type { DualOsIconPreviewUI } from '../ui';
5
+
6
+ interface LocalizedCopy {
7
+ locale: string;
8
+ slug: string;
9
+ title: string;
10
+ description: string;
11
+ faqTitle: string;
12
+ bibliographyTitle: string;
13
+ ui: DualOsIconPreviewUI;
14
+ faq: { question: string; answer: string }[];
15
+ howTo: { name: string; text: string }[];
16
+ seo: SEOSection[];
17
+ }
18
+
19
+ function createDualOsIconPreviewContent(copy: LocalizedCopy): ToolLocaleContent<DualOsIconPreviewUI> {
20
+ const faqSchema: WithContext<FAQPage> = { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: copy.faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) };
21
+ const howToSchema: WithContext<HowTo> = { '@context': 'https://schema.org', '@type': 'HowTo', name: copy.title, description: copy.description, step: copy.howTo.map((step, index) => ({ '@type': 'HowToStep', position: index + 1, name: step.name, text: step.text })) };
22
+ const appSchema: WithContext<SoftwareApplication> = { '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: copy.title, description: copy.description, applicationCategory: 'DesignApplication', operatingSystem: 'iOS, Android', offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' }, inLanguage: copy.locale };
23
+ return { slug: copy.slug, title: copy.title, description: copy.description, ui: copy.ui, faqTitle: copy.faqTitle, faq: copy.faq, bibliographyTitle: copy.bibliographyTitle, bibliography, howTo: copy.howTo, schemas: [appSchema, faqSchema, howToSchema], seo: copy.seo };
24
+ }
25
+
26
+ const title = 'Audyt ikon aplikacji dla iOS i Androida';
27
+ const description = 'Prześlij logo i sprawdź jego wygląd na iPhonie oraz Pixelu. Zobacz tryby iOS, adaptacyjne maski Androida, bezpieczne marginesy i ikony tematyczne w przeglądarce.';
28
+ const ui: DualOsIconPreviewUI = {
29
+ labelUpload: 'Prześlij logo', uploadAction: 'Wybierz obraz', uploadHint: 'Ten sam znak wypełnia oba telefony', dropHint: 'PNG, JPG, WEBP lub SVG', labelAppName: 'Nazwa aplikacji', appNamePlaceholder: 'Wyświetlana pod ikoną', labelBrandColor: 'Systemowy kolor akcentu', labelIosAppearance: 'Wygląd iOS', iosAppearanceHint: 'Sprawdź znak w każdym trybie ekranu początkowego', iosDefault: 'Domyślny', iosDark: 'Ciemny', iosClear: 'Jasny', iosTinted: 'Barwiony', labelAndroidShape: 'Adaptacyjna maska Androida', androidShapeHint: 'Launcher może zmienić zewnętrzny kształt', androidCircle: 'Okrąg', androidSquircle: 'Squircle', androidRounded: 'Zaokrąglony', androidTeardrop: 'Łza', labelAndroidTheme: 'Podgląd ikony tematycznej', androidThemeHint: 'Nadaje każdej ikonie jeden systemowy odcień i zachowuje jej sylwetkę', iosDeviceLabel: 'iPhone', androidDeviceLabel: 'Pixel', iosHomeLabel: 'Ekran początkowy', androidHomeLabel: 'Launcher', safeZoneLabel: 'Maska iOS', adaptiveLayerLabel: 'Ikona adaptacyjna', monochromeLabel: 'Warstwa motywu', nameFallback: 'Twoja aplikacja', emptyLogo: 'Twoje logo', fileError: 'Wybierz plik obrazu, aby kontynuować.', statusReady: 'Gotowe', statusNeedsReview: 'Dodaj logo', stageKicker: 'Dwa konteksty urządzeń, jeden audyt', stageNote: 'Sprawdź każde przetworzenie w kontekście', auditTitle: 'Audyt logo', auditHint: 'Zmierzono lokalnie na podstawie wczytanego obrazu', auditWaiting: 'Prześlij logo', auditNotChecked: 'Nie sprawdzono', auditFile: 'Obszar obrazu', auditAspect: 'Proporcje', auditResolution: 'Rozdzielczość', auditIosMask: 'Margines maski iOS', auditAndroidZone: 'Bezpieczna strefa Androida', auditMargin: 'Minimalny margines', auditTransparency: 'Krawędź alfa', auditTransparent: 'Przezroczyste', auditFullBleed: 'Pełne pokrycie', statusPass: 'OK', statusReview: 'SPRAWDŹ',
30
+ };
31
+ const faq = [
32
+ { question: 'Co sprawdza ten audyt ikony aplikacji?', answer: 'Sprawdza wymiary obrazu, proporcje, rozdzielczość, przezroczysty margines, zapas maski iOS oraz adaptacyjną bezpieczną strefę Androida. Pozwala też obejrzeć nazwę aplikacji w rozmiarze launchera.' },
33
+ { question: 'Czy mogę jednocześnie zobaczyć iPhone a i Androida?', answer: 'Tak. To samo logo i nazwa aplikacji są wyświetlane jednocześnie na ekranie początkowym iPhone a oraz w launcherze Pixela, więc zachowujesz kontekst obu urządzeń.' },
34
+ { question: 'Co robi tryb ikon tematycznych Androida?', answer: 'Nakłada jeden systemowy odcień i monochromatyczne przetworzenie na każdą ikonę Androida w scenie, także na przesłaną ikonę, sąsiednie aplikacje i dok. Dzięki temu widać, czy kształt pozostaje czytelny bez oryginalnych kolorów.' },
35
+ { question: 'Czy logo opuszcza moją przeglądarkę?', answer: 'Nie. Obraz jest odczytywany i mierzony lokalnie w przeglądarce. To narzędzie nie wysyła go na serwer.' },
36
+ { question: 'Czy wynik nadaje się do wysłania do sklepu z aplikacjami?', answer: 'Nie. To lokalny audyt projektu i assetów. Do końcowego eksportu, zachowania launchera i akceptacji sklepu użyj narzędzi Apple i Androida oraz prawdziwego urządzenia lub emulatora.' },
37
+ ];
38
+ const howTo = [
39
+ { name: 'Prześlij logo', text: 'Wybierz logo PNG, JPG, WEBP lub SVG. Ten sam lokalny obraz pojawi się w obu kontekstach urządzeń.' },
40
+ { name: 'Wpisz nazwę aplikacji', text: 'Wpisz etykietę launchera i sprawdź, czy pozostaje czytelna obok prawdziwych etykiet sąsiednich aplikacji.' },
41
+ { name: 'Sprawdź wygląd iOS', text: 'Przełącz Domyślny, Ciemny, Jasny i Barwiony, aby znaleźć słaby kontrast lub znikające szczegóły.' },
42
+ { name: 'Sprawdź maski Androida', text: 'Wypróbuj okrąg, squircle, zaokrąglenie i łzę. Następnie włącz ikony tematyczne i oceń wersję monochromatyczną w całym launcherze.' },
43
+ { name: 'Zareaguj na audyt', text: 'Dodaj oddech, uprość drobne szczegóły lub popraw kontrast przed przygotowaniem końcowych assetów platformy.' },
44
+ ];
45
+
46
+ export const content = createDualOsIconPreviewContent({ locale: 'pl', slug: 'audyt-ikon-aplikacji-ios-android', title, description, faqTitle: 'Najczęściej zadawane pytania', bibliographyTitle: 'Materiały źródłowe', ui, faq, howTo, seo: [
47
+ { type: 'title', text: 'Przeprowadź audyt ikony aplikacji przed publikacją', level: 2 },
48
+ { type: 'paragraph', html: 'Prześlij jedno logo i obejrzyj je jednocześnie w kontekście ekranu początkowego iPhone a oraz launchera Pixela. Ten audyt ikony aplikacji mierzy obszar obrazu, proporcje, rozdzielczość, przezroczysty margines, zapas maski iOS i adaptacyjną bezpieczną strefę Androida. Wpisz też prawdziwą nazwę aplikacji, ponieważ znak może przejść kontrolę ikony, ale zawieść, gdy etykieta launchera stanie się nieczytelna.' },
49
+ { type: 'title', text: 'Co sprawdza audyt ikony aplikacji', level: 3 },
50
+ { type: 'list', items: ['Obszar i proporcje: potwierdź, że źródło jest kwadratowe, zanim narzędzia platformy dodadzą własne przetworzenie.', 'Rozdzielczość: znajdź małe pliki źródłowe, zanim staną się miękkie lub bezużyteczne w większym launcherze.', 'Margines krawędzi: sprawdź, czy ważne kształty lub litery nie leżą zbyt blisko maski iOS albo bezpiecznej strefy Androida.', 'Etykieta launchera: obejrzyj nazwę aplikacji w tej samej skali co sąsiednie ikony i znajdź niezręczne łamanie tekstu.', 'Tematyczne przetworzenie Androida: nałóż monochromatyczny odcień systemu na cel, sąsiednie ikony i dok, aby kolor nie ukrywał słabej sylwetki.'] },
51
+ { type: 'title', text: 'Zobacz oba konteksty urządzeń jednocześnie', level: 3 },
52
+ { type: 'paragraph', html: 'Traktuj oba widoki telefonu jako jedną powierzchnię audytu. Przełączaj wygląd iOS Domyślny, Ciemny, Jasny i Barwiony, a potem wypróbuj maski Androida: okrąg, squircle, zaokrąglenie i łzę. Celem jest zebranie informacji o zachowaniu tego samego assetu na powierzchniach launchera, a nie rozstrzyganie, która platforma jest lepsza.' },
53
+ { type: 'title', text: 'Czego audyt nie może zagwarantować', level: 3 },
54
+ { type: 'paragraph', html: 'To przeglądarkowy przegląd projektu i assetów, a nie zamiennik Xcode, Android Studio, prawdziwego urządzenia ani emulatora. Launchery, wersje systemu i producenci mogą stosować inne maski, odstępy, kontrast oraz zasady ikon tematycznych. Wykorzystaj audyt do wczesnego wykrywania ryzyka, a następnie sprawdź końcowe assety platformy w obsługiwanych środowiskach.' },
55
+ { type: 'tip', title: 'Praktyczna procedura audytu', html: 'Oglądaj logo w najmniejszym praktycznym rozmiarze i w każdym dostępnym przetworzeniu. Jeśli działa tylko na jednym tle, w jednej masce lub w oryginalnych kolorach, uprość grafikę albo dodaj margines przed publikacją.' },
56
+ ] });
@@ -0,0 +1,56 @@
1
+ import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
2
+ import { bibliography } from '../bibliography';
3
+ import type { ToolLocaleContent, SEOSection } from '../../../types';
4
+ import type { DualOsIconPreviewUI } from '../ui';
5
+
6
+ interface LocalizedCopy {
7
+ locale: string;
8
+ slug: string;
9
+ title: string;
10
+ description: string;
11
+ faqTitle: string;
12
+ bibliographyTitle: string;
13
+ ui: DualOsIconPreviewUI;
14
+ faq: { question: string; answer: string }[];
15
+ howTo: { name: string; text: string }[];
16
+ seo: SEOSection[];
17
+ }
18
+
19
+ function createDualOsIconPreviewContent(copy: LocalizedCopy): ToolLocaleContent<DualOsIconPreviewUI> {
20
+ const faqSchema: WithContext<FAQPage> = { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: copy.faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) };
21
+ const howToSchema: WithContext<HowTo> = { '@context': 'https://schema.org', '@type': 'HowTo', name: copy.title, description: copy.description, step: copy.howTo.map((step, index) => ({ '@type': 'HowToStep', position: index + 1, name: step.name, text: step.text })) };
22
+ const appSchema: WithContext<SoftwareApplication> = { '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: copy.title, description: copy.description, applicationCategory: 'DesignApplication', operatingSystem: 'iOS, Android', offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' }, inLanguage: copy.locale };
23
+ return { slug: copy.slug, title: copy.title, description: copy.description, ui: copy.ui, faqTitle: copy.faqTitle, faq: copy.faq, bibliographyTitle: copy.bibliographyTitle, bibliography, howTo: copy.howTo, schemas: [appSchema, faqSchema, howToSchema], seo: copy.seo };
24
+ }
25
+
26
+ const title = 'Auditoria de ícones de app para iOS e Android';
27
+ const description = 'Envie um logótipo e audite o seu aspeto no iPhone e no Pixel. Inspecione modos do iOS, máscaras adaptativas do Android, margens seguras e ícones temáticos no navegador.';
28
+ const ui: DualOsIconPreviewUI = {
29
+ labelUpload: 'Enviar logótipo', uploadAction: 'Escolher uma imagem', uploadHint: 'A mesma marca preenche os dois telemóveis', dropHint: 'PNG, JPG, WEBP ou SVG', labelAppName: 'Nome da app', appNamePlaceholder: 'Mostrado por baixo do ícone', labelBrandColor: 'Cor de destaque do sistema', labelIosAppearance: 'Aspeto do iOS', iosAppearanceHint: 'Verifique a marca em todos os modos do ecrã principal', iosDefault: 'Predefinido', iosDark: 'Escuro', iosClear: 'Claro', iosTinted: 'Colorido', labelAndroidShape: 'Máscara adaptativa do Android', androidShapeHint: 'O launcher pode alterar a forma exterior', androidCircle: 'Círculo', androidSquircle: 'Squircle', androidRounded: 'Arredondado', androidTeardrop: 'Gota', labelAndroidTheme: 'Pré visualizar ícone temático', androidThemeHint: 'Recolore cada ícone com uma tonalidade do sistema e preserva a sua silhueta', iosDeviceLabel: 'iPhone', androidDeviceLabel: 'Pixel', iosHomeLabel: 'Ecrã principal', androidHomeLabel: 'Launcher', safeZoneLabel: 'Máscara do iOS', adaptiveLayerLabel: 'Ícone adaptativo', monochromeLabel: 'Camada temática', nameFallback: 'A sua app', emptyLogo: 'O seu logótipo', fileError: 'Escolha um ficheiro de imagem para continuar.', statusReady: 'Pronto', statusNeedsReview: 'Adicionar logótipo', stageKicker: 'Dois contextos de dispositivo, uma auditoria', stageNote: 'Inspecione cada tratamento no seu contexto', auditTitle: 'Auditoria do logótipo', auditHint: 'Medido localmente a partir da imagem carregada', auditWaiting: 'Envie um logótipo', auditNotChecked: 'Não verificado', auditFile: 'Tela', auditAspect: 'Proporção', auditResolution: 'Resolução', auditIosMask: 'Margem da máscara iOS', auditAndroidZone: 'Zona segura Android', auditMargin: 'Margem mínima', auditTransparency: 'Borda alfa', auditTransparent: 'Transparente', auditFullBleed: 'Preenchimento total', statusPass: 'PASSA', statusReview: 'REVER',
30
+ };
31
+ const faq = [
32
+ { question: 'O que verifica esta auditoria do ícone da app?', answer: 'Verifica dimensões, proporção, resolução, margem transparente, margem da máscara do iOS e zona segura adaptativa do Android. Também permite inspecionar o nome da app no tamanho do launcher.' },
33
+ { question: 'Posso ver iPhone e Android ao mesmo tempo?', answer: 'Sim. O mesmo logótipo e nome aparecem simultaneamente num ecrã principal do iPhone e num launcher Pixel, mantendo visível o contexto dos dois dispositivos.' },
34
+ { question: 'O que faz o modo de ícone temático do Android?', answer: 'Aplica uma tonalidade do sistema e um tratamento monocromático a todos os ícones Android da cena, incluindo o ícone enviado, as apps vizinhas e a dock. Assim pode verificar se a silhueta continua legível sem as cores originais.' },
35
+ { question: 'O logótipo sai do meu navegador?', answer: 'Não. A imagem é lida e medida localmente no navegador. Esta ferramenta não a envia para um servidor.' },
36
+ { question: 'Está pronto para enviar a app para uma loja?', answer: 'Não. É uma auditoria local de design e assets. Para a exportação final, o comportamento do launcher e a aprovação da loja, use as ferramentas da Apple e do Android, além de um dispositivo real ou emulador.' },
37
+ ];
38
+ const howTo = [
39
+ { name: 'Enviar o logótipo', text: 'Escolha um logótipo PNG, JPG, WEBP ou SVG. A mesma imagem local aparece nos dois contextos de dispositivo.' },
40
+ { name: 'Introduzir o nome da app', text: 'Escreva a etiqueta do launcher e confirme se continua legível junto dos nomes reais das apps vizinhas.' },
41
+ { name: 'Inspecionar os aspetos do iOS', text: 'Alterne entre Predefinido, Escuro, Claro e Colorido e procure contraste fraco ou detalhes que desaparecem.' },
42
+ { name: 'Inspecionar as máscaras do Android', text: 'Experimente círculo, squircle, arredondado e gota. Depois ative o modo temático para rever a versão monocromática em todo o launcher.' },
43
+ { name: 'Agir sobre a auditoria', text: 'Adicione espaço, simplifique detalhes finos ou melhore o contraste antes de preparar os assets finais da plataforma.' },
44
+ ];
45
+
46
+ export const content = createDualOsIconPreviewContent({ locale: 'pt', slug: 'auditoria-icones-app-ios-android', title, description, faqTitle: 'Perguntas frequentes', bibliographyTitle: 'Referências', ui, faq, howTo, seo: [
47
+ { type: 'title', text: 'Audite o ícone da sua app antes do lançamento', level: 2 },
48
+ { type: 'paragraph', html: 'Envie um logótipo e inspecione-o simultaneamente no contexto de um ecrã principal do iPhone e de um launcher Pixel. Esta auditoria de ícones mede a tela, a proporção, a resolução, a margem transparente, a margem da máscara do iOS e a zona segura adaptativa do Android. Introduza também o nome real da app, porque uma marca pode passar na verificação do ícone e falhar quando a etiqueta do launcher deixa de ser legível.' },
49
+ { type: 'title', text: 'O que esta auditoria do ícone verifica', level: 3 },
50
+ { type: 'list', items: ['Tela e proporção: confirme que a origem é quadrada antes de as ferramentas da plataforma adicionarem o seu próprio tratamento.', 'Resolução: detete ficheiros de origem pequenos antes de ficarem desfocados ou inutilizáveis em launchers maiores.', 'Margem exterior: veja se formas ou letras importantes estão demasiado próximas da máscara do iOS ou da zona segura do Android.', 'Etiqueta do launcher: verifique o nome da app à mesma escala dos ícones vizinhos e detete quebras de linha estranhas.', 'Tratamento temático do Android: aplique uma tonalidade monocromática do sistema ao alvo, aos ícones vizinhos e à dock para revelar uma silhueta fraca.'] },
51
+ { type: 'title', text: 'Veja os dois contextos de dispositivo ao mesmo tempo', level: 3 },
52
+ { type: 'paragraph', html: 'Use as duas vistas do telemóvel como uma única superfície de auditoria. Percorra os aspetos Predefinido, Escuro, Claro e Colorido do iOS e experimente depois as máscaras círculo, squircle, arredondado e gota do Android. O objetivo é perceber como o mesmo asset se comporta em superfícies de launcher, não declarar uma plataforma melhor do que a outra.' },
53
+ { type: 'title', text: 'O que a auditoria não pode garantir', level: 3 },
54
+ { type: 'paragraph', html: 'Esta é uma revisão de design e assets no navegador, não substitui Xcode, Android Studio, um dispositivo real ou um emulador. Launchers, versões do sistema e fabricantes podem aplicar máscaras, espaçamento, contraste e regras de ícones temáticos diferentes. Use a auditoria para encontrar riscos cedo e valide depois os assets finais nos ambientes que suporta.' },
55
+ { type: 'tip', title: 'Rotina prática de auditoria', html: 'Reveja o logótipo no menor tamanho prático e em todos os tratamentos disponíveis. Se só funcionar com um fundo, uma máscara ou as cores originais, simplifique o desenho ou acrescente margem antes de publicar.' },
56
+ ] });
@@ -0,0 +1,56 @@
1
+ import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
2
+ import { bibliography } from '../bibliography';
3
+ import type { ToolLocaleContent, SEOSection } from '../../../types';
4
+ import type { DualOsIconPreviewUI } from '../ui';
5
+
6
+ interface LocalizedCopy {
7
+ locale: string;
8
+ slug: string;
9
+ title: string;
10
+ description: string;
11
+ faqTitle: string;
12
+ bibliographyTitle: string;
13
+ ui: DualOsIconPreviewUI;
14
+ faq: { question: string; answer: string }[];
15
+ howTo: { name: string; text: string }[];
16
+ seo: SEOSection[];
17
+ }
18
+
19
+ function createDualOsIconPreviewContent(copy: LocalizedCopy): ToolLocaleContent<DualOsIconPreviewUI> {
20
+ const faqSchema: WithContext<FAQPage> = { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: copy.faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) };
21
+ const howToSchema: WithContext<HowTo> = { '@context': 'https://schema.org', '@type': 'HowTo', name: copy.title, description: copy.description, step: copy.howTo.map((step, index) => ({ '@type': 'HowToStep', position: index + 1, name: step.name, text: step.text })) };
22
+ const appSchema: WithContext<SoftwareApplication> = { '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: copy.title, description: copy.description, applicationCategory: 'DesignApplication', operatingSystem: 'iOS, Android', offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' }, inLanguage: copy.locale };
23
+ return { slug: copy.slug, title: copy.title, description: copy.description, ui: copy.ui, faqTitle: copy.faqTitle, faq: copy.faq, bibliographyTitle: copy.bibliographyTitle, bibliography, howTo: copy.howTo, schemas: [appSchema, faqSchema, howToSchema], seo: copy.seo };
24
+ }
25
+
26
+ const title = 'Аудит иконки приложения для iOS и Android';
27
+ const description = 'Загрузите логотип и проверьте его вид на iPhone и Pixel. Исследуйте режимы iOS, адаптивные маски Android, безопасные отступы и тематические иконки прямо в браузере.';
28
+ const ui: DualOsIconPreviewUI = {
29
+ labelUpload: 'Загрузить логотип', uploadAction: 'Выбрать изображение', uploadHint: 'Один знак отображается на обоих телефонах', dropHint: 'PNG, JPG, WEBP или SVG', labelAppName: 'Название приложения', appNamePlaceholder: 'Показывается под иконкой', labelBrandColor: 'Системный акцентный цвет', labelIosAppearance: 'Вид iOS', iosAppearanceHint: 'Проверьте знак во всех режимах домашнего экрана', iosDefault: 'По умолчанию', iosDark: 'Тёмный', iosClear: 'Светлый', iosTinted: 'Тонированный', labelAndroidShape: 'Адаптивная маска Android', androidShapeHint: 'Лаунчер может изменить внешнюю форму', androidCircle: 'Круг', androidSquircle: 'Сквиркл', androidRounded: 'Скруглённый', androidTeardrop: 'Капля', labelAndroidTheme: 'Предпросмотр тематической иконки', androidThemeHint: 'Перекрашивает все иконки одним системным оттенком и сохраняет силуэт', iosDeviceLabel: 'iPhone', androidDeviceLabel: 'Pixel', iosHomeLabel: 'Домашний экран', androidHomeLabel: 'Лаунчер', safeZoneLabel: 'Маска iOS', adaptiveLayerLabel: 'Адаптивная иконка', monochromeLabel: 'Слой темы', nameFallback: 'Ваше приложение', emptyLogo: 'Ваш логотип', fileError: 'Выберите файл изображения, чтобы продолжить.', statusReady: 'Готово', statusNeedsReview: 'Добавьте логотип', stageKicker: 'Два контекста устройства, один аудит', stageNote: 'Проверяйте каждую обработку в контексте', auditTitle: 'Аудит логотипа', auditHint: 'Измерено локально по загруженному изображению', auditWaiting: 'Загрузите логотип', auditNotChecked: 'Не проверено', auditFile: 'Холст', auditAspect: 'Соотношение сторон', auditResolution: 'Разрешение', auditIosMask: 'Отступ маски iOS', auditAndroidZone: 'Безопасная зона Android', auditMargin: 'Минимальный отступ', auditTransparency: 'Альфа край', auditTransparent: 'Прозрачный', auditFullBleed: 'Полное заполнение', statusPass: 'ПРОЙДЕНО', statusReview: 'ПРОВЕРИТЬ',
30
+ };
31
+ const faq = [
32
+ { question: 'Что проверяет этот аудит иконки приложения?', answer: 'Он проверяет размеры изображения, соотношение сторон, разрешение, прозрачный отступ по краям, запас маски iOS и адаптивную безопасную зону Android. Также можно посмотреть название приложения в размере лаунчера.' },
33
+ { question: 'Можно ли одновременно видеть iPhone и Android?', answer: 'Да. Один и тот же логотип и название одновременно показаны на домашнем экране iPhone и в лаунчере Pixel, поэтому контекст обоих устройств остаётся видимым.' },
34
+ { question: 'Что делает режим тематических иконок Android?', answer: 'Он применяет один системный оттенок и монохромную обработку ко всем иконкам Android в сцене, включая загруженную иконку, соседние приложения и док. Так видно, остаётся ли силуэт читаемым без исходных цветов.' },
35
+ { question: 'Логотип покидает мой браузер?', answer: 'Нет. Изображение читается и измеряется локально в браузере. Инструмент не отправляет его на сервер.' },
36
+ { question: 'Можно ли сразу отправить результат в магазин приложений?', answer: 'Нет. Это локальный аудит дизайна и ассетов. Для финального экспорта, поведения лаунчера и проверки магазина используйте инструменты Apple и Android, а также реальное устройство или эмулятор.' },
37
+ ];
38
+ const howTo = [
39
+ { name: 'Загрузите логотип', text: 'Выберите логотип PNG, JPG, WEBP или SVG. Одно локальное изображение появится в обоих контекстах устройства.' },
40
+ { name: 'Введите название приложения', text: 'Введите подпись лаунчера и проверьте, остаётся ли она читаемой рядом с настоящими подписями соседних приложений.' },
41
+ { name: 'Проверьте виды iOS', text: 'Переключайтесь между режимами По умолчанию, Тёмный, Светлый и Тонированный, чтобы найти слабый контраст или исчезающие детали.' },
42
+ { name: 'Проверьте маски Android', text: 'Попробуйте круг, сквиркл, скруглённую форму и каплю. Затем включите тематические иконки и оцените монохромную версию всего лаунчера.' },
43
+ { name: 'Исправьте найденные риски', text: 'Добавьте свободное пространство, упростите мелкие детали или улучшите контраст перед подготовкой финальных ассетов.' },
44
+ ];
45
+
46
+ export const content = createDualOsIconPreviewContent({ locale: 'ru', slug: 'audit-ikonki-prilozheniya-ios-android', title, description, faqTitle: 'Часто задаваемые вопросы', bibliographyTitle: 'Источники', ui, faq, howTo, seo: [
47
+ { type: 'title', text: 'Проверьте иконку приложения до публикации', level: 2 },
48
+ { type: 'paragraph', html: 'Загрузите один логотип и одновременно проверьте его в контексте домашнего экрана iPhone и лаунчера Pixel. Этот аудит иконки приложения измеряет холст, соотношение сторон, разрешение, прозрачный отступ, запас маски iOS и адаптивную безопасную зону Android. Введите настоящее название приложения: знак может пройти проверку иконки, но стать непонятным, если подпись лаунчера плохо читается.' },
49
+ { type: 'title', text: 'Что проверяет аудит иконки приложения', level: 3 },
50
+ { type: 'list', items: ['Холст и соотношение сторон: убедитесь, что исходник квадратный, прежде чем инструменты платформы добавят собственную обработку.', 'Разрешение: найдите маленькие исходные файлы до того, как они станут размытыми в крупном лаунчере.', 'Отступ от края: проверьте, не расположены ли важные формы или буквы слишком близко к маске iOS или безопасной зоне Android.', 'Подпись лаунчера: посмотрите название приложения в том же масштабе, что и соседние иконки, и найдите неудачные переносы.', 'Тематическая обработка Android: примените монохромный системный оттенок к цели, соседним иконкам и доку, чтобы цвет не скрывал слабый силуэт.'] },
51
+ { type: 'title', text: 'Смотрите оба контекста устройства одновременно', level: 3 },
52
+ { type: 'paragraph', html: 'Используйте два вида телефона как одну поверхность аудита. Переключайте режимы iOS По умолчанию, Тёмный, Светлый и Тонированный, а затем пробуйте маски Android Круг, Сквиркл, Скруглённая и Капля. Цель состоит в том, чтобы понять поведение одного ассета на разных поверхностях лаунчера, а не объявить одну платформу лучше другой.' },
53
+ { type: 'title', text: 'Чего аудит не может гарантировать', level: 3 },
54
+ { type: 'paragraph', html: 'Это проверка дизайна и ассетов в браузере, а не замена Xcode, Android Studio, реального устройства или эмулятора. Лаунчеры, версии операционной системы и производители могут по-разному применять маски, отступы, контраст и правила тематических иконок. Используйте аудит для раннего поиска рисков, затем проверьте финальные ассеты платформы в поддерживаемых средах.' },
55
+ { type: 'tip', title: 'Практический порядок аудита', html: 'Проверяйте логотип в самом маленьком практическом размере и во всех доступных режимах. Если он работает только с одним фоном, маской или исходными цветами, упростите графику или добавьте отступ перед публикацией.' },
56
+ ] });
@@ -0,0 +1,56 @@
1
+ import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
2
+ import { bibliography } from '../bibliography';
3
+ import type { ToolLocaleContent, SEOSection } from '../../../types';
4
+ import type { DualOsIconPreviewUI } from '../ui';
5
+
6
+ interface LocalizedCopy {
7
+ locale: string;
8
+ slug: string;
9
+ title: string;
10
+ description: string;
11
+ faqTitle: string;
12
+ bibliographyTitle: string;
13
+ ui: DualOsIconPreviewUI;
14
+ faq: { question: string; answer: string }[];
15
+ howTo: { name: string; text: string }[];
16
+ seo: SEOSection[];
17
+ }
18
+
19
+ function createDualOsIconPreviewContent(copy: LocalizedCopy): ToolLocaleContent<DualOsIconPreviewUI> {
20
+ const faqSchema: WithContext<FAQPage> = { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: copy.faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) };
21
+ const howToSchema: WithContext<HowTo> = { '@context': 'https://schema.org', '@type': 'HowTo', name: copy.title, description: copy.description, step: copy.howTo.map((step, index) => ({ '@type': 'HowToStep', position: index + 1, name: step.name, text: step.text })) };
22
+ const appSchema: WithContext<SoftwareApplication> = { '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: copy.title, description: copy.description, applicationCategory: 'DesignApplication', operatingSystem: 'iOS, Android', offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' }, inLanguage: copy.locale };
23
+ return { slug: copy.slug, title: copy.title, description: copy.description, ui: copy.ui, faqTitle: copy.faqTitle, faq: copy.faq, bibliographyTitle: copy.bibliographyTitle, bibliography, howTo: copy.howTo, schemas: [appSchema, faqSchema, howToSchema], seo: copy.seo };
24
+ }
25
+
26
+ const title = 'Granskning av appikoner för iOS och Android';
27
+ const description = 'Ladda upp en logotyp och granska hur den ser ut på iPhone och Pixel. Kontrollera iOS lägen, adaptiva Android masker, säkra marginaler och tematiska ikoner i webbläsaren.';
28
+ const ui: DualOsIconPreviewUI = {
29
+ labelUpload: 'Ladda upp logotyp', uploadAction: 'Välj en bild', uploadHint: 'Samma märke fyller båda telefonerna', dropHint: 'PNG, JPG, WEBP eller SVG', labelAppName: 'Appnamn', appNamePlaceholder: 'Visas under ikonen', labelBrandColor: 'Systemets accentfärg', labelIosAppearance: 'iOS utseende', iosAppearanceHint: 'Kontrollera märket i varje läge på hemskärmen', iosDefault: 'Standard', iosDark: 'Mörk', iosClear: 'Klar', iosTinted: 'Tonad', labelAndroidShape: 'Adaptiv Android mask', androidShapeHint: 'Launchern kan ändra ytterformen', androidCircle: 'Cirkel', androidSquircle: 'Squircle', androidRounded: 'Rundad', androidTeardrop: 'Droppe', labelAndroidTheme: 'Förhandsvisa tematisk ikon', androidThemeHint: 'Färgar om varje ikon med en systemton och bevarar dess siluett', iosDeviceLabel: 'iPhone', androidDeviceLabel: 'Pixel', iosHomeLabel: 'Hemskärm', androidHomeLabel: 'Launcher', safeZoneLabel: 'iOS mask', adaptiveLayerLabel: 'Adaptiv ikon', monochromeLabel: 'Temalager', nameFallback: 'Din app', emptyLogo: 'Din logotyp', fileError: 'Välj en bildfil för att fortsätta.', statusReady: 'Klar', statusNeedsReview: 'Lägg till en logotyp', stageKicker: 'Två enhetskontexter, en granskning', stageNote: 'Inspektera varje behandling i sitt sammanhang', auditTitle: 'Logotypgranskning', auditHint: 'Mätt lokalt från den inlästa bilden', auditWaiting: 'Ladda upp en logotyp', auditNotChecked: 'Inte kontrollerad', auditFile: 'Canvas', auditAspect: 'Bildförhållande', auditResolution: 'Upplösning', auditIosMask: 'iOS maskmarginal', auditAndroidZone: 'Android säker zon', auditMargin: 'Minsta kantmarginal', auditTransparency: 'Alfakant', auditTransparent: 'Transparent', auditFullBleed: 'Helt fylld', statusPass: 'GODKÄND', statusReview: 'GRANSKA',
30
+ };
31
+ const faq = [
32
+ { question: 'Vad kontrollerar denna granskning av appikonen?', answer: 'Den kontrollerar bildmått, bildförhållande, upplösning, transparent kantmarginal, iOS maskmarginal och Androids adaptiva säkra zon. Du kan också se appnamnet i launcherns storlek.' },
33
+ { question: 'Kan jag se iPhone och Android samtidigt?', answer: 'Ja. Samma logotyp och appnamn visas samtidigt på en iPhone hemskärm och i en Pixel launcher, så sammanhanget för båda enheterna finns kvar.' },
34
+ { question: 'Vad gör Androids läge för tematiska ikoner?', answer: 'Det lägger en systemton och en monokrom behandling på alla Android ikoner i scenen, inklusive den uppladdade ikonen, närliggande appar och dockan. Då syns om siluetten fortfarande går att läsa utan originalfärgerna.' },
35
+ { question: 'Lämnar logotypen min webbläsare?', answer: 'Nej. Bilden läses och mäts lokalt i webbläsaren. Verktyget laddar inte upp den till en server.' },
36
+ { question: 'Är resultatet klart för publicering i en appbutik?', answer: 'Nej. Det är en lokal granskning av design och tillgångar. Använd Apples och Androids plattformsverktyg samt en riktig enhet eller emulator för slutlig export, launcherbeteende och butiksgodkännande.' },
37
+ ];
38
+ const howTo = [
39
+ { name: 'Ladda upp logotypen', text: 'Välj en PNG, JPG, WEBP eller SVG logotyp. Samma lokala bild visas i båda enhetskontexterna.' },
40
+ { name: 'Skriv in appnamnet', text: 'Skriv launcherns etikett och kontrollera att den fortfarande är läsbar bredvid riktiga etiketter från närliggande appar.' },
41
+ { name: 'Inspektera iOS utseenden', text: 'Växla mellan Standard, Mörk, Klar och Tonad och leta efter svag kontrast eller detaljer som försvinner.' },
42
+ { name: 'Inspektera Android masker', text: 'Prova cirkel, squircle, rundad och droppe. Aktivera sedan tematiska ikoner för att granska den monokroma versionen i hela launchern.' },
43
+ { name: 'Agera på granskningen', text: 'Lägg till luft, förenkla små detaljer eller förbättra kontrasten innan du förbereder plattformsfilerna.' },
44
+ ];
45
+
46
+ export const content = createDualOsIconPreviewContent({ locale: 'sv', slug: 'granskning-appikoner-ios-android', title, description, faqTitle: 'Vanliga frågor', bibliographyTitle: 'Källor', ui, faq, howTo, seo: [
47
+ { type: 'title', text: 'Granska appikonen före lansering', level: 2 },
48
+ { type: 'paragraph', html: 'Ladda upp en logotyp och inspektera den samtidigt i en iPhone hemskärm och en Pixel launcher. Den här granskningen av appikonen mäter canvas, bildförhållande, upplösning, transparent kantmarginal, iOS maskmarginal och Androids adaptiva säkra zon. Skriv också in det riktiga appnamnet, eftersom ett märke kan klara ikonkontrollen men ändå misslyckas när launcherns etikett blir svårläst.' },
49
+ { type: 'title', text: 'Det här kontrollerar granskningen av appikonen', level: 3 },
50
+ { type: 'list', items: ['Canvas och bildförhållande: bekräfta att källan är kvadratisk innan plattformsverktygen lägger på sin egen behandling.', 'Upplösning: hitta små källfiler innan de blir suddiga eller oanvändbara i större launchers.', 'Kantmarginal: se om viktiga former eller bokstäver ligger för nära iOS masken eller Androids säkra zon.', 'Launcher etikett: kontrollera appnamnet i samma skala som ikonerna bredvid och upptäck dåliga radbrytningar.', 'Tematisk Android behandling: lägg en monokrom systemton på mål, närliggande ikoner och docka så att färgen inte döljer en svag siluett.'] },
51
+ { type: 'title', text: 'Se båda enhetskontexterna samtidigt', level: 3 },
52
+ { type: 'paragraph', html: 'Använd de två telefonvyerna som en enda granskningsyta. Gå igenom iOS Standard, Mörk, Klar och Tonad och prova sedan Android cirkel, squircle, rundad och droppe. Målet är att förstå hur samma tillgång fungerar på olika launcher ytor, inte att utse en plattform till bättre än den andra.' },
53
+ { type: 'title', text: 'Det här kan granskningen inte garantera', level: 3 },
54
+ { type: 'paragraph', html: 'Detta är en webbläsarbaserad granskning av design och tillgångar, inte en ersättning för Xcode, Android Studio, en riktig enhet eller en emulator. Launchers, operativsystemsversioner och tillverkare kan använda olika masker, avstånd, kontrast och regler för tematiska ikoner. Använd granskningen för att hitta risker tidigt och validera sedan de slutliga tillgångarna i miljöerna du stöder.' },
55
+ { type: 'tip', title: 'Praktisk granskningsrutin', html: 'Granska logotypen i den minsta praktiska storleken och i varje behandling. Om märket bara fungerar med en bakgrund, en mask eller originalfärgerna, förenkla bilden eller lägg till marginal innan publicering.' },
56
+ ] });
@@ -0,0 +1,43 @@
1
+ import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
2
+ import { bibliography } from '../bibliography';
3
+ import type { ToolLocaleContent, SEOSection } from '../../../types';
4
+ import type { DualOsIconPreviewUI } from '../ui';
5
+
6
+ interface LocalizedCopy { locale: string; slug: string; title: string; description: string; faqTitle: string; bibliographyTitle: string; ui: DualOsIconPreviewUI; faq: { question: string; answer: string }[]; howTo: { name: string; text: string }[]; seo: SEOSection[]; }
7
+ function createDualOsIconPreviewContent(copy: LocalizedCopy): ToolLocaleContent<DualOsIconPreviewUI> {
8
+ const faqSchema: WithContext<FAQPage> = { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: copy.faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) };
9
+ const howToSchema: WithContext<HowTo> = { '@context': 'https://schema.org', '@type': 'HowTo', name: copy.title, description: copy.description, step: copy.howTo.map((step, index) => ({ '@type': 'HowToStep', position: index + 1, name: step.name, text: step.text })) };
10
+ const appSchema: WithContext<SoftwareApplication> = { '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: copy.title, description: copy.description, applicationCategory: 'DesignApplication', operatingSystem: 'iOS, Android', offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' }, inLanguage: copy.locale };
11
+ return { slug: copy.slug, title: copy.title, description: copy.description, ui: copy.ui, faqTitle: copy.faqTitle, faq: copy.faq, bibliographyTitle: copy.bibliographyTitle, bibliography, howTo: copy.howTo, schemas: [appSchema, faqSchema, howToSchema], seo: copy.seo };
12
+ }
13
+ const title = 'iOS ve Android uygulama simgesi denetimi';
14
+ const description = 'Bir logo yükleyin ve iPhone ile Pixel üzerindeki görünümünü denetleyin. iOS modlarını, Android uyarlanabilir maskelerini, güvenli boşlukları ve temalı simgeleri tarayıcıda inceleyin.';
15
+ const ui: DualOsIconPreviewUI = {
16
+ labelUpload: 'Logo yükle', uploadAction: 'Görsel seç', uploadHint: 'Aynı işaret iki telefonu da doldurur', dropHint: 'PNG, JPG, WEBP veya SVG', labelAppName: 'Uygulama adı', appNamePlaceholder: 'Simgenin altında görünür', labelBrandColor: 'Sistemin vurgu rengi', labelIosAppearance: 'iOS görünümü', iosAppearanceHint: 'İşareti her ana ekran modunda kontrol edin', iosDefault: 'Varsayılan', iosDark: 'Koyu', iosClear: 'Açık', iosTinted: 'Tonlu', labelAndroidShape: 'Android uyarlanabilir maskesi', androidShapeHint: 'Başlatıcı dış şekli değiştirebilir', androidCircle: 'Daire', androidSquircle: 'Squircle', androidRounded: 'Yuvarlak', androidTeardrop: 'Damla', labelAndroidTheme: 'Temalı simge önizlemesi', androidThemeHint: 'Silüeti koruyarak her simgeyi tek sistem tonuyla yeniden renklendirir', iosDeviceLabel: 'iPhone', androidDeviceLabel: 'Pixel', iosHomeLabel: 'Ana ekran', androidHomeLabel: 'Başlatıcı', safeZoneLabel: 'iOS maskesi', adaptiveLayerLabel: 'Uyarlanabilir simge', monochromeLabel: 'Tema katmanı', nameFallback: 'Uygulamanız', emptyLogo: 'Logonuz', fileError: 'Devam etmek için bir görsel dosyası seçin.', statusReady: 'Hazır', statusNeedsReview: 'Logo ekle', stageKicker: 'İki cihaz bağlamı, tek denetim', stageNote: 'Her işlemi bağlam içinde inceleyin', auditTitle: 'Logo denetimi', auditHint: 'Yüklenen görselden yerel olarak ölçülür', auditWaiting: 'Logo yükleyin', auditNotChecked: 'Kontrol edilmedi', auditFile: 'Tuval', auditAspect: 'En boy oranı', auditResolution: 'Çözünürlük', auditIosMask: 'iOS maske boşluğu', auditAndroidZone: 'Android güvenli alanı', auditMargin: 'Minimum kenar boşluğu', auditTransparency: 'Alfa kenarı', auditTransparent: 'Saydam', auditFullBleed: 'Tam kaplama', statusPass: 'GEÇTİ', statusReview: 'İNCELE',
17
+ };
18
+ const faq = [
19
+ { question: 'Bu uygulama simgesi denetimi neyi kontrol eder?', answer: 'Görsel boyutlarını, en boy oranını, çözünürlüğü, saydam kenar boşluğunu, iOS maske payını ve Android uyarlanabilir güvenli alanını kontrol eder. Uygulama adını başlatıcı boyutunda da inceleyebilirsiniz.' },
20
+ { question: 'iPhone ve Android cihazlarını aynı anda görebilir miyim?', answer: 'Evet. Aynı logo ve uygulama adı iPhone ana ekranında ve Pixel başlatıcısında eş zamanlı gösterilir, böylece iki cihazın bağlamı korunur.' },
21
+ { question: 'Android temalı simge modu ne yapar?', answer: 'Yüklenen simge, yakındaki uygulamalar ve dock dahil sahnedeki tüm Android simgelerine tek bir sistem tonu ve tek renkli işlem uygular. Özgün renkler olmadan silüetin okunup okunmadığını görmenizi sağlar.' },
22
+ { question: 'Logo tarayıcımdan çıkar mı?', answer: 'Hayır. Görsel tarayıcıda yerel olarak okunur ve ölçülür. Bu araç görseli sunucuya yüklemez.' },
23
+ { question: 'Sonuç uygulama mağazasına gönderim için hazır mı?', answer: 'Hayır. Bu yerel bir tasarım ve varlık denetimidir. Son dışa aktarma, başlatıcı davranışı ve mağaza onayı için Apple ve Android araçlarını, gerçek cihazı veya emülatörü kullanın.' },
24
+ ];
25
+ const howTo = [
26
+ { name: 'Logoyu yükleyin', text: 'PNG, JPG, WEBP veya SVG logo seçin. Aynı yerel görsel iki cihaz bağlamında görünür.' },
27
+ { name: 'Uygulama adını girin', text: 'Başlatıcı etiketini yazın ve yakındaki gerçek uygulama etiketlerinin yanında okunabilir olduğunu kontrol edin.' },
28
+ { name: 'iOS görünümlerini inceleyin', text: 'Varsayılan, Koyu, Açık ve Tonlu seçenekleri arasında geçerek zayıf kontrastı veya kaybolan ayrıntıları bulun.' },
29
+ { name: 'Android maskelerini inceleyin', text: 'Daire, squircle, yuvarlak ve damla şekillerini deneyin. Ardından temalı simge modunu açıp tüm başlatıcıdaki tek renkli görünümü inceleyin.' },
30
+ { name: 'Denetim sonucuna göre hareket edin', text: 'Son platform varlıklarını hazırlamadan önce boşluk ekleyin, ince ayrıntıları sadeleştirin veya kontrastı artırın.' },
31
+ ];
32
+
33
+ export const content = createDualOsIconPreviewContent({ locale: 'tr', slug: 'ios-android-uygulama-simgesi-denetimi', title, description, faqTitle: 'Sık sorulan sorular', bibliographyTitle: 'Kaynaklar', ui, faq, howTo, seo: [
34
+ { type: 'title', text: 'Yayınlamadan önce uygulama simgenizi denetleyin', level: 2 },
35
+ { type: 'paragraph', html: 'Tek bir logo yükleyin ve iPhone ana ekranı ile Pixel başlatıcısı bağlamında eş zamanlı inceleyin. Bu uygulama simgesi denetimi tuvali, en boy oranını, çözünürlüğü, saydam kenar boşluğunu, iOS maske payını ve Android uyarlanabilir güvenli alanını ölçer. Gerçek uygulama adını da girin; çünkü işaret simge kontrolünü geçse bile başlatıcı etiketi okunamaz hale geldiğinde sorun yaşayabilir.' },
36
+ { type: 'title', text: 'Bu uygulama simgesi denetiminin kontrol ettikleri', level: 3 },
37
+ { type: 'list', items: ['Tuval ve en boy oranı: platform araçları kendi işlemlerini eklemeden önce kaynağın kare olduğunu doğrulayın.', 'Çözünürlük: Büyük başlatıcı bağlamlarında bulanıklaşacak küçük kaynak dosyalarını önceden bulun.', 'Kenar boşluğu: Önemli şekillerin veya harflerin iOS maskesine ya da Android güvenli alanına fazla yakın olup olmadığını görün.', 'Başlatıcı etiketi: Uygulama adını komşu simgelerle aynı ölçekte kontrol edin ve kötü satır bölünmelerini yakalayın.', 'Android temalı işlem: Renklerin zayıf bir silüeti gizlememesi için hedefe, komşu simgelere ve docka tek renkli sistem tonu uygulayın.'] },
38
+ { type: 'title', text: 'İki cihaz bağlamını aynı anda görün', level: 3 },
39
+ { type: 'paragraph', html: 'İki telefon görünümünü tek bir denetim yüzeyi olarak kullanın. iOS Varsayılan, Koyu, Açık ve Tonlu görünümlerini değiştirin, sonra Android daire, squircle, yuvarlak ve damla maskelerini deneyin. Amaç aynı varlığın farklı başlatıcı yüzeylerinde nasıl davrandığı hakkında bilgi toplamaktır; platformları yarıştırmak değildir.' },
40
+ { type: 'title', text: 'Denetimin garanti edemeyecekleri', level: 3 },
41
+ { type: 'paragraph', html: 'Bu, tarayıcı tabanlı bir tasarım ve varlık incelemesidir; Xcode, Android Studio, gerçek cihaz veya emülatör yerine geçmez. Başlatıcılar, işletim sistemi sürümleri ve üreticiler maskeleri, aralıkları, kontrastı ve temalı simge kurallarını farklı uygulayabilir. Riskleri erken bulmak için denetimi kullanın, ardından son platform varlıklarını desteklediğiniz ortamlarda doğrulayın.' },
42
+ { type: 'tip', title: 'Pratik denetim rutini', html: 'Logoyu her işlemde kullanılabilecek en küçük boyutta inceleyin. Yalnızca tek bir arka plan, maske veya özgün renklerle çalışıyorsa yayınlamadan önce grafiği sadeleştirin ya da boşluk ekleyin.' },
43
+ ] });
@@ -0,0 +1,43 @@
1
+ import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
2
+ import { bibliography } from '../bibliography';
3
+ import type { ToolLocaleContent, SEOSection } from '../../../types';
4
+ import type { DualOsIconPreviewUI } from '../ui';
5
+
6
+ interface LocalizedCopy { locale: string; slug: string; title: string; description: string; faqTitle: string; bibliographyTitle: string; ui: DualOsIconPreviewUI; faq: { question: string; answer: string }[]; howTo: { name: string; text: string }[]; seo: SEOSection[]; }
7
+ function createDualOsIconPreviewContent(copy: LocalizedCopy): ToolLocaleContent<DualOsIconPreviewUI> {
8
+ const faqSchema: WithContext<FAQPage> = { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: copy.faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) };
9
+ const howToSchema: WithContext<HowTo> = { '@context': 'https://schema.org', '@type': 'HowTo', name: copy.title, description: copy.description, step: copy.howTo.map((step, index) => ({ '@type': 'HowToStep', position: index + 1, name: step.name, text: step.text })) };
10
+ const appSchema: WithContext<SoftwareApplication> = { '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: copy.title, description: copy.description, applicationCategory: 'DesignApplication', operatingSystem: 'iOS, Android', offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' }, inLanguage: copy.locale };
11
+ return { slug: copy.slug, title: copy.title, description: copy.description, ui: copy.ui, faqTitle: copy.faqTitle, faq: copy.faq, bibliographyTitle: copy.bibliographyTitle, bibliography, howTo: copy.howTo, schemas: [appSchema, faqSchema, howToSchema], seo: copy.seo };
12
+ }
13
+ const title = 'iOS 和 Android 应用图标审计';
14
+ const description = '上传 logo,审计它在 iPhone 和 Pixel 上的显示效果。在浏览器中检查 iOS 模式、Android 自适应遮罩、安全留白和主题图标。';
15
+ const ui: DualOsIconPreviewUI = {
16
+ labelUpload: '上传 logo', uploadAction: '选择图片', uploadHint: '同一个标志填充两部手机', dropHint: 'PNG、JPG、WEBP 或 SVG', labelAppName: '应用名称', appNamePlaceholder: '显示在图标下方', labelBrandColor: '系统强调色', labelIosAppearance: 'iOS 外观', iosAppearanceHint: '在每种主屏幕模式中检查标志', iosDefault: '默认', iosDark: '深色', iosClear: '透明', iosTinted: '着色', labelAndroidShape: 'Android 自适应遮罩', androidShapeHint: '启动器可以改变外部形状', androidCircle: '圆形', androidSquircle: '圆角方形', androidRounded: '圆角', androidTeardrop: '水滴', labelAndroidTheme: '预览主题图标', androidThemeHint: '用一种系统色重新着色所有图标,同时保留轮廓', iosDeviceLabel: 'iPhone', androidDeviceLabel: 'Pixel', iosHomeLabel: '主屏幕', androidHomeLabel: '启动器', safeZoneLabel: 'iOS 遮罩', adaptiveLayerLabel: '自适应图标', monochromeLabel: '主题图层', nameFallback: '你的应用', emptyLogo: '你的 logo', fileError: '请选择图片文件后继续。', statusReady: '准备就绪', statusNeedsReview: '添加 logo', stageKicker: '两个设备场景,一次审计', stageNote: '在真实场景中检查每种处理', auditTitle: 'Logo 审计', auditHint: '根据已加载图片在本地测量', auditWaiting: '上传 logo', auditNotChecked: '尚未检查', auditFile: '画布', auditAspect: '宽高比', auditResolution: '分辨率', auditIosMask: 'iOS 遮罩留白', auditAndroidZone: 'Android 安全区域', auditMargin: '最小边缘留白', auditTransparency: 'Alpha 边缘', auditTransparent: '透明', auditFullBleed: '铺满', statusPass: '通过', statusReview: '检查',
17
+ };
18
+ const faq = [
19
+ { question: '这个应用图标审计会检查什么?', answer: '它会检查图片尺寸、宽高比、分辨率、透明边缘留白、iOS 遮罩留白和 Android 自适应安全区域,也可以查看启动器尺寸下的应用名称。' },
20
+ { question: '可以同时查看 iPhone 和 Android 吗?', answer: '可以。同一个 logo 和应用名称会同时显示在 iPhone 主屏幕和 Pixel 启动器中,两个设备的周围信息都会保留。' },
21
+ { question: 'Android 主题图标模式有什么作用?', answer: '它会对场景中的所有 Android 图标应用同一种系统色和单色处理,包括上传的图标、周围的应用和 dock。这样可以检查没有原始颜色时轮廓是否仍然清晰。' },
22
+ { question: 'Logo 会离开我的浏览器吗?', answer: '不会。图片会在浏览器中本地读取和测量,这个工具不会把它上传到服务器。' },
23
+ { question: '结果可以直接用于提交应用商店吗?', answer: '不可以。这是本地设计和资源审计。最终导出、启动器行为和商店审核仍应使用 Apple 与 Android 平台工具,以及真实设备或模拟器进行验证。' },
24
+ ];
25
+ const howTo = [
26
+ { name: '上传 logo', text: '选择 PNG、JPG、WEBP 或 SVG logo。同一张本地图片会显示在两个设备场景中。' },
27
+ { name: '输入应用名称', text: '输入启动器标签,检查它在周围真实应用标签旁边是否仍然清晰。' },
28
+ { name: '检查 iOS 外观', text: '切换默认、深色、透明和着色模式,查找对比度不足或消失的细节。' },
29
+ { name: '检查 Android 遮罩', text: '尝试圆形、圆角方形、圆角和水滴遮罩,然后启用主题图标检查整个启动器中的单色版本。' },
30
+ { name: '根据审计采取行动', text: '在准备最终平台资源前增加留白、简化细节或改善对比度。' },
31
+ ];
32
+
33
+ export const content = createDualOsIconPreviewContent({ locale: 'zh', slug: 'dual-ios-android-app-icon-preview', title, description, faqTitle: '常见问题', bibliographyTitle: '参考资料', ui, faq, howTo, seo: [
34
+ { type: 'title', text: '发布前审计应用图标', level: 2 },
35
+ { type: 'paragraph', html: '上传一个 logo,同时在 iPhone 主屏幕和 Pixel 启动器场景中检查它。这个应用图标审计会测量画布、宽高比、分辨率、透明边缘留白、iOS 遮罩留白和 Android 自适应安全区域。也请输入真实的应用名称,因为图标本身通过检查后,启动器标签仍可能变得难以阅读。' },
36
+ { type: 'title', text: '应用图标审计检查的内容', level: 3 },
37
+ { type: 'list', items: ['画布和宽高比: 在平台工具添加自己的处理前,确认源文件是正方形。', '分辨率: 在小源文件于较大的启动器场景中变模糊前发现它们。', '边缘留白: 查看重要的形状或文字是否离 iOS 遮罩或 Android 安全区域太近。', '启动器标签: 在与相邻图标相同的尺寸下检查应用名称,发现不自然的换行。', 'Android 主题处理: 对目标图标、周围图标和 dock 应用单色系统色,避免原始颜色掩盖脆弱的轮廓。'] },
38
+ { type: 'title', text: '同时查看两个设备场景', level: 3 },
39
+ { type: 'paragraph', html: '把两部手机的视图当作一个审计界面。切换 iOS 默认、深色、透明和着色外观,再尝试 Android 圆形、圆角方形、圆角和水滴遮罩。目的是了解同一资源在不同启动器表面上的表现,而不是让两个平台进行对比竞争。' },
40
+ { type: 'title', text: '这个审计无法保证什么', level: 3 },
41
+ { type: 'paragraph', html: '这是基于浏览器的设计和资源检查,不是 Xcode、Android Studio、真实设备或模拟器的替代品。启动器、操作系统版本和制造商可能使用不同的遮罩、间距、对比度和主题图标规则。先用审计尽早发现风险,再在你支持的环境中验证最终平台资源。' },
42
+ { type: 'tip', title: '实用的审计流程', html: '在每种处理下,以实际使用的最小尺寸检查 logo。如果它只有在某个背景、遮罩或原始颜色下才有效,请在发布前简化图形或增加留白。' },
43
+ ] });
@@ -0,0 +1,11 @@
1
+ import type { ToolDefinition } from '../../types';
2
+ import { dualOsIconPreview } from './entry';
3
+
4
+ export * from './entry';
5
+
6
+ export const DUAL_OS_ICON_PREVIEW_TOOL: ToolDefinition = {
7
+ entry: dualOsIconPreview,
8
+ Component: () => import('./component.astro'),
9
+ SEOComponent: () => import('./seo.astro'),
10
+ BibliographyComponent: () => import('./bibliography.astro'),
11
+ };
@@ -0,0 +1,63 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import {
3
+ DEFAULT_SETTINGS,
4
+ auditLogo,
5
+ buildPreviewState,
6
+ getIosSurface,
7
+ isAndroidShape,
8
+ isHexColor,
9
+ isIosAppearance,
10
+ normaliseAppName,
11
+ sanitiseSettings,
12
+ } from './logic';
13
+
14
+ describe('dual OS icon preview logic', () => {
15
+ it('recognises supported appearance and shape values', () => {
16
+ expect(isIosAppearance('tinted')).toBe(true);
17
+ expect(isIosAppearance('neon')).toBe(false);
18
+ expect(isAndroidShape('circle')).toBe(true);
19
+ expect(isAndroidShape('hexagon')).toBe(false);
20
+ });
21
+
22
+ it('normalises app names for launcher labels', () => {
23
+ expect(normaliseAppName(' North Star ')).toBe('North Star');
24
+ expect(normaliseAppName('x'.repeat(30))).toHaveLength(24);
25
+ expect(normaliseAppName(' ')).toBe('');
26
+ });
27
+
28
+ it('validates six digit hex colours', () => {
29
+ expect(isHexColor('#f4b942')).toBe(true);
30
+ expect(isHexColor('#fff')).toBe(false);
31
+ expect(isHexColor('gold')).toBe(false);
32
+ });
33
+
34
+ it('falls back safely when persisted settings are invalid', () => {
35
+ expect(sanitiseSettings({ appName: ' ', brandColor: 'red', iosAppearance: 'neon' as never })).toEqual(DEFAULT_SETTINGS);
36
+ expect(sanitiseSettings({ androidShape: 'circle', androidThemed: true }).androidThemed).toBe(true);
37
+ });
38
+
39
+ it('builds a state with the current logo availability', () => {
40
+ expect(buildPreviewState({ appName: ' Orbit ' }, true)).toMatchObject({ appName: 'Orbit', hasLogo: true });
41
+ });
42
+
43
+ it('audits a square logo against platform-safe margins', () => {
44
+ const audit = auditLogo({ width: 1024, height: 1024, leftMargin: 220, rightMargin: 220, topMargin: 220, bottomMargin: 220, visiblePixels: 400000 });
45
+ expect(audit).toMatchObject({ score: 100, dimensions: '1024 x 1024', aspect: '1:1', resolution: 'pass', iosMask: 'pass', androidSafeZone: 'pass', transparency: 'transparent' });
46
+ });
47
+
48
+ it('flags a small or edge-to-edge logo for review', () => {
49
+ const audit = auditLogo({ width: 320, height: 512, leftMargin: 4, rightMargin: 4, topMargin: 4, bottomMargin: 4, visiblePixels: 163840 });
50
+ expect(audit.score).toBe(0);
51
+ expect(audit.resolution).toBe('review');
52
+ expect(audit.iosMask).toBe('review');
53
+ expect(audit.androidSafeZone).toBe('review');
54
+ expect(audit.transparency).toBe('full-bleed');
55
+ });
56
+
57
+ it('maps every iOS appearance to a surface treatment', () => {
58
+ expect(getIosSurface('default')).toBe('light');
59
+ expect(getIosSurface('dark')).toBe('dark');
60
+ expect(getIosSurface('clear')).toBe('clear');
61
+ expect(getIosSurface('tinted')).toBe('tinted');
62
+ });
63
+ });