@jjlmoya/utils-tabletop 1.26.0 → 1.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/category/index.ts +2 -0
- package/src/entries.ts +2 -0
- package/src/index.ts +1 -0
- package/src/tests/locale_completeness.test.ts +1 -1
- package/src/tests/tool_validation.test.ts +1 -1
- package/src/tool/token-stamp-studio/bibliography.astro +16 -0
- package/src/tool/token-stamp-studio/bibliography.ts +12 -0
- package/src/tool/token-stamp-studio/component.astro +91 -0
- package/src/tool/token-stamp-studio/controller.ts +179 -0
- package/src/tool/token-stamp-studio/dom-views.ts +266 -0
- package/src/tool/token-stamp-studio/entry.ts +27 -0
- package/src/tool/token-stamp-studio/evaluator.ts +6 -0
- package/src/tool/token-stamp-studio/i18n/de.ts +132 -0
- package/src/tool/token-stamp-studio/i18n/en.ts +132 -0
- package/src/tool/token-stamp-studio/i18n/es.ts +132 -0
- package/src/tool/token-stamp-studio/i18n/fr.ts +132 -0
- package/src/tool/token-stamp-studio/i18n/id.ts +132 -0
- package/src/tool/token-stamp-studio/i18n/it.ts +132 -0
- package/src/tool/token-stamp-studio/i18n/ja.ts +132 -0
- package/src/tool/token-stamp-studio/i18n/ko.ts +132 -0
- package/src/tool/token-stamp-studio/i18n/nl.ts +132 -0
- package/src/tool/token-stamp-studio/i18n/pl.ts +132 -0
- package/src/tool/token-stamp-studio/i18n/pt.ts +132 -0
- package/src/tool/token-stamp-studio/i18n/ru.ts +132 -0
- package/src/tool/token-stamp-studio/i18n/sv.ts +132 -0
- package/src/tool/token-stamp-studio/i18n/tr.ts +132 -0
- package/src/tool/token-stamp-studio/i18n/zh.ts +132 -0
- package/src/tool/token-stamp-studio/index.ts +11 -0
- package/src/tool/token-stamp-studio/logic.test.ts +36 -0
- package/src/tool/token-stamp-studio/logic.ts +127 -0
- package/src/tool/token-stamp-studio/seo.astro +16 -0
- package/src/tool/token-stamp-studio/storage.ts +69 -0
- package/src/tool/token-stamp-studio/store.ts +139 -0
- package/src/tool/token-stamp-studio/token-stamp-studio.css +646 -0
- package/src/tool/token-stamp-studio/types.ts +65 -0
- package/src/tool/token-stamp-studio/ui.ts +50 -0
- package/src/tool/token-stamp-studio/workspace-media.ts +36 -0
- package/src/tool/token-stamp-studio/workspace.ts +83 -0
- package/src/tools.ts +2 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
|
|
2
|
+
import { bibliography } from '../bibliography';
|
|
3
|
+
import type { TokenStampLocaleContent, TokenStampUI } from '../entry';
|
|
4
|
+
|
|
5
|
+
const ui: TokenStampUI = {
|
|
6
|
+
frameLegend: 'Kies een frame',
|
|
7
|
+
frameHint: 'Kies het silhouet dat de tafel laat zien wie dit karakter is voordat iemand de naam leest.',
|
|
8
|
+
randomFrame: 'Willekeurig frame',
|
|
9
|
+
surfaceLegend: 'Geef kleur aan de token',
|
|
10
|
+
backgroundLabel: 'Achtergrond',
|
|
11
|
+
borderLabel: 'Rand',
|
|
12
|
+
textLabel: 'Tekst',
|
|
13
|
+
overlayLabel: 'Tint',
|
|
14
|
+
randomColors: 'Willekeurige kleuren',
|
|
15
|
+
borderWidthLabel: 'Randdikte',
|
|
16
|
+
opacityLabel: 'Randdekking',
|
|
17
|
+
overlayOpacityLabel: 'Portrettint',
|
|
18
|
+
stageLabel: 'Live token smederij',
|
|
19
|
+
chooseImage: 'Kies portret',
|
|
20
|
+
clearImage: 'Portret wissen',
|
|
21
|
+
positionHint: 'Sleep het portret of de labels rechtstreeks op de token.',
|
|
22
|
+
markerName: 'Markernaam',
|
|
23
|
+
markerNamePlaceholder: 'Geef deze marker een naam',
|
|
24
|
+
textLegend: 'Voeg leesbare details toe',
|
|
25
|
+
textHint: 'Gebruik korte labels zoals naam, niveau, rol of status. Sleep elk label naar de token.',
|
|
26
|
+
textPlaceholder: 'Karakternaam of rol',
|
|
27
|
+
addText: 'Label toevoegen',
|
|
28
|
+
removeText: 'Label verwijderen',
|
|
29
|
+
textSizeLabel: 'Tekstgrootte',
|
|
30
|
+
alignmentLabel: 'Tekstuitlijning',
|
|
31
|
+
alignLeft: 'Links uitlijnen',
|
|
32
|
+
alignCenter: 'Centreren',
|
|
33
|
+
alignRight: 'Rechts uitlijnen',
|
|
34
|
+
imageLegend: 'Pas het portret aan',
|
|
35
|
+
imageZoomLabel: 'Portretzoom',
|
|
36
|
+
scaleLabel: 'Exportschaal',
|
|
37
|
+
savedMarkers: 'Opgeslagen markers',
|
|
38
|
+
noSavedMarkers: 'Opgeslagen markers verschijnen hier om opnieuw te openen en te bewerken.',
|
|
39
|
+
reuseMarker: 'Selecteer een marker om deze opnieuw te openen.',
|
|
40
|
+
deleteMarker: 'Marker verwijderen',
|
|
41
|
+
newMarker: 'Nieuwe marker',
|
|
42
|
+
download: 'PNG downloaden',
|
|
43
|
+
copy: 'PNG kopiëren',
|
|
44
|
+
downloadBatch: 'Batch downloaden',
|
|
45
|
+
batchLabel: 'Geavanceerde batchexport',
|
|
46
|
+
batchHint: 'Optioneel: exporteer meerdere portretten met het huidige frame en de kleurinstellingen.',
|
|
47
|
+
chooseBatch: 'Kies portretten',
|
|
48
|
+
batchReady: '{count} portretten klaar om te smeden.',
|
|
49
|
+
noImage: 'Geen portret geladen',
|
|
50
|
+
noText: 'Nog geen labels. Voeg details toe die je groep nodig heeft.',
|
|
51
|
+
tokenDetails: 'Karaktertoken bediening',
|
|
52
|
+
exportHint: 'De PNG is transparant buiten het gekozen silhouet, klaar voor VTT of afdrukken.',
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const faq = [
|
|
56
|
+
{
|
|
57
|
+
question: 'Wat maakt een goed portret voor een karaktertoken?',
|
|
58
|
+
answer: 'Kies een afbeelding met een duidelijk gezicht en voldoende contrast met het frame. Een uitsnede van hoofd en schouders blijft goed leesbaar op het virtuele speelbord.',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
question: 'Hoe positioneer ik het portret het beste in het frame?',
|
|
62
|
+
answer: 'Upload de afbeelding en sleep deze op de token om het gezicht te centreren. Gebruik de portretzoom om het gezicht te vergroten zonder het frame aan te passen.',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
question: 'Kan ik een karakternaam en niveau toevoegen?',
|
|
66
|
+
answer: 'Ja. Voeg korte labels toe, pas de tekstgrootte en uitlijning aan, en sleep ze naar een goed leesbare plek op de token.',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
question: 'Blijft het PNG-bestand transparant buiten de token?',
|
|
70
|
+
answer: 'Ja. Het geëxporteerde bestand behoudt een transparante achtergrond buiten het gekozen silhouet, ideaal voor gebruik op digitale kaarten.',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
question: 'Kan ik in één keer tokens voor een hele groep maken?',
|
|
74
|
+
answer: 'Ja. Gebruik de batchexport om meerdere portretten in te laden en voor elk portret een transparante PNG te genereren.',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
question: 'Waar worden mijn opgeslagen markers opgeslagen?',
|
|
78
|
+
answer: 'Markers worden lokaal opgeslagen in je browser. Er worden geen afbeeldingen naar een externe server geüpload.',
|
|
79
|
+
},
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
const howTo = [
|
|
83
|
+
{ name: 'Kies het karaktersilhouet', text: 'Selecteer een frame dat bij de rol past: rond voor een held, zeshoekig voor tactische gevechten of een ster voor een baas.' },
|
|
84
|
+
{ name: 'Upload en centreer het portret', text: 'Kies een afbeelding, sleep deze naar de token en pas de zoom aan zodat het gezicht centraal staat.' },
|
|
85
|
+
{ name: 'Voeg belangrijke informatie toe', text: 'Plaats een korte naam of status op de token zonder de illustratie te overlappen.' },
|
|
86
|
+
{ name: 'Exporteer als transparante PNG', text: 'Download de transparante PNG voor gebruik op je digitale speelbord of printvel.' },
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
const faqSchema: WithContext<FAQPage> = {
|
|
90
|
+
'@context': 'https://schema.org',
|
|
91
|
+
'@type': 'FAQPage',
|
|
92
|
+
mainEntity: faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })),
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const appSchema: WithContext<SoftwareApplication> = {
|
|
96
|
+
'@context': 'https://schema.org',
|
|
97
|
+
'@type': 'SoftwareApplication',
|
|
98
|
+
name: 'Token Stamp Studio',
|
|
99
|
+
operatingSystem: 'All',
|
|
100
|
+
applicationCategory: 'DesignApplication',
|
|
101
|
+
description: 'Maak duidelijke karaktertokens voor tafel-RPG\'s met aangepaste frames, labels, transparantie en batchexport.',
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const howToSchema: WithContext<HowTo> = {
|
|
105
|
+
'@context': 'https://schema.org',
|
|
106
|
+
'@type': 'HowTo',
|
|
107
|
+
name: 'Hoe maak je een karaktertoken voor tafel-RPG\'s',
|
|
108
|
+
step: howTo.map((item) => ({ '@type': 'HowToStep', name: item.name, text: item.text })),
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
export const content: TokenStampLocaleContent = {
|
|
112
|
+
slug: 'karakter-token-maker-rpg-tafel',
|
|
113
|
+
title: 'Karakter Token Maker voor Tafel RPGs',
|
|
114
|
+
description: 'Maak duidelijke karaktertokens voor tafel-RPG\'s met aangepaste frames, labels, transparantie en batchexport.',
|
|
115
|
+
ui,
|
|
116
|
+
seo: [
|
|
117
|
+
{ type: 'title', text: 'Ontwerp duidelijke karaktertokens voor elke digitale kaart van je RPG avontuur', level: 2 },
|
|
118
|
+
{ type: 'paragraph', html: 'Een token is een essentieel visueel communicatiemiddel op de virtuele speeltafel. Het silhouet laat de groep meteen zien of het om een held, een gevaarlijk monster, een betoveringseffect of een belangrijke bondgenoot gaat voordat iemand inzoomt op de kaart. Kies het juiste frame en zorg dat het gezicht en de tekst goed zichtbaar blijven op de schaal van jouw speelbord.' },
|
|
119
|
+
{ type: 'title', text: 'Kies het juiste frame voor elk type karakter in je campagne', level: 2 },
|
|
120
|
+
{ type: 'list', items: ['<strong>Rond of ring:</strong> klassiek en betrouwbaar voor spelerskarakters en terugkerende bondgenoten.', '<strong>Zeshoek of achthoek:</strong> ideaal voor tactische gevechten met veel verschillende eenheden.', '<strong>Ster:</strong> perfect voor bazen, kampioenen of karakters die direct de aandacht vragen.', '<strong>Wolk:</strong> een zachte vorm voor geesten, magische wezens en fabeldieren.'] },
|
|
121
|
+
{ type: 'tip', title: 'Ontwerp voor het kleinste formaat waarop je daadwerkelijk speelt', html: 'Zoom uit op de digitale kaart totdat de token slechts enkele tientallen pixels groot is. Als gezicht, rand en tekst nog steeds goed te onderscheiden zijn, werkt je token perfect tijdens drukke gevechten.' },
|
|
122
|
+
{ type: 'title', text: 'Houd labels kort en functioneel tijdens het spelen', level: 2 },
|
|
123
|
+
{ type: 'paragraph', html: 'Een token is geen vervanging voor een volledig karakterblad. Voeg alleen de belangrijkste informatie toe die de tafel voortdurend nodig heeft: een korte naam, een niveau, een rol of een status zoals verdoofd. Te lange zinnen zorgen voor visuele ruis en leiden af van het portret.' },
|
|
124
|
+
{ type: 'title', text: 'Maak in één keer tokens voor de hele avonturiersgroep zonder hun identiteit te verliezen', level: 2 },
|
|
125
|
+
{ type: 'paragraph', html: 'Met de batchexport geef je de hele avonturiersgroep dezelfde visuele stijl terwijl elk portret zijn eigen unieke uitstraling behoudt. Een consistente framing zorgt voor eenheid in de groep terwijl de gezichten direct herkenbaar blijven.' },
|
|
126
|
+
{ type: 'tip', title: 'Automatische lokale opslag op jouw apparaat', html: 'Je actieve marker wordt automatisch opgeslagen in de lokale opslag van je browser zodat je deze later eenvoudig kunt openen en aanpassen wanneer het karakter in niveau stijgt.' },
|
|
127
|
+
],
|
|
128
|
+
faq,
|
|
129
|
+
bibliography,
|
|
130
|
+
howTo,
|
|
131
|
+
schemas: [faqSchema, appSchema, howToSchema] as unknown as Record<string, unknown>[],
|
|
132
|
+
};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
|
|
2
|
+
import { bibliography } from '../bibliography';
|
|
3
|
+
import type { TokenStampLocaleContent, TokenStampUI } from '../entry';
|
|
4
|
+
|
|
5
|
+
const ui: TokenStampUI = {
|
|
6
|
+
frameLegend: 'Wybierz ramkę',
|
|
7
|
+
frameHint: 'Wybierz sylwetkę, która informuje graczy, kim jest postać, zanim przeczytają jej imię.',
|
|
8
|
+
randomFrame: 'Losowa ramka',
|
|
9
|
+
surfaceLegend: 'Stylizuj żeton',
|
|
10
|
+
backgroundLabel: 'Tło',
|
|
11
|
+
borderLabel: 'Ramka',
|
|
12
|
+
textLabel: 'Tekst',
|
|
13
|
+
overlayLabel: 'Odcień',
|
|
14
|
+
randomColors: 'Losowe kolory',
|
|
15
|
+
borderWidthLabel: 'Grubość ramki',
|
|
16
|
+
opacityLabel: 'Przezroczystość ramki',
|
|
17
|
+
overlayOpacityLabel: 'Odcień portretu',
|
|
18
|
+
stageLabel: 'Kuźnia żetonów na żywo',
|
|
19
|
+
chooseImage: 'Wybierz portret',
|
|
20
|
+
clearImage: 'Usuń portret',
|
|
21
|
+
positionHint: 'Przeciągnij portret lub etykiety bezpośrednio na żetonie.',
|
|
22
|
+
markerName: 'Nazwa znacznika',
|
|
23
|
+
markerNamePlaceholder: 'Nazwij ten znacznik',
|
|
24
|
+
textLegend: 'Dodaj czytelne detale',
|
|
25
|
+
textHint: 'Używaj krótkich etykiet, takich jak imię, poziom, rola lub status. Przeciągnij każdą na żeton.',
|
|
26
|
+
textPlaceholder: 'Imię postaci lub rola',
|
|
27
|
+
addText: 'Dodaj etykietę',
|
|
28
|
+
removeText: 'Usuń etykietę',
|
|
29
|
+
textSizeLabel: 'Rozmiar czcionki',
|
|
30
|
+
alignmentLabel: 'Wyrównanie etykiety',
|
|
31
|
+
alignLeft: 'Wyrównaj do lewej',
|
|
32
|
+
alignCenter: 'Wyśrodkuj',
|
|
33
|
+
alignRight: 'Wyrównaj do prawej',
|
|
34
|
+
imageLegend: 'Dostosuj portret',
|
|
35
|
+
imageZoomLabel: 'Powiększenie portretu',
|
|
36
|
+
scaleLabel: 'Skala eksportu',
|
|
37
|
+
savedMarkers: 'Zapisane znaczniki',
|
|
38
|
+
noSavedMarkers: 'Zapisane znaczniki pojawią się tutaj, aby móc je ponownie otworzyć i edytować.',
|
|
39
|
+
reuseMarker: 'Wybierz znacznik, aby otworzyć go w kuźni.',
|
|
40
|
+
deleteMarker: 'Usuń znacznik',
|
|
41
|
+
newMarker: 'Nowy znacznik',
|
|
42
|
+
download: 'Pobierz PNG',
|
|
43
|
+
copy: 'Kopiuj PNG',
|
|
44
|
+
downloadBatch: 'Pobierz paczkę',
|
|
45
|
+
batchLabel: 'Zaawansowany eksport seryjny',
|
|
46
|
+
batchHint: 'Opcjonalnie: wyeksportuj kilka portretów z aktualną ramką i kolorami.',
|
|
47
|
+
chooseBatch: 'Wybierz portrety',
|
|
48
|
+
batchReady: '{count} portretów gotowych do wykucia.',
|
|
49
|
+
noImage: 'Brak załadowanego portretu',
|
|
50
|
+
noText: 'Brak etykiet. Dodaj szczegóły potrzebne twojej drużynie.',
|
|
51
|
+
tokenDetails: 'Sterowanie żetonem postaci',
|
|
52
|
+
exportHint: 'Plik PNG jest przezroczysty poza wybraną sylwetką, gotowy do VTT lub druku.',
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const faq = [
|
|
56
|
+
{
|
|
57
|
+
question: 'Co decyduje o dobrym portrecie na żetonie postaci?',
|
|
58
|
+
answer: 'Wybierz ilustrację z wyraźną twarzą i dobrym kontrastem względem ramki. Kadr od głowy do ramion pozostaje czytelny nawet przy znacznej pomniejszeniu na wirtualnym stole.',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
question: 'Jak najlepiej wykadrować portret w ramce?',
|
|
62
|
+
answer: 'Wgraj obraz i przeciągnij go bezpośrednio na żetonie. Użyj powiększenia portretu, aby przybliżyć twarz bez zmiany kształtu ramki.',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
question: 'Czy mogę dodać imię postaci i poziom?',
|
|
66
|
+
answer: 'Tak. Dodaj krótkie etykiety, dostosuj ich rozmiar i wyrównanie, a następnie przeciągnij je w czytelne miejsce na żetonie.',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
question: 'Czy plik PNG zachowuje przezroczystość poza ramką?',
|
|
70
|
+
answer: 'Tak. Wyeksportowany plik PNG ma przezroczyste tło poza wybraną sylwetką, co ułatwia nakładanie żetonu na mapy.',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
question: 'Czy mogę stworzyć żetony dla całej drużyny jednocześnie?',
|
|
74
|
+
answer: 'Tak. Użyj eksportu seryjnego, aby załadować wiele portretów i wygenerować przezroczysty plik PNG dla każdego z nich.',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
question: 'Gdzie przechowywane są moje zapisane znaczniki?',
|
|
78
|
+
answer: 'Zapisane znaczniki są przechowywane lokalnie w pamięci Twojej przeglądarki. Żadne pliki nie są wysyłane na zewnętrzne serwery.',
|
|
79
|
+
},
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
const howTo = [
|
|
83
|
+
{ name: 'Wybierz sylwetkę postaci', text: 'Zacznij od ramki pasującej do roli: okrągłej dla bohatera, sześciokątnej do walki taktycznej lub gwiazdy dla bossa.' },
|
|
84
|
+
{ name: 'Wgraj i dopasuj portret', text: 'Wybierz obraz, przeciągnij go na żeton i dostosuj powiększenie tak, aby twarz była w centrum.' },
|
|
85
|
+
{ name: 'Dodaj przydatne etykiety', text: 'Wpisz krótkie imię lub status, nie zasłaniając kluczowych elementów ilustracji.' },
|
|
86
|
+
{ name: 'Wyeksportuj jako przezroczysty PNG', text: 'Pobierz plik PNG gotowy do użycia na wirtualnym stole (VTT) lub w druku.' },
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
const faqSchema: WithContext<FAQPage> = {
|
|
90
|
+
'@context': 'https://schema.org',
|
|
91
|
+
'@type': 'FAQPage',
|
|
92
|
+
mainEntity: faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })),
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const appSchema: WithContext<SoftwareApplication> = {
|
|
96
|
+
'@context': 'https://schema.org',
|
|
97
|
+
'@type': 'SoftwareApplication',
|
|
98
|
+
name: 'Token Stamp Studio',
|
|
99
|
+
operatingSystem: 'All',
|
|
100
|
+
applicationCategory: 'DesignApplication',
|
|
101
|
+
description: 'Twórz czytelne żetony postaci do gier RPG z własnymi ramkami, etykietami, przezroczystością i eksportem seryjnym PNG.',
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const howToSchema: WithContext<HowTo> = {
|
|
105
|
+
'@context': 'https://schema.org',
|
|
106
|
+
'@type': 'HowTo',
|
|
107
|
+
name: 'Jak zrobić żeton postaci do RPG',
|
|
108
|
+
step: howTo.map((item) => ({ '@type': 'HowToStep', name: item.name, text: item.text })),
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
export const content: TokenStampLocaleContent = {
|
|
112
|
+
slug: 'kreator-zetonow-postaci-rpg-stolosw',
|
|
113
|
+
title: 'Kreator Żetonów Postaci do Gier RPG (Tokens)',
|
|
114
|
+
description: 'Twórz czytelne żetony postaci do gier RPG z własnymi ramkami, etykietami, przezroczystością i eksportem seryjnym PNG.',
|
|
115
|
+
ui,
|
|
116
|
+
seo: [
|
|
117
|
+
{ type: 'title', text: 'Projektuj czytelne żetony postaci na dowolną mapę gry RPG', level: 2 },
|
|
118
|
+
{ type: 'paragraph', html: 'Żeton to kluczowy element komunikacji wizualnej na stole gry RPG. Jego sylwetka natychmiast informuje drużynę, czy ma do czynienia z bohaterem, potworem, efektem zaklęcia czy postronnym NPC zanim ktokolwiek przybliży widok mapy. Wybierz odpowiednią ramkę i zadbaj o pełną czytelność ilustracji oraz napisów na wirtualnym stole.' },
|
|
119
|
+
{ type: 'title', text: 'Dobierz właściwą ramkę do charakteru i roli postaci', level: 2 },
|
|
120
|
+
{ type: 'list', items: ['<strong>Koło lub pierścień:</strong> klasyczny i niezawodny wybór dla postaci graczy oraz stałych sojuszników.', '<strong>Sześciokąt lub ośmiokąt:</strong> świetny do starć taktycznych z wieloma jednostkami na planszy.', '<strong>Gwiazda:</strong> idealna dla bossów, championów i kluczowych celów wymagających natychmiastowej uwagi.', '<strong>Chmura:</strong> miękki kształt dla istot duchowych, chowańców i istot fantastycznych.'] },
|
|
121
|
+
{ type: 'tip', title: 'Projektuj z myślą o najmniejszym rozmiarze na mapie taktycznej', html: 'Oddal widok mapy, aż żeton stanie się bardzo mały. Jeśli twarz, ramka i tekst nadal są wyraźnie rozróżnialne, Twój żeton sprawdzi się świetnie podczas dynamicznej rozgrywki.' },
|
|
122
|
+
{ type: 'title', text: 'Stosuj krótkie i przydatne etykiety podczas sesji', level: 2 },
|
|
123
|
+
{ type: 'paragraph', html: 'Żeton nie zastępuje karty postaci. Dodaj tylko najpotrzebniejsze informacje, takie jak imię, poziom lub aktualny status postaci (np. ogłuszony). Długie zdania tworzą szum wizualny i zasłaniają portret.' },
|
|
124
|
+
{ type: 'title', text: 'Przygotuj żetony dla całej drużyny za jednym razem bez utraty ich stylu', level: 2 },
|
|
125
|
+
{ type: 'paragraph', html: 'Eksport seryjny pozwala nadać spójny styl graficzny całej drużynie po sesji zero, zachowując indywidualny charakter każdego portretu. Jednolita ramka spaja drużynę wizualnie.' },
|
|
126
|
+
{ type: 'tip', title: 'Automatyczne zapisywanie lokalne na Twoim urządzeniu', html: 'Prace nad żetonem są automatycznie zapisywane w pamięci przeglądarki, dzięki czemu możesz łatwo modyfikować go w trakcie trwania całej kampanii.' },
|
|
127
|
+
],
|
|
128
|
+
faq,
|
|
129
|
+
bibliography,
|
|
130
|
+
howTo,
|
|
131
|
+
schemas: [faqSchema, appSchema, howToSchema] as unknown as Record<string, unknown>[],
|
|
132
|
+
};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
|
|
2
|
+
import { bibliography } from '../bibliography';
|
|
3
|
+
import type { TokenStampLocaleContent, TokenStampUI } from '../entry';
|
|
4
|
+
|
|
5
|
+
const ui: TokenStampUI = {
|
|
6
|
+
frameLegend: 'Escolha uma moldura',
|
|
7
|
+
frameHint: 'Escolha a silhueta que indica à mesa quem é a personagem antes mesmo de lerem o nome.',
|
|
8
|
+
randomFrame: 'Moldura aleatória',
|
|
9
|
+
surfaceLegend: 'Pinte o token',
|
|
10
|
+
backgroundLabel: 'Fundo',
|
|
11
|
+
borderLabel: 'Borda',
|
|
12
|
+
textLabel: 'Texto',
|
|
13
|
+
overlayLabel: 'Tinta',
|
|
14
|
+
randomColors: 'Cores aleatórias',
|
|
15
|
+
borderWidthLabel: 'Espessura da borda',
|
|
16
|
+
opacityLabel: 'Opacidade da borda',
|
|
17
|
+
overlayOpacityLabel: 'Tinta do retrato',
|
|
18
|
+
stageLabel: 'Forja de tokens em tempo real',
|
|
19
|
+
chooseImage: 'Escolher retrato',
|
|
20
|
+
clearImage: 'Remover retrato',
|
|
21
|
+
positionHint: 'Arraste o retrato ou as etiquetas diretamente sobre o token.',
|
|
22
|
+
markerName: 'Nome do marcador',
|
|
23
|
+
markerNamePlaceholder: 'Dê um nome a este marcador',
|
|
24
|
+
textLegend: 'Adicione detalhes legíveis',
|
|
25
|
+
textHint: 'Use etiquetas curtas como nome, nível, função ou estado. Arraste cada uma para o token.',
|
|
26
|
+
textPlaceholder: 'Nome da personagem ou função',
|
|
27
|
+
addText: 'Adicionar etiqueta',
|
|
28
|
+
removeText: 'Remover etiqueta',
|
|
29
|
+
textSizeLabel: 'Tamanho da fonte',
|
|
30
|
+
alignmentLabel: 'Alinhamento do texto',
|
|
31
|
+
alignLeft: 'Alinhar à esquerda',
|
|
32
|
+
alignCenter: 'Centralizar',
|
|
33
|
+
alignRight: 'Alinhar à direita',
|
|
34
|
+
imageLegend: 'Ajuste o retrato',
|
|
35
|
+
imageZoomLabel: 'Zoom do retrato',
|
|
36
|
+
scaleLabel: 'Escala de exportação',
|
|
37
|
+
savedMarkers: 'Marcadores salvos',
|
|
38
|
+
noSavedMarkers: 'Os marcadores salvos aparecerão aqui para você reabrir e editar quando quiser.',
|
|
39
|
+
reuseMarker: 'Selecione um marcador para reabri-lo na forja.',
|
|
40
|
+
deleteMarker: 'Excluir marcador',
|
|
41
|
+
newMarker: 'Novo marcador',
|
|
42
|
+
download: 'Baixar PNG',
|
|
43
|
+
copy: 'Copiar PNG',
|
|
44
|
+
downloadBatch: 'Baixar lote',
|
|
45
|
+
batchLabel: 'Exportação avançada em lote',
|
|
46
|
+
batchHint: 'Opcional: exporte vários retratos com a moldura e cores atuais.',
|
|
47
|
+
chooseBatch: 'Escolher retratos',
|
|
48
|
+
batchReady: '{count} retratos prontos para forjar.',
|
|
49
|
+
noImage: 'Nenhum retrato carregado',
|
|
50
|
+
noText: 'Sem etiquetas ainda. Adicione as informações de que seu grupo precisa.',
|
|
51
|
+
tokenDetails: 'Controles do token de personagem',
|
|
52
|
+
exportHint: 'O PNG é transparente fora da silhueta escolhida, pronto para VTT ou folha impressa.',
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const faq = [
|
|
56
|
+
{
|
|
57
|
+
question: 'O que faz um bom retrato para token de personagem?',
|
|
58
|
+
answer: 'Escolha uma ilustração com um rosto claro e bom contraste com a moldura. Um corte de cabeça e ombros permanece legível mesmo quando o token é pequeno na mesa virtual.',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
question: 'Como posicionar o retrato corretamente na moldura?',
|
|
62
|
+
answer: 'Carregue a imagem e arraste-a diretamente no token. Use o zoom de retrato para aproximar o rosto sem alterar o formato da borda.',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
question: 'Posso adicionar o nome e o nível da personagem?',
|
|
66
|
+
answer: 'Sim. Adicione etiquetas curtas, ajuste o tamanho e o alinhamento e arraste para uma posição legível no token.',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
question: 'O arquivo PNG mantém a transparência fora do token?',
|
|
70
|
+
answer: 'Sim. A imagem exportada mantém o fundo transparente fora da silhueta selecionada, facilitando a colocação sobre mapas.',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
question: 'Posso criar tokens para todo o grupo de uma vez?',
|
|
74
|
+
answer: 'Sim. Use a exportação em lote para carregar vários retratos e baixar um arquivo PNG transparente para cada um mantendo as configurações.',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
question: 'Onde meus marcadores salvos ficam armazenados?',
|
|
78
|
+
answer: 'Os marcadores salvos ficam armazenados localmente no seu navegador. Nenhuma imagem é enviada para servidores externos.',
|
|
79
|
+
},
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
const howTo = [
|
|
83
|
+
{ name: 'Escolha a silhueta da personagem', text: 'Selecione a moldura ideal: circular para heróis, hexagonal para combate tático ou estrela para chefes.' },
|
|
84
|
+
{ name: 'Carregue e enquadre o retrato', text: 'Escolha a imagem, arraste-a no token e ajuste o zoom para centralizar o rosto.' },
|
|
85
|
+
{ name: 'Adicione informações importantes', text: 'Insira um nome curto ou estado sem poluir a ilustração.' },
|
|
86
|
+
{ name: 'Exporte como PNG transparente', text: 'Baixe o arquivo PNG transparente pronto para ser usado no seu VTT ou impresso.' },
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
const faqSchema: WithContext<FAQPage> = {
|
|
90
|
+
'@context': 'https://schema.org',
|
|
91
|
+
'@type': 'FAQPage',
|
|
92
|
+
mainEntity: faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })),
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const appSchema: WithContext<SoftwareApplication> = {
|
|
96
|
+
'@context': 'https://schema.org',
|
|
97
|
+
'@type': 'SoftwareApplication',
|
|
98
|
+
name: 'Token Stamp Studio',
|
|
99
|
+
operatingSystem: 'All',
|
|
100
|
+
applicationCategory: 'DesignApplication',
|
|
101
|
+
description: 'Crie tokens de personagem legíveis para RPG de mesa com molduras personalizadas, etiquetas, transparência e exportação em lote.',
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const howToSchema: WithContext<HowTo> = {
|
|
105
|
+
'@context': 'https://schema.org',
|
|
106
|
+
'@type': 'HowTo',
|
|
107
|
+
name: 'Como fazer um token de personagem para RPG de mesa',
|
|
108
|
+
step: howTo.map((item) => ({ '@type': 'HowToStep', name: item.name, text: item.text })),
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
export const content: TokenStampLocaleContent = {
|
|
112
|
+
slug: 'criador-tokens-personagens-rpg-mesa',
|
|
113
|
+
title: 'Criador de Tokens de Personagem para RPG de Mesa',
|
|
114
|
+
description: 'Crie tokens de personagem legíveis para RPG de mesa com molduras personalizadas, etiquetas, transparência e exportação em lote.',
|
|
115
|
+
ui,
|
|
116
|
+
seo: [
|
|
117
|
+
{ type: 'title', text: 'Crie tokens de personagem claros e legíveis no mapa', level: 2 },
|
|
118
|
+
{ type: 'paragraph', html: 'Um token é um elemento fundamental de comunicação na mesa de jogo. Sua silhueta mostra imediatamente ao grupo se trata de um herói, monstro ou aliado. Escolha a moldura certa e mantenha o rosto e o texto legíveis.' },
|
|
119
|
+
{ type: 'title', text: 'Escolha a moldura certa para a personagem', level: 2 },
|
|
120
|
+
{ type: 'list', items: ['<strong>Círculo:</strong> padrão para personagens de jogadores e aliados.', '<strong>Hexágono ou octógono:</strong> ótimo para combates táticos com muitas unidades.', '<strong>Estrela:</strong> perfeito para chefes, campeões ou alvos prioritários.', '<strong>Nuvem:</strong> formato suave para espíritos, familiares e criaturas místicas.'] },
|
|
121
|
+
{ type: 'tip', title: 'Projete pensando no menor tamanho de exibição', html: 'Reduza o zoom do mapa até que o token fique pequeno. Se o rosto e o texto continuarem visíveis, seu token funcionará perfeitamente.' },
|
|
122
|
+
{ type: 'title', text: 'Etiquetas curtas e úteis durante a partida', level: 2 },
|
|
123
|
+
{ type: 'paragraph', html: 'O token não deve substituir a ficha de personagem. Adicione apenas os dados mais consultados: nome curto, nível ou estado atual.' },
|
|
124
|
+
{ type: 'title', text: 'Prepare todo o grupo de aventureiros de uma só vez', level: 2 },
|
|
125
|
+
{ type: 'paragraph', html: 'A exportação em lote permite padronizar o estilo do grupo mantendo a identidade visual de cada personagem.' },
|
|
126
|
+
{ type: 'tip', title: 'Salvamento automático no seu dispositivo', html: 'O marcador ativo fica salvo no seu navegador para que você possa editá-lo facilmente quando a personagem subir de nível.' },
|
|
127
|
+
],
|
|
128
|
+
faq,
|
|
129
|
+
bibliography,
|
|
130
|
+
howTo,
|
|
131
|
+
schemas: [faqSchema, appSchema, howToSchema] as unknown as Record<string, unknown>[],
|
|
132
|
+
};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
|
|
2
|
+
import { bibliography } from '../bibliography';
|
|
3
|
+
import type { TokenStampLocaleContent, TokenStampUI } from '../entry';
|
|
4
|
+
|
|
5
|
+
const ui: TokenStampUI = {
|
|
6
|
+
frameLegend: 'Выберите рамку',
|
|
7
|
+
frameHint: 'Выберите силуэт, который указывает игрокам на роль персонажа еще до чтения имени.',
|
|
8
|
+
randomFrame: 'Случайная рамка',
|
|
9
|
+
surfaceLegend: 'Оформление жетона',
|
|
10
|
+
backgroundLabel: 'Фон',
|
|
11
|
+
borderLabel: 'Рамка',
|
|
12
|
+
textLabel: 'Текст',
|
|
13
|
+
overlayLabel: 'Оттенок',
|
|
14
|
+
randomColors: 'Случайные цвета',
|
|
15
|
+
borderWidthLabel: 'Толщина рамки',
|
|
16
|
+
opacityLabel: 'Прозрачность рамки',
|
|
17
|
+
overlayOpacityLabel: 'Оттенок портрета',
|
|
18
|
+
stageLabel: 'Кузница жетонов',
|
|
19
|
+
chooseImage: 'Выбрать портрет',
|
|
20
|
+
clearImage: 'Удалить портрет',
|
|
21
|
+
positionHint: 'Перетаскивайте портрет и подписи прямо на жетоне.',
|
|
22
|
+
markerName: 'Название маркера',
|
|
23
|
+
markerNamePlaceholder: 'Назовите этот маркер',
|
|
24
|
+
textLegend: 'Добавьте понятные детали',
|
|
25
|
+
textHint: 'Используйте короткие подписи: имя, уровень, роль или статус. Перетащите их на жетон.',
|
|
26
|
+
textPlaceholder: 'Имя персонажа или роль',
|
|
27
|
+
addText: 'Добавить подпись',
|
|
28
|
+
removeText: 'Удалить подпись',
|
|
29
|
+
textSizeLabel: 'Размер шрифта',
|
|
30
|
+
alignmentLabel: 'Выравнивание текста',
|
|
31
|
+
alignLeft: 'По левому краю',
|
|
32
|
+
alignCenter: 'По центру',
|
|
33
|
+
alignRight: 'По правому краю',
|
|
34
|
+
imageLegend: 'Настройка портрета',
|
|
35
|
+
imageZoomLabel: 'Масштаб портрета',
|
|
36
|
+
scaleLabel: 'Масштаб экспорта',
|
|
37
|
+
savedMarkers: 'Сохраненные маркеры',
|
|
38
|
+
noSavedMarkers: 'Сохраненные маркеры появятся здесь для повторного редактирования и использования.',
|
|
39
|
+
reuseMarker: 'Выберите маркер для повторного открытия.',
|
|
40
|
+
deleteMarker: 'Удалить маркер',
|
|
41
|
+
newMarker: 'Новый маркер',
|
|
42
|
+
download: 'Скачать PNG',
|
|
43
|
+
copy: 'Копировать PNG',
|
|
44
|
+
downloadBatch: 'Скачать пакет',
|
|
45
|
+
batchLabel: 'Расширенный пакетный экспорт',
|
|
46
|
+
batchHint: 'Экспортируйте несколько портретов с текущими настройками рамки и цвета.',
|
|
47
|
+
chooseBatch: 'Выбрать портреты',
|
|
48
|
+
batchReady: '{count} портретов готово к созданию.',
|
|
49
|
+
noImage: 'Портрет не загружен',
|
|
50
|
+
noText: 'Подписей пока нет. Добавьте нужную информацию.',
|
|
51
|
+
tokenDetails: 'Управление жетоном персонажа',
|
|
52
|
+
exportHint: 'Файл PNG прозрачен за пределами силуэта и готов для VTT или печати.',
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const faq = [
|
|
56
|
+
{
|
|
57
|
+
question: 'Каким должен быть хороший портрет для жетона персонажа?',
|
|
58
|
+
answer: 'Выбирайте изображение с четким лицом и контрастным фоном. Кадрирование по плечи остается читаемым даже при сильном уменьшении жетона на виртуальном столе.',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
question: 'Как правильно расположить портрет в рамке?',
|
|
62
|
+
answer: 'Загрузите картинку и перетащите ее прямо на жетоне. Используйте масштаб портрета, чтобы приблизить лицо без изменения формы рамки.',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
question: 'Можно ли добавить имя и уровень персонажа?',
|
|
66
|
+
answer: 'Да. Добавляйте короткие подписи, настраивайте их размер и выравнивание, а затем перетаскивайте в удобное место на жетоне.',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
question: 'Сохраняется ли прозрачность фона в формате PNG?',
|
|
70
|
+
answer: 'Да. Экспортированное изображение имеет прозрачный фон за пределами силуэта, что удобно для размещения на картах.',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
question: 'Можно ли создать жетоны для всей группы одновременно?',
|
|
74
|
+
answer: 'Да. Используйте пакетный экспорт, чтобы загрузить несколько портретов и получить прозрачные PNG для каждого из них.',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
question: 'Где хранятся мои сохраненные маркеры?',
|
|
78
|
+
answer: 'Маркеры сохраняются локально в вашем браузере. Изображения не отправляются на сторонние серверы.',
|
|
79
|
+
},
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
const howTo = [
|
|
83
|
+
{ name: 'Выберите силуэт персонажа', text: 'Подберите рамку: круглую для героя, шестигранную для тактического боя или звезду для босса.' },
|
|
84
|
+
{ name: 'Загрузите и выровняйте портрет', text: 'Перетащите файл на жетон и настройте масштаб так, чтобы лицо было в центре.' },
|
|
85
|
+
{ name: 'Добавьте важную информацию', text: 'Укажите короткое имя или статус, не перекрывая важные детали иллюстрации.' },
|
|
86
|
+
{ name: 'Экспортируйте в PNG с прозрачностью', text: 'Скачайте готовый файл PNG для использования на VTT или для печати.' },
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
const faqSchema: WithContext<FAQPage> = {
|
|
90
|
+
'@context': 'https://schema.org',
|
|
91
|
+
'@type': 'FAQPage',
|
|
92
|
+
mainEntity: faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })),
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const appSchema: WithContext<SoftwareApplication> = {
|
|
96
|
+
'@context': 'https://schema.org',
|
|
97
|
+
'@type': 'SoftwareApplication',
|
|
98
|
+
name: 'Token Stamp Studio',
|
|
99
|
+
operatingSystem: 'All',
|
|
100
|
+
applicationCategory: 'DesignApplication',
|
|
101
|
+
description: 'Создание понятных жетонов персонажей для настольных RPG с рамками, подписями, прозрачным фоном и пакетным экспортом.',
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const howToSchema: WithContext<HowTo> = {
|
|
105
|
+
'@context': 'https://schema.org',
|
|
106
|
+
'@type': 'HowTo',
|
|
107
|
+
name: 'Как создать жетон персонажа для настольных RPG',
|
|
108
|
+
step: howTo.map((item) => ({ '@type': 'HowToStep', name: item.name, text: item.text })),
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
export const content: TokenStampLocaleContent = {
|
|
112
|
+
slug: 'sozdatel-zhetonov-personazhey-rpg-nastolnyh',
|
|
113
|
+
title: 'Создатель Жетонов Персонажей для Настольных RPG (Tokens)',
|
|
114
|
+
description: 'Создание понятных жетонов персонажей для настольных RPG с рамками, подписями, прозрачным фоном и пакетным экспортом.',
|
|
115
|
+
ui,
|
|
116
|
+
seo: [
|
|
117
|
+
{ type: 'title', text: 'Создавайте четкие и понятные жетоны персонажей для любых карт настольных RPG', level: 2 },
|
|
118
|
+
{ type: 'paragraph', html: 'Жетон - это важнейший элемент визуальной коммуникации за игровым столом. Его силуэт сразу показывает всем участникам группы, кто перед ними: главный герой, опасный монстр, заклинание или важный союзник до того, как кто-то приблизит виртуальную карту. Выбирайте подходящую рамку и следите за тем, чтобы лицо и подписи оставались читаемыми.' },
|
|
119
|
+
{ type: 'title', text: 'Подберите подходящую рамку под роль и тип персонажа', level: 2 },
|
|
120
|
+
{ type: 'list', items: ['<strong>Круг или кольцо:</strong> классический и надежный выбор для персонажей игроков и постоянных союзников.', '<strong>Шестиугольник или восьмиугольник:</strong> очень удобен в тактических боях с большим количеством юнитов на поле.', '<strong>Звезда:</strong> идеально подходит для боссов, чемпионов и ключевых целей, требующих внимания.', '<strong>Облако:</strong> мягкая и стильная форма для духов, фамильяров и волшебных существ.'] },
|
|
121
|
+
{ type: 'tip', title: 'Проектируйте с учетом минимального размера на игровой карте', html: 'Уменьшите карту так, чтобы жетон стал совсем маленьким. Если лицо, границы и текст остаются разборчивыми, жетон отлично сработает во время насыщенного боя.' },
|
|
122
|
+
{ type: 'title', text: 'Короткие и полезные подписи для удобства во время игры', level: 2 },
|
|
123
|
+
{ type: 'paragraph', html: 'Жетон не должен заменять полный лист персонажа. Добавляйте только самое необходимое за столом: короткое имя, уровень или текущий статус (например, оглушен). Длинные предложения создают визуальный шум и отвлекают от иллюстрации.' },
|
|
124
|
+
{ type: 'title', text: 'Подготовьте жетоны для всего отряда одновременно без потери стиля', level: 2 },
|
|
125
|
+
{ type: 'paragraph', html: 'Пакетный экспорт позволяет оформить всю партию в едином стиле, сохраняя при этом уникальность и индивидуальность каждого портрета.' },
|
|
126
|
+
{ type: 'tip', title: 'Автоматическое локальное сохранение на вашем устройстве', html: 'Активный маркер автоматически сохраняется в браузере, чтобы вы могли легко отредактировать его при повышении уровня персонажа.' },
|
|
127
|
+
],
|
|
128
|
+
faq,
|
|
129
|
+
bibliography,
|
|
130
|
+
howTo,
|
|
131
|
+
schemas: [faqSchema, appSchema, howToSchema] as unknown as Record<string, unknown>[],
|
|
132
|
+
};
|