@jjlmoya/utils-games-development 1.46.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 +67 -0
- package/scripts/postinstall.mjs +27 -0
- package/src/category/GamesCategorySEO.astro +19 -0
- package/src/category/i18n/de.ts +15 -0
- package/src/category/i18n/en.ts +15 -0
- package/src/category/i18n/es.ts +15 -0
- package/src/category/i18n/fr.ts +15 -0
- package/src/category/i18n/id.ts +10 -0
- package/src/category/i18n/it.ts +10 -0
- package/src/category/i18n/ja.ts +10 -0
- package/src/category/i18n/ko.ts +10 -0
- package/src/category/i18n/nl.ts +10 -0
- package/src/category/i18n/pl.ts +10 -0
- package/src/category/i18n/pt.ts +10 -0
- package/src/category/i18n/ru.ts +10 -0
- package/src/category/i18n/sv.ts +10 -0
- package/src/category/i18n/tr.ts +10 -0
- package/src/category/i18n/zh.ts +10 -0
- package/src/category/index.ts +24 -0
- package/src/category/seo.astro +15 -0
- package/src/components/PreviewNavSidebar.astro +116 -0
- package/src/components/PreviewToolbar.astro +143 -0
- package/src/data.ts +11 -0
- package/src/entries.ts +5 -0
- package/src/env.d.ts +5 -0
- package/src/index.ts +21 -0
- package/src/layouts/PreviewLayout.astro +122 -0
- package/src/pages/[locale]/[slug].astro +165 -0
- package/src/pages/[locale].astro +251 -0
- package/src/pages/index.astro +4 -0
- package/src/tests/diacritics_density.test.ts +118 -0
- package/src/tests/faq_count.test.ts +19 -0
- package/src/tests/i18n_coverage.test.ts +36 -0
- package/src/tests/inverted_punctuation.test.ts +84 -0
- package/src/tests/locale_completeness.test.ts +27 -0
- package/src/tests/mocks/astro_mock.js +2 -0
- package/src/tests/no_en_dash.test.ts +70 -0
- package/src/tests/no_h1_in_components.test.ts +48 -0
- package/src/tests/pagespeed_best_practices.test.ts +198 -0
- package/src/tests/qa-test-helpers.ts +32 -0
- package/src/tests/qa_bibliography_links.test.ts +41 -0
- package/src/tests/qa_claim_evidence.test.ts +69 -0
- package/src/tests/qa_logic_reference_coverage.test.ts +46 -0
- package/src/tests/qa_runtime_i18n.test.ts +100 -0
- package/src/tests/schemas_fulfillment.test.ts +23 -0
- package/src/tests/script_density.test.ts +94 -0
- package/src/tests/seo_length.test.ts +23 -0
- package/src/tests/slug_language_code_format.test.ts +23 -0
- package/src/tests/slug_uniqueness.test.ts +81 -0
- package/src/tests/title_quality.test.ts +56 -0
- package/src/tests/tool_validation.test.ts +17 -0
- package/src/tool/steamCapsuleGenerator/bibliography.astro +6 -0
- package/src/tool/steamCapsuleGenerator/bibliography.ts +6 -0
- package/src/tool/steamCapsuleGenerator/component.astro +289 -0
- package/src/tool/steamCapsuleGenerator/components/SteamLibraryGridMockup.astro +51 -0
- package/src/tool/steamCapsuleGenerator/components/SteamLibraryMockup.astro +64 -0
- package/src/tool/steamCapsuleGenerator/components/SteamMasterControls.astro +2 -0
- package/src/tool/steamCapsuleGenerator/components/SteamStoreMockup.astro +90 -0
- package/src/tool/steamCapsuleGenerator/entry.ts +28 -0
- package/src/tool/steamCapsuleGenerator/i18n/de.ts +144 -0
- package/src/tool/steamCapsuleGenerator/i18n/en.ts +243 -0
- package/src/tool/steamCapsuleGenerator/i18n/es.ts +243 -0
- package/src/tool/steamCapsuleGenerator/i18n/fr.ts +165 -0
- package/src/tool/steamCapsuleGenerator/i18n/id.ts +144 -0
- package/src/tool/steamCapsuleGenerator/i18n/it.ts +144 -0
- package/src/tool/steamCapsuleGenerator/i18n/ja.ts +144 -0
- package/src/tool/steamCapsuleGenerator/i18n/ko.ts +144 -0
- package/src/tool/steamCapsuleGenerator/i18n/nl.ts +144 -0
- package/src/tool/steamCapsuleGenerator/i18n/pl.ts +144 -0
- package/src/tool/steamCapsuleGenerator/i18n/pt.ts +144 -0
- package/src/tool/steamCapsuleGenerator/i18n/ru.ts +144 -0
- package/src/tool/steamCapsuleGenerator/i18n/shared.ts +46 -0
- package/src/tool/steamCapsuleGenerator/i18n/sv.ts +144 -0
- package/src/tool/steamCapsuleGenerator/i18n/tr.ts +144 -0
- package/src/tool/steamCapsuleGenerator/i18n/zh.ts +144 -0
- package/src/tool/steamCapsuleGenerator/index.ts +9 -0
- package/src/tool/steamCapsuleGenerator/logic.test.ts +72 -0
- package/src/tool/steamCapsuleGenerator/logic.ts +259 -0
- package/src/tool/steamCapsuleGenerator/seo.astro +15 -0
- package/src/tool/steamCapsuleGenerator/steam-capsule-generator.css +697 -0
- package/src/tool/steamCapsuleGenerator/ui.ts +23 -0
- package/src/tool/steamCapsuleGenerator/validation.ts +22 -0
- package/src/tools.ts +8 -0
- package/src/types.ts +72 -0
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jjlmoya/utils-games-development",
|
|
3
|
+
"version": "1.46.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./src/index.ts",
|
|
6
|
+
"types": "./src/index.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.ts",
|
|
9
|
+
"./data": "./src/data.ts",
|
|
10
|
+
"./entries": "./src/entries.ts",
|
|
11
|
+
"./runtime/*": "./src/tool/*/index.ts",
|
|
12
|
+
"./category-seo": "./src/category/seo.astro"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"src",
|
|
16
|
+
"scripts"
|
|
17
|
+
],
|
|
18
|
+
"publishConfig": {
|
|
19
|
+
"access": "public"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"dev": "astro dev",
|
|
23
|
+
"start": "astro dev",
|
|
24
|
+
"build": "astro build",
|
|
25
|
+
"preview": "astro preview",
|
|
26
|
+
"astro": "astro",
|
|
27
|
+
"lint": "eslint src/ --max-warnings 0 && stylelint \"src/**/*.{css,astro}\"",
|
|
28
|
+
"check": "astro check",
|
|
29
|
+
"type-check": "astro check",
|
|
30
|
+
"test": "vitest run",
|
|
31
|
+
"preversion": "npm run lint && npm run test && npm run build",
|
|
32
|
+
"postversion": "git push && git push --tags",
|
|
33
|
+
"patch": "npm version patch",
|
|
34
|
+
"minor": "npm version minor",
|
|
35
|
+
"major": "npm version major",
|
|
36
|
+
"postinstall": "node scripts/postinstall.mjs"
|
|
37
|
+
},
|
|
38
|
+
"lint-staged": {
|
|
39
|
+
"*.{ts,tsx,astro}": [
|
|
40
|
+
"eslint --fix"
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@iconify-json/mdi": "^1.2.3",
|
|
45
|
+
"@jjlmoya/prompagate": "^1.1.0",
|
|
46
|
+
"@jjlmoya/utils-shared": "1.2.0",
|
|
47
|
+
"astro": "^6.1.2",
|
|
48
|
+
"astro-icon": "^1.1.0",
|
|
49
|
+
"jszip": "^3.10.1"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@astrojs/check": "^0.9.8",
|
|
53
|
+
"eslint": "^9.39.4",
|
|
54
|
+
"eslint-plugin-astro": "^1.6.0",
|
|
55
|
+
"eslint-plugin-no-comments": "^1.1.10",
|
|
56
|
+
"husky": "^9.1.7",
|
|
57
|
+
"lint-staged": "^16.4.0",
|
|
58
|
+
"postcss-html": "^1.8.1",
|
|
59
|
+
"schema-dts": "^1.1.2",
|
|
60
|
+
"stylelint": "^17.6.0",
|
|
61
|
+
"stylelint-config-standard": "^40.0.0",
|
|
62
|
+
"stylelint-declaration-strict-value": "^1.11.1",
|
|
63
|
+
"typescript": "^5.4.0",
|
|
64
|
+
"typescript-eslint": "^8.58.0",
|
|
65
|
+
"vitest": "^4.1.2"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, mkdirSync, readdirSync } from 'fs';
|
|
2
|
+
import { join, dirname } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
|
|
5
|
+
const libDir = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const toolsDir = join(libDir, '../src/tool');
|
|
7
|
+
|
|
8
|
+
const inNodeModules = libDir.includes('node_modules');
|
|
9
|
+
if (!inNodeModules) process.exit(0);
|
|
10
|
+
|
|
11
|
+
const projectRoot = join(libDir, '../../../..');
|
|
12
|
+
const categoryKey = JSON.parse(readFileSync(join(libDir, '../package.json'), 'utf8')).name.replace('@jjlmoya/utils-', '');
|
|
13
|
+
const destDir = join(projectRoot, `public/styles/lib/${categoryKey}`);
|
|
14
|
+
|
|
15
|
+
mkdirSync(destDir, { recursive: true });
|
|
16
|
+
|
|
17
|
+
const tools = readdirSync(toolsDir, { withFileTypes: true }).filter(d => d.isDirectory());
|
|
18
|
+
for (const tool of tools) {
|
|
19
|
+
const toolDir = join(toolsDir, tool.name);
|
|
20
|
+
let files;
|
|
21
|
+
try { files = readdirSync(toolDir).filter(f => f.endsWith('.css')); }
|
|
22
|
+
catch { continue; }
|
|
23
|
+
for (const file of files) {
|
|
24
|
+
writeFileSync(join(destDir, file), readFileSync(join(toolDir, file)));
|
|
25
|
+
console.log(`[@jjlmoya/utils-${categoryKey}] copied ${file}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { SEORenderer } from "@jjlmoya/utils-shared";
|
|
3
|
+
import { gamesCategory } from "./index";
|
|
4
|
+
|
|
5
|
+
import type { KnownLocale } from "../types";
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
locale?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const { locale = "es" } = Astro.props;
|
|
12
|
+
const categoryContent = await gamesCategory.i18n[locale as KnownLocale]?.();
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
{
|
|
16
|
+
categoryContent && (
|
|
17
|
+
<SEORenderer content={{ locale, sections: categoryContent.seo }} />
|
|
18
|
+
)
|
|
19
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CategoryLocaleContent } from '../../types';
|
|
2
|
+
|
|
3
|
+
export const content: CategoryLocaleContent = {
|
|
4
|
+
slug: 'spieleentwicklung',
|
|
5
|
+
title: 'Werkzeuge für Spieleentwicklung',
|
|
6
|
+
description: 'Praktische Browserwerkzeuge für Indie Entwickler, von Storegrafik bis zur Produktionsübergabe.',
|
|
7
|
+
seo: [
|
|
8
|
+
{ type: 'title', text: 'Werkzeuge für die Entwicklung eigener Spiele', level: 2 },
|
|
9
|
+
{ type: 'paragraph', html: 'Spieleentwicklung besteht aus vielen kleinen Entscheidungen: Eine Komposition muss mehrere Storeformate überstehen, ein Symbol muss sofort lesbar bleiben und ein Produktionsschritt sollte wiederholbar sein. Diese Kategorie bündelt fokussierte Werkzeuge für Menschen, die Spiele bauen, veröffentlichen und präsentieren.' },
|
|
10
|
+
{ type: 'title', text: 'Für unabhängige Teams gemacht', level: 2 },
|
|
11
|
+
{ type: 'paragraph', html: 'Indie Teams wechseln oft zwischen Grafiksoftware, Veröffentlichungsseiten und Review Ordnern. Eine gute Utility verkürzt diese Übergabe, macht wichtige Entscheidungen sichtbar und lässt die Kontrolle über Quelldateien beim Ersteller.' },
|
|
12
|
+
{ type: 'list', items: ['Konkrete Abläufe mit sichtbaren Ergebnissen', 'Lokale Verarbeitung im Browser, wenn sinnvoll', 'Klare Maße und Exportzustände', 'Hinweise ergänzend zur offiziellen Dokumentation'] },
|
|
13
|
+
{ type: 'tip', html: 'Nutze die Werkzeuge als Preflight Ebene. Bewahre die Projektdateien auf und vergleiche den kleinsten Export mit den aktuellen Plattformvorgaben.' },
|
|
14
|
+
],
|
|
15
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CategoryLocaleContent } from '../../types';
|
|
2
|
+
|
|
3
|
+
export const content: CategoryLocaleContent = {
|
|
4
|
+
slug: 'game-development',
|
|
5
|
+
title: 'Game Development Utilities',
|
|
6
|
+
description: 'Practical browser tools for indie game creators, from store artwork preparation to production handoffs.',
|
|
7
|
+
seo: [
|
|
8
|
+
{ type: 'title', text: 'Tools for the craft of game development', level: 2 },
|
|
9
|
+
{ type: 'paragraph', html: 'Game development is a chain of small decisions: a composition must survive several storefront formats, an icon must remain readable at a glance and a production task must be easy to repeat. This category collects focused utilities for people who build, publish and promote games. Each tool is designed to turn a narrow but frustrating workflow into a clear browser interaction.' },
|
|
10
|
+
{ type: 'title', text: 'Made for independent creators', level: 2 },
|
|
11
|
+
{ type: 'paragraph', html: 'Indie teams often move between art software, publishing dashboards and review folders without a dedicated production department. A useful utility should shorten that handoff, expose the important decisions and keep the creator in control of the source files.' },
|
|
12
|
+
{ type: 'list', items: ['Focused workflows with visible outputs', 'Local browser processing where practical', 'Clear dimensions and export states', 'Guidance that complements official platform documentation'] },
|
|
13
|
+
{ type: 'tip', html: 'Use these tools as a preflight layer. Keep your source project files, compare final exports with the platform owner\'s current requirements and ask a teammate to review the smallest output.' },
|
|
14
|
+
],
|
|
15
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CategoryLocaleContent } from '../../types';
|
|
2
|
+
|
|
3
|
+
export const content: CategoryLocaleContent = {
|
|
4
|
+
slug: 'desarrollo-de-videojuegos',
|
|
5
|
+
title: 'Utilidades para desarrollo de videojuegos',
|
|
6
|
+
description: 'Herramientas de navegador para creadores indie, desde preparar arte para tiendas hasta organizar entregas de producción.',
|
|
7
|
+
seo: [
|
|
8
|
+
{ type: 'title', text: 'Herramientas para el oficio de crear videojuegos', level: 2 },
|
|
9
|
+
{ type: 'paragraph', html: 'Crear un videojuego está formado por pequeñas decisiones: una composición debe resistir varios formatos de tienda, un icono debe leerse de un vistazo y una tarea de producción debe poder repetirse. Esta categoría reúne utilidades enfocadas para quienes diseñan, publican y presentan juegos. Cada herramienta convierte un flujo estrecho pero frustrante en una interacción clara dentro del navegador.' },
|
|
10
|
+
{ type: 'title', text: 'Pensadas para creadores independientes', level: 2 },
|
|
11
|
+
{ type: 'paragraph', html: 'Los equipos indie suelen alternar entre programas de arte, paneles de publicación y carpetas de revisión sin contar con un departamento de producción. Una buena utilidad acorta esa entrega, hace visibles las decisiones importantes y mantiene al creador al mando de sus archivos fuente.' },
|
|
12
|
+
{ type: 'list', items: ['Flujos concretos con resultados visibles', 'Procesamiento local en el navegador cuando es posible', 'Dimensiones y estados de exportación claros', 'Guías que complementan la documentación oficial'] },
|
|
13
|
+
{ type: 'tip', html: 'Usa estas herramientas como una capa de previsualización. Conserva los archivos fuente, compara la exportación con los requisitos actuales de cada plataforma y revisa la salida más pequeña.' },
|
|
14
|
+
],
|
|
15
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CategoryLocaleContent } from '../../types';
|
|
2
|
+
|
|
3
|
+
export const content: CategoryLocaleContent = {
|
|
4
|
+
slug: 'developpement-de-jeux-video',
|
|
5
|
+
title: 'Outils pour le développement de jeux vidéo',
|
|
6
|
+
description: 'Des outils pratiques dans le navigateur pour les créateurs indépendants, de l\'image de boutique aux livrables de production.',
|
|
7
|
+
seo: [
|
|
8
|
+
{ type: 'title', text: 'Des outils pour fabriquer ses jeux vidéo', level: 2 },
|
|
9
|
+
{ type: 'paragraph', html: 'Le développement d\'un jeu repose sur de nombreuses petites décisions: une composition doit résister à plusieurs formats de boutique, une icône doit rester lisible immédiatement et une tâche de production doit pouvoir être répétée. Cette catégorie rassemble des outils ciblés pour concevoir, publier et présenter des jeux.' },
|
|
10
|
+
{ type: 'title', text: 'Pensé pour les créateurs indépendants', level: 2 },
|
|
11
|
+
{ type: 'paragraph', html: 'Les équipes indépendantes passent souvent d\'un logiciel graphique à un tableau de publication puis à un dossier de validation. Un bon outil raccourcit ce passage, rend les choix importants visibles et laisse les fichiers source sous le contrôle du créateur.' },
|
|
12
|
+
{ type: 'list', items: ['Des parcours précis avec des résultats visibles', 'Un traitement local lorsque cela est pertinent', 'Des dimensions et états d\'export clairs', 'Des conseils complémentaires aux documents officiels'] },
|
|
13
|
+
{ type: 'tip', html: 'Utilisez ces outils comme une étape de vérification. Conservez les sources et comparez chaque export aux exigences actuelles de la plateforme.' },
|
|
14
|
+
],
|
|
15
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CategoryLocaleContent } from '../../types';
|
|
2
|
+
|
|
3
|
+
export const content: CategoryLocaleContent = { slug: 'pengembangan-game', title: 'Alat untuk pengembangan game', description: 'Alat browser praktis untuk pembuat game indie, dari karya toko hingga serah terima produksi.', seo: [
|
|
4
|
+
{ type: 'title', text: 'Alat untuk membuat game sendiri', level: 2 },
|
|
5
|
+
{ type: 'paragraph', html: 'Pengembangan game terdiri dari banyak keputusan kecil: komposisi harus tetap cocok di berbagai format, ikon harus terbaca sekilas, dan tugas produksi harus mudah diulang. Kategori ini mengumpulkan alat terarah untuk orang yang membuat, menerbitkan, dan memperkenalkan game.' },
|
|
6
|
+
{ type: 'title', text: 'Dibuat untuk kreator mandiri', level: 2 },
|
|
7
|
+
{ type: 'paragraph', html: 'Tim indie sering berpindah dari aplikasi seni ke dasbor penerbitan lalu ke folder peninjauan. Alat yang baik mempersingkat serah terima, menampilkan keputusan penting, dan menjaga kendali file sumber di tangan kreator.' },
|
|
8
|
+
{ type: 'list', items: ['Alur terfokus dengan hasil yang terlihat', 'Pemrosesan lokal jika sesuai', 'Ukuran dan status ekspor yang jelas', 'Panduan pelengkap dokumentasi resmi'] },
|
|
9
|
+
{ type: 'tip', html: 'Gunakan alat ini sebagai pemeriksaan awal. Simpan sumber dan bandingkan ekspor dengan persyaratan platform terbaru.' },
|
|
10
|
+
] };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CategoryLocaleContent } from '../../types';
|
|
2
|
+
|
|
3
|
+
export const content: CategoryLocaleContent = { slug: 'sviluppo-di-videogiochi', title: 'Strumenti per lo sviluppo di videogiochi', description: 'Strumenti pratici nel browser per creatori indie, dalla grafica dello store alle consegne di produzione.', seo: [
|
|
4
|
+
{ type: 'title', text: 'Strumenti per creare videogiochi', level: 2 },
|
|
5
|
+
{ type: 'paragraph', html: 'Sviluppare un gioco significa prendere molte piccole decisioni: una composizione deve funzionare in più formati, un\'icona deve restare leggibile e un passaggio produttivo deve essere ripetibile. Questa categoria raccoglie utilità mirate per chi progetta, pubblica e presenta giochi.' },
|
|
6
|
+
{ type: 'title', text: 'Pensati per team indipendenti', level: 2 },
|
|
7
|
+
{ type: 'paragraph', html: 'I team indie passano spesso dal software grafico alle pagine di pubblicazione e alle cartelle di revisione. Uno strumento utile accorcia il passaggio, rende visibili le decisioni e lascia il controllo dei file sorgente al creatore.' },
|
|
8
|
+
{ type: 'list', items: ['Flussi mirati con risultati visibili', 'Elaborazione locale quando possibile', 'Dimensioni e stati di esportazione chiari', 'Indicazioni che completano la documentazione ufficiale'] },
|
|
9
|
+
{ type: 'tip', html: 'Usa questi strumenti come controllo preliminare. Conserva i sorgenti e confronta ogni esportazione con i requisiti aggiornati della piattaforma.' },
|
|
10
|
+
] };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CategoryLocaleContent } from '../../types';
|
|
2
|
+
|
|
3
|
+
export const content: CategoryLocaleContent = { slug: 'game-development', title: 'ゲーム開発のためのツール', description: 'ストア画像の準備から制作の受け渡しまで、インディー開発者向けの実用的なブラウザツールです。', seo: [
|
|
4
|
+
{ type: 'title', text: 'ゲームを作る人のためのツール', level: 2 },
|
|
5
|
+
{ type: 'paragraph', html: 'ゲーム開発には多くの小さな判断があります。構図は複数のストア形式に対応し、アイコンは一目で読め、制作作業は繰り返せなければなりません。このカテゴリでは、ゲームを作り、公開し、紹介する人のために目的を絞ったツールをまとめています。' },
|
|
6
|
+
{ type: 'title', text: '個人や小規模チーム向け', level: 2 },
|
|
7
|
+
{ type: 'paragraph', html: 'インディー開発では画像ソフト、公開画面、確認用フォルダーを行き来します。便利なツールは受け渡しを短くし、重要な判断を見えるようにし、元ファイルの管理を制作者に残します。' },
|
|
8
|
+
{ type: 'list', items: ['結果を確認しやすい目的別の操作', '可能な場合はブラウザ内で処理', '明確なサイズと保存状態', '公式ドキュメントを補う案内'] },
|
|
9
|
+
{ type: 'tip', html: '公開前の確認工程として使い、元データを保存したうえで、各プラットフォームの最新要件と比較してください。' },
|
|
10
|
+
] };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CategoryLocaleContent } from '../../types';
|
|
2
|
+
|
|
3
|
+
export const content: CategoryLocaleContent = { slug: 'game-development', title: '게임 개발 도구', description: '스토어 아트 준비부터 제작 전달까지 인디 개발자를 위한 실용적인 브라우저 도구입니다.', seo: [
|
|
4
|
+
{ type: 'title', text: '게임을 만드는 사람을 위한 도구', level: 2 },
|
|
5
|
+
{ type: 'paragraph', html: '게임 개발은 작은 판단의 연속입니다. 하나의 구성은 여러 스토어 형식에서 살아남아야 하고 아이콘은 한눈에 읽혀야 하며 제작 작업은 반복할 수 있어야 합니다. 이 카테고리는 게임을 만들고 출시하고 소개하는 사람을 위한 집중형 도구를 모읍니다.' },
|
|
6
|
+
{ type: 'title', text: '독립 개발자를 위해 설계', level: 2 },
|
|
7
|
+
{ type: 'paragraph', html: '인디 팀은 그래픽 소프트웨어, 출시 화면, 검토 폴더를 자주 오갑니다. 좋은 도구는 전달 과정을 줄이고 중요한 결정을 보여 주며 원본 파일의 통제권을 제작자에게 남깁니다.' },
|
|
8
|
+
{ type: 'list', items: ['결과가 보이는 집중형 작업 흐름', '가능한 경우 브라우저 내부 처리', '명확한 크기와 내보내기 상태', '공식 플랫폼 문서를 보완하는 안내'] },
|
|
9
|
+
{ type: 'tip', html: '도구를 출시 전 점검 단계로 사용하고 원본을 보관한 뒤 플랫폼의 최신 요구사항과 결과를 비교하세요.' },
|
|
10
|
+
] };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CategoryLocaleContent } from '../../types';
|
|
2
|
+
|
|
3
|
+
export const content: CategoryLocaleContent = { slug: 'gameontwikkeling', title: 'Hulpmiddelen voor gameontwikkeling', description: 'Praktische browsertools voor indiemakers, van winkelafbeeldingen tot productieleveringen.', seo: [
|
|
4
|
+
{ type: 'title', text: 'Tools voor het maken van games', level: 2 },
|
|
5
|
+
{ type: 'paragraph', html: 'Gameontwikkeling bestaat uit veel kleine beslissingen: een compositie moet meerdere formaten overleven, een pictogram moet direct leesbaar blijven en een productietaak moet herhaalbaar zijn. Deze categorie verzamelt gerichte hulpmiddelen voor makers die games bouwen, publiceren en presenteren.' },
|
|
6
|
+
{ type: 'title', text: 'Voor onafhankelijke makers', level: 2 },
|
|
7
|
+
{ type: 'paragraph', html: 'Indieteams schakelen vaak tussen beeldsoftware, publicatiedashboards en reviewmappen. Een goede tool verkort die overdracht, maakt keuzes zichtbaar en houdt de bronbestanden bij de maker.' },
|
|
8
|
+
{ type: 'list', items: ['Gerichte workflows met zichtbare resultaten', 'Lokale verwerking waar dat kan', 'Duidelijke maten en exportstatussen', 'Aanvulling op officiule platformdocumentatie'] },
|
|
9
|
+
{ type: 'tip', html: 'Gebruik deze tools als preflight. Bewaar de bronnen en vergelijk elke export met de actuele platformeisen.' },
|
|
10
|
+
] };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CategoryLocaleContent } from '../../types';
|
|
2
|
+
|
|
3
|
+
export const content: CategoryLocaleContent = { slug: 'tworzenie-gier', title: 'Narzędzia do tworzenia gier', description: 'Praktyczne narzędzia przeglądarkowe dla twórców indie, od grafiki sklepu po przekazanie produkcji.', seo: [
|
|
4
|
+
{ type: 'title', text: 'Narzędzia do tworzenia własnych gier', level: 2 },
|
|
5
|
+
{ type: 'paragraph', html: 'Tworzenie gry składa się z wielu drobnych decyzji: kompozycja musi działać w kilku formatach, ikona powinna być czytelna od razu, a zadanie produkcyjne łatwe do powtórzenia. Ta kategoria zbiera wyspecjalizowane narzędzia dla osób projektujących, publikujących i pokazujących gry.' },
|
|
6
|
+
{ type: 'title', text: 'Dla niezależnych twórców', level: 2 },
|
|
7
|
+
{ type: 'paragraph', html: 'Zespoły indie przechodzą między programem graficznym, panelem publikacji i folderem z recenzją. Dobre narzędzie skraca tę drogę, pokazuje ważne decyzje i zostawia pliki źródłowe pod kontrolą twórcy.' },
|
|
8
|
+
{ type: 'list', items: ['Skupione przepływy z widocznym wynikiem', 'Przetwarzanie lokalne, gdy jest możliwe', 'Jasne wymiary i stany eksportu', 'Wskazówki uzupełniające oficjalną dokumentację'] },
|
|
9
|
+
{ type: 'tip', html: 'Traktuj te narzędzia jako etap kontroli. Zachowaj źródła i porównaj eksport z aktualnymi wymaganiami platformy.' },
|
|
10
|
+
] };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CategoryLocaleContent } from '../../types';
|
|
2
|
+
|
|
3
|
+
export const content: CategoryLocaleContent = { slug: 'desenvolvimento-de-jogos', title: 'Ferramentas para desenvolvimento de jogos', description: 'Ferramentas práticas no navegador para criadores indie, da arte da loja às entregas de produção.', seo: [
|
|
4
|
+
{ type: 'title', text: 'Ferramentas para criar seus jogos', level: 2 },
|
|
5
|
+
{ type: 'paragraph', html: 'Desenvolver um jogo envolve muitas decisões pequenas: uma composição precisa funcionar em vários formatos, um ícone deve continuar legível e uma tarefa deve ser repetível. Esta categoria reúne utilidades focadas para quem cria, publica e apresenta jogos.' },
|
|
6
|
+
{ type: 'title', text: 'Feitas para equipes independentes', level: 2 },
|
|
7
|
+
{ type: 'paragraph', html: 'Equipes indie alternam entre software de arte, painéis de publicação e pastas de revisão. Uma boa ferramenta reduz essa passagem, mostra as decisões importantes e mantém os arquivos fonte sob controle do criador.' },
|
|
8
|
+
{ type: 'list', items: ['Fluxos específicos com resultados visíveis', 'Processamento local quando possível', 'Dimensões e estados de exportação claros', 'Orientações complementares à documentação oficial'] },
|
|
9
|
+
{ type: 'tip', html: 'Use as ferramentas como uma etapa de conferência. Guarde os arquivos fonte e compare cada exportação com os requisitos atuais da plataforma.' },
|
|
10
|
+
] };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CategoryLocaleContent } from '../../types';
|
|
2
|
+
|
|
3
|
+
export const content: CategoryLocaleContent = { slug: 'razrabotka-igr', title: 'Инструменты для разработки игр', description: 'Практические браузерные инструменты для инди создателей: от графики магазина до производственных задач.', seo: [
|
|
4
|
+
{ type: 'title', text: 'Инструменты для создания собственных игр', level: 2 },
|
|
5
|
+
{ type: 'paragraph', html: 'Разработка игры состоит из множества небольших решений: композиция должна работать в нескольких форматах, значок обязан читаться с первого взгляда, а производственный шаг должен легко повторяться. В этой категории собраны точечные инструменты для тех, кто создаёт, публикует и показывает игры.' },
|
|
6
|
+
{ type: 'title', text: 'Для независимых создателей', level: 2 },
|
|
7
|
+
{ type: 'paragraph', html: 'Инди команды часто переходят от графического редактора к панели публикации и папке проверки. Хороший инструмент сокращает этот переход, показывает важные решения и оставляет исходные файлы под контролем автора.' },
|
|
8
|
+
{ type: 'list', items: ['Понятные процессы с видимым результатом', 'Локальная обработка, когда это возможно', 'Ясные размеры и состояния экспорта', 'Подсказки в дополнение к официальной документации'] },
|
|
9
|
+
{ type: 'tip', html: 'Используйте эти инструменты как предварительную проверку. Храните исходники и сравнивайте экспорт с актуальными требованиями платформы.' },
|
|
10
|
+
] };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CategoryLocaleContent } from '../../types';
|
|
2
|
+
|
|
3
|
+
export const content: CategoryLocaleContent = { slug: 'spelutveckling', title: 'Verktyg för spelutveckling', description: 'Praktiska webbläsarverktyg för indieskapare, från butiksgrafik till produktionsleveranser.', seo: [
|
|
4
|
+
{ type: 'title', text: 'Verktyg för att skapa egna spel', level: 2 },
|
|
5
|
+
{ type: 'paragraph', html: 'Spelutveckling består av många små beslut: en komposition ska fungera i flera format, en ikon ska vara lätt att läsa och en produktionsuppgift ska gå att upprepa. Den här kategorin samlar fokuserade verktyg för personer som bygger, publicerar och presenterar spel.' },
|
|
6
|
+
{ type: 'title', text: 'För oberoende skapare', level: 2 },
|
|
7
|
+
{ type: 'paragraph', html: 'Indieteam växlar ofta mellan grafikprogram, publiceringspaneler och granskningsmappar. Ett bra verktyg kortar överlämningen, visar viktiga beslut och låter skaparen behålla kontrollen över källfilerna.' },
|
|
8
|
+
{ type: 'list', items: ['Fokuserade flöden med synliga resultat', 'Lokal behandling när det passar', 'Tydliga mått och exportlägen', 'Råd som kompletterar officiell dokumentation'] },
|
|
9
|
+
{ type: 'tip', html: 'Använd verktygen som en förkontroll. Spara källorna och jämför exporten med plattformens aktuella krav.' },
|
|
10
|
+
] };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CategoryLocaleContent } from '../../types';
|
|
2
|
+
|
|
3
|
+
export const content: CategoryLocaleContent = { slug: 'oyun-gelistirme', title: 'Oyun geliştirme araçları', description: 'Mağaza görsellerinden üretim teslimlerine kadar bağımsız oyun üreticileri için pratik tarayıcı araçları.', seo: [
|
|
4
|
+
{ type: 'title', text: 'Kendi oyunlarınızı üretmek için araçlar', level: 2 },
|
|
5
|
+
{ type: 'paragraph', html: 'Oyun geliştirme birçok küçük karardan oluşur: bir kompozisyon farklı mağaza biçimlerinde çalışmalı, bir simge ilk bakışta okunmalı ve üretim görevi tekrarlanabilmelidir. Bu kategori oyun tasarlayan, yayınlayan ve tanıtan kişiler için odaklanmış araçlar sunar.' },
|
|
6
|
+
{ type: 'title', text: 'Bağımsız üreticiler için', level: 2 },
|
|
7
|
+
{ type: 'paragraph', html: 'Bağımsız ekipler grafik yazılımı, yayın panosu ve inceleme klasörleri arasında sıkça geçiş yapar. İyi bir araç bu aktarımı kısaltır, önemli kararları görünür kılar ve kaynak dosyaların kontrolünü üreticide bırakır.' },
|
|
8
|
+
{ type: 'list', items: ['Görünür sonuçlara sahip odaklı akışlar', 'Uygun olduğunda yerel işleme', 'Net boyutlar ve dışa aktarma durumları', 'Resmî platform belgelerini tamamlayan bilgiler'] },
|
|
9
|
+
{ type: 'tip', html: 'Bu araçları ön kontrol katmanı olarak kullanın. Kaynakları saklayın ve dışa aktarımları platformun güncel şartlarıyla karşılaştırın.' },
|
|
10
|
+
] };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CategoryLocaleContent } from '../../types';
|
|
2
|
+
|
|
3
|
+
export const content: CategoryLocaleContent = { slug: 'game-development', title: '游戏开发工具', description: '面向独立开发者的实用浏览器工具,帮助准备商店美术并完成制作交付。', seo: [
|
|
4
|
+
{ type: 'title', text: '为游戏创作者准备的工具', level: 2 },
|
|
5
|
+
{ type: 'paragraph', html: '游戏开发由许多小决定组成:构图要适应多种商店尺寸,图标要一眼可读,制作任务也要容易重复。本分类为制作、发布和展示游戏的人整理了目标明确的工具,把繁琐工作变成清晰的浏览器操作。' },
|
|
6
|
+
{ type: 'title', text: '适合独立开发者', level: 2 },
|
|
7
|
+
{ type: 'paragraph', html: '独立团队经常在美术软件、发布面板和审核文件夹之间切换。好的工具可以缩短交接过程,让关键决定可见,并让创作者继续掌握源文件。' },
|
|
8
|
+
{ type: 'list', items: ['结果清晰的专注流程', '适合时在浏览器本地处理', '明确的尺寸和导出状态', '补充官方平台文档的说明'] },
|
|
9
|
+
{ type: 'tip', html: '把这些工具当作发布前检查层,保留源文件,并将结果与平台当前要求进行比较。' },
|
|
10
|
+
] };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { GamesCategoryEntry } from '../types';
|
|
2
|
+
import { steamCapsuleGenerator } from '../tool/steamCapsuleGenerator/entry';
|
|
3
|
+
|
|
4
|
+
export const gamesCategory: GamesCategoryEntry = {
|
|
5
|
+
icon: 'mdi:gamepad-variant',
|
|
6
|
+
tools: [steamCapsuleGenerator],
|
|
7
|
+
i18n: {
|
|
8
|
+
de: () => import('./i18n/de').then((m) => m.content),
|
|
9
|
+
en: () => import('./i18n/en').then((m) => m.content),
|
|
10
|
+
es: () => import('./i18n/es').then((m) => m.content),
|
|
11
|
+
fr: () => import('./i18n/fr').then((m) => m.content),
|
|
12
|
+
id: () => import('./i18n/id').then((m) => m.content),
|
|
13
|
+
it: () => import('./i18n/it').then((m) => m.content),
|
|
14
|
+
ja: () => import('./i18n/ja').then((m) => m.content),
|
|
15
|
+
ko: () => import('./i18n/ko').then((m) => m.content),
|
|
16
|
+
nl: () => import('./i18n/nl').then((m) => m.content),
|
|
17
|
+
pl: () => import('./i18n/pl').then((m) => m.content),
|
|
18
|
+
pt: () => import('./i18n/pt').then((m) => m.content),
|
|
19
|
+
ru: () => import('./i18n/ru').then((m) => m.content),
|
|
20
|
+
sv: () => import('./i18n/sv').then((m) => m.content),
|
|
21
|
+
tr: () => import('./i18n/tr').then((m) => m.content),
|
|
22
|
+
zh: () => import('./i18n/zh').then((m) => m.content),
|
|
23
|
+
},
|
|
24
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { SEORenderer } from '@jjlmoya/utils-shared';
|
|
3
|
+
import { gamesCategory } from './index';
|
|
4
|
+
import type { KnownLocale } from '../types';
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
locale?: KnownLocale;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const { locale = 'es' } = Astro.props;
|
|
11
|
+
const content = await gamesCategory.i18n[locale as KnownLocale]?.();
|
|
12
|
+
if (!content) return null;
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
<SEORenderer content={{ sections: content.seo, locale }} />
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
interface NavItem {
|
|
3
|
+
id: string;
|
|
4
|
+
title: string;
|
|
5
|
+
href: string;
|
|
6
|
+
isActive?: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
categoryTitle: string;
|
|
11
|
+
tools?: NavItem[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const { categoryTitle, tools = [] } = Astro.props;
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
<nav class="preview-nav-sidebar">
|
|
18
|
+
<div class="sidebar-header">
|
|
19
|
+
<h3>{categoryTitle}</h3>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<ul class="tools-list">
|
|
23
|
+
{tools.map((tool) => (
|
|
24
|
+
<li>
|
|
25
|
+
<a
|
|
26
|
+
href={tool.href}
|
|
27
|
+
class:list={['tool-link', { active: tool.isActive }]}
|
|
28
|
+
>
|
|
29
|
+
<span class="tool-title">{tool.title}</span>
|
|
30
|
+
</a>
|
|
31
|
+
</li>
|
|
32
|
+
))}
|
|
33
|
+
</ul>
|
|
34
|
+
</nav>
|
|
35
|
+
|
|
36
|
+
<style>
|
|
37
|
+
.preview-nav-sidebar {
|
|
38
|
+
display: flex;
|
|
39
|
+
flex-direction: column;
|
|
40
|
+
height: 100%;
|
|
41
|
+
background: var(--bg-surface, #0f172a);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.sidebar-header {
|
|
45
|
+
padding: 2rem 1.5rem 1.5rem;
|
|
46
|
+
border-bottom: 1px solid var(--border-color, #1e293b);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.sidebar-header h3 {
|
|
50
|
+
margin: 0;
|
|
51
|
+
font-size: 0.75rem;
|
|
52
|
+
font-weight: 900;
|
|
53
|
+
text-transform: uppercase;
|
|
54
|
+
letter-spacing: 0.1em;
|
|
55
|
+
color: var(--text-muted, #94a3b8);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.tools-list {
|
|
59
|
+
list-style: none;
|
|
60
|
+
margin: 0;
|
|
61
|
+
padding: 0.5rem 0;
|
|
62
|
+
display: flex;
|
|
63
|
+
flex-direction: column;
|
|
64
|
+
gap: 0.25rem;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.tools-list li {
|
|
68
|
+
margin: 0;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.tool-link {
|
|
72
|
+
display: flex;
|
|
73
|
+
align-items: center;
|
|
74
|
+
padding: 0.75rem 1.5rem;
|
|
75
|
+
color: var(--text-muted, #94a3b8);
|
|
76
|
+
text-decoration: none;
|
|
77
|
+
font-size: 0.9375rem;
|
|
78
|
+
font-weight: 500;
|
|
79
|
+
transition: all 0.15s cubic-bezier(0.4, 0, 0.2, 1);
|
|
80
|
+
border-left: 3px solid transparent;
|
|
81
|
+
position: relative;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.tool-link:hover {
|
|
85
|
+
color: var(--text-base, #f1f5f9);
|
|
86
|
+
background: rgba(255, 255, 255, 0.08);
|
|
87
|
+
padding-left: 1.75rem;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.tool-link.active {
|
|
91
|
+
color: var(--accent, #f43f5e);
|
|
92
|
+
background: rgba(244, 63, 94, 0.15);
|
|
93
|
+
border-left-color: var(--accent, #f43f5e);
|
|
94
|
+
font-weight: 600;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.tool-link.active::before {
|
|
98
|
+
content: '';
|
|
99
|
+
position: absolute;
|
|
100
|
+
left: 0;
|
|
101
|
+
top: 50%;
|
|
102
|
+
transform: translateY(-50%);
|
|
103
|
+
width: 3px;
|
|
104
|
+
height: 24px;
|
|
105
|
+
background: var(--accent, #f43f5e);
|
|
106
|
+
border-radius: 0 2px 2px 0;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.tool-title {
|
|
110
|
+
display: block;
|
|
111
|
+
overflow: hidden;
|
|
112
|
+
text-overflow: ellipsis;
|
|
113
|
+
white-space: nowrap;
|
|
114
|
+
}
|
|
115
|
+
</style>
|
|
116
|
+
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { KnownLocale } from '../types';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
currentLocale: KnownLocale;
|
|
6
|
+
localeUrls?: Partial<Record<KnownLocale, string>>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const { currentLocale, localeUrls = {} } = Astro.props;
|
|
10
|
+
|
|
11
|
+
const otherLocales = Object.entries(localeUrls).filter(([l]) => l !== currentLocale) as [
|
|
12
|
+
KnownLocale,
|
|
13
|
+
string,
|
|
14
|
+
][];
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
<nav class="preview-toolbar">
|
|
18
|
+
{
|
|
19
|
+
otherLocales.length > 0 && (
|
|
20
|
+
<div class="locale-group">
|
|
21
|
+
<span class="locale-current">{currentLocale.toUpperCase()}</span>
|
|
22
|
+
{otherLocales.map(([locale, url]) => (
|
|
23
|
+
<a href={url} class="btn-locale">
|
|
24
|
+
{locale.toUpperCase()}
|
|
25
|
+
</a>
|
|
26
|
+
))}
|
|
27
|
+
</div>
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
<button id="theme-toggle" class="btn-theme" aria-label="Toggle theme" title="Toggle theme">
|
|
32
|
+
<span class="theme-icon"></span>
|
|
33
|
+
</button>
|
|
34
|
+
</nav>
|
|
35
|
+
|
|
36
|
+
<script>
|
|
37
|
+
function initToolbar() {
|
|
38
|
+
const btn = document.getElementById('theme-toggle');
|
|
39
|
+
if (!btn) return;
|
|
40
|
+
|
|
41
|
+
const applyTheme = (theme: string) => {
|
|
42
|
+
document.documentElement.classList.remove('theme-light', 'theme-dark');
|
|
43
|
+
document.documentElement.classList.add(theme);
|
|
44
|
+
localStorage.setItem('theme', theme);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
btn.addEventListener('click', () => {
|
|
48
|
+
const next = document.documentElement.classList.contains('theme-dark')
|
|
49
|
+
? 'theme-light'
|
|
50
|
+
: 'theme-dark';
|
|
51
|
+
applyTheme(next);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
initToolbar();
|
|
56
|
+
document.addEventListener('astro:after-swap', initToolbar);
|
|
57
|
+
</script>
|
|
58
|
+
|
|
59
|
+
<style>
|
|
60
|
+
.preview-toolbar {
|
|
61
|
+
position: fixed;
|
|
62
|
+
top: 1rem;
|
|
63
|
+
right: 1.5rem;
|
|
64
|
+
display: flex;
|
|
65
|
+
align-items: center;
|
|
66
|
+
gap: 0.5rem;
|
|
67
|
+
z-index: 1000;
|
|
68
|
+
background: var(--bg-surface);
|
|
69
|
+
padding: 0.4rem;
|
|
70
|
+
border-radius: 1rem;
|
|
71
|
+
border: 1px solid var(--border-color);
|
|
72
|
+
backdrop-filter: blur(12px);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.locale-group {
|
|
76
|
+
display: flex;
|
|
77
|
+
align-items: center;
|
|
78
|
+
gap: 0.25rem;
|
|
79
|
+
padding-right: 0.5rem;
|
|
80
|
+
border-right: 1px solid var(--border-color);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.locale-current {
|
|
84
|
+
font-size: 0.7rem;
|
|
85
|
+
font-weight: 900;
|
|
86
|
+
color: var(--text-muted);
|
|
87
|
+
padding: 0.4rem 0.6rem;
|
|
88
|
+
letter-spacing: 0.08em;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.btn-locale {
|
|
92
|
+
background: transparent;
|
|
93
|
+
border: 1px solid var(--border-color);
|
|
94
|
+
color: var(--text-main);
|
|
95
|
+
cursor: pointer;
|
|
96
|
+
padding: 0.4rem 0.7rem;
|
|
97
|
+
border-radius: 0.5rem;
|
|
98
|
+
font-weight: 700;
|
|
99
|
+
font-size: 0.7rem;
|
|
100
|
+
text-decoration: none;
|
|
101
|
+
letter-spacing: 0.08em;
|
|
102
|
+
transition: all 0.2s ease;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.btn-locale:hover {
|
|
106
|
+
border-color: var(--accent);
|
|
107
|
+
color: var(--accent);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.btn-theme {
|
|
111
|
+
background: transparent;
|
|
112
|
+
border: none;
|
|
113
|
+
cursor: pointer;
|
|
114
|
+
padding: 0.5rem;
|
|
115
|
+
border-radius: 0.6rem;
|
|
116
|
+
display: flex;
|
|
117
|
+
align-items: center;
|
|
118
|
+
justify-content: center;
|
|
119
|
+
transition: background 0.2s ease;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.btn-theme:hover {
|
|
123
|
+
background: rgba(255, 255, 255, 0.08);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.theme-icon {
|
|
127
|
+
display: block;
|
|
128
|
+
width: 16px;
|
|
129
|
+
height: 16px;
|
|
130
|
+
border-radius: 50%;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
:global(.theme-light) .theme-icon {
|
|
134
|
+
background: #f59e0b;
|
|
135
|
+
box-shadow: 0 0 8px #fbbf24;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
:global(.theme-dark) .theme-icon {
|
|
139
|
+
background: #94a3b8;
|
|
140
|
+
box-shadow: inset -4px -2px 0 #1e293b;
|
|
141
|
+
}
|
|
142
|
+
</style>
|
|
143
|
+
|
package/src/data.ts
ADDED
package/src/entries.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { steamCapsuleGenerator } from './tool/steamCapsuleGenerator/entry';
|
|
2
|
+
export type { SteamCapsuleGeneratorUI, SteamCapsuleGeneratorLocaleContent } from './tool/steamCapsuleGenerator/entry';
|
|
3
|
+
export { gamesCategory } from './category';
|
|
4
|
+
import { steamCapsuleGenerator } from './tool/steamCapsuleGenerator/entry';
|
|
5
|
+
export const ALL_ENTRIES = [steamCapsuleGenerator];
|