@jjlmoya/utils-games-development 1.53.0 → 1.55.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 (72) hide show
  1. package/package.json +1 -1
  2. package/src/category/index.ts +2 -1
  3. package/src/entries.ts +6 -1
  4. package/src/index.ts +2 -0
  5. package/src/tests/contrast_legibility.test.ts +245 -0
  6. package/src/tests/locale_completeness.test.ts +2 -2
  7. package/src/tests/tool_validation.test.ts +2 -2
  8. package/src/tool/itchioGameTester/itchio-game-tester.css +3 -3
  9. package/src/tool/localizationSanitizer/localization-sanitizer.css +13 -13
  10. package/src/tool/retroSfxGenerator/bibliography.astro +6 -0
  11. package/src/tool/retroSfxGenerator/bibliography.ts +16 -0
  12. package/src/tool/retroSfxGenerator/client.ts +256 -0
  13. package/src/tool/retroSfxGenerator/component.astro +146 -0
  14. package/src/tool/retroSfxGenerator/entry.ts +27 -0
  15. package/src/tool/retroSfxGenerator/i18n/de.ts +211 -0
  16. package/src/tool/retroSfxGenerator/i18n/en.ts +224 -0
  17. package/src/tool/retroSfxGenerator/i18n/es.ts +211 -0
  18. package/src/tool/retroSfxGenerator/i18n/fr.ts +211 -0
  19. package/src/tool/retroSfxGenerator/i18n/id.ts +211 -0
  20. package/src/tool/retroSfxGenerator/i18n/it.ts +211 -0
  21. package/src/tool/retroSfxGenerator/i18n/ja.ts +211 -0
  22. package/src/tool/retroSfxGenerator/i18n/ko.ts +211 -0
  23. package/src/tool/retroSfxGenerator/i18n/nl.ts +211 -0
  24. package/src/tool/retroSfxGenerator/i18n/pl.ts +211 -0
  25. package/src/tool/retroSfxGenerator/i18n/pt.ts +211 -0
  26. package/src/tool/retroSfxGenerator/i18n/ru.ts +211 -0
  27. package/src/tool/retroSfxGenerator/i18n/sv.ts +211 -0
  28. package/src/tool/retroSfxGenerator/i18n/tr.ts +211 -0
  29. package/src/tool/retroSfxGenerator/i18n/zh.ts +211 -0
  30. package/src/tool/retroSfxGenerator/index.ts +11 -0
  31. package/src/tool/retroSfxGenerator/logic.test.ts +40 -0
  32. package/src/tool/retroSfxGenerator/logic.ts +214 -0
  33. package/src/tool/retroSfxGenerator/retro-sfx-generator.css +429 -0
  34. package/src/tool/retroSfxGenerator/seo.astro +15 -0
  35. package/src/tool/retroSfxGenerator/ui.ts +41 -0
  36. package/src/tool/saveFileEditor/game-save-file-editor.css +5 -5
  37. package/src/tool/spriteSheetPacker/sprite-sheet-packer.css +5 -5
  38. package/src/tool/steamBbcodeTranslator/app-client.ts +125 -0
  39. package/src/tool/steamBbcodeTranslator/bbcode-parser.ts +110 -0
  40. package/src/tool/steamBbcodeTranslator/bibliography.astro +6 -0
  41. package/src/tool/steamBbcodeTranslator/bibliography.ts +14 -0
  42. package/src/tool/steamBbcodeTranslator/component.astro +83 -0
  43. package/src/tool/steamBbcodeTranslator/entry.ts +28 -0
  44. package/src/tool/steamBbcodeTranslator/html-parser.ts +42 -0
  45. package/src/tool/steamBbcodeTranslator/html-renderer.ts +71 -0
  46. package/src/tool/steamBbcodeTranslator/i18n/de.ts +207 -0
  47. package/src/tool/steamBbcodeTranslator/i18n/en.ts +236 -0
  48. package/src/tool/steamBbcodeTranslator/i18n/es.ts +207 -0
  49. package/src/tool/steamBbcodeTranslator/i18n/fr.ts +195 -0
  50. package/src/tool/steamBbcodeTranslator/i18n/id.ts +195 -0
  51. package/src/tool/steamBbcodeTranslator/i18n/it.ts +195 -0
  52. package/src/tool/steamBbcodeTranslator/i18n/ja.ts +195 -0
  53. package/src/tool/steamBbcodeTranslator/i18n/ko.ts +195 -0
  54. package/src/tool/steamBbcodeTranslator/i18n/nl.ts +195 -0
  55. package/src/tool/steamBbcodeTranslator/i18n/pl.ts +195 -0
  56. package/src/tool/steamBbcodeTranslator/i18n/pt.ts +195 -0
  57. package/src/tool/steamBbcodeTranslator/i18n/ru.ts +195 -0
  58. package/src/tool/steamBbcodeTranslator/i18n/sv.ts +195 -0
  59. package/src/tool/steamBbcodeTranslator/i18n/tr.ts +195 -0
  60. package/src/tool/steamBbcodeTranslator/i18n/zh.ts +195 -0
  61. package/src/tool/steamBbcodeTranslator/index.ts +12 -0
  62. package/src/tool/steamBbcodeTranslator/logic.test.ts +41 -0
  63. package/src/tool/steamBbcodeTranslator/logic.ts +96 -0
  64. package/src/tool/steamBbcodeTranslator/markdown-parser.ts +115 -0
  65. package/src/tool/steamBbcodeTranslator/markdown-renderer.ts +85 -0
  66. package/src/tool/steamBbcodeTranslator/seo.astro +15 -0
  67. package/src/tool/steamBbcodeTranslator/steam-bbcode-translator.css +392 -0
  68. package/src/tool/steamBbcodeTranslator/storage.ts +30 -0
  69. package/src/tool/steamBbcodeTranslator/types.ts +36 -0
  70. package/src/tool/steamBbcodeTranslator/ui.ts +18 -0
  71. package/src/tool/steamCapsuleGenerator/steam-capsule-generator.css +6 -6
  72. package/src/tools.ts +4 -0
@@ -0,0 +1,85 @@
1
+ import type { Node, TagNode } from './types';
2
+
3
+ function escapeMarkdown(value: string): string {
4
+ return value.replace(/([\\`*_{}[\]()#+!|>])/g, '\\$1');
5
+ }
6
+
7
+ function escapeMarkdownUrl(value: string): string {
8
+ return value.replace(/[()\\ ]/g, (character) => `\\${character}`);
9
+ }
10
+
11
+ function cleanInline(value: string): string {
12
+ return value.replace(/[ \t]+\n/g, '\n').replace(/\n[ \t]+/g, '\n');
13
+ }
14
+
15
+ function indent(value: string): string {
16
+ return value.split('\n').map((line) => line ? ` ${line}` : line).join('\n');
17
+ }
18
+
19
+ export function inlineMarkdown(nodes: Node[]): string {
20
+ return cleanInline(nodes.map((node) => {
21
+ if (node.kind === 'text') return escapeMarkdown(node.value);
22
+ return renderMarkdownNode(node, true);
23
+ }).join(''));
24
+ }
25
+
26
+ export function renderMarkdownList(node: TagNode, ordered: boolean): string {
27
+ const items = node.children.filter((child): child is TagNode => child.kind === 'tag' && child.name === '*');
28
+ return items.map((item, index) => {
29
+ const content = item.children.map((child) => {
30
+ if (child.kind === 'tag' && (child.name === 'list' || child.name === 'olist')) {
31
+ return `\n${indent(renderMarkdownList(child, child.name === 'olist'))}`;
32
+ }
33
+ if (child.kind === 'text') return escapeMarkdown(child.value);
34
+ return renderMarkdownNode(child, true);
35
+ }).join('').trim();
36
+ return `${ordered ? `${index + 1}.` : '-'} ${content}`;
37
+ }).join('\n');
38
+ }
39
+
40
+ function renderCodeNode(node: TagNode, inline: boolean): string {
41
+ const inner = node.children.map((child) => child.kind === 'text' ? child.value : renderMarkdownNode(child, true)).join('');
42
+ return inline ? `\`${inner}\`` : `\`\`\`\n${inner}\n\`\`\`\n\n`;
43
+ }
44
+
45
+ function renderQuoteNode(node: TagNode): string {
46
+ return node.children.map((child) => inlineMarkdown([child])).join('').split('\n').map((line) => `> ${line}`).join('\n') + '\n\n';
47
+ }
48
+
49
+ function renderMarkdownBasicInline(name: string, content: string): string | null {
50
+ if (name === 'b' || name === 'strong') return `**${content}**`;
51
+ if (name === 'i' || name === 'em') return `*${content}*`;
52
+ if (name === 'u') return `<u>${content}</u>`;
53
+ if (name === 's' || name === 'strike') return `~~${content}~~`;
54
+ return null;
55
+ }
56
+
57
+ function renderMarkdownInlineNode(name: string, content: string, value?: string): string {
58
+ const basic = renderMarkdownBasicInline(name, content);
59
+ if (basic !== null) return basic;
60
+ if (name === 'url') return value ? `[${content || escapeMarkdown(value)}](${escapeMarkdownUrl(value)})` : content;
61
+ return content;
62
+ }
63
+
64
+ function renderMarkdownHeadingOrBlock(name: string, content: string, node: TagNode, inline: boolean): string | null {
65
+ if (name === 'h1') return `# ${content.trim()}\n\n`;
66
+ if (name === 'h2') return `## ${content.trim()}\n\n`;
67
+ if (name === 'h3') return `### ${content.trim()}\n\n`;
68
+ if (name === 'code') return renderCodeNode(node, inline);
69
+ if (name === 'quote') return renderQuoteNode(node);
70
+ if (name === 'spoiler') return `<details><summary>Spoiler</summary>${content}</details>`;
71
+ return null;
72
+ }
73
+
74
+ export function renderMarkdownNode(node: TagNode, inline = false): string {
75
+ const content = inlineMarkdown(node.children);
76
+ const headingOrBlock = renderMarkdownHeadingOrBlock(node.name, content, node, inline);
77
+ if (headingOrBlock !== null) return headingOrBlock;
78
+ if (node.name === 'list') return `${renderMarkdownList(node, false)}\n\n`;
79
+ if (node.name === 'olist') return `${renderMarkdownList(node, true)}\n\n`;
80
+ return renderMarkdownInlineNode(node.name, content, node.value);
81
+ }
82
+
83
+ export function renderMarkdown(nodes: Node[]): string {
84
+ return nodes.map((node) => node.kind === 'text' ? escapeMarkdown(node.value) : renderMarkdownNode(node)).join('').replace(/\n{3,}/g, '\n\n').trim();
85
+ }
@@ -0,0 +1,15 @@
1
+ ---
2
+ import { SEORenderer } from '@jjlmoya/utils-shared';
3
+ import { steamBbcodeTranslator } from './entry';
4
+ import type { KnownLocale } from '../../types';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ }
9
+
10
+ const { locale = 'en' } = Astro.props;
11
+ const loader = steamBbcodeTranslator.i18n[locale] ?? steamBbcodeTranslator.i18n.en;
12
+ const content = loader ? await loader() : null;
13
+ ---
14
+
15
+ {content && content.seo && content.seo.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
@@ -0,0 +1,392 @@
1
+ .bbcode-root {
2
+ --bb-ink: #211e2d;
3
+ --bb-muted: #77728a;
4
+ --bb-line: #dcd8e7;
5
+ --bb-panel: #fffdfb;
6
+ --bb-soft: #f4f0f7;
7
+ --bb-accent: #724ee8;
8
+ --bb-accent-deep: #4c2fba;
9
+ --bb-cyan: #20a8b5;
10
+ --bb-warm: #ed8a52;
11
+
12
+ color: var(--bb-ink);
13
+ margin: 0 auto;
14
+ max-width: 1120px;
15
+ width: 100%;
16
+ }
17
+
18
+ .theme-dark .bbcode-root {
19
+ --bb-ink: #f4f1fb;
20
+ --bb-muted: #aaa4bb;
21
+ --bb-line: #342e47;
22
+ --bb-panel: #171422;
23
+ --bb-soft: #211c30;
24
+ --bb-accent: #a68cff;
25
+ --bb-accent-deep: #c0b0ff;
26
+ --bb-cyan: #63d2dc;
27
+ --bb-warm: #f3a06d;
28
+ }
29
+
30
+ .bbcode-root * {
31
+ box-sizing: border-box;
32
+ }
33
+
34
+ .bbcode-root button,
35
+ .bbcode-root textarea {
36
+ font: inherit;
37
+ }
38
+
39
+ .bbcode-header,
40
+ .bbcode-input-card,
41
+ .bbcode-output-card,
42
+ .bbcode-preview-card {
43
+ background: var(--bb-panel);
44
+ border: 1px solid var(--bb-line);
45
+ }
46
+
47
+ .bbcode-header {
48
+ align-items: center;
49
+ border-radius: 18px 18px 0 0;
50
+ display: flex;
51
+ justify-content: space-between;
52
+ gap: 1rem;
53
+ padding: 1rem 1.2rem;
54
+ }
55
+
56
+ .bbcode-title-row {
57
+ align-items: center;
58
+ display: flex;
59
+ gap: 0.75rem;
60
+ min-width: 0;
61
+ }
62
+
63
+ .bbcode-mark {
64
+ align-items: center;
65
+ background: var(--bb-soft);
66
+ border: 1px solid var(--bb-line);
67
+ border-radius: 8px;
68
+ color: var(--bb-accent);
69
+ display: inline-flex;
70
+ font-size: 0.9rem;
71
+ font-weight: 900;
72
+ height: 36px;
73
+ justify-content: center;
74
+ width: 58px;
75
+ }
76
+
77
+ .bbcode-kicker {
78
+ color: var(--bb-accent);
79
+ display: block;
80
+ font-size: 0.75rem;
81
+ font-weight: 900;
82
+ letter-spacing: 0.14em;
83
+ }
84
+
85
+ .bbcode-title-row strong,
86
+ .bbcode-draft-note {
87
+ color: var(--bb-muted);
88
+ display: block;
89
+ font-size: 0.75rem;
90
+ font-weight: 600;
91
+ }
92
+
93
+ .bbcode-draft-note {
94
+ text-align: right;
95
+ }
96
+
97
+ .bbcode-input-card {
98
+ border-top: 0;
99
+ padding: 1.2rem;
100
+ }
101
+
102
+ .bbcode-section-head,
103
+ .bbcode-output-heading,
104
+ .bbcode-output-card-head,
105
+ .bbcode-input-footer {
106
+ align-items: flex-start;
107
+ display: flex;
108
+ justify-content: space-between;
109
+ gap: 1rem;
110
+ }
111
+
112
+ .bbcode-section-head {
113
+ margin-bottom: 0.7rem;
114
+ }
115
+
116
+ .bbcode-section-head h2,
117
+ .bbcode-output-heading h2 {
118
+ display: inline;
119
+ font-size: 1rem;
120
+ margin: 0;
121
+ }
122
+
123
+ .bbcode-step {
124
+ color: var(--bb-warm);
125
+ font-size: 0.75rem;
126
+ font-weight: 900;
127
+ margin-right: 0.45rem;
128
+ }
129
+
130
+ .bbcode-detected {
131
+ background: var(--bb-soft);
132
+ border-radius: 999px;
133
+ color: var(--bb-accent-deep);
134
+ font-size: 0.75rem;
135
+ padding: 0.3rem 0.55rem;
136
+ }
137
+
138
+ .bbcode-input-card textarea {
139
+ background: var(--bb-soft);
140
+ border: 1px solid var(--bb-line);
141
+ border-radius: 9px;
142
+ color: var(--bb-ink);
143
+ display: block;
144
+ font-size: 0.8rem;
145
+ line-height: 1.65;
146
+ min-height: 240px;
147
+ padding: 1rem;
148
+ resize: vertical;
149
+ width: 100%;
150
+ }
151
+
152
+ .bbcode-input-card textarea:focus {
153
+ border-color: var(--bb-accent);
154
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--bb-accent) 18%, transparent);
155
+ outline: 0;
156
+ }
157
+
158
+ .bbcode-input-footer {
159
+ align-items: center;
160
+ margin-top: 0.6rem;
161
+ }
162
+
163
+ .bbcode-input-footer p {
164
+ color: var(--bb-muted);
165
+ font-size: 0.75rem;
166
+ line-height: 1.4;
167
+ margin: 0;
168
+ }
169
+
170
+ .bbcode-input-meta {
171
+ align-items: center;
172
+ color: var(--bb-muted);
173
+ display: flex;
174
+ flex-wrap: wrap;
175
+ font-size: 0.75rem;
176
+ gap: 0.8rem;
177
+ }
178
+
179
+ .bbcode-input-meta strong {
180
+ color: var(--bb-ink);
181
+ }
182
+
183
+ .bbcode-clear-button,
184
+ .bbcode-icon-button {
185
+ background: transparent;
186
+ border: 1px solid var(--bb-line);
187
+ border-radius: 6px;
188
+ color: var(--bb-ink);
189
+ cursor: pointer;
190
+ font-size: 0.75rem;
191
+ font-weight: 800;
192
+ padding: 0.38rem 0.6rem;
193
+ }
194
+
195
+ .bbcode-clear-button:hover,
196
+ .bbcode-icon-button:hover {
197
+ border-color: var(--bb-accent);
198
+ color: var(--bb-accent-deep);
199
+ }
200
+
201
+ .bbcode-output-section {
202
+ background: var(--bb-soft);
203
+ border-left: 1px solid var(--bb-line);
204
+ border-right: 1px solid var(--bb-line);
205
+ padding: 1rem 1.2rem;
206
+ }
207
+
208
+ .bbcode-output-heading {
209
+ align-items: center;
210
+ margin-bottom: 0.7rem;
211
+ }
212
+
213
+ .bbcode-output-grid {
214
+ display: grid;
215
+ gap: 0.8rem;
216
+ grid-template-columns: repeat(2, minmax(0, 1fr));
217
+ }
218
+
219
+ .bbcode-output-card {
220
+ border-radius: 10px;
221
+ min-width: 0;
222
+ padding: 0.8rem;
223
+ }
224
+
225
+ .bbcode-output-card-head {
226
+ align-items: center;
227
+ margin-bottom: 0.55rem;
228
+ }
229
+
230
+ .bbcode-output-card h3 {
231
+ font-size: 0.78rem;
232
+ margin: 0;
233
+ }
234
+
235
+ .bbcode-output-card pre {
236
+ background: var(--bb-soft);
237
+ border: 1px solid var(--bb-line);
238
+ border-radius: 7px;
239
+ color: var(--bb-ink);
240
+ font-size: 0.75rem;
241
+ line-height: 1.6;
242
+ margin: 0;
243
+ min-height: 180px;
244
+ max-height: 330px;
245
+ overflow: auto;
246
+ padding: 0.8rem;
247
+ white-space: pre-wrap;
248
+ overflow-wrap: anywhere;
249
+ }
250
+
251
+ .bbcode-preview-card {
252
+ border-radius: 0 0 18px 18px;
253
+ border-top: 0;
254
+ padding: 1rem 1.2rem 1.2rem;
255
+ }
256
+
257
+ .bbcode-preview-surface {
258
+ background: var(--bb-soft);
259
+ border: 1px solid var(--bb-line);
260
+ border-radius: 9px;
261
+ color: var(--bb-ink);
262
+ font-size: 0.82rem;
263
+ line-height: 1.6;
264
+ min-height: 110px;
265
+ padding: 1rem;
266
+ }
267
+
268
+ .bbcode-preview-surface h1,
269
+ .bbcode-preview-surface h2,
270
+ .bbcode-preview-surface h3 {
271
+ line-height: 1.15;
272
+ margin: 0 0 0.6rem;
273
+ }
274
+
275
+ .bbcode-preview-surface h1 {
276
+ font-size: 1.35rem;
277
+ }
278
+
279
+ .bbcode-preview-surface h2 {
280
+ font-size: 1.12rem;
281
+ }
282
+
283
+ .bbcode-preview-surface h3 {
284
+ font-size: 0.98rem;
285
+ }
286
+
287
+ .bbcode-preview-surface p {
288
+ margin: 0.3rem 0;
289
+ }
290
+
291
+ .bbcode-preview-surface ul,
292
+ .bbcode-preview-surface ol {
293
+ margin: 0.45rem 0;
294
+ padding-left: 1.3rem;
295
+ }
296
+
297
+ .bbcode-preview-surface li {
298
+ margin: 0.15rem 0;
299
+ }
300
+
301
+ .bbcode-preview-surface blockquote {
302
+ border-left: 3px solid var(--bb-accent);
303
+ color: var(--bb-muted);
304
+ margin: 0.6rem 0;
305
+ padding-left: 0.7rem;
306
+ }
307
+
308
+ .bbcode-preview-surface a {
309
+ color: var(--bb-accent-deep);
310
+ }
311
+
312
+ .bbcode-preview-surface code,
313
+ .bbcode-preview-surface pre {
314
+ background: var(--bb-panel);
315
+ border: 1px solid var(--bb-line);
316
+ border-radius: 5px;
317
+ }
318
+
319
+ .bbcode-preview-surface code {
320
+ padding: 0.1rem 0.25rem;
321
+ }
322
+
323
+ .bbcode-preview-surface pre {
324
+ overflow: auto;
325
+ padding: 0.6rem;
326
+ }
327
+
328
+ .bbcode-preview-surface pre code {
329
+ border: 0;
330
+ padding: 0;
331
+ }
332
+
333
+ .bbcode-preview-surface p:first-child:last-child {
334
+ color: var(--bb-muted);
335
+ margin: 0;
336
+ }
337
+
338
+ .bbcode-sr-only {
339
+ height: 1px;
340
+ margin: -1px;
341
+ overflow: hidden;
342
+ position: absolute;
343
+ width: 1px;
344
+ clip-path: inset(50%);
345
+ }
346
+
347
+ .bbcode-root button:focus-visible,
348
+ .bbcode-root textarea:focus-visible {
349
+ outline: 3px solid color-mix(in srgb, var(--bb-cyan) 45%, transparent);
350
+ outline-offset: 2px;
351
+ }
352
+
353
+ @media (max-width: 700px) {
354
+ .bbcode-header,
355
+ .bbcode-input-footer {
356
+ align-items: flex-start;
357
+ flex-direction: column;
358
+ }
359
+
360
+ .bbcode-draft-note {
361
+ text-align: left;
362
+ }
363
+
364
+ .bbcode-input-meta {
365
+ width: 100%;
366
+ }
367
+
368
+ .bbcode-output-grid {
369
+ grid-template-columns: 1fr;
370
+ }
371
+ }
372
+
373
+ @media (max-width: 460px) {
374
+ .bbcode-header,
375
+ .bbcode-input-card,
376
+ .bbcode-output-section,
377
+ .bbcode-preview-card {
378
+ padding-left: 0.85rem;
379
+ padding-right: 0.85rem;
380
+ }
381
+
382
+ .bbcode-input-meta {
383
+ justify-content: space-between;
384
+ }
385
+ }
386
+
387
+ @media (prefers-reduced-motion: reduce) {
388
+ .bbcode-root * {
389
+ scroll-behavior: auto;
390
+ transition-duration: 0.01ms;
391
+ }
392
+ }
@@ -0,0 +1,30 @@
1
+ import { STORAGE_KEY } from './types';
2
+
3
+ export function loadSourceFromStorage(): string | null {
4
+ if (typeof window === 'undefined') return null;
5
+ try {
6
+ const value = window.localStorage.getItem(STORAGE_KEY);
7
+ return value?.trim() ? value : null;
8
+ } catch {
9
+ return null;
10
+ }
11
+ }
12
+
13
+ export function saveSourceToStorage(source: string): void {
14
+ if (typeof window === 'undefined') return;
15
+ try {
16
+ if (source.trim()) window.localStorage.setItem(STORAGE_KEY, source);
17
+ else window.localStorage.removeItem(STORAGE_KEY);
18
+ } catch {
19
+ return;
20
+ }
21
+ }
22
+
23
+ export function clearSourceFromStorage(): void {
24
+ if (typeof window === 'undefined') return;
25
+ try {
26
+ window.localStorage.removeItem(STORAGE_KEY);
27
+ } catch {
28
+ return;
29
+ }
30
+ }
@@ -0,0 +1,36 @@
1
+ export type OutputFormat = 'markdown' | 'html';
2
+ export type TranslationDirection = 'bbcode-to-output' | 'output-to-bbcode';
3
+ export type MarkupSyntax = 'bbcode' | 'markdown' | 'html';
4
+
5
+ export interface TranslationStats {
6
+ characters: number;
7
+ tags: number;
8
+ blocks: number;
9
+ }
10
+
11
+ export interface TranslationResult {
12
+ output: string;
13
+ warnings: string[];
14
+ stats: TranslationStats;
15
+ }
16
+
17
+ export interface AutoTranslationResult {
18
+ detected: MarkupSyntax;
19
+ outputs: Partial<Record<MarkupSyntax, TranslationResult>>;
20
+ }
21
+
22
+ export interface TextNode {
23
+ kind: 'text';
24
+ value: string;
25
+ }
26
+
27
+ export interface TagNode {
28
+ kind: 'tag';
29
+ name: string;
30
+ value?: string | undefined;
31
+ children: Node[];
32
+ }
33
+
34
+ export type Node = TextNode | TagNode;
35
+
36
+ export const STORAGE_KEY = 'steam-bbcode-translator-draft-v1';
@@ -0,0 +1,18 @@
1
+ export interface SteamBbcodeTranslatorUI extends Record<string, string> {
2
+ editorLabel: string;
3
+ editorHint: string;
4
+ detectedLabel: string;
5
+ detectedEmpty: string;
6
+ bbcode: string;
7
+ markdown: string;
8
+ html: string;
9
+ copy: string;
10
+ copied: string;
11
+ clear: string;
12
+ characters: string;
13
+ blocks: string;
14
+ privacyNote: string;
15
+ persistenceNote: string;
16
+ previewLabel: string;
17
+ previewEmpty: string;
18
+ }
@@ -62,7 +62,7 @@
62
62
  }
63
63
 
64
64
  .steam-tab-btn.active {
65
- color: var(--text-light, #fff);
65
+ color: var(--text-dark, #0f172a);
66
66
  background: var(--accent-steam, #66c0f4);
67
67
  box-shadow: 0 2px 8px var(--accent-shadow, rgba(102, 192, 244, 0.3));
68
68
  }
@@ -298,7 +298,7 @@
298
298
  border: 2px dashed var(--accent-safe, #ff4757);
299
299
  background: var(--bg-safe, rgba(255, 71, 87, 0.15));
300
300
  color: var(--text-light, #fff);
301
- font-size: 0.7rem;
301
+ font-size: 0.75rem;
302
302
  font-weight: 700;
303
303
  padding: 0.25rem 0.5rem;
304
304
  pointer-events: none;
@@ -322,7 +322,7 @@
322
322
 
323
323
  .discount-tag {
324
324
  background: var(--bg-discount, #4c6b22);
325
- color: var(--accent-discount, #beee11);
325
+ color: var(--accent-discount, #fff);
326
326
  font-size: 1.1rem;
327
327
  font-weight: 800;
328
328
  padding: 0.35rem 0.6rem;
@@ -336,7 +336,7 @@
336
336
  }
337
337
 
338
338
  .original-price {
339
- font-size: 0.7rem;
339
+ font-size: 0.75rem;
340
340
  text-decoration: line-through;
341
341
  color: var(--text-muted-alt, #556772);
342
342
  }
@@ -546,7 +546,7 @@
546
546
  }
547
547
 
548
548
  .stat-label {
549
- font-size: 0.65rem;
549
+ font-size: 0.75rem;
550
550
  color: var(--text-muted, #8b99a8);
551
551
  text-transform: uppercase;
552
552
  }
@@ -672,7 +672,7 @@
672
672
  .steam-asset-badge {
673
673
  background: var(--bg-topbar, #0d121a);
674
674
  color: var(--accent-active, #67c1f5);
675
- font-size: 0.7rem;
675
+ font-size: 0.75rem;
676
676
  font-weight: 700;
677
677
  padding: 0.15rem 0.4rem;
678
678
  border-radius: 3px;
package/src/tools.ts CHANGED
@@ -6,6 +6,8 @@ import { SPRITE_SHEET_PACKER_TOOL } from './tool/spriteSheetPacker';
6
6
  import { AUDIO_LOOP_POINT_FINDER_TOOL } from './tool/audioLoopPointFinder';
7
7
  import { SAVE_FILE_EDITOR_TOOL } from './tool/saveFileEditor';
8
8
  import { LOCALIZATION_SANITIZER_TOOL } from './tool/localizationSanitizer';
9
+ import { STEAM_BBCODE_TRANSLATOR_TOOL } from './tool/steamBbcodeTranslator';
10
+ import { RETRO_SFX_GENERATOR_TOOL } from './tool/retroSfxGenerator';
9
11
 
10
12
  export const ALL_TOOLS: ToolDefinition[] = [
11
13
  STEAM_CAPSULE_GENERATOR_TOOL,
@@ -14,4 +16,6 @@ export const ALL_TOOLS: ToolDefinition[] = [
14
16
  AUDIO_LOOP_POINT_FINDER_TOOL,
15
17
  SAVE_FILE_EDITOR_TOOL,
16
18
  LOCALIZATION_SANITIZER_TOOL,
19
+ STEAM_BBCODE_TRANSLATOR_TOOL,
20
+ RETRO_SFX_GENERATOR_TOOL,
17
21
  ];