@jjlmoya/utils-developer 1.28.0 → 1.29.1

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 (457) hide show
  1. package/package.json +1 -1
  2. package/src/entries.ts +4 -1
  3. package/src/tests/entry_contract.test.ts +10 -0
  4. package/src/tests/i18n_coverage.test.ts +5 -2
  5. package/src/tests/locale_completeness.test.ts +1 -1
  6. package/src/tests/qa-test-helpers.ts +32 -0
  7. package/src/tests/qa_bibliography_links.test.ts +43 -0
  8. package/src/tests/qa_claim_evidence.test.ts +69 -0
  9. package/src/tests/qa_logic_reference_coverage.test.ts +46 -0
  10. package/src/tests/qa_runtime_i18n.test.ts +115 -0
  11. package/src/tests/tool_validation.test.ts +1 -1
  12. package/src/tool/aspectRatio/bibliography.astro +2 -10
  13. package/src/tool/aspectRatio/bibliography.ts +7 -0
  14. package/src/tool/aspectRatio/i18n/de.ts +2 -14
  15. package/src/tool/aspectRatio/i18n/en.ts +2 -14
  16. package/src/tool/aspectRatio/i18n/es.ts +2 -14
  17. package/src/tool/aspectRatio/i18n/fr.ts +2 -14
  18. package/src/tool/aspectRatio/i18n/id.ts +2 -14
  19. package/src/tool/aspectRatio/i18n/it.ts +2 -14
  20. package/src/tool/aspectRatio/i18n/ja.ts +2 -14
  21. package/src/tool/aspectRatio/i18n/ko.ts +2 -14
  22. package/src/tool/aspectRatio/i18n/nl.ts +2 -14
  23. package/src/tool/aspectRatio/i18n/pl.ts +2 -14
  24. package/src/tool/aspectRatio/i18n/pt.ts +2 -14
  25. package/src/tool/aspectRatio/i18n/ru.ts +2 -14
  26. package/src/tool/aspectRatio/i18n/sv.ts +2 -14
  27. package/src/tool/aspectRatio/i18n/tr.ts +2 -14
  28. package/src/tool/aspectRatio/i18n/zh.ts +2 -14
  29. package/src/tool/calculadoraTiempoDatos/bibliography.astro +2 -10
  30. package/src/tool/calculadoraTiempoDatos/bibliography.ts +8 -0
  31. package/src/tool/calculadoraTiempoDatos/component.astro +6 -2
  32. package/src/tool/calculadoraTiempoDatos/i18n/de.ts +2 -6
  33. package/src/tool/calculadoraTiempoDatos/i18n/en.ts +2 -6
  34. package/src/tool/calculadoraTiempoDatos/i18n/es.ts +2 -6
  35. package/src/tool/calculadoraTiempoDatos/i18n/fr.ts +2 -6
  36. package/src/tool/calculadoraTiempoDatos/i18n/id.ts +2 -6
  37. package/src/tool/calculadoraTiempoDatos/i18n/it.ts +2 -6
  38. package/src/tool/calculadoraTiempoDatos/i18n/ja.ts +2 -6
  39. package/src/tool/calculadoraTiempoDatos/i18n/ko.ts +2 -6
  40. package/src/tool/calculadoraTiempoDatos/i18n/nl.ts +2 -6
  41. package/src/tool/calculadoraTiempoDatos/i18n/pl.ts +2 -6
  42. package/src/tool/calculadoraTiempoDatos/i18n/pt.ts +2 -6
  43. package/src/tool/calculadoraTiempoDatos/i18n/ru.ts +2 -6
  44. package/src/tool/calculadoraTiempoDatos/i18n/sv.ts +2 -6
  45. package/src/tool/calculadoraTiempoDatos/i18n/tr.ts +2 -6
  46. package/src/tool/calculadoraTiempoDatos/i18n/zh.ts +2 -6
  47. package/src/tool/colorConverter/bibliography.astro +2 -10
  48. package/src/tool/colorConverter/bibliography.ts +7 -0
  49. package/src/tool/colorConverter/i18n/de.ts +2 -5
  50. package/src/tool/colorConverter/i18n/en.ts +5 -8
  51. package/src/tool/colorConverter/i18n/es.ts +4 -7
  52. package/src/tool/colorConverter/i18n/fr.ts +2 -5
  53. package/src/tool/colorConverter/i18n/id.ts +2 -5
  54. package/src/tool/colorConverter/i18n/it.ts +2 -5
  55. package/src/tool/colorConverter/i18n/ja.ts +2 -5
  56. package/src/tool/colorConverter/i18n/ko.ts +2 -5
  57. package/src/tool/colorConverter/i18n/nl.ts +2 -5
  58. package/src/tool/colorConverter/i18n/pl.ts +2 -5
  59. package/src/tool/colorConverter/i18n/pt.ts +2 -5
  60. package/src/tool/colorConverter/i18n/ru.ts +2 -5
  61. package/src/tool/colorConverter/i18n/sv.ts +2 -5
  62. package/src/tool/colorConverter/i18n/tr.ts +2 -5
  63. package/src/tool/colorConverter/i18n/zh.ts +2 -5
  64. package/src/tool/conversorExcelCsvHtml/bibliography.astro +2 -10
  65. package/src/tool/conversorExcelCsvHtml/bibliography.ts +8 -0
  66. package/src/tool/conversorExcelCsvHtml/component.astro +4 -3
  67. package/src/tool/conversorExcelCsvHtml/i18n/de.ts +2 -6
  68. package/src/tool/conversorExcelCsvHtml/i18n/en.ts +2 -6
  69. package/src/tool/conversorExcelCsvHtml/i18n/es.ts +2 -6
  70. package/src/tool/conversorExcelCsvHtml/i18n/fr.ts +2 -6
  71. package/src/tool/conversorExcelCsvHtml/i18n/id.ts +2 -6
  72. package/src/tool/conversorExcelCsvHtml/i18n/it.ts +2 -6
  73. package/src/tool/conversorExcelCsvHtml/i18n/ja.ts +2 -6
  74. package/src/tool/conversorExcelCsvHtml/i18n/ko.ts +2 -6
  75. package/src/tool/conversorExcelCsvHtml/i18n/nl.ts +2 -6
  76. package/src/tool/conversorExcelCsvHtml/i18n/pl.ts +2 -6
  77. package/src/tool/conversorExcelCsvHtml/i18n/pt.ts +2 -6
  78. package/src/tool/conversorExcelCsvHtml/i18n/ru.ts +2 -6
  79. package/src/tool/conversorExcelCsvHtml/i18n/sv.ts +2 -6
  80. package/src/tool/conversorExcelCsvHtml/i18n/tr.ts +2 -6
  81. package/src/tool/conversorExcelCsvHtml/i18n/zh.ts +2 -6
  82. package/src/tool/cronGenerator/bibliography.astro +2 -10
  83. package/src/tool/cronGenerator/bibliography.ts +6 -0
  84. package/src/tool/cronGenerator/component.astro +5 -1
  85. package/src/tool/cronGenerator/i18n/de.ts +2 -10
  86. package/src/tool/cronGenerator/i18n/en.ts +2 -10
  87. package/src/tool/cronGenerator/i18n/es.ts +2 -10
  88. package/src/tool/cronGenerator/i18n/fr.ts +2 -10
  89. package/src/tool/cronGenerator/i18n/id.ts +2 -10
  90. package/src/tool/cronGenerator/i18n/it.ts +2 -10
  91. package/src/tool/cronGenerator/i18n/ja.ts +2 -10
  92. package/src/tool/cronGenerator/i18n/ko.ts +2 -10
  93. package/src/tool/cronGenerator/i18n/nl.ts +2 -10
  94. package/src/tool/cronGenerator/i18n/pl.ts +2 -10
  95. package/src/tool/cronGenerator/i18n/pt.ts +2 -10
  96. package/src/tool/cronGenerator/i18n/ru.ts +2 -10
  97. package/src/tool/cronGenerator/i18n/sv.ts +2 -10
  98. package/src/tool/cronGenerator/i18n/tr.ts +2 -10
  99. package/src/tool/cronGenerator/i18n/zh.ts +2 -10
  100. package/src/tool/cssBoxShadowGenerator/component.astro +2 -1
  101. package/src/tool/cssBoxShadowGenerator/logic.test.ts +28 -0
  102. package/src/tool/cssSpecificityCalculator/bibliography.astro +2 -10
  103. package/src/tool/cssSpecificityCalculator/bibliography.ts +6 -0
  104. package/src/tool/cssSpecificityCalculator/i18n/de.ts +2 -10
  105. package/src/tool/cssSpecificityCalculator/i18n/en.ts +2 -10
  106. package/src/tool/cssSpecificityCalculator/i18n/es.ts +2 -10
  107. package/src/tool/cssSpecificityCalculator/i18n/fr.ts +2 -10
  108. package/src/tool/cssSpecificityCalculator/i18n/id.ts +2 -10
  109. package/src/tool/cssSpecificityCalculator/i18n/it.ts +2 -10
  110. package/src/tool/cssSpecificityCalculator/i18n/ja.ts +2 -10
  111. package/src/tool/cssSpecificityCalculator/i18n/ko.ts +2 -10
  112. package/src/tool/cssSpecificityCalculator/i18n/nl.ts +2 -10
  113. package/src/tool/cssSpecificityCalculator/i18n/pl.ts +2 -10
  114. package/src/tool/cssSpecificityCalculator/i18n/pt.ts +2 -10
  115. package/src/tool/cssSpecificityCalculator/i18n/ru.ts +2 -10
  116. package/src/tool/cssSpecificityCalculator/i18n/sv.ts +2 -10
  117. package/src/tool/cssSpecificityCalculator/i18n/tr.ts +2 -10
  118. package/src/tool/cssSpecificityCalculator/i18n/zh.ts +2 -10
  119. package/src/tool/cssToInlineConverter/bibliography.astro +2 -10
  120. package/src/tool/cssToInlineConverter/bibliography.ts +7 -0
  121. package/src/tool/cssToInlineConverter/i18n/de.ts +2 -14
  122. package/src/tool/cssToInlineConverter/i18n/en.ts +4 -16
  123. package/src/tool/cssToInlineConverter/i18n/es.ts +5 -17
  124. package/src/tool/cssToInlineConverter/i18n/fr.ts +2 -14
  125. package/src/tool/cssToInlineConverter/i18n/id.ts +2 -14
  126. package/src/tool/cssToInlineConverter/i18n/it.ts +2 -14
  127. package/src/tool/cssToInlineConverter/i18n/ja.ts +2 -14
  128. package/src/tool/cssToInlineConverter/i18n/ko.ts +2 -14
  129. package/src/tool/cssToInlineConverter/i18n/nl.ts +2 -14
  130. package/src/tool/cssToInlineConverter/i18n/pl.ts +2 -14
  131. package/src/tool/cssToInlineConverter/i18n/pt.ts +2 -14
  132. package/src/tool/cssToInlineConverter/i18n/ru.ts +2 -14
  133. package/src/tool/cssToInlineConverter/i18n/sv.ts +2 -14
  134. package/src/tool/cssToInlineConverter/i18n/tr.ts +2 -14
  135. package/src/tool/cssToInlineConverter/i18n/zh.ts +2 -14
  136. package/src/tool/duplicateCssRemover/bibliography.astro +2 -10
  137. package/src/tool/duplicateCssRemover/bibliography.ts +7 -0
  138. package/src/tool/duplicateCssRemover/i18n/de.ts +2 -14
  139. package/src/tool/duplicateCssRemover/i18n/en.ts +4 -16
  140. package/src/tool/duplicateCssRemover/i18n/es.ts +4 -16
  141. package/src/tool/duplicateCssRemover/i18n/fr.ts +2 -14
  142. package/src/tool/duplicateCssRemover/i18n/id.ts +2 -14
  143. package/src/tool/duplicateCssRemover/i18n/it.ts +2 -14
  144. package/src/tool/duplicateCssRemover/i18n/ja.ts +2 -14
  145. package/src/tool/duplicateCssRemover/i18n/ko.ts +2 -14
  146. package/src/tool/duplicateCssRemover/i18n/nl.ts +2 -14
  147. package/src/tool/duplicateCssRemover/i18n/pl.ts +2 -14
  148. package/src/tool/duplicateCssRemover/i18n/pt.ts +2 -14
  149. package/src/tool/duplicateCssRemover/i18n/ru.ts +2 -14
  150. package/src/tool/duplicateCssRemover/i18n/sv.ts +2 -14
  151. package/src/tool/duplicateCssRemover/i18n/tr.ts +2 -14
  152. package/src/tool/duplicateCssRemover/i18n/zh.ts +2 -14
  153. package/src/tool/generadorSecurityTxt/bibliography.astro +2 -10
  154. package/src/tool/generadorSecurityTxt/bibliography.ts +7 -0
  155. package/src/tool/generadorSecurityTxt/component.astro +1 -2
  156. package/src/tool/generadorSecurityTxt/i18n/de.ts +2 -5
  157. package/src/tool/generadorSecurityTxt/i18n/en.ts +2 -5
  158. package/src/tool/generadorSecurityTxt/i18n/es.ts +2 -5
  159. package/src/tool/generadorSecurityTxt/i18n/fr.ts +2 -5
  160. package/src/tool/generadorSecurityTxt/i18n/id.ts +2 -5
  161. package/src/tool/generadorSecurityTxt/i18n/it.ts +2 -5
  162. package/src/tool/generadorSecurityTxt/i18n/ja.ts +2 -5
  163. package/src/tool/generadorSecurityTxt/i18n/ko.ts +2 -5
  164. package/src/tool/generadorSecurityTxt/i18n/nl.ts +2 -5
  165. package/src/tool/generadorSecurityTxt/i18n/pl.ts +2 -5
  166. package/src/tool/generadorSecurityTxt/i18n/pt.ts +2 -5
  167. package/src/tool/generadorSecurityTxt/i18n/ru.ts +2 -5
  168. package/src/tool/generadorSecurityTxt/i18n/sv.ts +2 -5
  169. package/src/tool/generadorSecurityTxt/i18n/tr.ts +2 -5
  170. package/src/tool/generadorSecurityTxt/i18n/zh.ts +2 -5
  171. package/src/tool/hashGenerator/bibliography.astro +2 -10
  172. package/src/tool/hashGenerator/bibliography.ts +7 -0
  173. package/src/tool/hashGenerator/i18n/de.ts +2 -5
  174. package/src/tool/hashGenerator/i18n/en.ts +2 -5
  175. package/src/tool/hashGenerator/i18n/es.ts +2 -5
  176. package/src/tool/hashGenerator/i18n/fr.ts +2 -5
  177. package/src/tool/hashGenerator/i18n/id.ts +2 -5
  178. package/src/tool/hashGenerator/i18n/it.ts +2 -5
  179. package/src/tool/hashGenerator/i18n/ja.ts +2 -5
  180. package/src/tool/hashGenerator/i18n/ko.ts +2 -5
  181. package/src/tool/hashGenerator/i18n/nl.ts +2 -5
  182. package/src/tool/hashGenerator/i18n/pl.ts +2 -5
  183. package/src/tool/hashGenerator/i18n/pt.ts +2 -5
  184. package/src/tool/hashGenerator/i18n/ru.ts +2 -5
  185. package/src/tool/hashGenerator/i18n/sv.ts +2 -5
  186. package/src/tool/hashGenerator/i18n/tr.ts +2 -5
  187. package/src/tool/hashGenerator/i18n/zh.ts +2 -5
  188. package/src/tool/inspectorCertificadosSsl/bibliography.astro +2 -10
  189. package/src/tool/inspectorCertificadosSsl/bibliography.ts +8 -0
  190. package/src/tool/inspectorCertificadosSsl/component.astro +4 -3
  191. package/src/tool/inspectorCertificadosSsl/i18n/de.ts +2 -6
  192. package/src/tool/inspectorCertificadosSsl/i18n/en.ts +2 -6
  193. package/src/tool/inspectorCertificadosSsl/i18n/es.ts +2 -6
  194. package/src/tool/inspectorCertificadosSsl/i18n/fr.ts +2 -6
  195. package/src/tool/inspectorCertificadosSsl/i18n/id.ts +2 -6
  196. package/src/tool/inspectorCertificadosSsl/i18n/it.ts +2 -6
  197. package/src/tool/inspectorCertificadosSsl/i18n/ja.ts +2 -6
  198. package/src/tool/inspectorCertificadosSsl/i18n/ko.ts +2 -6
  199. package/src/tool/inspectorCertificadosSsl/i18n/nl.ts +2 -6
  200. package/src/tool/inspectorCertificadosSsl/i18n/pl.ts +2 -6
  201. package/src/tool/inspectorCertificadosSsl/i18n/pt.ts +2 -6
  202. package/src/tool/inspectorCertificadosSsl/i18n/ru.ts +2 -6
  203. package/src/tool/inspectorCertificadosSsl/i18n/sv.ts +2 -6
  204. package/src/tool/inspectorCertificadosSsl/i18n/tr.ts +2 -6
  205. package/src/tool/inspectorCertificadosSsl/i18n/zh.ts +2 -6
  206. package/src/tool/jsonFormatter/bibliography.astro +2 -10
  207. package/src/tool/jsonFormatter/bibliography.ts +8 -0
  208. package/src/tool/jsonFormatter/i18n/de.ts +2 -18
  209. package/src/tool/jsonFormatter/i18n/en.ts +2 -18
  210. package/src/tool/jsonFormatter/i18n/es.ts +2 -18
  211. package/src/tool/jsonFormatter/i18n/fr.ts +2 -18
  212. package/src/tool/jsonFormatter/i18n/id.ts +2 -18
  213. package/src/tool/jsonFormatter/i18n/it.ts +2 -18
  214. package/src/tool/jsonFormatter/i18n/ja.ts +2 -18
  215. package/src/tool/jsonFormatter/i18n/ko.ts +2 -18
  216. package/src/tool/jsonFormatter/i18n/nl.ts +2 -18
  217. package/src/tool/jsonFormatter/i18n/pl.ts +2 -18
  218. package/src/tool/jsonFormatter/i18n/pt.ts +2 -18
  219. package/src/tool/jsonFormatter/i18n/ru.ts +2 -18
  220. package/src/tool/jsonFormatter/i18n/sv.ts +2 -18
  221. package/src/tool/jsonFormatter/i18n/tr.ts +2 -18
  222. package/src/tool/jsonFormatter/i18n/zh.ts +2 -18
  223. package/src/tool/jwtDecoder/component.astro +2 -1
  224. package/src/tool/jwtDecoder/logic.test.ts +32 -0
  225. package/src/tool/keycode/bibliography.astro +2 -10
  226. package/src/tool/keycode/bibliography.ts +7 -0
  227. package/src/tool/keycode/i18n/de.ts +2 -14
  228. package/src/tool/keycode/i18n/en.ts +2 -14
  229. package/src/tool/keycode/i18n/es.ts +2 -14
  230. package/src/tool/keycode/i18n/fr.ts +2 -14
  231. package/src/tool/keycode/i18n/id.ts +2 -14
  232. package/src/tool/keycode/i18n/it.ts +2 -14
  233. package/src/tool/keycode/i18n/ja.ts +2 -14
  234. package/src/tool/keycode/i18n/ko.ts +2 -14
  235. package/src/tool/keycode/i18n/nl.ts +2 -14
  236. package/src/tool/keycode/i18n/pl.ts +2 -14
  237. package/src/tool/keycode/i18n/pt.ts +2 -14
  238. package/src/tool/keycode/i18n/ru.ts +2 -14
  239. package/src/tool/keycode/i18n/sv.ts +2 -14
  240. package/src/tool/keycode/i18n/tr.ts +2 -14
  241. package/src/tool/keycode/i18n/zh.ts +2 -14
  242. package/src/tool/llmCostCalculator/bibliography.astro +2 -10
  243. package/src/tool/llmCostCalculator/bibliography.ts +8 -0
  244. package/src/tool/llmCostCalculator/i18n/de.ts +2 -18
  245. package/src/tool/llmCostCalculator/i18n/en.ts +2 -18
  246. package/src/tool/llmCostCalculator/i18n/es.ts +2 -18
  247. package/src/tool/llmCostCalculator/i18n/fr.ts +2 -18
  248. package/src/tool/llmCostCalculator/i18n/id.ts +2 -18
  249. package/src/tool/llmCostCalculator/i18n/it.ts +2 -18
  250. package/src/tool/llmCostCalculator/i18n/ja.ts +2 -18
  251. package/src/tool/llmCostCalculator/i18n/ko.ts +2 -18
  252. package/src/tool/llmCostCalculator/i18n/nl.ts +2 -18
  253. package/src/tool/llmCostCalculator/i18n/pl.ts +2 -18
  254. package/src/tool/llmCostCalculator/i18n/pt.ts +2 -18
  255. package/src/tool/llmCostCalculator/i18n/ru.ts +2 -18
  256. package/src/tool/llmCostCalculator/i18n/sv.ts +2 -18
  257. package/src/tool/llmCostCalculator/i18n/tr.ts +2 -18
  258. package/src/tool/llmCostCalculator/i18n/zh.ts +2 -18
  259. package/src/tool/mobileMockupGenerator/bibliography.astro +2 -10
  260. package/src/tool/mobileMockupGenerator/bibliography.ts +6 -0
  261. package/src/tool/mobileMockupGenerator/i18n/de.ts +2 -4
  262. package/src/tool/mobileMockupGenerator/i18n/en.ts +2 -4
  263. package/src/tool/mobileMockupGenerator/i18n/es.ts +2 -4
  264. package/src/tool/mobileMockupGenerator/i18n/fr.ts +2 -4
  265. package/src/tool/mobileMockupGenerator/i18n/id.ts +2 -4
  266. package/src/tool/mobileMockupGenerator/i18n/it.ts +2 -4
  267. package/src/tool/mobileMockupGenerator/i18n/ja.ts +2 -4
  268. package/src/tool/mobileMockupGenerator/i18n/ko.ts +2 -4
  269. package/src/tool/mobileMockupGenerator/i18n/nl.ts +2 -4
  270. package/src/tool/mobileMockupGenerator/i18n/pl.ts +2 -1
  271. package/src/tool/mobileMockupGenerator/i18n/pt.ts +2 -4
  272. package/src/tool/mobileMockupGenerator/i18n/ru.ts +2 -4
  273. package/src/tool/mobileMockupGenerator/i18n/sv.ts +2 -4
  274. package/src/tool/mobileMockupGenerator/i18n/tr.ts +2 -4
  275. package/src/tool/mobileMockupGenerator/i18n/zh.ts +2 -4
  276. package/src/tool/musicalTypography/bibliography.astro +2 -10
  277. package/src/tool/musicalTypography/bibliography.ts +7 -0
  278. package/src/tool/musicalTypography/i18n/de.ts +2 -14
  279. package/src/tool/musicalTypography/i18n/en.ts +3 -15
  280. package/src/tool/musicalTypography/i18n/es.ts +3 -15
  281. package/src/tool/musicalTypography/i18n/fr.ts +2 -14
  282. package/src/tool/musicalTypography/i18n/id.ts +2 -14
  283. package/src/tool/musicalTypography/i18n/it.ts +2 -14
  284. package/src/tool/musicalTypography/i18n/ja.ts +2 -14
  285. package/src/tool/musicalTypography/i18n/ko.ts +2 -14
  286. package/src/tool/musicalTypography/i18n/nl.ts +2 -14
  287. package/src/tool/musicalTypography/i18n/pl.ts +2 -14
  288. package/src/tool/musicalTypography/i18n/pt.ts +2 -5
  289. package/src/tool/musicalTypography/i18n/ru.ts +2 -5
  290. package/src/tool/musicalTypography/i18n/sv.ts +2 -1
  291. package/src/tool/musicalTypography/i18n/tr.ts +2 -1
  292. package/src/tool/musicalTypography/i18n/zh.ts +2 -1
  293. package/src/tool/placeholderGenerator/bibliography.astro +2 -10
  294. package/src/tool/placeholderGenerator/bibliography.ts +7 -0
  295. package/src/tool/placeholderGenerator/i18n/de.ts +2 -14
  296. package/src/tool/placeholderGenerator/i18n/en.ts +4 -16
  297. package/src/tool/placeholderGenerator/i18n/es.ts +4 -16
  298. package/src/tool/placeholderGenerator/i18n/fr.ts +2 -14
  299. package/src/tool/placeholderGenerator/i18n/id.ts +2 -14
  300. package/src/tool/placeholderGenerator/i18n/it.ts +2 -14
  301. package/src/tool/placeholderGenerator/i18n/ja.ts +2 -14
  302. package/src/tool/placeholderGenerator/i18n/ko.ts +2 -14
  303. package/src/tool/placeholderGenerator/i18n/nl.ts +2 -14
  304. package/src/tool/placeholderGenerator/i18n/pl.ts +2 -14
  305. package/src/tool/placeholderGenerator/i18n/pt.ts +2 -14
  306. package/src/tool/placeholderGenerator/i18n/ru.ts +2 -14
  307. package/src/tool/placeholderGenerator/i18n/sv.ts +2 -14
  308. package/src/tool/placeholderGenerator/i18n/tr.ts +2 -14
  309. package/src/tool/placeholderGenerator/i18n/zh.ts +2 -14
  310. package/src/tool/promoteThisWebsite/asset-bindings.ts +73 -0
  311. package/src/tool/promoteThisWebsite/bibliography.astro +14 -0
  312. package/src/tool/promoteThisWebsite/bibliography.ts +14 -0
  313. package/src/tool/promoteThisWebsite/component.astro +136 -0
  314. package/src/tool/promoteThisWebsite/control-views.ts +83 -0
  315. package/src/tool/promoteThisWebsite/controller.ts +232 -0
  316. package/src/tool/promoteThisWebsite/dom-views.ts +322 -0
  317. package/src/tool/promoteThisWebsite/entry.ts +16 -0
  318. package/src/tool/promoteThisWebsite/evaluator.ts +9 -0
  319. package/src/tool/promoteThisWebsite/i18n/en.ts +111 -0
  320. package/src/tool/promoteThisWebsite/i18n/es.ts +111 -0
  321. package/src/tool/promoteThisWebsite/index.ts +11 -0
  322. package/src/tool/promoteThisWebsite/jjlmoya-overlay.png +0 -0
  323. package/src/tool/promoteThisWebsite/logic.test.ts +29 -0
  324. package/src/tool/promoteThisWebsite/logic.ts +108 -0
  325. package/src/tool/promoteThisWebsite/pixel-cat.png +0 -0
  326. package/src/tool/promoteThisWebsite/promote-this-website.css +322 -0
  327. package/src/tool/promoteThisWebsite/seo.astro +15 -0
  328. package/src/tool/promoteThisWebsite/storage.ts +28 -0
  329. package/src/tool/promoteThisWebsite/title-view.ts +206 -0
  330. package/src/tool/promoteThisWebsite/ui.ts +59 -0
  331. package/src/tool/promptLibrary/bibliography.astro +2 -10
  332. package/src/tool/promptLibrary/bibliography.ts +6 -0
  333. package/src/tool/promptLibrary/i18n/de.ts +2 -4
  334. package/src/tool/promptLibrary/i18n/en.ts +2 -4
  335. package/src/tool/promptLibrary/i18n/es.ts +2 -4
  336. package/src/tool/promptLibrary/i18n/fr.ts +2 -4
  337. package/src/tool/promptLibrary/i18n/id.ts +2 -4
  338. package/src/tool/promptLibrary/i18n/it.ts +2 -4
  339. package/src/tool/promptLibrary/i18n/ja.ts +2 -4
  340. package/src/tool/promptLibrary/i18n/ko.ts +2 -4
  341. package/src/tool/promptLibrary/i18n/nl.ts +2 -4
  342. package/src/tool/promptLibrary/i18n/pl.ts +2 -1
  343. package/src/tool/promptLibrary/i18n/pt.ts +2 -4
  344. package/src/tool/promptLibrary/i18n/ru.ts +2 -4
  345. package/src/tool/promptLibrary/i18n/sv.ts +2 -4
  346. package/src/tool/promptLibrary/i18n/tr.ts +2 -4
  347. package/src/tool/promptLibrary/i18n/zh.ts +2 -4
  348. package/src/tool/readabilityCalculator/bibliography.astro +2 -10
  349. package/src/tool/readabilityCalculator/bibliography.ts +7 -0
  350. package/src/tool/readabilityCalculator/i18n/de.ts +2 -5
  351. package/src/tool/readabilityCalculator/i18n/en.ts +2 -5
  352. package/src/tool/readabilityCalculator/i18n/es.ts +2 -5
  353. package/src/tool/readabilityCalculator/i18n/fr.ts +2 -5
  354. package/src/tool/readabilityCalculator/i18n/id.ts +2 -5
  355. package/src/tool/readabilityCalculator/i18n/it.ts +2 -5
  356. package/src/tool/readabilityCalculator/i18n/ja.ts +2 -5
  357. package/src/tool/readabilityCalculator/i18n/ko.ts +2 -5
  358. package/src/tool/readabilityCalculator/i18n/nl.ts +2 -5
  359. package/src/tool/readabilityCalculator/i18n/pl.ts +2 -1
  360. package/src/tool/readabilityCalculator/i18n/pt.ts +2 -5
  361. package/src/tool/readabilityCalculator/i18n/ru.ts +2 -5
  362. package/src/tool/readabilityCalculator/i18n/sv.ts +2 -5
  363. package/src/tool/readabilityCalculator/i18n/tr.ts +2 -5
  364. package/src/tool/readabilityCalculator/i18n/zh.ts +2 -5
  365. package/src/tool/serpPixelSimulator/controller.ts +1 -0
  366. package/src/tool/serpPixelSimulator/i18n/en.ts +2 -2
  367. package/src/tool/serpPixelSimulator/i18n/es.ts +2 -2
  368. package/src/tool/serpPixelSimulator/logic.test.ts +25 -0
  369. package/src/tool/svgSanitizer/bibliography.astro +2 -10
  370. package/src/tool/svgSanitizer/bibliography.ts +7 -0
  371. package/src/tool/svgSanitizer/i18n/de.ts +2 -5
  372. package/src/tool/svgSanitizer/i18n/en.ts +2 -5
  373. package/src/tool/svgSanitizer/i18n/es.ts +2 -5
  374. package/src/tool/svgSanitizer/i18n/fr.ts +2 -5
  375. package/src/tool/svgSanitizer/i18n/id.ts +2 -5
  376. package/src/tool/svgSanitizer/i18n/it.ts +2 -5
  377. package/src/tool/svgSanitizer/i18n/ja.ts +2 -5
  378. package/src/tool/svgSanitizer/i18n/ko.ts +2 -5
  379. package/src/tool/svgSanitizer/i18n/nl.ts +2 -5
  380. package/src/tool/svgSanitizer/i18n/pl.ts +2 -5
  381. package/src/tool/svgSanitizer/i18n/pt.ts +2 -1
  382. package/src/tool/svgSanitizer/i18n/ru.ts +2 -5
  383. package/src/tool/svgSanitizer/i18n/sv.ts +2 -5
  384. package/src/tool/svgSanitizer/i18n/tr.ts +2 -5
  385. package/src/tool/svgSanitizer/i18n/zh.ts +2 -5
  386. package/src/tool/svgToCss/bibliography.astro +2 -10
  387. package/src/tool/svgToCss/bibliography.ts +8 -0
  388. package/src/tool/svgToCss/i18n/de.ts +2 -18
  389. package/src/tool/svgToCss/i18n/en.ts +2 -18
  390. package/src/tool/svgToCss/i18n/es.ts +2 -18
  391. package/src/tool/svgToCss/i18n/fr.ts +2 -18
  392. package/src/tool/svgToCss/i18n/id.ts +2 -18
  393. package/src/tool/svgToCss/i18n/it.ts +2 -18
  394. package/src/tool/svgToCss/i18n/ja.ts +2 -18
  395. package/src/tool/svgToCss/i18n/ko.ts +2 -18
  396. package/src/tool/svgToCss/i18n/nl.ts +2 -18
  397. package/src/tool/svgToCss/i18n/pl.ts +2 -18
  398. package/src/tool/svgToCss/i18n/pt.ts +2 -18
  399. package/src/tool/svgToCss/i18n/ru.ts +2 -18
  400. package/src/tool/svgToCss/i18n/sv.ts +2 -18
  401. package/src/tool/svgToCss/i18n/tr.ts +2 -18
  402. package/src/tool/svgToCss/i18n/zh.ts +2 -18
  403. package/src/tool/urlCleaner/bibliography.astro +2 -10
  404. package/src/tool/urlCleaner/bibliography.ts +7 -0
  405. package/src/tool/urlCleaner/i18n/de.ts +2 -5
  406. package/src/tool/urlCleaner/i18n/en.ts +2 -5
  407. package/src/tool/urlCleaner/i18n/es.ts +2 -5
  408. package/src/tool/urlCleaner/i18n/fr.ts +2 -5
  409. package/src/tool/urlCleaner/i18n/id.ts +2 -5
  410. package/src/tool/urlCleaner/i18n/it.ts +2 -5
  411. package/src/tool/urlCleaner/i18n/ja.ts +2 -5
  412. package/src/tool/urlCleaner/i18n/ko.ts +2 -5
  413. package/src/tool/urlCleaner/i18n/nl.ts +2 -5
  414. package/src/tool/urlCleaner/i18n/pl.ts +2 -1
  415. package/src/tool/urlCleaner/i18n/pt.ts +2 -5
  416. package/src/tool/urlCleaner/i18n/ru.ts +2 -5
  417. package/src/tool/urlCleaner/i18n/sv.ts +2 -5
  418. package/src/tool/urlCleaner/i18n/tr.ts +2 -5
  419. package/src/tool/urlCleaner/i18n/zh.ts +2 -5
  420. package/src/tool/urlEncoderDecoder/bibliography.astro +2 -10
  421. package/src/tool/urlEncoderDecoder/bibliography.ts +7 -0
  422. package/src/tool/urlEncoderDecoder/i18n/de.ts +2 -14
  423. package/src/tool/urlEncoderDecoder/i18n/en.ts +3 -15
  424. package/src/tool/urlEncoderDecoder/i18n/es.ts +3 -15
  425. package/src/tool/urlEncoderDecoder/i18n/fr.ts +2 -14
  426. package/src/tool/urlEncoderDecoder/i18n/id.ts +2 -14
  427. package/src/tool/urlEncoderDecoder/i18n/it.ts +2 -14
  428. package/src/tool/urlEncoderDecoder/i18n/ja.ts +2 -14
  429. package/src/tool/urlEncoderDecoder/i18n/ko.ts +2 -14
  430. package/src/tool/urlEncoderDecoder/i18n/nl.ts +2 -14
  431. package/src/tool/urlEncoderDecoder/i18n/pl.ts +2 -14
  432. package/src/tool/urlEncoderDecoder/i18n/pt.ts +2 -14
  433. package/src/tool/urlEncoderDecoder/i18n/ru.ts +2 -14
  434. package/src/tool/urlEncoderDecoder/i18n/sv.ts +2 -14
  435. package/src/tool/urlEncoderDecoder/i18n/tr.ts +2 -14
  436. package/src/tool/urlEncoderDecoder/i18n/zh.ts +2 -14
  437. package/src/tool/utmGenerator/bibliography.astro +2 -10
  438. package/src/tool/utmGenerator/bibliography.ts +6 -0
  439. package/src/tool/utmGenerator/i18n/de.ts +2 -4
  440. package/src/tool/utmGenerator/i18n/en.ts +2 -4
  441. package/src/tool/utmGenerator/i18n/es.ts +2 -4
  442. package/src/tool/utmGenerator/i18n/fr.ts +2 -4
  443. package/src/tool/utmGenerator/i18n/id.ts +2 -4
  444. package/src/tool/utmGenerator/i18n/it.ts +2 -4
  445. package/src/tool/utmGenerator/i18n/ja.ts +2 -4
  446. package/src/tool/utmGenerator/i18n/ko.ts +2 -4
  447. package/src/tool/utmGenerator/i18n/nl.ts +2 -4
  448. package/src/tool/utmGenerator/i18n/pl.ts +2 -4
  449. package/src/tool/utmGenerator/i18n/pt.ts +2 -4
  450. package/src/tool/utmGenerator/i18n/ru.ts +2 -4
  451. package/src/tool/utmGenerator/i18n/sv.ts +2 -4
  452. package/src/tool/utmGenerator/i18n/tr.ts +2 -4
  453. package/src/tool/utmGenerator/i18n/zh.ts +2 -4
  454. package/src/tool/visualCssGridFlexboxGenerator/component.astro +1 -0
  455. package/src/tool/visualCssGridFlexboxGenerator/logic.test.ts +29 -0
  456. package/src/tool/visualCssGridFlexboxGenerator/workspace.ts +13 -1
  457. package/src/tools.ts +2 -1
@@ -0,0 +1,111 @@
1
+ import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+ import type { PromoteThisWebsiteUI } from '../ui';
4
+ import { bibliography } from '../bibliography';
5
+
6
+ const slug = 'promote-this-website';
7
+ const title = 'Promote this website';
8
+ const description = 'The internal propaganda desk for jjlmoya.es in Spanish and GameBob.dev internationally. Turn screenshots from your own pages into social images before Bob decides the feed is embarrassing.';
9
+
10
+ const howTo = [
11
+ { name: 'Paste one of our screenshots', text: 'Paste a screenshot from a page on jjlmoya.es or GameBob.dev with Ctrl+V. The board has requested evidence from its own empire.' },
12
+ { name: 'Choose the language house', text: 'Pick jjlmoya.es for Spanish or GameBob.dev for the international page. This is not a marketplace. The cat already owns the premises.' },
13
+ { name: 'Arrange the public narrative', text: 'Drag the screenshot, title, logo, background and mascot until the composition looks intentional rather than accidentally exported at 2 a.m.' },
14
+ { name: 'Export before the cat notices', text: 'Download a PNG at the selected dimensions and publish it. Bob will take the credit because that is how management works.' },
15
+ ];
16
+
17
+ const faq = [
18
+ { question: 'Who is this tool actually for?', answer: 'For promoting the pages on jjlmoya.es in Spanish and GameBob.dev internationally. Everyone else is welcome to look through the window.' },
19
+ { question: 'Can I paste a screenshot directly into the tool?', answer: 'Yes. Copy a screenshot from one of our pages to the clipboard and press Ctrl+V. It becomes the tool layer, because even the feline board accepts evidence when it arrives in the correct format.' },
20
+ { question: 'What happens when I paste a production URL?', answer: 'The tool reads the page meta title, chooses the Spanish jjlmoya.es or international GameBob.dev brand, loads the Open Graph image and uses it as the visual evidence until a more specific tool image is available. The slug is finally denied a promotion.' },
21
+ { question: 'Why are there two brands?', answer: 'jjlmoya.es is the Spanish page and GameBob.dev is the international page. The distinction is important for language and completely ignored by the cats.' },
22
+ { question: 'Does the tool upload my images?', answer: 'No. Images stay in the browser and the composition is rendered locally. The only thing leaving the page is the PNG you deliberately download, assuming Bob has approved the export.' },
23
+ ];
24
+
25
+ const ui: PromoteThisWebsiteUI = {
26
+ urlLabel: 'Website URL',
27
+ urlPlaceholder: 'https://www.example.com/tools/example/',
28
+ applyUrl: 'Apply',
29
+ formatLabel: 'Format',
30
+ panoramic: 'Panoramic · 1536 × 1024',
31
+ instagram: 'Instagram · 1080 × 1350',
32
+ square: 'Square · 1080 × 1080',
33
+ story: 'Story · 1080 × 1920',
34
+ titleLabel: 'Title',
35
+ titlePlaceholder: 'A short title for the image',
36
+ titleSizeLabel: 'Title font size',
37
+ titleBoxSizeLabel: 'Title box size',
38
+ titleStyleLabel: 'Title treatment',
39
+ brandLabel: 'Brand',
40
+ brandStyleLabel: 'Brand treatment',
41
+ advancedLabel: 'Advanced composition',
42
+ assetsLabel: 'Assets',
43
+ backgroundLabel: 'Background',
44
+ toolLabel: 'Tool screenshot',
45
+ logoLabel: 'Logo',
46
+ mascotLabel: 'Mascot',
47
+ layersLabel: 'Layers',
48
+ backgroundLayer: 'Background',
49
+ toolLayer: 'Tool',
50
+ logoLayer: 'Logo',
51
+ mascotLayer: 'Mascot',
52
+ titleLayer: 'Title',
53
+ reset: 'Reset',
54
+ download: 'Download PNG',
55
+ activeLayer: 'Active layer',
56
+ canvasHint: 'Drag the layers directly on the canvas. Paste a screenshot with Ctrl+V.',
57
+ pasted: 'Screenshot pasted as the tool layer.',
58
+ urlApplied: 'URL applied. Adjust the title and add the screenshot you want to promote.',
59
+ urlLoading: 'Reading the page title and its official image...',
60
+ urlFailed: 'Could not read that page. Check the URL or add the assets manually.',
61
+ fileLoaded: 'Asset loaded.',
62
+ titlePaper: 'Editorial paper',
63
+ titleRibbon: 'Folded ribbon',
64
+ titleInk: 'Ink splash',
65
+ titlePoster: 'Night poster',
66
+ titleTicket: 'Ticket stub',
67
+ titleMarker: 'Material underline',
68
+ titleSplit: 'Split block',
69
+ titleCapsule: 'Minimal capsule',
70
+ titleCorner: 'Editorial corner',
71
+ titleVertical: 'Vertical accent',
72
+ brandPlain: 'Plain mark',
73
+ brandPlaque: 'Ceramic plaque',
74
+ brandTicket: 'Admit one',
75
+ brandStamp: 'Rubber stamp',
76
+ brandNeon: 'Neon sign',
77
+ brandRibbon: 'Signal ribbon',
78
+ brandCorner: 'Editorial corner',
79
+ brandPixel: 'Pixel block',
80
+ brandHalo: 'Soft halo',
81
+ brandEditorial: 'Editorial line',
82
+ defaultTool: 'Paste your tool screenshot',
83
+ };
84
+
85
+ const faqSchema: WithContext<FAQPage> = { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) };
86
+ const howToSchema: WithContext<HowTo> = { '@context': 'https://schema.org', '@type': 'HowTo', name: title, description, step: howTo.map((step, index) => ({ '@type': 'HowToStep', position: index + 1, name: step.name, text: step.text })) };
87
+ const appSchema: WithContext<SoftwareApplication> = { '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: title, description, applicationCategory: 'DeveloperApplication', operatingSystem: 'Any', offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' } };
88
+
89
+ export const content: ToolLocaleContent<PromoteThisWebsiteUI> = {
90
+ slug,
91
+ title,
92
+ description,
93
+ ui,
94
+ faqTitle: 'Promote this website without angering the cat',
95
+ faq,
96
+ bibliographyTitle: 'Pages from the operation',
97
+ bibliography,
98
+ howTo,
99
+ schemas: [appSchema, faqSchema, howToSchema],
100
+ seo: [
101
+ { type: 'title', text: 'The official propaganda desk for jjlmoya and GameBob', level: 2 },
102
+ { type: 'paragraph', html: 'This is not a generic social media composer for a person who has just discovered the word branding. It exists to promote the pages published under <strong>jjlmoya.es</strong> in Spanish and <strong>GameBob.dev</strong> internationally, while the cats supervise from somewhere just outside the brief.' },
103
+ { type: 'stats', columns: 3, items: [{ value: '2', label: 'House brands to glorify', icon: 'mdi:domain' }, { value: '4', label: 'Formats for the propaganda', icon: 'mdi:crop' }, { value: '0', label: 'Meetings requested by Bob', icon: 'mdi:cat' }] },
104
+ { type: 'title', text: 'The screenshot remains in charge', level: 3 },
105
+ { type: 'paragraph', html: 'Paste a real screenshot from one of our pages or load a production URL. The tool reads the page title instead of guessing from the slug, loads the official Open Graph image and keeps the visual evidence visible while the supporting cast gets arranged around it.' },
106
+ { type: 'title', text: 'Two domains one suspiciously small team', level: 3 },
107
+ { type: 'paragraph', html: '<strong>jjlmoya.es</strong> is the Spanish page. <strong>GameBob.dev</strong> is the international page. The language changes, the propaganda department does not. The human prepares the image. The cats retain editorial authority.' },
108
+ { type: 'table', headers: ['Layer', 'What it does', 'What the board calls it'], rows: [['Tool', 'Position, scale, frame', 'The evidence'], ['Title', 'Text, size, treatment, color', 'The approved narrative'], ['Brand', 'Spanish or international page', 'The house whose glory is required'], ['Background', 'Open Graph image or upload', 'The respectable context']] },
109
+ { type: 'tip', title: 'Start with one of our pages', html: 'Paste a production URL from <strong>jjlmoya.es</strong> or <strong>GameBob.dev</strong>. If the page title, brand and Open Graph image do not load, the board will blame the network, then the human, then the cats.' },
110
+ ],
111
+ };
@@ -0,0 +1,111 @@
1
+ import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+ import type { PromoteThisWebsiteUI } from '../ui';
4
+ import { bibliography } from '../bibliography';
5
+
6
+ const slug = 'promociona-esta-web';
7
+ const title = 'Promociona esta web';
8
+ const description = 'La mesa de propaganda interna de jjlmoya.es en español y GameBob.dev a nivel internacional. Convierte capturas de tus propias páginas en imágenes para redes antes de que Bob decida que el feed da vergüenza.';
9
+
10
+ const howTo = [
11
+ { name: 'Pega una de nuestras capturas', text: 'Pega con Ctrl+V una captura de una página de jjlmoya.es o GameBob.dev. La junta necesita pruebas de su propio imperio.' },
12
+ { name: 'Elige la casa lingüística', text: 'Escoge jjlmoya.es para español o GameBob.dev para la página internacional. Esto no es un marketplace. La gata ya es dueña del local.' },
13
+ { name: 'Ordena el relato oficial', text: 'Arrastra la captura, el título, el logo, el fondo y la mascota hasta que la composición parezca intencionada y no exportada accidentalmente a las dos de la mañana.' },
14
+ { name: 'Descarga antes de que la gata se entere', text: 'Descarga un PNG con las dimensiones elegidas y publícalo. Bob se llevará el mérito porque así funciona la dirección.' },
15
+ ];
16
+
17
+ const faq = [
18
+ { question: '¿Para quién es realmente esta herramienta?', answer: 'Para promocionar las páginas de jjlmoya.es en español y GameBob.dev a nivel internacional. El resto puede mirar por la ventana.' },
19
+ { question: '¿Puedo pegar directamente una captura?', answer: 'Sí. Copia una captura de una de nuestras páginas y pulsa Ctrl+V. Se convierte en la capa de la herramienta, porque hasta la junta felina acepta pruebas si llegan en el formato correcto.' },
20
+ { question: '¿Qué pasa cuando pego una URL de producción?', answer: 'La herramienta lee el título meta de la página, elige la marca española jjlmoya.es o la internacional GameBob.dev, carga la imagen Open Graph y la usa como evidencia visual hasta que haya una imagen más concreta. Al slug se le acaba por fin el ascenso.' },
21
+ { question: '¿Por qué hay dos marcas?', answer: 'jjlmoya.es es la página en español y GameBob.dev es la página internacional. La diferencia importa para el idioma y a las gatas les da exactamente igual.' },
22
+ { question: '¿La herramienta sube mis imágenes?', answer: 'No. Las imágenes se quedan en el navegador y la composición se renderiza localmente. Lo único que sale de la página es el PNG que tú descargas deliberadamente, suponiendo que Bob haya aprobado la exportación.' },
23
+ ];
24
+
25
+ const ui: PromoteThisWebsiteUI = {
26
+ urlLabel: 'URL de la web',
27
+ urlPlaceholder: 'https://www.example.com/utilidades/ejemplo/',
28
+ applyUrl: 'Aplicar',
29
+ formatLabel: 'Formato',
30
+ panoramic: 'Panorámico · 1536 × 1024',
31
+ instagram: 'Instagram · 1080 × 1350',
32
+ square: 'Cuadrado · 1080 × 1080',
33
+ story: 'Historia · 1080 × 1920',
34
+ titleLabel: 'Título',
35
+ titlePlaceholder: 'Un título corto para la imagen',
36
+ titleSizeLabel: 'Tamaño de fuente del título',
37
+ titleBoxSizeLabel: 'Tamaño de la caja del título',
38
+ titleStyleLabel: 'Diseño del título',
39
+ brandLabel: 'Marca',
40
+ brandStyleLabel: 'Diseño de la marca',
41
+ advancedLabel: 'Composición avanzada',
42
+ assetsLabel: 'Recursos',
43
+ backgroundLabel: 'Fondo',
44
+ toolLabel: 'Captura de la herramienta',
45
+ logoLabel: 'Logo',
46
+ mascotLabel: 'Mascota',
47
+ layersLabel: 'Capas',
48
+ backgroundLayer: 'Fondo',
49
+ toolLayer: 'Herramienta',
50
+ logoLayer: 'Logo',
51
+ mascotLayer: 'Mascota',
52
+ titleLayer: 'Título',
53
+ reset: 'Restablecer',
54
+ download: 'Descargar PNG',
55
+ activeLayer: 'Capa activa',
56
+ canvasHint: 'Arrastra las capas directamente sobre el lienzo. Pega una captura con Ctrl+V.',
57
+ pasted: 'Captura pegada como capa de la herramienta.',
58
+ urlApplied: 'URL aplicada. Ajusta el título y añade la captura que quieras promocionar.',
59
+ urlLoading: 'Leyendo el título de la página y su imagen oficial...',
60
+ urlFailed: 'No se ha podido leer esa página. Comprueba la URL o añade los recursos manualmente.',
61
+ fileLoaded: 'Recurso cargado.',
62
+ titlePaper: 'Papel editorial',
63
+ titleRibbon: 'Cinta doblada',
64
+ titleInk: 'Mancha de tinta',
65
+ titlePoster: 'Cartel nocturno',
66
+ titleTicket: 'Entrada recortada',
67
+ titleMarker: 'Subrayado material',
68
+ titleSplit: 'Bloque partido',
69
+ titleCapsule: 'Cápsula mínima',
70
+ titleCorner: 'Esquina editorial',
71
+ titleVertical: 'Acento vertical',
72
+ brandPlain: 'Marca simple',
73
+ brandPlaque: 'Placa cerámica',
74
+ brandTicket: 'Admit one',
75
+ brandStamp: 'Sello de goma',
76
+ brandNeon: 'Rótulo de neón',
77
+ brandRibbon: 'Cinta de señal',
78
+ brandCorner: 'Esquina editorial',
79
+ brandPixel: 'Bloque pixel',
80
+ brandHalo: 'Halo suave',
81
+ brandEditorial: 'Línea editorial',
82
+ defaultTool: 'Pega la captura de tu herramienta',
83
+ };
84
+
85
+ const faqSchema: WithContext<FAQPage> = { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) };
86
+ const howToSchema: WithContext<HowTo> = { '@context': 'https://schema.org', '@type': 'HowTo', name: title, description, step: howTo.map((step, index) => ({ '@type': 'HowToStep', position: index + 1, name: step.name, text: step.text })) };
87
+ const appSchema: WithContext<SoftwareApplication> = { '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: title, description, applicationCategory: 'DeveloperApplication', operatingSystem: 'Any', offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' } };
88
+
89
+ export const content: ToolLocaleContent<PromoteThisWebsiteUI> = {
90
+ slug,
91
+ title,
92
+ description,
93
+ ui,
94
+ faqTitle: 'Promociona esta web sin enfadar a la gata',
95
+ faq,
96
+ bibliographyTitle: 'Páginas de la operación',
97
+ bibliography,
98
+ howTo,
99
+ schemas: [appSchema, faqSchema, howToSchema],
100
+ seo: [
101
+ { type: 'title', text: 'La mesa oficial de propaganda de jjlmoya y GameBob', level: 2 },
102
+ { type: 'paragraph', html: 'Esto no es un compositor genérico de imágenes sociales para alguien que acaba de descubrir la palabra branding. Existe para promocionar las páginas publicadas bajo <strong>jjlmoya.es</strong> en español y <strong>GameBob.dev</strong> a nivel internacional, mientras las gatas supervisan desde algún lugar justo fuera del briefing.' },
103
+ { type: 'stats', columns: 3, items: [{ value: '2', label: 'Marcas de la casa que glorificar', icon: 'mdi:domain' }, { value: '4', label: 'Formatos para la propaganda', icon: 'mdi:crop' }, { value: '0', label: 'Reuniones solicitadas por Bob', icon: 'mdi:cat' }] },
104
+ { type: 'title', text: 'La captura sigue mandando', level: 3 },
105
+ { type: 'paragraph', html: 'Pega una captura real de una de nuestras páginas o carga una URL de producción. La herramienta lee el título de la página en vez de inventárselo mirando el slug, carga la imagen Open Graph oficial y mantiene visible la prueba mientras el reparto secundario se coloca alrededor.' },
106
+ { type: 'title', text: 'Dos dominios y un equipo sospechosamente pequeño', level: 3 },
107
+ { type: 'paragraph', html: '<strong>jjlmoya.es</strong> es la página en español. <strong>GameBob.dev</strong> es la página internacional. Cambia el idioma, pero no el departamento de propaganda. El humano prepara la imagen. Las gatas conservan la autoridad editorial.' },
108
+ { type: 'table', headers: ['Capa', 'Qué hace', 'Cómo la llama la junta'], rows: [['Herramienta', 'Posición, escala y marco', 'La evidencia'], ['Título', 'Texto, tamaño, diseño y color', 'El relato aprobado'], ['Marca', 'Página española o internacional', 'La casa cuya gloria toca exigir'], ['Fondo', 'Imagen Open Graph o subida', 'El contexto respetable']] },
109
+ { type: 'tip', title: 'Empieza por una de nuestras páginas', html: 'Pega una URL de producción de <strong>jjlmoya.es</strong> o <strong>GameBob.dev</strong>. Si no cargan el título, la marca o la imagen Open Graph, la junta culpará a la red, después al humano y finalmente a las gatas.' },
110
+ ],
111
+ };
@@ -0,0 +1,11 @@
1
+ import type { ToolDefinition } from '../../types';
2
+ import { promoteThisWebsite } from './entry';
3
+
4
+ export * from './entry';
5
+
6
+ export const PROMOTE_THIS_WEBSITE_TOOL: ToolDefinition = {
7
+ entry: promoteThisWebsite,
8
+ Component: () => import('./component.astro'),
9
+ SEOComponent: () => import('./seo.astro'),
10
+ BibliographyComponent: () => import('./bibliography.astro'),
11
+ };
@@ -0,0 +1,29 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { brandFromUrl, containRect, defaultState, firstNonEmpty } from './logic';
3
+
4
+ describe('promote this website logic', () => {
5
+ it('keeps an uploaded image inside the tool frame', () => {
6
+ expect(containRect(1600, 900, { x: 100, y: 50, width: 700, height: 500 })).toEqual({
7
+ x: 100,
8
+ y: 103.125,
9
+ width: 700,
10
+ height: 393.75,
11
+ });
12
+ });
13
+
14
+ it('detects the site brand from a production URL', () => {
15
+ expect(brandFromUrl('https://gamebob.dev/tools/')).toBe('GameBob.dev');
16
+ expect(brandFromUrl('https://jjlmoya.es/utilidades/test/')).toBe('jjlmoya.es');
17
+ });
18
+
19
+ it('uses the first available page metadata title instead of a URL slug', () => {
20
+ expect(firstNonEmpty(['', 'Real Page Title', 'slug-title'], '')).toBe('Real Page Title');
21
+ expect(firstNonEmpty(['', ''], '')).toBe('');
22
+ });
23
+
24
+ it('starts without inventing a tool title', () => {
25
+ expect(defaultState().title).toBe('');
26
+ expect(defaultState().titleFontSize).toBe(1);
27
+ });
28
+
29
+ });
@@ -0,0 +1,108 @@
1
+ export type FormatId = 'panoramic' | 'instagram' | 'square' | 'story';
2
+ export type LayerKey = 'background' | 'tool' | 'brand' | 'mascot' | 'title';
3
+ export type TitleStyle = 'paper' | 'ribbon' | 'ink' | 'poster' | 'ticket' | 'marker' | 'split' | 'capsule' | 'corner' | 'vertical';
4
+ export type BrandStyle = 'plain' | 'plaque' | 'ticket' | 'stamp' | 'neon' | 'ribbon' | 'corner' | 'pixel' | 'halo' | 'editorial';
5
+ export const LAYOUT_REVISION = 2;
6
+
7
+ export interface FormatPreset {
8
+ width: number;
9
+ height: number;
10
+ }
11
+
12
+ export interface LayerPosition {
13
+ x: number;
14
+ y: number;
15
+ width: number;
16
+ height: number;
17
+ }
18
+
19
+ export interface CompositionState {
20
+ layoutRevision: number;
21
+ format: FormatId;
22
+ sourceUrl: string;
23
+ title: string;
24
+ titleFontSize: number;
25
+ titleStyle: TitleStyle;
26
+ brandStyle: BrandStyle;
27
+ brand: 'jjlmoya.es' | 'GameBob.dev';
28
+ active: LayerKey;
29
+ visible: Record<LayerKey, boolean>;
30
+ scale: Record<LayerKey, number>;
31
+ positions: Record<LayerKey, LayerPosition>;
32
+ colors: {
33
+ fill: string;
34
+ text: string;
35
+ accent: string;
36
+ frame: string;
37
+ };
38
+ }
39
+
40
+ export const FORMAT_PRESETS: Record<FormatId, FormatPreset> = {
41
+ panoramic: { width: 1536, height: 1024 },
42
+ instagram: { width: 1080, height: 1350 },
43
+ square: { width: 1080, height: 1080 },
44
+ story: { width: 1080, height: 1920 },
45
+ };
46
+
47
+ export function clamp(value: number, min: number, max: number): number {
48
+ return Math.min(Math.max(value, min), max);
49
+ }
50
+
51
+ export function containRect(imageWidth: number, imageHeight: number, box: LayerPosition): LayerPosition {
52
+ const ratio = Math.min(box.width / imageWidth, box.height / imageHeight);
53
+ const width = imageWidth * ratio;
54
+ const height = imageHeight * ratio;
55
+ return { x: box.x + (box.width - width) / 2, y: box.y + (box.height - height) / 2, width, height };
56
+ }
57
+
58
+ export function getFormat(format: FormatId): FormatPreset {
59
+ return FORMAT_PRESETS[format];
60
+ }
61
+
62
+ export function brandFromUrl(value: string): 'jjlmoya.es' | 'GameBob.dev' {
63
+ try {
64
+ const hostname = new URL(value).hostname.toLowerCase();
65
+ return hostname.includes('gamebob') ? 'GameBob.dev' : 'jjlmoya.es';
66
+ } catch {
67
+ return value.toLowerCase().includes('gamebob') ? 'GameBob.dev' : 'jjlmoya.es';
68
+ }
69
+ }
70
+
71
+ export function firstNonEmpty(values: string[], fallback = ''): string {
72
+ return values.map((value) => value.trim()).find(Boolean) || fallback;
73
+ }
74
+
75
+ export function defaultPositions(format: FormatId): Record<LayerKey, LayerPosition> {
76
+ const { width, height } = getFormat(format);
77
+ const panelWidth = width * 0.7;
78
+ const panelHeight = height * 0.54;
79
+ return {
80
+ background: { x: 0, y: 0, width, height },
81
+ tool: { x: width * 0.2, y: height * 0.2, width: panelWidth, height: panelHeight },
82
+ brand: { x: width * 0.62, y: height * 0.86, width: width * 0.30, height: height * 0.07 },
83
+ mascot: { x: width * 0.84, y: height * 0.75, width: width * 0.13, height: width * 0.13 },
84
+ title: { x: width * 0.28, y: height * 0.08, width: width * 0.44, height: height * 0.12 },
85
+ };
86
+ }
87
+
88
+ export function defaultState(format: FormatId = 'panoramic'): CompositionState {
89
+ return {
90
+ layoutRevision: LAYOUT_REVISION,
91
+ format,
92
+ sourceUrl: '',
93
+ title: '',
94
+ titleFontSize: 1,
95
+ titleStyle: 'paper',
96
+ brandStyle: 'plain',
97
+ brand: 'jjlmoya.es',
98
+ active: 'tool',
99
+ visible: { background: true, tool: true, brand: true, mascot: true, title: true },
100
+ scale: { background: 1, tool: 1, brand: 1, mascot: 1, title: 1 },
101
+ positions: defaultPositions(format),
102
+ colors: { fill: '#f7ebd7', text: '#08182b', accent: '#c45a2f', frame: '#f7ebd7' },
103
+ };
104
+ }
105
+
106
+ export function inside(point: { x: number; y: number }, position: LayerPosition): boolean {
107
+ return point.x >= position.x && point.x <= position.x + position.width && point.y >= position.y && point.y <= position.y + position.height;
108
+ }