@jjlmoya/utils-developer 1.17.0 → 1.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/package.json +1 -1
  2. package/src/category/index.ts +2 -1
  3. package/src/entries.ts +7 -1
  4. package/src/index.ts +3 -0
  5. package/src/tests/locale_completeness.test.ts +2 -2
  6. package/src/tests/tool_validation.test.ts +2 -2
  7. package/src/tool/calculadoraTiempoDatos/data-time-calculator-web-speed-impact.css +498 -499
  8. package/src/tool/cssBoxShadowGenerator/bibliography.astro +14 -0
  9. package/src/tool/cssBoxShadowGenerator/bibliography.ts +14 -0
  10. package/src/tool/cssBoxShadowGenerator/box-shadow-generator.css +376 -0
  11. package/src/tool/cssBoxShadowGenerator/component.astro +234 -0
  12. package/src/tool/cssBoxShadowGenerator/entry.ts +29 -0
  13. package/src/tool/cssBoxShadowGenerator/i18n/de.ts +69 -0
  14. package/src/tool/cssBoxShadowGenerator/i18n/en.ts +71 -0
  15. package/src/tool/cssBoxShadowGenerator/i18n/es.ts +69 -0
  16. package/src/tool/cssBoxShadowGenerator/i18n/fr.ts +69 -0
  17. package/src/tool/cssBoxShadowGenerator/i18n/id.ts +69 -0
  18. package/src/tool/cssBoxShadowGenerator/i18n/it.ts +69 -0
  19. package/src/tool/cssBoxShadowGenerator/i18n/ja.ts +69 -0
  20. package/src/tool/cssBoxShadowGenerator/i18n/ko.ts +69 -0
  21. package/src/tool/cssBoxShadowGenerator/i18n/nl.ts +69 -0
  22. package/src/tool/cssBoxShadowGenerator/i18n/pl.ts +69 -0
  23. package/src/tool/cssBoxShadowGenerator/i18n/pt.ts +69 -0
  24. package/src/tool/cssBoxShadowGenerator/i18n/ru.ts +69 -0
  25. package/src/tool/cssBoxShadowGenerator/i18n/sv.ts +69 -0
  26. package/src/tool/cssBoxShadowGenerator/i18n/tr.ts +69 -0
  27. package/src/tool/cssBoxShadowGenerator/i18n/zh.ts +69 -0
  28. package/src/tool/cssBoxShadowGenerator/index.ts +9 -0
  29. package/src/tool/cssBoxShadowGenerator/logic.ts +35 -0
  30. package/src/tool/cssBoxShadowGenerator/seo.astro +15 -0
  31. package/src/tool/cssBoxShadowGenerator/ui.ts +23 -0
  32. package/src/tool/visualCssGridFlexboxGenerator/bibliography.astro +14 -0
  33. package/src/tool/visualCssGridFlexboxGenerator/bibliography.ts +20 -0
  34. package/src/tool/visualCssGridFlexboxGenerator/canvas.ts +103 -0
  35. package/src/tool/visualCssGridFlexboxGenerator/component.astro +218 -0
  36. package/src/tool/visualCssGridFlexboxGenerator/entry.ts +30 -0
  37. package/src/tool/visualCssGridFlexboxGenerator/i18n/de.ts +110 -0
  38. package/src/tool/visualCssGridFlexboxGenerator/i18n/en.ts +256 -0
  39. package/src/tool/visualCssGridFlexboxGenerator/i18n/es.ts +110 -0
  40. package/src/tool/visualCssGridFlexboxGenerator/i18n/fr.ts +110 -0
  41. package/src/tool/visualCssGridFlexboxGenerator/i18n/id.ts +110 -0
  42. package/src/tool/visualCssGridFlexboxGenerator/i18n/it.ts +110 -0
  43. package/src/tool/visualCssGridFlexboxGenerator/i18n/ja.ts +110 -0
  44. package/src/tool/visualCssGridFlexboxGenerator/i18n/ko.ts +110 -0
  45. package/src/tool/visualCssGridFlexboxGenerator/i18n/nl.ts +110 -0
  46. package/src/tool/visualCssGridFlexboxGenerator/i18n/pl.ts +110 -0
  47. package/src/tool/visualCssGridFlexboxGenerator/i18n/pt.ts +110 -0
  48. package/src/tool/visualCssGridFlexboxGenerator/i18n/ru.ts +110 -0
  49. package/src/tool/visualCssGridFlexboxGenerator/i18n/sv.ts +110 -0
  50. package/src/tool/visualCssGridFlexboxGenerator/i18n/tr.ts +110 -0
  51. package/src/tool/visualCssGridFlexboxGenerator/i18n/zh.ts +110 -0
  52. package/src/tool/visualCssGridFlexboxGenerator/index.ts +11 -0
  53. package/src/tool/visualCssGridFlexboxGenerator/interactions.ts +45 -0
  54. package/src/tool/visualCssGridFlexboxGenerator/logic.ts +49 -0
  55. package/src/tool/visualCssGridFlexboxGenerator/presets.ts +63 -0
  56. package/src/tool/visualCssGridFlexboxGenerator/seo.astro +15 -0
  57. package/src/tool/visualCssGridFlexboxGenerator/ui.ts +58 -0
  58. package/src/tool/visualCssGridFlexboxGenerator/visual-css-grid-flexbox-generator.css +816 -0
  59. package/src/tool/visualCssGridFlexboxGenerator/workspace.ts +192 -0
  60. package/src/tools.ts +3 -1
@@ -0,0 +1,45 @@
1
+ import type { LayoutMode } from './logic';
2
+
3
+ export function setupSpanHandler(
4
+ canvas: HTMLElement,
5
+ modeFn: () => LayoutMode,
6
+ itemPrefix: string,
7
+ onUpdate: () => void,
8
+ ) {
9
+ canvas.addEventListener('dblclick', (e: MouseEvent) => {
10
+ const item = (e.target as HTMLElement).closest('.vcg-item') as HTMLElement | null;
11
+ if (!item || modeFn() !== 'grid') return;
12
+ const cur = Number(item.dataset.span ?? '1');
13
+ const next = cur >= 3 ? 1 : cur + 1;
14
+ item.dataset.span = String(next);
15
+ const label = item.querySelector('span');
16
+ if (label) {
17
+ const num = item.dataset.item;
18
+ label.textContent = next > 1 ? `${itemPrefix} ${num} (${next}x)` : `${itemPrefix} ${num}`;
19
+ }
20
+ onUpdate();
21
+ });
22
+ }
23
+
24
+ export function spawnConfetti(x: number, y: number) {
25
+ const container = document.createElement('div');
26
+ container.className = 'vcg-confetti-container';
27
+ const colors = ['#2dd4bf', '#fbbf24', '#6366f1', '#f472b6', '#34d399', '#f97316', '#a78bfa', '#22d3ee', '#fde047'];
28
+ for (let i = 0; i < 32; i++) {
29
+ const p = document.createElement('div');
30
+ p.className = 'vcg-confetti-piece';
31
+ p.style.left = `${x}px`;
32
+ p.style.top = `${y}px`;
33
+ p.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)]!;
34
+ p.style.width = `${5 + Math.random() * 7}px`;
35
+ p.style.height = `${5 + Math.random() * 7}px`;
36
+ const a = Math.random() * Math.PI * 2;
37
+ const d = 40 + Math.random() * 80;
38
+ p.style.setProperty('--cx', `${Math.cos(a) * d}px`);
39
+ p.style.setProperty('--cy', `${Math.sin(a) * d - 30}px`);
40
+ p.style.setProperty('--cr', `${Math.random() * 720 - 360}deg`);
41
+ container.append(p);
42
+ }
43
+ document.body.append(container);
44
+ setTimeout(() => container.remove(), 900);
45
+ }
@@ -0,0 +1,49 @@
1
+ export type LayoutMode = 'flex' | 'grid';
2
+
3
+ export interface LayoutState {
4
+ mode: LayoutMode;
5
+ gap: number;
6
+ columns: number;
7
+ width: number;
8
+ height: number;
9
+ itemSize: number;
10
+ justifyContent: string;
11
+ alignItems: string;
12
+ flexDirection: string;
13
+ flexWrap: string;
14
+ alignContent: string;
15
+ itemSpans: Record<string, number>;
16
+ }
17
+
18
+ function buildSpanRules(spans: Record<string, number>): string[] {
19
+ const lines: string[] = [];
20
+ for (const [id, span] of Object.entries(spans)) {
21
+ if (span > 1) {
22
+ lines.push(`.layout-item[data-item="${id}"] {`, ` grid-column: span ${span};`, '}');
23
+ }
24
+ }
25
+ return lines;
26
+ }
27
+
28
+ export function buildLayoutCss(state: LayoutState): string {
29
+ const lines: string[] = ['.layout-playground {'];
30
+
31
+ if (state.mode === 'grid') {
32
+ lines.push(' display: grid;', ` grid-template-columns: repeat(${state.columns}, minmax(0, 1fr));`);
33
+ } else {
34
+ lines.push(' display: flex;', ` flex-direction: ${state.flexDirection};`, ` flex-wrap: ${state.flexWrap};`);
35
+ }
36
+
37
+ lines.push(` gap: ${state.gap}px;`, ` justify-content: ${state.justifyContent};`, ` align-items: ${state.alignItems};`);
38
+
39
+ if (state.mode === 'flex' && state.flexWrap !== 'nowrap') {
40
+ lines.push(` align-content: ${state.alignContent};`);
41
+ }
42
+
43
+ lines.push(` width: ${state.width}px;`, ` min-height: ${state.height}px;`, '}', '', '.layout-item {', ` min-width: ${state.itemSize}px;`, ` min-height: ${state.itemSize}px;`, '}');
44
+
45
+ if (state.mode === 'grid') {
46
+ lines.push(...buildSpanRules(state.itemSpans));
47
+ }
48
+ return lines.join('\n');
49
+ }
@@ -0,0 +1,63 @@
1
+ import type { LayoutMode } from './logic';
2
+ import { getAllItems, clearPresetActive } from './canvas';
3
+
4
+ type PresetCfg = Partial<{
5
+ mode: LayoutMode;
6
+ gap: number; columns: number; width: number; height: number; itemSize: number;
7
+ justifyContent: string; alignItems: string; flexDirection: string;
8
+ flexWrap: string; alignContent: string;
9
+ }>;
10
+
11
+ export const PRESETS: Record<string, PresetCfg> = {
12
+ navbar: { mode: 'flex', flexDirection: 'row', flexWrap: 'nowrap', gap: 12, justifyContent: 'space-between', alignItems: 'center', alignContent: 'stretch', width: 760, height: 220, itemSize: 80 },
13
+ cards: { mode: 'grid', columns: 3, gap: 24, justifyContent: 'center', alignItems: 'center', width: 760, height: 420, itemSize: 100 },
14
+ hero: { mode: 'flex', flexDirection: 'column', flexWrap: 'nowrap', gap: 20, justifyContent: 'center', alignItems: 'center', alignContent: 'center', width: 600, height: 500, itemSize: 120 },
15
+ sidebar: { mode: 'grid', columns: 2, gap: 16, justifyContent: 'start', alignItems: 'stretch', width: 760, height: 460, itemSize: 100 },
16
+ gallery: { mode: 'grid', columns: 4, gap: 12, justifyContent: 'center', alignItems: 'start', width: 760, height: 400, itemSize: 80 },
17
+ };
18
+
19
+ interface PresetCtrls {
20
+ gapInput: HTMLInputElement;
21
+ columnsInput: HTMLInputElement;
22
+ widthInput: HTMLInputElement;
23
+ heightInput: HTMLInputElement;
24
+ itemSizeInput: HTMLInputElement;
25
+ justifySelect: HTMLSelectElement;
26
+ alignSelect: HTMLSelectElement;
27
+ directionSelect: HTMLSelectElement;
28
+ wrapSelect: HTMLSelectElement;
29
+ alignContentSelect: HTMLSelectElement;
30
+ }
31
+
32
+ const KEY_MAP: Record<string, keyof PresetCtrls> = {
33
+ gap: 'gapInput', columns: 'columnsInput', width: 'widthInput', height: 'heightInput',
34
+ itemSize: 'itemSizeInput', justifyContent: 'justifySelect', alignItems: 'alignSelect',
35
+ flexDirection: 'directionSelect', flexWrap: 'wrapSelect', alignContent: 'alignContentSelect',
36
+ };
37
+
38
+ interface PresetContext {
39
+ canvas: HTMLElement;
40
+ ctrls: PresetCtrls;
41
+ setMode: (m: LayoutMode) => void;
42
+ update: () => void;
43
+ }
44
+
45
+ export function applyPreset(name: string, ctx: PresetContext) {
46
+ const cfg = PRESETS[name];
47
+ if (!cfg) return;
48
+
49
+ clearPresetActive();
50
+ const btn = document.querySelector(`[data-preset="${name}"]`);
51
+ if (btn) btn.classList.add('vcg-preset-active');
52
+
53
+ getAllItems(ctx.canvas).forEach((item) => { item.dataset.span = '1'; });
54
+ if (cfg.mode) ctx.setMode(cfg.mode);
55
+
56
+ for (const [key, value] of Object.entries(cfg)) {
57
+ if (key === 'mode') continue;
58
+ const ck = KEY_MAP[key] as keyof PresetCtrls | undefined;
59
+ if (ck && ctx.ctrls[ck]) ctx.ctrls[ck].value = String(value);
60
+ }
61
+
62
+ ctx.update();
63
+ }
@@ -0,0 +1,15 @@
1
+ ---
2
+ import { SEORenderer } from '@jjlmoya/utils-shared';
3
+ import { visualCssGridFlexboxGenerator } 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 visualCssGridFlexboxGenerator.i18n[locale]?.();
12
+ if (!content) return null;
13
+ ---
14
+
15
+ {content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
@@ -0,0 +1,58 @@
1
+ export interface VisualCssGridFlexboxGeneratorUI extends Record<string, string> {
2
+ modeLabel: string;
3
+ flexMode: string;
4
+ gridMode: string;
5
+ canvasLabel: string;
6
+ addItem: string;
7
+ removeItem: string;
8
+ resetLayout: string;
9
+ gapLabel: string;
10
+ columnsLabel: string;
11
+ widthLabel: string;
12
+ heightLabel: string;
13
+ justifyLabel: string;
14
+ alignLabel: string;
15
+ itemSizeLabel: string;
16
+ codeTitle: string;
17
+ copyCode: string;
18
+ copied: string;
19
+ dragHint: string;
20
+ outputLabel: string;
21
+ justifyStart: string;
22
+ justifyCenter: string;
23
+ justifyEnd: string;
24
+ justifyBetween: string;
25
+ justifyAround: string;
26
+ justifyEvenly: string;
27
+ alignStart: string;
28
+ alignCenter: string;
29
+ alignEnd: string;
30
+ alignStretch: string;
31
+ alignBaseline: string;
32
+ itemPrefix: string;
33
+ directionLabel: string;
34
+ directionRow: string;
35
+ directionRowReverse: string;
36
+ directionColumn: string;
37
+ directionColumnReverse: string;
38
+ wrapLabel: string;
39
+ wrapNoWrap: string;
40
+ wrapWrap: string;
41
+ wrapWrapReverse: string;
42
+ alignContentLabel: string;
43
+ alignContentStart: string;
44
+ alignContentCenter: string;
45
+ alignContentEnd: string;
46
+ alignContentBetween: string;
47
+ alignContentAround: string;
48
+ alignContentEvenly: string;
49
+ alignContentStretch: string;
50
+ presetsLabel: string;
51
+ presetNavbar: string;
52
+ presetCards: string;
53
+ presetHero: string;
54
+ presetSidebar: string;
55
+ presetGallery: string;
56
+ shakeLimit: string;
57
+ spanHint: string;
58
+ }