@jjlmoya/utils-developer 1.17.0 → 1.18.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 (36) hide show
  1. package/package.json +1 -1
  2. package/src/category/index.ts +2 -1
  3. package/src/entries.ts +4 -1
  4. package/src/index.ts +2 -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/visualCssGridFlexboxGenerator/bibliography.astro +14 -0
  9. package/src/tool/visualCssGridFlexboxGenerator/bibliography.ts +20 -0
  10. package/src/tool/visualCssGridFlexboxGenerator/canvas.ts +103 -0
  11. package/src/tool/visualCssGridFlexboxGenerator/component.astro +218 -0
  12. package/src/tool/visualCssGridFlexboxGenerator/entry.ts +30 -0
  13. package/src/tool/visualCssGridFlexboxGenerator/i18n/de.ts +110 -0
  14. package/src/tool/visualCssGridFlexboxGenerator/i18n/en.ts +256 -0
  15. package/src/tool/visualCssGridFlexboxGenerator/i18n/es.ts +110 -0
  16. package/src/tool/visualCssGridFlexboxGenerator/i18n/fr.ts +110 -0
  17. package/src/tool/visualCssGridFlexboxGenerator/i18n/id.ts +110 -0
  18. package/src/tool/visualCssGridFlexboxGenerator/i18n/it.ts +110 -0
  19. package/src/tool/visualCssGridFlexboxGenerator/i18n/ja.ts +110 -0
  20. package/src/tool/visualCssGridFlexboxGenerator/i18n/ko.ts +110 -0
  21. package/src/tool/visualCssGridFlexboxGenerator/i18n/nl.ts +110 -0
  22. package/src/tool/visualCssGridFlexboxGenerator/i18n/pl.ts +110 -0
  23. package/src/tool/visualCssGridFlexboxGenerator/i18n/pt.ts +110 -0
  24. package/src/tool/visualCssGridFlexboxGenerator/i18n/ru.ts +110 -0
  25. package/src/tool/visualCssGridFlexboxGenerator/i18n/sv.ts +110 -0
  26. package/src/tool/visualCssGridFlexboxGenerator/i18n/tr.ts +110 -0
  27. package/src/tool/visualCssGridFlexboxGenerator/i18n/zh.ts +110 -0
  28. package/src/tool/visualCssGridFlexboxGenerator/index.ts +11 -0
  29. package/src/tool/visualCssGridFlexboxGenerator/interactions.ts +45 -0
  30. package/src/tool/visualCssGridFlexboxGenerator/logic.ts +49 -0
  31. package/src/tool/visualCssGridFlexboxGenerator/presets.ts +63 -0
  32. package/src/tool/visualCssGridFlexboxGenerator/seo.astro +15 -0
  33. package/src/tool/visualCssGridFlexboxGenerator/ui.ts +58 -0
  34. package/src/tool/visualCssGridFlexboxGenerator/visual-css-grid-flexbox-generator.css +816 -0
  35. package/src/tool/visualCssGridFlexboxGenerator/workspace.ts +192 -0
  36. package/src/tools.ts +2 -1
@@ -0,0 +1,256 @@
1
+ import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+ import type { VisualCssGridFlexboxGeneratorUI } from '../ui';
4
+ import { bibliography } from '../bibliography';
5
+
6
+ const slug = 'visual-css-grid-flexbox-generator';
7
+ const title = 'Visual CSS Grid & Flexbox Layout Generator';
8
+ const description = 'Design responsive layouts by dragging visual blocks, resizing the container, tuning alignment controls and using presets - then copy clean native CSS instantly.';
9
+
10
+ const howTo = [
11
+ {
12
+ name: 'Choose a preset or Flexbox / Grid',
13
+ text: 'Start with a layout preset (navbar, cards, hero, sidebar, gallery) or switch between Flexbox and Grid mode manually.',
14
+ },
15
+ {
16
+ name: 'Drag and resize the layout',
17
+ text: 'Reorder items by dragging them and resize the container from the corner handle to test how the design reacts to available space.',
18
+ },
19
+ {
20
+ name: 'Tune alignment controls',
21
+ text: 'Use sliders and selects for direction, wrap, gap, columns, justify-content, align-items, align-content, width, height and item size.',
22
+ },
23
+ {
24
+ name: 'Copy production-ready CSS',
25
+ text: 'Copy the generated CSS when the visual result matches the structure you want to implement. No framework dependencies.',
26
+ },
27
+ ];
28
+
29
+ const faq = [
30
+ {
31
+ question: 'When should I use Flexbox instead of CSS Grid?',
32
+ answer: 'Use Flexbox when the layout is mainly one-dimensional - navigation bars, button groups, wrapped cards, centered content. Use Grid when rows and columns matter together - dashboards, galleries, form layouts and structured page sections.',
33
+ },
34
+ {
35
+ question: 'Can this generator create responsive layouts?',
36
+ answer: 'Yes. The generated CSS uses native flex wrapping or grid repeat columns. Resize the visual canvas to test how spacing and alignment behave at different sizes before writing media queries.',
37
+ },
38
+ {
39
+ question: 'Why do justify-content and align-items feel different in grid and flex?',
40
+ answer: 'Flexbox distributes items along a main axis and cross axis. Grid places items into tracks first, then aligns content inside those tracks. Toggling both modes on the same canvas makes that behavioral difference immediately visible.',
41
+ },
42
+ {
43
+ question: 'Is the generated CSS tied to a framework?',
44
+ answer: 'No. The output is pure native CSS. Use it in plain HTML, Astro, React, Vue, Svelte, Web Components or any project that accepts standard CSS.',
45
+ },
46
+ {
47
+ question: 'What are the layout presets for?',
48
+ answer: 'Presets jump-start common layouts so you can see realistic configurations instead of starting from scratch. Each preset sets mode, direction, wrap, alignment and container size to match a real-world pattern.',
49
+ },
50
+ ];
51
+
52
+ const ui: VisualCssGridFlexboxGeneratorUI = {
53
+ modeLabel: 'Layout mode',
54
+ flexMode: 'Flexbox',
55
+ gridMode: 'Grid',
56
+ canvasLabel: 'Interactive layout canvas',
57
+ addItem: 'Add item',
58
+ removeItem: 'Remove item',
59
+ resetLayout: 'Reset layout',
60
+ gapLabel: 'Gap',
61
+ columnsLabel: 'Grid columns',
62
+ widthLabel: 'Container width',
63
+ heightLabel: 'Container height',
64
+ justifyLabel: 'Justify',
65
+ alignLabel: 'Align',
66
+ itemSizeLabel: 'Item size',
67
+ codeTitle: 'Generated CSS',
68
+ copyCode: 'Copy CSS',
69
+ copied: 'Copied!',
70
+ dragHint: 'Resize the bordered canvas from the corner handle - CSS updates live!',
71
+ outputLabel: 'Generated CSS output',
72
+ justifyStart: 'Start',
73
+ justifyCenter: 'Center',
74
+ justifyEnd: 'End',
75
+ justifyBetween: 'Space between',
76
+ justifyAround: 'Space around',
77
+ justifyEvenly: 'Space evenly',
78
+ alignStart: 'Start',
79
+ alignCenter: 'Center',
80
+ alignEnd: 'End',
81
+ alignStretch: 'Stretch',
82
+ alignBaseline: 'Baseline',
83
+ itemPrefix: 'Block',
84
+ directionLabel: 'Direction',
85
+ directionRow: 'Row →',
86
+ directionRowReverse: '← Row rev',
87
+ directionColumn: 'Column ↓',
88
+ directionColumnReverse: '↑ Col rev',
89
+ wrapLabel: 'Wrap',
90
+ wrapNoWrap: 'No wrap',
91
+ wrapWrap: 'Wrap',
92
+ wrapWrapReverse: 'Wrap rev',
93
+ alignContentLabel: 'Align content',
94
+ alignContentStart: 'Start',
95
+ alignContentCenter: 'Center',
96
+ alignContentEnd: 'End',
97
+ alignContentBetween: 'Space between',
98
+ alignContentAround: 'Space around',
99
+ alignContentEvenly: 'Space evenly',
100
+ alignContentStretch: 'Stretch',
101
+ presetsLabel: 'Presets',
102
+ presetNavbar: 'Navbar',
103
+ presetCards: 'Cards',
104
+ presetHero: 'Hero',
105
+ presetSidebar: 'Sidebar',
106
+ presetGallery: 'Gallery',
107
+ shakeLimit: 'Need at least 2 items!',
108
+ spanHint: 'Double-click an item to change its column span (1-3) in Grid mode',
109
+ };
110
+
111
+ const faqSchema: WithContext<FAQPage> = {
112
+ '@context': 'https://schema.org',
113
+ '@type': 'FAQPage',
114
+ mainEntity: faq.map((item) => ({
115
+ '@type': 'Question',
116
+ name: item.question,
117
+ acceptedAnswer: {
118
+ '@type': 'Answer',
119
+ text: item.answer,
120
+ },
121
+ })),
122
+ };
123
+
124
+ const howToSchema: WithContext<HowTo> = {
125
+ '@context': 'https://schema.org',
126
+ '@type': 'HowTo',
127
+ name: title,
128
+ description,
129
+ step: howTo.map((step, index) => ({
130
+ '@type': 'HowToStep',
131
+ position: index + 1,
132
+ name: step.name,
133
+ text: step.text,
134
+ })),
135
+ };
136
+
137
+ const appSchema: WithContext<SoftwareApplication> = {
138
+ '@context': 'https://schema.org',
139
+ '@type': 'SoftwareApplication',
140
+ name: title,
141
+ description,
142
+ applicationCategory: 'DeveloperApplication',
143
+ operatingSystem: 'Any',
144
+ offers: {
145
+ '@type': 'Offer',
146
+ price: '0',
147
+ priceCurrency: 'EUR',
148
+ },
149
+ };
150
+
151
+ export const content: ToolLocaleContent<VisualCssGridFlexboxGeneratorUI> = {
152
+ slug,
153
+ title,
154
+ description,
155
+ ui,
156
+ faqTitle: 'CSS layout generator FAQ',
157
+ faq,
158
+ bibliographyTitle: 'CSS Grid and Flexbox references',
159
+ bibliography,
160
+ howTo,
161
+ schemas: [appSchema, faqSchema, howToSchema],
162
+ seo: [
163
+ {
164
+ type: 'title',
165
+ text: 'Build CSS layouts by seeing the behavior, not memorizing properties',
166
+ level: 2,
167
+ },
168
+ {
169
+ type: 'paragraph',
170
+ html: 'CSS Grid and Flexbox are powerful because they describe layout relationships instead of fixed coordinates. The hard part is predicting how <strong>gap</strong>, <strong>justify-content</strong>, <strong>align-items</strong>, direction, wrapping, tracks and available space interact. This visual generator turns those abstract properties into a live playground with presets, drag-and-drop reordering and real-time CSS output.',
171
+ },
172
+ {
173
+ type: 'stats',
174
+ columns: 3,
175
+ items: [
176
+ { value: '5', label: 'Quick-start layout presets', icon: 'mdi:view-grid-plus' },
177
+ { value: 'Live', label: 'CSS output updates on every change', icon: 'mdi:code-braces' },
178
+ { value: '0', label: 'Framework dependencies in generated CSS', icon: 'mdi:language-css3' },
179
+ ],
180
+ },
181
+ {
182
+ type: 'title',
183
+ text: 'Flexbox vs Grid: choose the model before polishing alignment',
184
+ level: 3,
185
+ },
186
+ {
187
+ type: 'comparative',
188
+ columns: 2,
189
+ items: [
190
+ {
191
+ title: 'Flexbox',
192
+ description: 'Best for one-dimensional flows where items line up along a row or column and may wrap naturally.',
193
+ icon: 'mdi:format-align-justify',
194
+ highlight: true,
195
+ points: ['Navigation bars', 'Button groups', 'Wrapped cards', 'Centered content'],
196
+ },
197
+ {
198
+ title: 'CSS Grid',
199
+ description: 'Best for two-dimensional structures where rows and columns define the shape of the composition.',
200
+ icon: 'mdi:grid',
201
+ points: ['Dashboards', 'Galleries', 'Form layouts', 'Editorial sections'],
202
+ },
203
+ ],
204
+ },
205
+ {
206
+ type: 'title',
207
+ text: 'What each control teaches you',
208
+ level: 3,
209
+ },
210
+ {
211
+ type: 'table',
212
+ headers: ['Control', 'CSS property', 'What to watch'],
213
+ rows: [
214
+ ['Direction', '<code>flex-direction</code>', 'How the main axis flows - swap row for column to change the entire layout logic.'],
215
+ ['Wrap', '<code>flex-wrap</code>', 'Whether items stay on one line or flow to new rows when space runs out.'],
216
+ ['Gap', '<code>gap</code>', 'The space between items without adding margins that break at edges.'],
217
+ ['Justify', '<code>justify-content</code>', 'How free space is distributed along the main axis or inline axis.'],
218
+ ['Align', '<code>align-items</code>', 'How items sit on the cross axis or inside their grid area.'],
219
+ ['Align content', '<code>align-content</code>', 'How wrapped flex lines or grid rows distribute extra cross-axis space.'],
220
+ ['Grid columns', '<code>grid-template-columns</code>', 'How many equal tracks the grid creates before items wrap to another row.'],
221
+ ['Container size', '<code>width</code> and <code>min-height</code>', 'How the same CSS reacts when available space changes.'],
222
+ ],
223
+ },
224
+ {
225
+ type: 'tip',
226
+ title: 'Drag first, optimize second',
227
+ html: 'Start by dragging blocks into the visual order that matches the intended reading flow. Then adjust gap and alignment. This keeps the generated CSS aligned with document order instead of hiding structure with fragile positioning tricks.',
228
+ },
229
+ {
230
+ type: 'title',
231
+ text: 'Clean CSS output you can adapt',
232
+ level: 3,
233
+ },
234
+ {
235
+ type: 'code',
236
+ ariaLabel: 'Example generated CSS',
237
+ code: '.layout-playground {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n gap: 24px;\n justify-content: center;\n align-items: center;\n}',
238
+ },
239
+ {
240
+ type: 'diagnostic',
241
+ variant: 'info',
242
+ title: 'Why visual resizing matters',
243
+ html: 'Many layout bugs appear only when the container is narrower, taller or filled with different item counts. Resizing the playground while the CSS updates live helps you spot awkward wrapping, excessive gaps and alignment choices that only work at one viewport size.',
244
+ },
245
+ {
246
+ type: 'summary',
247
+ title: 'Best practice workflow',
248
+ items: [
249
+ 'Choose a preset or Flexbox for one-dimensional flows and Grid for two-dimensional structure.',
250
+ 'Resize the visual canvas before copying CSS so the layout survives realistic constraints.',
251
+ 'Use gap for spacing between items instead of adding margins to every child.',
252
+ 'Copy the generated CSS as a starting point, then add project-specific selectors and media queries.',
253
+ ],
254
+ },
255
+ ],
256
+ };
@@ -0,0 +1,110 @@
1
+ import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+ import type { VisualCssGridFlexboxGeneratorUI } from '../ui';
4
+ import { bibliography } from '../bibliography';
5
+
6
+ const slug = 'generador-visual-css-grid-flexbox';
7
+ const title = 'Generador Visual de Layouts CSS Grid y Flexbox';
8
+ const description = 'Diseña layouts responsive arrastrando bloques visuales, redimensionando el contenedor, ajustando controles de alineación y usando presets - luego copia CSS nativo limpio al instante.';
9
+
10
+ const howTo = [
11
+ { name: 'Elige un preset o Flexbox / Grid', text: 'Empieza con un preset de layout (navbar, cards, hero, sidebar, gallery) o cambia entre Flexbox y Grid manualmente.' },
12
+ { name: 'Redimensiona el layout', text: 'Redimensiona el contenedor desde la esquina inferior para probar cómo reacciona el diseño al espacio disponible.' },
13
+ { name: 'Ajusta los controles de alineación', text: 'Usa sliders y selects para dirección, wrap, gap, columnas, justify-content, align-items, align-content, ancho, alto y tamaño de ítem.' },
14
+ { name: 'Copia CSS listo para producción', text: 'Copia el CSS generado cuando el resultado visual coincida con la estructura que quieres implementar. Sin dependencias de frameworks.' },
15
+ ];
16
+
17
+ const faq = [
18
+ { question: '¿Cuándo debo usar Flexbox en vez de CSS Grid?', answer: 'Usa Flexbox cuando el layout sea principalmente unidimensional - barras de navegación, grupos de botones, cards envueltas, contenido centrado. Usa Grid cuando filas y columnas importan juntas - dashboards, galerías, formularios y secciones de página estructuradas.' },
19
+ { question: '¿Puede este generador crear layouts responsive?', answer: 'Sí. El CSS generado usa flex wrapping nativo o grid repeat columns. Redimensiona el canvas visual para probar cómo se comportan el espaciado y la alineación a diferentes tamaños antes de escribir media queries.' },
20
+ { question: '¿Por qué justify-content y align-items se sienten diferentes en grid y flex?', answer: 'Flexbox distribuye ítems a lo largo de un eje principal y un eje transversal. Grid coloca ítems en tracks primero, luego alinea el contenido dentro de esos tracks. Alternar entre ambos modos en el mismo canvas hace visible esa diferencia de comportamiento.' },
21
+ { question: '¿El CSS generado está atado a algún framework?', answer: 'No. El resultado es CSS nativo puro. Úsalo en HTML plano, Astro, React, Vue, Svelte, Web Components o cualquier proyecto que acepte CSS estándar.' },
22
+ { question: '¿Para qué sirven los presets de layout?', answer: 'Los presets aceleran layouts comunes para que veas configuraciones realistas sin empezar desde cero. Cada preset configura modo, dirección, wrap, alineación y tamaño del contenedor para un patrón del mundo real.' },
23
+ ];
24
+
25
+ const ui: VisualCssGridFlexboxGeneratorUI = {
26
+ modeLabel: 'Modo de layout',
27
+ flexMode: 'Flexbox',
28
+ gridMode: 'Grid',
29
+ canvasLabel: 'Canvas de layout interactivo',
30
+ addItem: 'Añadir ítem',
31
+ removeItem: 'Quitar ítem',
32
+ resetLayout: 'Restablecer layout',
33
+ gapLabel: 'Espaciado',
34
+ columnsLabel: 'Columnas del grid',
35
+ widthLabel: 'Ancho del contenedor',
36
+ heightLabel: 'Alto del contenedor',
37
+ justifyLabel: 'Justificar',
38
+ alignLabel: 'Alinear',
39
+ itemSizeLabel: 'Tamaño de ítem',
40
+ codeTitle: 'CSS Generado',
41
+ copyCode: 'Copiar CSS',
42
+ copied: '¡Copiado!',
43
+ dragHint: 'Redimensiona el canvas desde la esquina - ¡el CSS se actualiza en vivo!',
44
+ outputLabel: 'Salida de CSS generado',
45
+ justifyStart: 'Inicio',
46
+ justifyCenter: 'Centro',
47
+ justifyEnd: 'Fin',
48
+ justifyBetween: 'Space between',
49
+ justifyAround: 'Space around',
50
+ justifyEvenly: 'Space evenly',
51
+ alignStart: 'Inicio',
52
+ alignCenter: 'Centro',
53
+ alignEnd: 'Fin',
54
+ alignStretch: 'Estirar',
55
+ alignBaseline: 'Línea base',
56
+ itemPrefix: 'Bloque',
57
+ directionLabel: 'Dirección',
58
+ directionRow: 'Fila →',
59
+ directionRowReverse: '← Fila rev',
60
+ directionColumn: 'Columna ↓',
61
+ directionColumnReverse: '↑ Col rev',
62
+ wrapLabel: 'Wrap',
63
+ wrapNoWrap: 'Sin wrap',
64
+ wrapWrap: 'Wrap',
65
+ wrapWrapReverse: 'Wrap rev',
66
+ alignContentLabel: 'Al content',
67
+ alignContentStart: 'Inicio',
68
+ alignContentCenter: 'Centro',
69
+ alignContentEnd: 'Fin',
70
+ alignContentBetween: 'Space between',
71
+ alignContentAround: 'Space around',
72
+ alignContentEvenly: 'Space evenly',
73
+ alignContentStretch: 'Estirar',
74
+ presetsLabel: 'Presets',
75
+ presetNavbar: 'Navbar',
76
+ presetCards: 'Cards',
77
+ presetHero: 'Hero',
78
+ presetSidebar: 'Sidebar',
79
+ presetGallery: 'Galería',
80
+ shakeLimit: '¡Se necesitan al menos 2 ítems!',
81
+ spanHint: 'Doble clic en un ítem para cambiar su span de columna (1-3) en modo Grid',
82
+ };
83
+
84
+ 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 } })) };
85
+ 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 })) };
86
+ const appSchema: WithContext<SoftwareApplication> = { '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: title, description, applicationCategory: 'DeveloperApplication', operatingSystem: 'Any', offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' } };
87
+
88
+ export const content: ToolLocaleContent<VisualCssGridFlexboxGeneratorUI> = {
89
+ slug, title, description, ui,
90
+ faqTitle: 'FAQ del generador de layouts CSS',
91
+ faq,
92
+ bibliographyTitle: 'Referencias de CSS Grid y Flexbox',
93
+ bibliography,
94
+ howTo,
95
+ schemas: [appSchema, faqSchema, howToSchema],
96
+ seo: [
97
+ { type: 'title', text: 'Construye layouts CSS viendo el comportamiento, no memorizando propiedades', level: 2 },
98
+ { type: 'paragraph', html: 'CSS Grid y Flexbox son potentes porque describen relaciones de layout en vez de coordenadas fijas. Lo difícil es predecir cómo interactúan <strong>gap</strong>, <strong>justify-content</strong>, <strong>align-items</strong>, dirección, wrapping, tracks y el espacio disponible. Este generador visual convierte esas propiedades abstractas en un playground vivo con presets, reordenación y salida CSS en tiempo real.' },
99
+ { type: 'stats', columns: 3, items: [{ value: '5', label: 'Presets de layout rápidos', icon: 'mdi:view-grid-plus' }, { value: 'En vivo', label: 'CSS se actualiza con cada cambio', icon: 'mdi:code-braces' }, { value: '0', label: 'Dependencias de framework en el CSS', icon: 'mdi:language-css3' }] },
100
+ { type: 'title', text: 'Flexbox vs Grid: elige el modelo antes de pulir la alineación', level: 3 },
101
+ { type: 'comparative', columns: 2, items: [{ title: 'Flexbox', description: 'Ideal para flujos unidimensionales donde los ítems se alinean en fila o columna y pueden envolverse.', icon: 'mdi:format-align-justify', highlight: true, points: ['Barras de navegación', 'Grupos de botones', 'Cards envueltas', 'Contenido centrado'] }, { title: 'CSS Grid', description: 'Ideal para estructuras bidimensionales donde filas y columnas definen la forma de la composición.', icon: 'mdi:grid', points: ['Dashboards', 'Galerías', 'Formularios', 'Secciones editoriales'] }] },
102
+ { type: 'title', text: 'Qué te enseña cada control', level: 3 },
103
+ { type: 'table', headers: ['Control', 'Propiedad CSS', 'Qué observar'], rows: [['Dirección', '<code>flex-direction</code>', 'Cómo fluye el eje principal - cambia fila por columna para cambiar toda la lógica del layout.'], ['Wrap', '<code>flex-wrap</code>', 'Si los ítems se quedan en una línea o fluyen a nuevas filas cuando se acaba el espacio.'], ['Gap', '<code>gap</code>', 'El espacio entre ítems sin añadir márgenes que se rompen en los bordes.'], ['Justificar', '<code>justify-content</code>', 'Cómo se distribuye el espacio libre a lo largo del eje principal.'], ['Alinear', '<code>align-items</code>', 'Cómo se sitúan los ítems en el eje transversal.'], ['Align content', '<code>align-content</code>', 'Cómo las líneas envueltas o filas del grid distribuyen el espacio extra del eje transversal.'], ['Columnas', '<code>grid-template-columns</code>', 'Cuántos tracks iguales crea el grid antes de que los ítems pasen a otra fila.'], ['Tamaño contenedor', '<code>width</code> y <code>min-height</code>', 'Cómo reacciona el mismo CSS cuando cambia el espacio disponible.']] },
104
+ { type: 'tip', title: 'Primero redimensiona, luego optimiza', html: 'Empieza por redimensionar el canvas visual a un tamaño realista. Luego ajusta gap y alineación. Así el CSS generado funciona en escenarios reales, no solo en el tamaño por defecto.' },
105
+ { type: 'title', text: 'CSS limpio que puedes adaptar', level: 3 },
106
+ { type: 'code', ariaLabel: 'Ejemplo de CSS generado', code: '.layout-playground {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n gap: 24px;\n justify-content: center;\n align-items: center;\n}' },
107
+ { type: 'diagnostic', variant: 'info', title: 'Por qué importa el redimensionado visual', html: 'Muchos bugs de layout solo aparecen cuando el contenedor es más estrecho, más alto o tiene distinto número de ítems. Redimensionar el playground mientras el CSS se actualiza en vivo te ayuda a detectar wrapping incómodo, gaps excesivos y decisiones de alineación que solo funcionan a un tamaño.' },
108
+ { type: 'summary', title: 'Flujo de trabajo recomendado', items: ['Elige un preset o Flexbox para flujos unidimensionales y Grid para estructura bidimensional.', 'Redimensiona el canvas visual antes de copiar CSS para que el layout sobreviva restricciones realistas.', 'Usa gap para espaciado entre ítems en vez de añadir márgenes a cada hijo.', 'Copia el CSS generado como punto de partida, luego añade selectores específicos y media queries.'] },
109
+ ],
110
+ };
@@ -0,0 +1,110 @@
1
+ import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+ import type { VisualCssGridFlexboxGeneratorUI } from '../ui';
4
+ import { bibliography } from '../bibliography';
5
+
6
+ const slug = 'generateur-visuel-css-grid-flexbox';
7
+ const title = 'Générateur Visuel de Layout CSS Grid & Flexbox';
8
+ const description = 'Concevez des layouts responsives en déplaçant des blocs visuels, en redimensionnant le conteneur, en ajustant l\'alignement et en utilisant des presets - puis copiez du CSS natif propre instantanément.';
9
+
10
+ const howTo = [
11
+ { name: 'Choisissez un preset ou Flexbox / Grid', text: 'Commencez avec un preset de layout (navbar, cards, hero, sidebar, gallery) ou basculez entre Flexbox et Grid manuellement.' },
12
+ { name: 'Redimensionnez le layout', text: 'Redimensionnez le conteneur depuis le coin inférieur pour tester comment le design réagit à l\'espace disponible.' },
13
+ { name: 'Ajustez les contrôles d\'alignement', text: 'Utilisez les sliders et selects pour la direction, le wrap, l\'écart, les colonnes, justify-content, align-items, align-content, la largeur, la hauteur et la taille des éléments.' },
14
+ { name: 'Copiez du CSS prêt pour la production', text: 'Copiez le CSS généré quand le résultat visuel correspond à la structure souhaitée. Sans dépendance de framework.' },
15
+ ];
16
+
17
+ const faq = [
18
+ { question: 'Quand utiliser Flexbox plutôt que CSS Grid ?', answer: 'Utilisez Flexbox pour les layouts unidimensionnels - barres de navigation, groupes de boutons, cartes enveloppées, contenu centré. Grid quand lignes et colonnes comptent ensemble - dashboards, galeries, formulaires, sections structurées.' },
19
+ { question: 'Ce générateur peut-il créer des layouts responsives ?', answer: 'Oui. Le CSS généré utilise le flex wrapping natif ou les colonnes répétées de grid. Redimensionnez le canvas visuel pour tester l\'espacement et l\'alignement à différentes tailles.' },
20
+ { question: 'Pourquoi justify-content et align-items semblent-ils différents en grid et flex ?', answer: 'Flexbox distribue les éléments le long d\'un axe principal et d\'un axe transversal. Grid place d\'abord les éléments dans des tracks, puis aligne le contenu dans ces tracks. Basculer entre les deux modes rend cette différence immédiatement visible.' },
21
+ { question: 'Le CSS généré est-il lié à un framework ?', answer: 'Non. Le résultat est du CSS natif pur. Utilisez-le en HTML simple, Astro, React, Vue, Svelte, Web Components ou tout projet acceptant du CSS standard.' },
22
+ { question: 'À quoi servent les presets de layout ?', answer: 'Les presets accélèrent les layouts courants pour voir des configurations réalistes sans partir de zéro. Chaque preset configure le mode, la direction, le wrap, l\'alignement et la taille du conteneur pour un motif réel.' },
23
+ ];
24
+
25
+ const ui: VisualCssGridFlexboxGeneratorUI = {
26
+ modeLabel: 'Mode de layout',
27
+ flexMode: 'Flexbox',
28
+ gridMode: 'Grid',
29
+ canvasLabel: 'Canvas de layout interactif',
30
+ addItem: 'Ajouter élément',
31
+ removeItem: 'Retirer élément',
32
+ resetLayout: 'Réinitialiser',
33
+ gapLabel: 'Écart',
34
+ columnsLabel: 'Colonnes grid',
35
+ widthLabel: 'Largeur conteneur',
36
+ heightLabel: 'Hauteur conteneur',
37
+ justifyLabel: 'Justifier',
38
+ alignLabel: 'Aligner',
39
+ itemSizeLabel: 'Taille élément',
40
+ codeTitle: 'CSS Généré',
41
+ copyCode: 'Copier CSS',
42
+ copied: 'Copié !',
43
+ dragHint: 'Redimensionnez le canvas depuis le coin - le CSS se met à jour en direct !',
44
+ outputLabel: 'Sortie CSS générée',
45
+ justifyStart: 'Début',
46
+ justifyCenter: 'Centre',
47
+ justifyEnd: 'Fin',
48
+ justifyBetween: 'Space between',
49
+ justifyAround: 'Space around',
50
+ justifyEvenly: 'Space evenly',
51
+ alignStart: 'Début',
52
+ alignCenter: 'Centre',
53
+ alignEnd: 'Fin',
54
+ alignStretch: 'Étirer',
55
+ alignBaseline: 'Ligne de base',
56
+ itemPrefix: 'Bloc',
57
+ directionLabel: 'Direction',
58
+ directionRow: 'Ligne →',
59
+ directionRowReverse: '← Ligne inv',
60
+ directionColumn: 'Colonne ↓',
61
+ directionColumnReverse: '↑ Col inv',
62
+ wrapLabel: 'Retour',
63
+ wrapNoWrap: 'Sans retour',
64
+ wrapWrap: 'Avec retour',
65
+ wrapWrapReverse: 'Retour inv',
66
+ alignContentLabel: 'Aligner contenu',
67
+ alignContentStart: 'Début',
68
+ alignContentCenter: 'Centre',
69
+ alignContentEnd: 'Fin',
70
+ alignContentBetween: 'Space between',
71
+ alignContentAround: 'Space around',
72
+ alignContentEvenly: 'Space evenly',
73
+ alignContentStretch: 'Étirer',
74
+ presetsLabel: 'Presets',
75
+ presetNavbar: 'Navbar',
76
+ presetCards: 'Cartes',
77
+ presetHero: 'Hero',
78
+ presetSidebar: 'Sidebar',
79
+ presetGallery: 'Galerie',
80
+ shakeLimit: 'Au moins 2 éléments requis !',
81
+ spanHint: 'Double-cliquez sur un élément pour changer sa portée de colonne (1-3) en mode Grid',
82
+ };
83
+
84
+ 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 } })) };
85
+ 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 })) };
86
+ const appSchema: WithContext<SoftwareApplication> = { '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: title, description, applicationCategory: 'DeveloperApplication', operatingSystem: 'Any', offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' } };
87
+
88
+ export const content: ToolLocaleContent<VisualCssGridFlexboxGeneratorUI> = {
89
+ slug, title, description, ui,
90
+ faqTitle: 'FAQ du générateur de layout CSS',
91
+ faq,
92
+ bibliographyTitle: 'Références CSS Grid et Flexbox',
93
+ bibliography,
94
+ howTo,
95
+ schemas: [appSchema, faqSchema, howToSchema],
96
+ seo: [
97
+ { type: 'title', text: 'Créez des layouts CSS en observant le comportement, pas en mémorisant', level: 2 },
98
+ { type: 'paragraph', html: 'CSS Grid et Flexbox sont puissants car ils décrivent des relations de layout au lieu de coordonnées fixes. Le difficile est de prédire comment <strong>gap</strong>, <strong>justify-content</strong>, <strong>align-items</strong>, direction, retour, tracks et espace disponible interagissent. Ce générateur transforme ces propriétés abstraites en un terrain de jeu vivant avec presets et CSS en temps réel.' },
99
+ { type: 'stats', columns: 3, items: [{ value: '5', label: 'Presets de démarrage rapide', icon: 'mdi:view-grid-plus' }, { value: 'Direct', label: 'CSS mis à jour à chaque changement', icon: 'mdi:code-braces' }, { value: '0', label: 'Dépendances framework dans le CSS', icon: 'mdi:language-css3' }] },
100
+ { type: 'title', text: 'Flexbox vs Grid: choisissez le modèle avant de peaufiner l\'alignement', level: 3 },
101
+ { type: 'comparative', columns: 2, items: [{ title: 'Flexbox', description: 'Idéal pour les flux unidimensionnels où les éléments s\'alignent en ligne ou colonne et peuvent se retourner.', icon: 'mdi:format-align-justify', highlight: true, points: ['Navigation', 'Groupes de boutons', 'Cartes enveloppées', 'Contenu centré'] }, { title: 'CSS Grid', description: 'Idéal pour les structures bidimensionnelles où lignes et colonnes définissent la composition.', icon: 'mdi:grid', points: ['Dashboards', 'Galeries', 'Formulaires', 'Sections éditoriales'] }] },
102
+ { type: 'title', text: 'Ce que chaque contrôle vous apprend', level: 3 },
103
+ { type: 'table', headers: ['Contrôle', 'Propriété CSS', 'À observer'], rows: [['Direction', '<code>flex-direction</code>', 'Comment l\'axe principal s\'écoule - passer de ligne à colonne change toute la logique.'], ['Retour', '<code>flex-wrap</code>', 'Si les éléments restent sur une ligne ou passent à la ligne suivante.'], ['Écart', '<code>gap</code>', 'L\'espace entre éléments sans marges qui cassent aux bords.'], ['Justifier', '<code>justify-content</code>', 'Comment l\'espace libre est distribué le long de l\'axe principal.'], ['Aligner', '<code>align-items</code>', 'Comment les éléments se positionnent sur l\'axe transversal.'], ['Aligner contenu', '<code>align-content</code>', 'Comment les lignes enveloppées ou rangées de grid distribuent l\'espace supplémentaire.'], ['Colonnes', '<code>grid-template-columns</code>', 'Combien de tracks égales le grid crée avant que les éléments passent à une autre ligne.'], ['Taille conteneur', '<code>width</code> et <code>min-height</code>', 'Comment le même CSS réagit quand l\'espace disponible change.']] },
104
+ { type: 'tip', title: 'Redimensionnez d\'abord, optimisez ensuite', html: 'Commencez par redimensionner le canvas à une taille réaliste. Puis ajustez l\'écart et l\'alignement. Ainsi le CSS généré fonctionne dans des conditions réelles.' },
105
+ { type: 'title', text: 'CSS propre que vous pouvez adapter', level: 3 },
106
+ { type: 'code', ariaLabel: 'Exemple de CSS généré', code: '.layout-playground {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n gap: 24px;\n justify-content: center;\n align-items: center;\n}' },
107
+ { type: 'diagnostic', variant: 'info', title: 'Pourquoi le redimensionnement visuel est important', html: 'Beaucoup de bugs de layout n\'apparaissent que lorsque le conteneur est plus étroit, plus haut ou rempli différemment. Redimensionner pendant que le CSS se met à jour en direct aide à repérer les retours gênants et les choix d\'alignement fragiles.' },
108
+ { type: 'summary', title: 'Workflow recommandé', items: ['Choisissez un preset ou Flexbox pour les flux unidimensionnels et Grid pour la structure bidimensionnelle.', 'Redimensionnez le canvas avant de copier le CSS pour que le layout survive aux contraintes réelles.', 'Utilisez gap pour l\'espacement entre éléments au lieu d\'ajouter des marges à chaque enfant.', 'Copiez le CSS généré comme point de départ, puis ajoutez des sélecteurs spécifiques et des media queries.'] },
109
+ ],
110
+ };
@@ -0,0 +1,110 @@
1
+ import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+ import type { VisualCssGridFlexboxGeneratorUI } from '../ui';
4
+ import { bibliography } from '../bibliography';
5
+
6
+ const slug = 'generator-visual-css-grid-flexbox';
7
+ const title = 'Generator Visual Layout CSS Grid & Flexbox';
8
+ const description = 'Rancang layout responsif dengan memindahkan blok visual, mengubah ukuran kontainer, menyesuaikan perataan, dan menggunakan preset - lalu salin CSS native bersih secara instan.';
9
+
10
+ const howTo = [
11
+ { name: 'Pilih preset atau Flexbox / Grid', text: 'Mulai dengan preset layout (navbar, cards, hero, sidebar, gallery) atau beralih antara Flexbox dan Grid secara manual.' },
12
+ { name: 'Ubah ukuran layout', text: 'Ubah ukuran kontainer dari sudut bawah untuk menguji bagaimana desain bereaksi terhadap ruang yang tersedia.' },
13
+ { name: 'Sesuaikan kontrol perataan', text: 'Gunakan slider dan dropdown untuk arah, wrap, jarak, kolom, justify-content, align-items, align-content, lebar, tinggi, dan ukuran item.' },
14
+ { name: 'Salin CSS siap produksi', text: 'Salin CSS yang dihasilkan saat hasil visual sesuai dengan struktur yang diinginkan. Tanpa ketergantungan framework.' },
15
+ ];
16
+
17
+ const faq = [
18
+ { question: 'Kapan menggunakan Flexbox daripada CSS Grid?', answer: 'Gunakan Flexbox untuk layout satu dimensi - bilah navigasi, grup tombol, kartu yang membungkus, konten terpusat. Grid saat baris dan kolom sama-sama penting - dashboard, galeri, formulir, bagian halaman terstruktur.' },
19
+ { question: 'Bisakah generator ini membuat layout responsif?', answer: 'Ya. CSS yang dihasilkan menggunakan flex wrapping native atau kolom berulang grid. Ubah ukuran kanvas visual untuk menguji jarak dan perataan pada berbagai ukuran.' },
20
+ { question: 'Mengapa justify-content dan align-items terasa berbeda di grid dan flex?', answer: 'Flexbox mendistribusikan item di sepanjang sumbu utama dan sumbu silang. Grid menempatkan item di track terlebih dahulu, lalu meratakan konten di dalamnya. Beralih antara kedua mode membuat perbedaan itu langsung terlihat.' },
21
+ { question: 'Apakah CSS yang dihasilkan terikat pada framework?', answer: 'Tidak. Hasilnya adalah CSS native murni. Gunakan di HTML biasa, Astro, React, Vue, Svelte, Web Components, atau proyek apa pun yang menerima CSS standar.' },
22
+ { question: 'Untuk apa preset layout?', answer: 'Preset mempercepat layout umum sehingga Anda melihat konfigurasi realistis tanpa mulai dari nol. Setiap preset mengatur mode, arah, wrap, perataan, dan ukuran kontainer untuk pola dunia nyata.' },
23
+ ];
24
+
25
+ const ui: VisualCssGridFlexboxGeneratorUI = {
26
+ modeLabel: 'Mode layout',
27
+ flexMode: 'Flexbox',
28
+ gridMode: 'Grid',
29
+ canvasLabel: 'Kanvas layout interaktif',
30
+ addItem: 'Tambah item',
31
+ removeItem: 'Hapus item',
32
+ resetLayout: 'Reset layout',
33
+ gapLabel: 'Jarak',
34
+ columnsLabel: 'Kolom grid',
35
+ widthLabel: 'Lebar kontainer',
36
+ heightLabel: 'Tinggi kontainer',
37
+ justifyLabel: 'Ratakan',
38
+ alignLabel: 'Ratakan',
39
+ itemSizeLabel: 'Ukuran item',
40
+ codeTitle: 'CSS Dihasilkan',
41
+ copyCode: 'Salin CSS',
42
+ copied: 'Tersalin!',
43
+ dragHint: 'Ubah ukuran kanvas dari sudut - CSS diperbarui langsung!',
44
+ outputLabel: 'Output CSS yang dihasilkan',
45
+ justifyStart: 'Awal',
46
+ justifyCenter: 'Tengah',
47
+ justifyEnd: 'Akhir',
48
+ justifyBetween: 'Space between',
49
+ justifyAround: 'Space around',
50
+ justifyEvenly: 'Space evenly',
51
+ alignStart: 'Awal',
52
+ alignCenter: 'Tengah',
53
+ alignEnd: 'Akhir',
54
+ alignStretch: 'Rentang',
55
+ alignBaseline: 'Garis dasar',
56
+ itemPrefix: 'Blok',
57
+ directionLabel: 'Arah',
58
+ directionRow: 'Baris →',
59
+ directionRowReverse: '← Baris blk',
60
+ directionColumn: 'Kolom ↓',
61
+ directionColumnReverse: '↑ Kol blk',
62
+ wrapLabel: 'Bungkus',
63
+ wrapNoWrap: 'Tanpa bungkus',
64
+ wrapWrap: 'Bungkus',
65
+ wrapWrapReverse: 'Bungkus blk',
66
+ alignContentLabel: 'Ratakan konten',
67
+ alignContentStart: 'Awal',
68
+ alignContentCenter: 'Tengah',
69
+ alignContentEnd: 'Akhir',
70
+ alignContentBetween: 'Space between',
71
+ alignContentAround: 'Space around',
72
+ alignContentEvenly: 'Space evenly',
73
+ alignContentStretch: 'Rentang',
74
+ presetsLabel: 'Preset',
75
+ presetNavbar: 'Navbar',
76
+ presetCards: 'Kartu',
77
+ presetHero: 'Hero',
78
+ presetSidebar: 'Sidebar',
79
+ presetGallery: 'Galeri',
80
+ shakeLimit: 'Butuh minimal 2 item!',
81
+ spanHint: 'Klik dua kali item untuk mengubah rentang kolom (1-3) dalam mode Grid',
82
+ };
83
+
84
+ 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 } })) };
85
+ 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 })) };
86
+ const appSchema: WithContext<SoftwareApplication> = { '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: title, description, applicationCategory: 'DeveloperApplication', operatingSystem: 'Any', offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' } };
87
+
88
+ export const content: ToolLocaleContent<VisualCssGridFlexboxGeneratorUI> = {
89
+ slug, title, description, ui,
90
+ faqTitle: 'FAQ generator layout CSS',
91
+ faq,
92
+ bibliographyTitle: 'Referensi CSS Grid dan Flexbox',
93
+ bibliography,
94
+ howTo,
95
+ schemas: [appSchema, faqSchema, howToSchema],
96
+ seo: [
97
+ { type: 'title', text: 'Bangun layout CSS dengan melihat perilaku, bukan menghafal properti', level: 2 },
98
+ { type: 'paragraph', html: 'CSS Grid dan Flexbox kuat karena mendeskripsikan hubungan layout alih-alih koordinat tetap. Yang sulit adalah memprediksi bagaimana <strong>gap</strong>, <strong>justify-content</strong>, <strong>align-items</strong>, arah, pembungkusan, track, dan ruang yang tersedia berinteraksi. Generator ini mengubah properti abstrak menjadi taman bermain langsung dengan preset dan CSS real-time.' },
99
+ { type: 'stats', columns: 3, items: [{ value: '5', label: 'Preset layout cepat', icon: 'mdi:view-grid-plus' }, { value: 'Langsung', label: 'CSS diperbarui setiap perubahan', icon: 'mdi:code-braces' }, { value: '0', label: 'Ketergantungan framework di CSS', icon: 'mdi:language-css3' }] },
100
+ { type: 'title', text: 'Flexbox vs Grid: pilih model sebelum menyempurnakan perataan', level: 3 },
101
+ { type: 'comparative', columns: 2, items: [{ title: 'Flexbox', description: 'Terbaik untuk aliran satu dimensi di mana item berbaris dalam baris atau kolom dan membungkus secara alami.', icon: 'mdi:format-align-justify', highlight: true, points: ['Bilah navigasi', 'Grup tombol', 'Kartu membungkus', 'Konten terpusat'] }, { title: 'CSS Grid', description: 'Terbaik untuk struktur dua dimensi di mana baris dan kolom menentukan bentuk komposisi.', icon: 'mdi:grid', points: ['Dashboard', 'Galeri', 'Formulir', 'Bagian editorial'] }] },
102
+ { type: 'title', text: 'Apa yang diajarkan setiap kontrol', level: 3 },
103
+ { type: 'table', headers: ['Kontrol', 'Properti CSS', 'Yang perlu diperhatikan'], rows: [['Arah', '<code>flex-direction</code>', 'Bagaimana sumbu utama mengalir - beralih dari baris ke kolom mengubah seluruh logika layout.'], ['Bungkus', '<code>flex-wrap</code>', 'Apakah item tetap di satu baris atau mengalir ke baris baru saat ruang habis.'], ['Jarak', '<code>gap</code>', 'Ruang antara item tanpa margin yang rusak di tepi.'], ['Ratakan', '<code>justify-content</code>', 'Bagaimana ruang kosong didistribusikan di sepanjang sumbu utama.'], ['Ratakan', '<code>align-items</code>', 'Bagaimana item duduk di sumbu silang.'], ['Ratakan konten', '<code>align-content</code>', 'Bagaimana baris flex yang terbungkus atau baris grid mendistribusikan ruang sumbu silang tambahan.'], ['Kolom', '<code>grid-template-columns</code>', 'Berapa banyak track sama yang dibuat grid sebelum item pindah ke baris lain.'], ['Ukuran kontainer', '<code>width</code> dan <code>min-height</code>', 'Bagaimana CSS yang sama bereaksi saat ruang yang tersedia berubah.']] },
104
+ { type: 'tip', title: 'Skalakan dulu, optimalkan kemudian', html: 'Mulailah dengan menskalakan kanvas ke ukuran realistis. Kemudian sesuaikan jarak dan perataan. Dengan begitu CSS yang dihasilkan berfungsi dalam kondisi nyata.' },
105
+ { type: 'title', text: 'CSS bersih yang dapat Anda adaptasi', level: 3 },
106
+ { type: 'code', ariaLabel: 'Contoh CSS yang dihasilkan', code: '.layout-playground {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n gap: 24px;\n justify-content: center;\n align-items: center;\n}' },
107
+ { type: 'diagnostic', variant: 'info', title: 'Mengapa penskalaan visual penting', html: 'Banyak bug layout hanya muncul saat kontainer lebih sempit, lebih tinggi, atau diisi dengan jumlah item berbeda. Menskalakan saat CSS diperbarui langsung membantu menemukan pembungkusan yang canggung dan pilihan perataan yang rapuh.' },
108
+ { type: 'summary', title: 'Alur kerja yang direkomendasikan', items: ['Pilih preset atau Flexbox untuk aliran satu dimensi dan Grid untuk struktur dua dimensi.', 'Skalakan kanvas sebelum menyalin CSS agar layout bertahan dalam batasan realistis.', 'Gunakan gap untuk jarak antar item alih-alih menambahkan margin ke setiap anak.', 'Salin CSS yang dihasilkan sebagai titik awal, lalu tambahkan selector spesifik proyek dan media queries.'] },
109
+ ],
110
+ };