@jjlmoya/utils-developer 1.28.0 → 1.29.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/entries.ts +4 -1
- package/src/tests/i18n_coverage.test.ts +5 -2
- package/src/tests/locale_completeness.test.ts +1 -1
- package/src/tests/qa-test-helpers.ts +32 -0
- package/src/tests/qa_bibliography_links.test.ts +43 -0
- package/src/tests/qa_claim_evidence.test.ts +69 -0
- package/src/tests/qa_logic_reference_coverage.test.ts +46 -0
- package/src/tests/qa_runtime_i18n.test.ts +115 -0
- package/src/tests/tool_validation.test.ts +1 -1
- package/src/tool/aspectRatio/bibliography.astro +2 -10
- package/src/tool/aspectRatio/bibliography.ts +7 -0
- package/src/tool/aspectRatio/i18n/de.ts +2 -14
- package/src/tool/aspectRatio/i18n/en.ts +2 -14
- package/src/tool/aspectRatio/i18n/es.ts +2 -14
- package/src/tool/aspectRatio/i18n/fr.ts +2 -14
- package/src/tool/aspectRatio/i18n/id.ts +2 -14
- package/src/tool/aspectRatio/i18n/it.ts +2 -14
- package/src/tool/aspectRatio/i18n/ja.ts +2 -14
- package/src/tool/aspectRatio/i18n/ko.ts +2 -14
- package/src/tool/aspectRatio/i18n/nl.ts +2 -14
- package/src/tool/aspectRatio/i18n/pl.ts +2 -14
- package/src/tool/aspectRatio/i18n/pt.ts +2 -14
- package/src/tool/aspectRatio/i18n/ru.ts +2 -14
- package/src/tool/aspectRatio/i18n/sv.ts +2 -14
- package/src/tool/aspectRatio/i18n/tr.ts +2 -14
- package/src/tool/aspectRatio/i18n/zh.ts +2 -14
- package/src/tool/calculadoraTiempoDatos/bibliography.astro +2 -10
- package/src/tool/calculadoraTiempoDatos/bibliography.ts +8 -0
- package/src/tool/calculadoraTiempoDatos/component.astro +6 -2
- package/src/tool/calculadoraTiempoDatos/i18n/de.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/en.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/es.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/fr.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/id.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/it.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/ja.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/ko.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/nl.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/pl.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/pt.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/ru.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/sv.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/tr.ts +2 -6
- package/src/tool/calculadoraTiempoDatos/i18n/zh.ts +2 -6
- package/src/tool/colorConverter/bibliography.astro +2 -10
- package/src/tool/colorConverter/bibliography.ts +7 -0
- package/src/tool/colorConverter/i18n/de.ts +2 -5
- package/src/tool/colorConverter/i18n/en.ts +5 -8
- package/src/tool/colorConverter/i18n/es.ts +4 -7
- package/src/tool/colorConverter/i18n/fr.ts +2 -5
- package/src/tool/colorConverter/i18n/id.ts +2 -5
- package/src/tool/colorConverter/i18n/it.ts +2 -5
- package/src/tool/colorConverter/i18n/ja.ts +2 -5
- package/src/tool/colorConverter/i18n/ko.ts +2 -5
- package/src/tool/colorConverter/i18n/nl.ts +2 -5
- package/src/tool/colorConverter/i18n/pl.ts +2 -5
- package/src/tool/colorConverter/i18n/pt.ts +2 -5
- package/src/tool/colorConverter/i18n/ru.ts +2 -5
- package/src/tool/colorConverter/i18n/sv.ts +2 -5
- package/src/tool/colorConverter/i18n/tr.ts +2 -5
- package/src/tool/colorConverter/i18n/zh.ts +2 -5
- package/src/tool/conversorExcelCsvHtml/bibliography.astro +2 -10
- package/src/tool/conversorExcelCsvHtml/bibliography.ts +8 -0
- package/src/tool/conversorExcelCsvHtml/component.astro +4 -3
- package/src/tool/conversorExcelCsvHtml/i18n/de.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/en.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/es.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/fr.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/id.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/it.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/ja.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/ko.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/nl.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/pl.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/pt.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/ru.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/sv.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/tr.ts +2 -6
- package/src/tool/conversorExcelCsvHtml/i18n/zh.ts +2 -6
- package/src/tool/cronGenerator/bibliography.astro +2 -10
- package/src/tool/cronGenerator/bibliography.ts +6 -0
- package/src/tool/cronGenerator/component.astro +5 -1
- package/src/tool/cronGenerator/i18n/de.ts +2 -10
- package/src/tool/cronGenerator/i18n/en.ts +2 -10
- package/src/tool/cronGenerator/i18n/es.ts +2 -10
- package/src/tool/cronGenerator/i18n/fr.ts +2 -10
- package/src/tool/cronGenerator/i18n/id.ts +2 -10
- package/src/tool/cronGenerator/i18n/it.ts +2 -10
- package/src/tool/cronGenerator/i18n/ja.ts +2 -10
- package/src/tool/cronGenerator/i18n/ko.ts +2 -10
- package/src/tool/cronGenerator/i18n/nl.ts +2 -10
- package/src/tool/cronGenerator/i18n/pl.ts +2 -10
- package/src/tool/cronGenerator/i18n/pt.ts +2 -10
- package/src/tool/cronGenerator/i18n/ru.ts +2 -10
- package/src/tool/cronGenerator/i18n/sv.ts +2 -10
- package/src/tool/cronGenerator/i18n/tr.ts +2 -10
- package/src/tool/cronGenerator/i18n/zh.ts +2 -10
- package/src/tool/cssBoxShadowGenerator/component.astro +2 -1
- package/src/tool/cssBoxShadowGenerator/logic.test.ts +28 -0
- package/src/tool/cssSpecificityCalculator/bibliography.astro +2 -10
- package/src/tool/cssSpecificityCalculator/bibliography.ts +6 -0
- package/src/tool/cssSpecificityCalculator/i18n/de.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/en.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/es.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/fr.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/id.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/it.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/ja.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/ko.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/nl.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/pl.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/pt.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/ru.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/sv.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/tr.ts +2 -10
- package/src/tool/cssSpecificityCalculator/i18n/zh.ts +2 -10
- package/src/tool/cssToInlineConverter/bibliography.astro +2 -10
- package/src/tool/cssToInlineConverter/bibliography.ts +7 -0
- package/src/tool/cssToInlineConverter/i18n/de.ts +2 -14
- package/src/tool/cssToInlineConverter/i18n/en.ts +4 -16
- package/src/tool/cssToInlineConverter/i18n/es.ts +5 -17
- package/src/tool/cssToInlineConverter/i18n/fr.ts +2 -14
- package/src/tool/cssToInlineConverter/i18n/id.ts +2 -14
- package/src/tool/cssToInlineConverter/i18n/it.ts +2 -14
- package/src/tool/cssToInlineConverter/i18n/ja.ts +2 -14
- package/src/tool/cssToInlineConverter/i18n/ko.ts +2 -14
- package/src/tool/cssToInlineConverter/i18n/nl.ts +2 -14
- package/src/tool/cssToInlineConverter/i18n/pl.ts +2 -14
- package/src/tool/cssToInlineConverter/i18n/pt.ts +2 -14
- package/src/tool/cssToInlineConverter/i18n/ru.ts +2 -14
- package/src/tool/cssToInlineConverter/i18n/sv.ts +2 -14
- package/src/tool/cssToInlineConverter/i18n/tr.ts +2 -14
- package/src/tool/cssToInlineConverter/i18n/zh.ts +2 -14
- package/src/tool/duplicateCssRemover/bibliography.astro +2 -10
- package/src/tool/duplicateCssRemover/bibliography.ts +7 -0
- package/src/tool/duplicateCssRemover/i18n/de.ts +2 -14
- package/src/tool/duplicateCssRemover/i18n/en.ts +4 -16
- package/src/tool/duplicateCssRemover/i18n/es.ts +4 -16
- package/src/tool/duplicateCssRemover/i18n/fr.ts +2 -14
- package/src/tool/duplicateCssRemover/i18n/id.ts +2 -14
- package/src/tool/duplicateCssRemover/i18n/it.ts +2 -14
- package/src/tool/duplicateCssRemover/i18n/ja.ts +2 -14
- package/src/tool/duplicateCssRemover/i18n/ko.ts +2 -14
- package/src/tool/duplicateCssRemover/i18n/nl.ts +2 -14
- package/src/tool/duplicateCssRemover/i18n/pl.ts +2 -14
- package/src/tool/duplicateCssRemover/i18n/pt.ts +2 -14
- package/src/tool/duplicateCssRemover/i18n/ru.ts +2 -14
- package/src/tool/duplicateCssRemover/i18n/sv.ts +2 -14
- package/src/tool/duplicateCssRemover/i18n/tr.ts +2 -14
- package/src/tool/duplicateCssRemover/i18n/zh.ts +2 -14
- package/src/tool/generadorSecurityTxt/bibliography.astro +2 -10
- package/src/tool/generadorSecurityTxt/bibliography.ts +7 -0
- package/src/tool/generadorSecurityTxt/component.astro +1 -2
- package/src/tool/generadorSecurityTxt/i18n/de.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/en.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/es.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/fr.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/id.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/it.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/ja.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/ko.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/nl.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/pl.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/pt.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/ru.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/sv.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/tr.ts +2 -5
- package/src/tool/generadorSecurityTxt/i18n/zh.ts +2 -5
- package/src/tool/hashGenerator/bibliography.astro +2 -10
- package/src/tool/hashGenerator/bibliography.ts +7 -0
- package/src/tool/hashGenerator/i18n/de.ts +2 -5
- package/src/tool/hashGenerator/i18n/en.ts +2 -5
- package/src/tool/hashGenerator/i18n/es.ts +2 -5
- package/src/tool/hashGenerator/i18n/fr.ts +2 -5
- package/src/tool/hashGenerator/i18n/id.ts +2 -5
- package/src/tool/hashGenerator/i18n/it.ts +2 -5
- package/src/tool/hashGenerator/i18n/ja.ts +2 -5
- package/src/tool/hashGenerator/i18n/ko.ts +2 -5
- package/src/tool/hashGenerator/i18n/nl.ts +2 -5
- package/src/tool/hashGenerator/i18n/pl.ts +2 -5
- package/src/tool/hashGenerator/i18n/pt.ts +2 -5
- package/src/tool/hashGenerator/i18n/ru.ts +2 -5
- package/src/tool/hashGenerator/i18n/sv.ts +2 -5
- package/src/tool/hashGenerator/i18n/tr.ts +2 -5
- package/src/tool/hashGenerator/i18n/zh.ts +2 -5
- package/src/tool/inspectorCertificadosSsl/bibliography.astro +2 -10
- package/src/tool/inspectorCertificadosSsl/bibliography.ts +8 -0
- package/src/tool/inspectorCertificadosSsl/component.astro +4 -3
- package/src/tool/inspectorCertificadosSsl/i18n/de.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/en.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/es.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/fr.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/id.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/it.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/ja.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/ko.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/nl.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/pl.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/pt.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/ru.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/sv.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/tr.ts +2 -6
- package/src/tool/inspectorCertificadosSsl/i18n/zh.ts +2 -6
- package/src/tool/jsonFormatter/bibliography.astro +2 -10
- package/src/tool/jsonFormatter/bibliography.ts +8 -0
- package/src/tool/jsonFormatter/i18n/de.ts +2 -18
- package/src/tool/jsonFormatter/i18n/en.ts +2 -18
- package/src/tool/jsonFormatter/i18n/es.ts +2 -18
- package/src/tool/jsonFormatter/i18n/fr.ts +2 -18
- package/src/tool/jsonFormatter/i18n/id.ts +2 -18
- package/src/tool/jsonFormatter/i18n/it.ts +2 -18
- package/src/tool/jsonFormatter/i18n/ja.ts +2 -18
- package/src/tool/jsonFormatter/i18n/ko.ts +2 -18
- package/src/tool/jsonFormatter/i18n/nl.ts +2 -18
- package/src/tool/jsonFormatter/i18n/pl.ts +2 -18
- package/src/tool/jsonFormatter/i18n/pt.ts +2 -18
- package/src/tool/jsonFormatter/i18n/ru.ts +2 -18
- package/src/tool/jsonFormatter/i18n/sv.ts +2 -18
- package/src/tool/jsonFormatter/i18n/tr.ts +2 -18
- package/src/tool/jsonFormatter/i18n/zh.ts +2 -18
- package/src/tool/jwtDecoder/component.astro +2 -1
- package/src/tool/jwtDecoder/logic.test.ts +32 -0
- package/src/tool/keycode/bibliography.astro +2 -10
- package/src/tool/keycode/bibliography.ts +7 -0
- package/src/tool/keycode/i18n/de.ts +2 -14
- package/src/tool/keycode/i18n/en.ts +2 -14
- package/src/tool/keycode/i18n/es.ts +2 -14
- package/src/tool/keycode/i18n/fr.ts +2 -14
- package/src/tool/keycode/i18n/id.ts +2 -14
- package/src/tool/keycode/i18n/it.ts +2 -14
- package/src/tool/keycode/i18n/ja.ts +2 -14
- package/src/tool/keycode/i18n/ko.ts +2 -14
- package/src/tool/keycode/i18n/nl.ts +2 -14
- package/src/tool/keycode/i18n/pl.ts +2 -14
- package/src/tool/keycode/i18n/pt.ts +2 -14
- package/src/tool/keycode/i18n/ru.ts +2 -14
- package/src/tool/keycode/i18n/sv.ts +2 -14
- package/src/tool/keycode/i18n/tr.ts +2 -14
- package/src/tool/keycode/i18n/zh.ts +2 -14
- package/src/tool/llmCostCalculator/bibliography.astro +2 -10
- package/src/tool/llmCostCalculator/bibliography.ts +8 -0
- package/src/tool/llmCostCalculator/i18n/de.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/en.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/es.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/fr.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/id.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/it.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/ja.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/ko.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/nl.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/pl.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/pt.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/ru.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/sv.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/tr.ts +2 -18
- package/src/tool/llmCostCalculator/i18n/zh.ts +2 -18
- package/src/tool/mobileMockupGenerator/bibliography.astro +2 -10
- package/src/tool/mobileMockupGenerator/bibliography.ts +6 -0
- package/src/tool/mobileMockupGenerator/i18n/de.ts +2 -4
- package/src/tool/mobileMockupGenerator/i18n/en.ts +2 -4
- package/src/tool/mobileMockupGenerator/i18n/es.ts +2 -4
- package/src/tool/mobileMockupGenerator/i18n/fr.ts +2 -4
- package/src/tool/mobileMockupGenerator/i18n/id.ts +2 -4
- package/src/tool/mobileMockupGenerator/i18n/it.ts +2 -4
- package/src/tool/mobileMockupGenerator/i18n/ja.ts +2 -4
- package/src/tool/mobileMockupGenerator/i18n/ko.ts +2 -4
- package/src/tool/mobileMockupGenerator/i18n/nl.ts +2 -4
- package/src/tool/mobileMockupGenerator/i18n/pl.ts +2 -1
- package/src/tool/mobileMockupGenerator/i18n/pt.ts +2 -4
- package/src/tool/mobileMockupGenerator/i18n/ru.ts +2 -4
- package/src/tool/mobileMockupGenerator/i18n/sv.ts +2 -4
- package/src/tool/mobileMockupGenerator/i18n/tr.ts +2 -4
- package/src/tool/mobileMockupGenerator/i18n/zh.ts +2 -4
- package/src/tool/musicalTypography/bibliography.astro +2 -10
- package/src/tool/musicalTypography/bibliography.ts +7 -0
- package/src/tool/musicalTypography/i18n/de.ts +2 -14
- package/src/tool/musicalTypography/i18n/en.ts +3 -15
- package/src/tool/musicalTypography/i18n/es.ts +3 -15
- package/src/tool/musicalTypography/i18n/fr.ts +2 -14
- package/src/tool/musicalTypography/i18n/id.ts +2 -14
- package/src/tool/musicalTypography/i18n/it.ts +2 -14
- package/src/tool/musicalTypography/i18n/ja.ts +2 -14
- package/src/tool/musicalTypography/i18n/ko.ts +2 -14
- package/src/tool/musicalTypography/i18n/nl.ts +2 -14
- package/src/tool/musicalTypography/i18n/pl.ts +2 -14
- package/src/tool/musicalTypography/i18n/pt.ts +2 -5
- package/src/tool/musicalTypography/i18n/ru.ts +2 -5
- package/src/tool/musicalTypography/i18n/sv.ts +2 -1
- package/src/tool/musicalTypography/i18n/tr.ts +2 -1
- package/src/tool/musicalTypography/i18n/zh.ts +2 -1
- package/src/tool/placeholderGenerator/bibliography.astro +2 -10
- package/src/tool/placeholderGenerator/bibliography.ts +7 -0
- package/src/tool/placeholderGenerator/i18n/de.ts +2 -14
- package/src/tool/placeholderGenerator/i18n/en.ts +4 -16
- package/src/tool/placeholderGenerator/i18n/es.ts +4 -16
- package/src/tool/placeholderGenerator/i18n/fr.ts +2 -14
- package/src/tool/placeholderGenerator/i18n/id.ts +2 -14
- package/src/tool/placeholderGenerator/i18n/it.ts +2 -14
- package/src/tool/placeholderGenerator/i18n/ja.ts +2 -14
- package/src/tool/placeholderGenerator/i18n/ko.ts +2 -14
- package/src/tool/placeholderGenerator/i18n/nl.ts +2 -14
- package/src/tool/placeholderGenerator/i18n/pl.ts +2 -14
- package/src/tool/placeholderGenerator/i18n/pt.ts +2 -14
- package/src/tool/placeholderGenerator/i18n/ru.ts +2 -14
- package/src/tool/placeholderGenerator/i18n/sv.ts +2 -14
- package/src/tool/placeholderGenerator/i18n/tr.ts +2 -14
- package/src/tool/placeholderGenerator/i18n/zh.ts +2 -14
- package/src/tool/promoteThisWebsite/asset-bindings.ts +73 -0
- package/src/tool/promoteThisWebsite/bibliography.astro +14 -0
- package/src/tool/promoteThisWebsite/bibliography.ts +14 -0
- package/src/tool/promoteThisWebsite/component.astro +136 -0
- package/src/tool/promoteThisWebsite/control-views.ts +83 -0
- package/src/tool/promoteThisWebsite/controller.ts +232 -0
- package/src/tool/promoteThisWebsite/dom-views.ts +322 -0
- package/src/tool/promoteThisWebsite/entry.ts +15 -0
- package/src/tool/promoteThisWebsite/evaluator.ts +9 -0
- package/src/tool/promoteThisWebsite/i18n/en.ts +111 -0
- package/src/tool/promoteThisWebsite/index.ts +11 -0
- package/src/tool/promoteThisWebsite/jjlmoya-overlay.png +0 -0
- package/src/tool/promoteThisWebsite/logic.test.ts +29 -0
- package/src/tool/promoteThisWebsite/logic.ts +108 -0
- package/src/tool/promoteThisWebsite/pixel-cat.png +0 -0
- package/src/tool/promoteThisWebsite/promote-this-website.css +322 -0
- package/src/tool/promoteThisWebsite/seo.astro +15 -0
- package/src/tool/promoteThisWebsite/storage.ts +28 -0
- package/src/tool/promoteThisWebsite/title-view.ts +206 -0
- package/src/tool/promoteThisWebsite/ui.ts +59 -0
- package/src/tool/promptLibrary/bibliography.astro +2 -10
- package/src/tool/promptLibrary/bibliography.ts +6 -0
- package/src/tool/promptLibrary/i18n/de.ts +2 -4
- package/src/tool/promptLibrary/i18n/en.ts +2 -4
- package/src/tool/promptLibrary/i18n/es.ts +2 -4
- package/src/tool/promptLibrary/i18n/fr.ts +2 -4
- package/src/tool/promptLibrary/i18n/id.ts +2 -4
- package/src/tool/promptLibrary/i18n/it.ts +2 -4
- package/src/tool/promptLibrary/i18n/ja.ts +2 -4
- package/src/tool/promptLibrary/i18n/ko.ts +2 -4
- package/src/tool/promptLibrary/i18n/nl.ts +2 -4
- package/src/tool/promptLibrary/i18n/pl.ts +2 -1
- package/src/tool/promptLibrary/i18n/pt.ts +2 -4
- package/src/tool/promptLibrary/i18n/ru.ts +2 -4
- package/src/tool/promptLibrary/i18n/sv.ts +2 -4
- package/src/tool/promptLibrary/i18n/tr.ts +2 -4
- package/src/tool/promptLibrary/i18n/zh.ts +2 -4
- package/src/tool/readabilityCalculator/bibliography.astro +2 -10
- package/src/tool/readabilityCalculator/bibliography.ts +7 -0
- package/src/tool/readabilityCalculator/i18n/de.ts +2 -5
- package/src/tool/readabilityCalculator/i18n/en.ts +2 -5
- package/src/tool/readabilityCalculator/i18n/es.ts +2 -5
- package/src/tool/readabilityCalculator/i18n/fr.ts +2 -5
- package/src/tool/readabilityCalculator/i18n/id.ts +2 -5
- package/src/tool/readabilityCalculator/i18n/it.ts +2 -5
- package/src/tool/readabilityCalculator/i18n/ja.ts +2 -5
- package/src/tool/readabilityCalculator/i18n/ko.ts +2 -5
- package/src/tool/readabilityCalculator/i18n/nl.ts +2 -5
- package/src/tool/readabilityCalculator/i18n/pl.ts +2 -1
- package/src/tool/readabilityCalculator/i18n/pt.ts +2 -5
- package/src/tool/readabilityCalculator/i18n/ru.ts +2 -5
- package/src/tool/readabilityCalculator/i18n/sv.ts +2 -5
- package/src/tool/readabilityCalculator/i18n/tr.ts +2 -5
- package/src/tool/readabilityCalculator/i18n/zh.ts +2 -5
- package/src/tool/serpPixelSimulator/controller.ts +1 -0
- package/src/tool/serpPixelSimulator/i18n/en.ts +2 -2
- package/src/tool/serpPixelSimulator/i18n/es.ts +2 -2
- package/src/tool/serpPixelSimulator/logic.test.ts +25 -0
- package/src/tool/svgSanitizer/bibliography.astro +2 -10
- package/src/tool/svgSanitizer/bibliography.ts +7 -0
- package/src/tool/svgSanitizer/i18n/de.ts +2 -5
- package/src/tool/svgSanitizer/i18n/en.ts +2 -5
- package/src/tool/svgSanitizer/i18n/es.ts +2 -5
- package/src/tool/svgSanitizer/i18n/fr.ts +2 -5
- package/src/tool/svgSanitizer/i18n/id.ts +2 -5
- package/src/tool/svgSanitizer/i18n/it.ts +2 -5
- package/src/tool/svgSanitizer/i18n/ja.ts +2 -5
- package/src/tool/svgSanitizer/i18n/ko.ts +2 -5
- package/src/tool/svgSanitizer/i18n/nl.ts +2 -5
- package/src/tool/svgSanitizer/i18n/pl.ts +2 -5
- package/src/tool/svgSanitizer/i18n/pt.ts +2 -1
- package/src/tool/svgSanitizer/i18n/ru.ts +2 -5
- package/src/tool/svgSanitizer/i18n/sv.ts +2 -5
- package/src/tool/svgSanitizer/i18n/tr.ts +2 -5
- package/src/tool/svgSanitizer/i18n/zh.ts +2 -5
- package/src/tool/svgToCss/bibliography.astro +2 -10
- package/src/tool/svgToCss/bibliography.ts +8 -0
- package/src/tool/svgToCss/i18n/de.ts +2 -18
- package/src/tool/svgToCss/i18n/en.ts +2 -18
- package/src/tool/svgToCss/i18n/es.ts +2 -18
- package/src/tool/svgToCss/i18n/fr.ts +2 -18
- package/src/tool/svgToCss/i18n/id.ts +2 -18
- package/src/tool/svgToCss/i18n/it.ts +2 -18
- package/src/tool/svgToCss/i18n/ja.ts +2 -18
- package/src/tool/svgToCss/i18n/ko.ts +2 -18
- package/src/tool/svgToCss/i18n/nl.ts +2 -18
- package/src/tool/svgToCss/i18n/pl.ts +2 -18
- package/src/tool/svgToCss/i18n/pt.ts +2 -18
- package/src/tool/svgToCss/i18n/ru.ts +2 -18
- package/src/tool/svgToCss/i18n/sv.ts +2 -18
- package/src/tool/svgToCss/i18n/tr.ts +2 -18
- package/src/tool/svgToCss/i18n/zh.ts +2 -18
- package/src/tool/urlCleaner/bibliography.astro +2 -10
- package/src/tool/urlCleaner/bibliography.ts +7 -0
- package/src/tool/urlCleaner/i18n/de.ts +2 -5
- package/src/tool/urlCleaner/i18n/en.ts +2 -5
- package/src/tool/urlCleaner/i18n/es.ts +2 -5
- package/src/tool/urlCleaner/i18n/fr.ts +2 -5
- package/src/tool/urlCleaner/i18n/id.ts +2 -5
- package/src/tool/urlCleaner/i18n/it.ts +2 -5
- package/src/tool/urlCleaner/i18n/ja.ts +2 -5
- package/src/tool/urlCleaner/i18n/ko.ts +2 -5
- package/src/tool/urlCleaner/i18n/nl.ts +2 -5
- package/src/tool/urlCleaner/i18n/pl.ts +2 -1
- package/src/tool/urlCleaner/i18n/pt.ts +2 -5
- package/src/tool/urlCleaner/i18n/ru.ts +2 -5
- package/src/tool/urlCleaner/i18n/sv.ts +2 -5
- package/src/tool/urlCleaner/i18n/tr.ts +2 -5
- package/src/tool/urlCleaner/i18n/zh.ts +2 -5
- package/src/tool/urlEncoderDecoder/bibliography.astro +2 -10
- package/src/tool/urlEncoderDecoder/bibliography.ts +7 -0
- package/src/tool/urlEncoderDecoder/i18n/de.ts +2 -14
- package/src/tool/urlEncoderDecoder/i18n/en.ts +3 -15
- package/src/tool/urlEncoderDecoder/i18n/es.ts +3 -15
- package/src/tool/urlEncoderDecoder/i18n/fr.ts +2 -14
- package/src/tool/urlEncoderDecoder/i18n/id.ts +2 -14
- package/src/tool/urlEncoderDecoder/i18n/it.ts +2 -14
- package/src/tool/urlEncoderDecoder/i18n/ja.ts +2 -14
- package/src/tool/urlEncoderDecoder/i18n/ko.ts +2 -14
- package/src/tool/urlEncoderDecoder/i18n/nl.ts +2 -14
- package/src/tool/urlEncoderDecoder/i18n/pl.ts +2 -14
- package/src/tool/urlEncoderDecoder/i18n/pt.ts +2 -14
- package/src/tool/urlEncoderDecoder/i18n/ru.ts +2 -14
- package/src/tool/urlEncoderDecoder/i18n/sv.ts +2 -14
- package/src/tool/urlEncoderDecoder/i18n/tr.ts +2 -14
- package/src/tool/urlEncoderDecoder/i18n/zh.ts +2 -14
- package/src/tool/utmGenerator/bibliography.astro +2 -10
- package/src/tool/utmGenerator/bibliography.ts +6 -0
- package/src/tool/utmGenerator/i18n/de.ts +2 -4
- package/src/tool/utmGenerator/i18n/en.ts +2 -4
- package/src/tool/utmGenerator/i18n/es.ts +2 -4
- package/src/tool/utmGenerator/i18n/fr.ts +2 -4
- package/src/tool/utmGenerator/i18n/id.ts +2 -4
- package/src/tool/utmGenerator/i18n/it.ts +2 -4
- package/src/tool/utmGenerator/i18n/ja.ts +2 -4
- package/src/tool/utmGenerator/i18n/ko.ts +2 -4
- package/src/tool/utmGenerator/i18n/nl.ts +2 -4
- package/src/tool/utmGenerator/i18n/pl.ts +2 -4
- package/src/tool/utmGenerator/i18n/pt.ts +2 -4
- package/src/tool/utmGenerator/i18n/ru.ts +2 -4
- package/src/tool/utmGenerator/i18n/sv.ts +2 -4
- package/src/tool/utmGenerator/i18n/tr.ts +2 -4
- package/src/tool/utmGenerator/i18n/zh.ts +2 -4
- package/src/tool/visualCssGridFlexboxGenerator/component.astro +1 -0
- package/src/tool/visualCssGridFlexboxGenerator/logic.test.ts +29 -0
- package/src/tool/visualCssGridFlexboxGenerator/workspace.ts +13 -1
- 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,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
|
+
};
|
|
Binary file
|
|
@@ -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
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
.promote-tool {
|
|
2
|
+
--promote-ink: #091426;
|
|
3
|
+
--promote-muted: #617078;
|
|
4
|
+
--promote-line: rgba(9, 20, 38, 0.12);
|
|
5
|
+
--promote-panel: rgba(255, 252, 244, 0.86);
|
|
6
|
+
--promote-accent: #c45a2f;
|
|
7
|
+
|
|
8
|
+
display: grid;
|
|
9
|
+
grid-template-columns: minmax(260px, 330px) minmax(0, 1fr);
|
|
10
|
+
gap: 1rem;
|
|
11
|
+
width: min(100%, 1320px);
|
|
12
|
+
min-height: 740px;
|
|
13
|
+
padding: 1rem;
|
|
14
|
+
color: var(--promote-ink);
|
|
15
|
+
background: linear-gradient(135deg, #f4ecdf, #d8e5e3);
|
|
16
|
+
border: 1px solid var(--promote-line);
|
|
17
|
+
border-radius: 24px;
|
|
18
|
+
box-shadow: 0 30px 80px rgba(9, 20, 38, 0.16);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.theme-dark .promote-tool {
|
|
22
|
+
--promote-ink: #f7ebd7;
|
|
23
|
+
--promote-muted: #9aabae;
|
|
24
|
+
--promote-line: rgba(247, 235, 215, 0.15);
|
|
25
|
+
--promote-panel: rgba(9, 20, 38, 0.86);
|
|
26
|
+
|
|
27
|
+
background: linear-gradient(135deg, #0b1526, #19344a);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.promote-sidebar,
|
|
31
|
+
.promote-stage {
|
|
32
|
+
min-width: 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.promote-sidebar {
|
|
36
|
+
display: grid;
|
|
37
|
+
align-content: start;
|
|
38
|
+
gap: 0.85rem;
|
|
39
|
+
padding: 1.05rem;
|
|
40
|
+
background: var(--promote-panel);
|
|
41
|
+
border: 1px solid var(--promote-line);
|
|
42
|
+
border-radius: 18px;
|
|
43
|
+
backdrop-filter: blur(18px);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.promote-control-group > label,
|
|
47
|
+
.promote-control-grid > label,
|
|
48
|
+
.promote-fieldset legend,
|
|
49
|
+
.promote-layer {
|
|
50
|
+
color: var(--promote-muted);
|
|
51
|
+
font-size: 0.68rem;
|
|
52
|
+
font-weight: 850;
|
|
53
|
+
letter-spacing: 0.05em;
|
|
54
|
+
text-transform: uppercase;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.promote-status {
|
|
58
|
+
margin: 0;
|
|
59
|
+
color: var(--promote-muted);
|
|
60
|
+
font-size: 0.78rem;
|
|
61
|
+
line-height: 1.45;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.promote-control-group,
|
|
65
|
+
.promote-control-grid,
|
|
66
|
+
.promote-fieldset {
|
|
67
|
+
display: grid;
|
|
68
|
+
gap: 0.45rem;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.promote-advanced {
|
|
72
|
+
display: grid;
|
|
73
|
+
gap: 0.75rem;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.promote-advanced summary {
|
|
77
|
+
padding: 0.55rem 0;
|
|
78
|
+
color: var(--promote-muted);
|
|
79
|
+
font-size: 0.68rem;
|
|
80
|
+
font-weight: 850;
|
|
81
|
+
letter-spacing: 0.05em;
|
|
82
|
+
text-transform: uppercase;
|
|
83
|
+
cursor: pointer;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.promote-inline-control {
|
|
87
|
+
display: grid;
|
|
88
|
+
grid-template-columns: 1fr auto;
|
|
89
|
+
gap: 0.4rem;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.promote-control-grid {
|
|
93
|
+
grid-template-columns: 1fr 1fr;
|
|
94
|
+
align-items: center;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.promote-control-grid > label {
|
|
98
|
+
letter-spacing: 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.promote-tool input[type='url'],
|
|
102
|
+
.promote-tool input[type='text'],
|
|
103
|
+
.promote-custom-select,
|
|
104
|
+
.promote-tool button {
|
|
105
|
+
min-height: 2.2rem;
|
|
106
|
+
color: var(--promote-ink);
|
|
107
|
+
font: inherit;
|
|
108
|
+
border: 1px solid var(--promote-line);
|
|
109
|
+
border-radius: 9px;
|
|
110
|
+
background: rgba(255, 255, 255, 0.45);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.theme-dark .promote-tool input[type='url'],
|
|
114
|
+
.theme-dark .promote-tool input[type='text'],
|
|
115
|
+
.theme-dark .promote-custom-select,
|
|
116
|
+
.theme-dark .promote-tool button {
|
|
117
|
+
background: rgba(0, 0, 0, 0.2);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.promote-tool input[type='url'],
|
|
121
|
+
.promote-tool input[type='text'] {
|
|
122
|
+
width: 100%;
|
|
123
|
+
padding: 0.5rem 0.6rem;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.promote-custom-select {
|
|
127
|
+
position: relative;
|
|
128
|
+
min-width: 0;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.promote-select-trigger {
|
|
132
|
+
display: flex;
|
|
133
|
+
align-items: center;
|
|
134
|
+
justify-content: space-between;
|
|
135
|
+
width: 100%;
|
|
136
|
+
padding: 0.5rem 0.6rem;
|
|
137
|
+
text-align: left;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.promote-select-trigger span:first-child {
|
|
141
|
+
min-width: 0;
|
|
142
|
+
overflow: hidden;
|
|
143
|
+
text-overflow: ellipsis;
|
|
144
|
+
white-space: nowrap;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.promote-select-menu {
|
|
148
|
+
position: absolute;
|
|
149
|
+
z-index: 20;
|
|
150
|
+
top: calc(100% + 0.25rem);
|
|
151
|
+
right: 0;
|
|
152
|
+
width: max-content;
|
|
153
|
+
min-width: 100%;
|
|
154
|
+
max-width: min(260px, calc(100vw - 2rem));
|
|
155
|
+
display: grid;
|
|
156
|
+
padding: 0.25rem;
|
|
157
|
+
overflow: visible;
|
|
158
|
+
background: #fffaf0;
|
|
159
|
+
border: 1px solid var(--promote-accent);
|
|
160
|
+
border-radius: 10px;
|
|
161
|
+
box-shadow: 0 14px 28px rgba(4, 11, 24, 0.3);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.promote-select-menu[data-placement='top'] {
|
|
165
|
+
top: auto;
|
|
166
|
+
bottom: calc(100% + 0.25rem);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.promote-select-menu[hidden] {
|
|
170
|
+
display: none;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.theme-dark .promote-select-menu {
|
|
174
|
+
background: #14243b;
|
|
175
|
+
border-color: #11d6c4;
|
|
176
|
+
box-shadow: 0 14px 28px rgba(0, 0, 0, 0.45);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.promote-tool .promote-select-option {
|
|
180
|
+
width: 100%;
|
|
181
|
+
min-height: 1.95rem;
|
|
182
|
+
padding: 0.45rem 0.55rem;
|
|
183
|
+
color: #071226;
|
|
184
|
+
text-align: left;
|
|
185
|
+
background: transparent;
|
|
186
|
+
border: 0;
|
|
187
|
+
border-radius: 7px;
|
|
188
|
+
white-space: nowrap;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.theme-dark .promote-tool .promote-select-option {
|
|
192
|
+
color: #f7ebd7;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.promote-tool .promote-select-option:hover,
|
|
196
|
+
.promote-tool .promote-select-option:focus-visible,
|
|
197
|
+
.promote-tool .promote-select-option[aria-selected='true'] {
|
|
198
|
+
color: #fffaf0;
|
|
199
|
+
background: var(--promote-accent);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.promote-tool button {
|
|
203
|
+
padding: 0.5rem 0.7rem;
|
|
204
|
+
cursor: pointer;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.promote-tool button:hover,
|
|
208
|
+
.promote-tool button:focus-visible {
|
|
209
|
+
border-color: var(--promote-accent);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.promote-tool .promote-primary {
|
|
213
|
+
color: #fffaf0;
|
|
214
|
+
background: var(--promote-accent);
|
|
215
|
+
border-color: var(--promote-accent);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.promote-fieldset {
|
|
219
|
+
margin: 0;
|
|
220
|
+
padding: 0.7rem;
|
|
221
|
+
border: 1px solid var(--promote-line);
|
|
222
|
+
border-radius: 12px;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.promote-fieldset label {
|
|
226
|
+
display: grid;
|
|
227
|
+
gap: 0.28rem;
|
|
228
|
+
color: var(--promote-muted);
|
|
229
|
+
font-size: 0.72rem;
|
|
230
|
+
font-weight: 700;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.promote-fieldset input[type='file'] {
|
|
234
|
+
width: 100%;
|
|
235
|
+
font-size: 0.68rem;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.promote-fieldset label.promote-layer {
|
|
239
|
+
display: grid;
|
|
240
|
+
grid-template-columns: 1fr 90px;
|
|
241
|
+
align-items: center;
|
|
242
|
+
gap: 0.5rem;
|
|
243
|
+
letter-spacing: 0;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.promote-layer span {
|
|
247
|
+
min-width: 0;
|
|
248
|
+
overflow: hidden;
|
|
249
|
+
text-overflow: ellipsis;
|
|
250
|
+
white-space: nowrap;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.promote-layer input[type='range'] {
|
|
254
|
+
accent-color: var(--promote-accent);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.promote-actions {
|
|
258
|
+
display: grid;
|
|
259
|
+
grid-template-columns: 1fr 1fr;
|
|
260
|
+
gap: 0.5rem;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.promote-stage {
|
|
264
|
+
display: grid;
|
|
265
|
+
grid-template-rows: auto minmax(0, 1fr);
|
|
266
|
+
gap: 0.65rem;
|
|
267
|
+
min-height: 0;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.promote-stage-meta {
|
|
271
|
+
display: flex;
|
|
272
|
+
justify-content: space-between;
|
|
273
|
+
color: var(--promote-muted);
|
|
274
|
+
font-size: 0.72rem;
|
|
275
|
+
font-weight: 800;
|
|
276
|
+
letter-spacing: 0.04em;
|
|
277
|
+
text-transform: uppercase;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.promote-canvas-wrap {
|
|
281
|
+
position: relative;
|
|
282
|
+
display: grid;
|
|
283
|
+
min-height: 0;
|
|
284
|
+
place-items: center;
|
|
285
|
+
padding: clamp(0.5rem, 3vw, 2rem);
|
|
286
|
+
overflow: hidden;
|
|
287
|
+
background: rgba(9, 20, 38, 0.15);
|
|
288
|
+
border: 1px solid var(--promote-line);
|
|
289
|
+
border-radius: 18px;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.promote-canvas-wrap canvas {
|
|
293
|
+
position: relative;
|
|
294
|
+
z-index: 2;
|
|
295
|
+
display: block;
|
|
296
|
+
width: min(100%, 1000px);
|
|
297
|
+
height: auto;
|
|
298
|
+
max-height: 100%;
|
|
299
|
+
object-fit: contain;
|
|
300
|
+
border-radius: 4px;
|
|
301
|
+
box-shadow: 0 24px 50px rgba(9, 20, 38, 0.25);
|
|
302
|
+
cursor: grab;
|
|
303
|
+
touch-action: none;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.promote-canvas-wrap canvas:active {
|
|
307
|
+
cursor: grabbing;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
@media (max-width: 850px) {
|
|
311
|
+
.promote-tool {
|
|
312
|
+
grid-template-columns: 1fr;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.promote-sidebar {
|
|
316
|
+
order: 2;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.promote-stage {
|
|
320
|
+
min-height: 50vh;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { SEORenderer } from '@jjlmoya/utils-shared';
|
|
3
|
+
import { promoteThisWebsite } from './index';
|
|
4
|
+
import type { KnownLocale } from '../../types';
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
locale?: KnownLocale;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const { locale = 'en' } = Astro.props;
|
|
11
|
+
const content = await promoteThisWebsite.i18n[locale]?.();
|
|
12
|
+
if (!content) return null;
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
{content.seo.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { CompositionState } from './logic';
|
|
2
|
+
|
|
3
|
+
const STORAGE_KEY = 'promote-this-website-state-v2';
|
|
4
|
+
|
|
5
|
+
export function readState(): Partial<CompositionState> | null {
|
|
6
|
+
try {
|
|
7
|
+
const raw = window.localStorage.getItem(STORAGE_KEY);
|
|
8
|
+
return raw ? JSON.parse(raw) as Partial<CompositionState> : null;
|
|
9
|
+
} catch {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function writeState(state: CompositionState): void {
|
|
15
|
+
try {
|
|
16
|
+
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
|
|
17
|
+
} catch {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function clearState(): void {
|
|
23
|
+
try {
|
|
24
|
+
window.localStorage.removeItem(STORAGE_KEY);
|
|
25
|
+
} catch {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
}
|