@jjlmoya/utils-diy 1.1.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 (135) hide show
  1. package/package.json +60 -0
  2. package/src/category/i18n/en.ts +110 -0
  3. package/src/category/i18n/es.ts +110 -0
  4. package/src/category/i18n/fr.ts +101 -0
  5. package/src/category/index.ts +25 -0
  6. package/src/category/seo.astro +15 -0
  7. package/src/components/PreviewNavSidebar.astro +116 -0
  8. package/src/components/PreviewToolbar.astro +143 -0
  9. package/src/data.ts +11 -0
  10. package/src/env.d.ts +5 -0
  11. package/src/index.ts +57 -0
  12. package/src/layouts/PreviewLayout.astro +117 -0
  13. package/src/pages/[locale]/[slug].astro +146 -0
  14. package/src/pages/[locale].astro +251 -0
  15. package/src/pages/index.astro +4 -0
  16. package/src/tests/faq_count.test.ts +19 -0
  17. package/src/tests/locale_completeness.test.ts +42 -0
  18. package/src/tests/mocks/astro_mock.js +2 -0
  19. package/src/tests/no_h1_in_components.test.ts +48 -0
  20. package/src/tests/schemas_fulfillment.test.ts +23 -0
  21. package/src/tests/seo_length.test.ts +22 -0
  22. package/src/tests/title_quality.test.ts +55 -0
  23. package/src/tests/tool_validation.test.ts +17 -0
  24. package/src/tool/balusterCalculator/bibliography.astro +14 -0
  25. package/src/tool/balusterCalculator/component.astro +605 -0
  26. package/src/tool/balusterCalculator/i18n/en.ts +264 -0
  27. package/src/tool/balusterCalculator/i18n/es.ts +264 -0
  28. package/src/tool/balusterCalculator/i18n/fr.ts +264 -0
  29. package/src/tool/balusterCalculator/index.ts +33 -0
  30. package/src/tool/balusterCalculator/seo.astro +15 -0
  31. package/src/tool/balusterCalculator/ui.ts +15 -0
  32. package/src/tool/clayCalculator/bibliography.astro +14 -0
  33. package/src/tool/clayCalculator/component.astro +731 -0
  34. package/src/tool/clayCalculator/i18n/en.ts +183 -0
  35. package/src/tool/clayCalculator/i18n/es.ts +183 -0
  36. package/src/tool/clayCalculator/i18n/fr.ts +183 -0
  37. package/src/tool/clayCalculator/index.ts +33 -0
  38. package/src/tool/clayCalculator/seo.astro +15 -0
  39. package/src/tool/clayCalculator/ui.ts +19 -0
  40. package/src/tool/concreteCalculator/bibliography.astro +13 -0
  41. package/src/tool/concreteCalculator/component.astro +1089 -0
  42. package/src/tool/concreteCalculator/i18n/en.ts +201 -0
  43. package/src/tool/concreteCalculator/i18n/es.ts +201 -0
  44. package/src/tool/concreteCalculator/i18n/fr.ts +201 -0
  45. package/src/tool/concreteCalculator/index.ts +28 -0
  46. package/src/tool/concreteCalculator/seo.astro +14 -0
  47. package/src/tool/concreteCalculator/ui.ts +35 -0
  48. package/src/tool/cutOptimizer/bibliography.astro +13 -0
  49. package/src/tool/cutOptimizer/component.astro +825 -0
  50. package/src/tool/cutOptimizer/i18n/en.ts +178 -0
  51. package/src/tool/cutOptimizer/i18n/es.ts +178 -0
  52. package/src/tool/cutOptimizer/i18n/fr.ts +178 -0
  53. package/src/tool/cutOptimizer/index.ts +28 -0
  54. package/src/tool/cutOptimizer/optimizer.ts +199 -0
  55. package/src/tool/cutOptimizer/seo.astro +14 -0
  56. package/src/tool/cutOptimizer/ui.ts +25 -0
  57. package/src/tool/drillCalculator/bibliography.astro +13 -0
  58. package/src/tool/drillCalculator/component.astro +1210 -0
  59. package/src/tool/drillCalculator/engine.ts +63 -0
  60. package/src/tool/drillCalculator/i18n/en.ts +137 -0
  61. package/src/tool/drillCalculator/i18n/es.ts +137 -0
  62. package/src/tool/drillCalculator/i18n/fr.ts +137 -0
  63. package/src/tool/drillCalculator/index.ts +28 -0
  64. package/src/tool/drillCalculator/seo.astro +14 -0
  65. package/src/tool/drillCalculator/ui.ts +41 -0
  66. package/src/tool/drillSharpener/bibliography.astro +13 -0
  67. package/src/tool/drillSharpener/component.astro +712 -0
  68. package/src/tool/drillSharpener/engine.ts +42 -0
  69. package/src/tool/drillSharpener/i18n/en.ts +121 -0
  70. package/src/tool/drillSharpener/i18n/es.ts +121 -0
  71. package/src/tool/drillSharpener/i18n/fr.ts +121 -0
  72. package/src/tool/drillSharpener/index.ts +31 -0
  73. package/src/tool/drillSharpener/seo.astro +14 -0
  74. package/src/tool/drillSharpener/ui.ts +53 -0
  75. package/src/tool/epoxyCalculator/bibliography.astro +14 -0
  76. package/src/tool/epoxyCalculator/component.astro +888 -0
  77. package/src/tool/epoxyCalculator/i18n/en.ts +195 -0
  78. package/src/tool/epoxyCalculator/i18n/es.ts +195 -0
  79. package/src/tool/epoxyCalculator/i18n/fr.ts +195 -0
  80. package/src/tool/epoxyCalculator/index.ts +33 -0
  81. package/src/tool/epoxyCalculator/seo.astro +15 -0
  82. package/src/tool/epoxyCalculator/ui.ts +22 -0
  83. package/src/tool/furnitureFit/bibliography.astro +13 -0
  84. package/src/tool/furnitureFit/component.astro +552 -0
  85. package/src/tool/furnitureFit/engine.ts +51 -0
  86. package/src/tool/furnitureFit/i18n/en.ts +152 -0
  87. package/src/tool/furnitureFit/i18n/es.ts +152 -0
  88. package/src/tool/furnitureFit/i18n/fr.ts +152 -0
  89. package/src/tool/furnitureFit/index.ts +28 -0
  90. package/src/tool/furnitureFit/seo.astro +14 -0
  91. package/src/tool/furnitureFit/ui.ts +21 -0
  92. package/src/tool/mortarCalculator/bibliography.astro +13 -0
  93. package/src/tool/mortarCalculator/component.astro +1139 -0
  94. package/src/tool/mortarCalculator/i18n/en.ts +219 -0
  95. package/src/tool/mortarCalculator/i18n/es.ts +205 -0
  96. package/src/tool/mortarCalculator/i18n/fr.ts +220 -0
  97. package/src/tool/mortarCalculator/index.ts +24 -0
  98. package/src/tool/mortarCalculator/seo.astro +14 -0
  99. package/src/tool/mortarCalculator/ui.ts +37 -0
  100. package/src/tool/passepartoutCalculator/bibliography.astro +13 -0
  101. package/src/tool/passepartoutCalculator/component.astro +741 -0
  102. package/src/tool/passepartoutCalculator/i18n/en.ts +178 -0
  103. package/src/tool/passepartoutCalculator/i18n/es.ts +178 -0
  104. package/src/tool/passepartoutCalculator/i18n/fr.ts +178 -0
  105. package/src/tool/passepartoutCalculator/index.ts +28 -0
  106. package/src/tool/passepartoutCalculator/seo.astro +14 -0
  107. package/src/tool/passepartoutCalculator/ui.ts +17 -0
  108. package/src/tool/stairCalculator/bibliography.astro +52 -0
  109. package/src/tool/stairCalculator/component.astro +766 -0
  110. package/src/tool/stairCalculator/engine.ts +128 -0
  111. package/src/tool/stairCalculator/i18n/en.ts +149 -0
  112. package/src/tool/stairCalculator/i18n/es.ts +149 -0
  113. package/src/tool/stairCalculator/i18n/fr.ts +149 -0
  114. package/src/tool/stairCalculator/index.ts +31 -0
  115. package/src/tool/stairCalculator/seo.astro +211 -0
  116. package/src/tool/stairCalculator/ui.ts +109 -0
  117. package/src/tool/thermalExpansionCalculator/bibliography.astro +13 -0
  118. package/src/tool/thermalExpansionCalculator/component.astro +771 -0
  119. package/src/tool/thermalExpansionCalculator/engine.ts +23 -0
  120. package/src/tool/thermalExpansionCalculator/i18n/en.ts +174 -0
  121. package/src/tool/thermalExpansionCalculator/i18n/es.ts +174 -0
  122. package/src/tool/thermalExpansionCalculator/i18n/fr.ts +174 -0
  123. package/src/tool/thermalExpansionCalculator/index.ts +28 -0
  124. package/src/tool/thermalExpansionCalculator/seo.astro +14 -0
  125. package/src/tool/thermalExpansionCalculator/ui.ts +41 -0
  126. package/src/tool/voltageDropCalculator/bibliography.astro +13 -0
  127. package/src/tool/voltageDropCalculator/component.astro +1022 -0
  128. package/src/tool/voltageDropCalculator/i18n/en.ts +155 -0
  129. package/src/tool/voltageDropCalculator/i18n/es.ts +155 -0
  130. package/src/tool/voltageDropCalculator/i18n/fr.ts +148 -0
  131. package/src/tool/voltageDropCalculator/index.ts +28 -0
  132. package/src/tool/voltageDropCalculator/seo.astro +14 -0
  133. package/src/tool/voltageDropCalculator/ui.ts +22 -0
  134. package/src/tools.ts +16 -0
  135. package/src/types.ts +72 -0
@@ -0,0 +1,152 @@
1
+ import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+ import type { FurnitureFitUI } from '../ui';
4
+
5
+ const slug = 'furniture-fit-calculator';
6
+ const title = 'Furniture Fit Calculator: Will It Go Through the Door?';
7
+ const description =
8
+ 'Check if your sofa, wardrobe or dining table fits through the elevator or door. Use the 3D Pythagorean theorem to calculate tilt clearance and avoid expensive moving disasters.';
9
+
10
+ const faqData = [
11
+ {
12
+ question: 'Why can a sofa not fit even if it is smaller than the doorway?',
13
+ answer:
14
+ 'Because of the turning angle. If the hallway is narrow, the sofa must enter sideways or tilted. The limiting factor is not just the door width, but the turning radius available in the entrance area.',
15
+ },
16
+ {
17
+ question: 'What is the diagonal of a piece of furniture and why does it matter?',
18
+ answer:
19
+ 'It is the longest distance between two opposite corners. It is critical for knowing whether a tall piece of furniture can be lifted upright in a room with a low ceiling after being assembled on the floor.',
20
+ },
21
+ {
22
+ question: 'How do I measure a lift correctly?',
23
+ answer:
24
+ 'Do not just measure the floor. Measure the width of the open door (which is often smaller than the lift interior), the free depth, and the total height. The diagonal from the base of the door to the upper rear corner is the most important figure.',
25
+ },
26
+ {
27
+ question: 'What parts should be disassembled first?',
28
+ answer:
29
+ 'Sofa legs, wardrobe handles and fridge doors typically gain 5 to 10 critical centimetres that make the difference between a piece fitting or being left on the street.',
30
+ },
31
+ ];
32
+
33
+ const howToData = [
34
+ {
35
+ name: 'Measure the furniture (Length, Width, Height)',
36
+ text: 'Take the maximum dimensions of the object, including any protrusions such as armrests or handles.',
37
+ },
38
+ {
39
+ name: 'Measure the critical passages',
40
+ text: 'Measure the clear opening of the door (frame to frame), the lift interior and the corridor width.',
41
+ },
42
+ {
43
+ name: 'Enter the data in the simulator',
44
+ text: 'Type the dimensions into the tool to see whether the furniture volume is compatible with the passage space.',
45
+ },
46
+ {
47
+ name: 'Calculate tilt clearance',
48
+ text: 'If the furniture is very tall, use the calculated diagonal to verify whether you can rotate it on the staircase landing or inside the lift.',
49
+ },
50
+ ];
51
+
52
+ const faqSchema: WithContext<FAQPage> = {
53
+ '@context': 'https://schema.org',
54
+ '@type': 'FAQPage',
55
+ mainEntity: faqData.map((item) => ({
56
+ '@type': 'Question',
57
+ name: item.question,
58
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
59
+ })),
60
+ };
61
+
62
+ const howToSchema: WithContext<HowToThing> = {
63
+ '@context': 'https://schema.org',
64
+ '@type': 'HowTo',
65
+ name: title,
66
+ description,
67
+ step: howToData.map((step, i) => ({
68
+ '@type': 'HowToStep',
69
+ position: i + 1,
70
+ name: step.name,
71
+ text: step.text,
72
+ })),
73
+ };
74
+
75
+ const appSchema: WithContext<SoftwareApplication> = {
76
+ '@context': 'https://schema.org',
77
+ '@type': 'SoftwareApplication',
78
+ name: title,
79
+ description,
80
+ applicationCategory: 'UtilityApplication',
81
+ operatingSystem: 'All',
82
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
83
+ inLanguage: 'en',
84
+ };
85
+
86
+ export const content: ToolLocaleContent<FurnitureFitUI> = {
87
+ slug,
88
+ title,
89
+ description,
90
+ faqTitle: 'Frequently Asked Questions',
91
+ faq: faqData,
92
+ bibliographyTitle: 'Technical References',
93
+ bibliography: [
94
+ { name: 'Geometric Fit in Confined Spaces (MDPI Buildings)', url: 'https://www.mdpi.com/2075-5309/15/2/157' },
95
+ { name: 'Moving Sofa Problem: Wolfram MathWorld', url: 'https://mathworld.wolfram.com/MovingSofaProblem.html' },
96
+ ],
97
+ howTo: howToData,
98
+ schemas: [faqSchema, howToSchema, appSchema],
99
+ seo: [
100
+ { type: 'title', text: 'The Science of Moving House: Pythagorean Theorem in Practice', level: 2 },
101
+ {
102
+ type: 'paragraph',
103
+ html: 'Moving house is not just a physical challenge — it is a complex geometric puzzle. The apparent space of a room or lift deceives the human eye, especially when we ignore the third dimension. Applied mathematics can save you hundreds of pounds in returns and failed deliveries.',
104
+ },
105
+ { type: 'title', text: 'The 3D Diagonal Trick', level: 3 },
106
+ {
107
+ type: 'card',
108
+ icon: 'mdi:math-log',
109
+ title: 'The Golden Rule of Measuring',
110
+ html: '<p>Never just measure the furniture. Always measure the <strong>critical access points</strong>: the clear width of the door frame (subtract door thickness if it does not open 180°), the lowest point of the ceiling on the landing, and the actual depth of the lift with doors closed. The formula <code>d = √(w² + h² + z²)</code> reveals whether the piece fits when tilted.</p>',
111
+ },
112
+ { type: 'title', text: 'The Moving Sofa Problem', level: 3 },
113
+ {
114
+ type: 'card',
115
+ icon: 'mdi:sofa',
116
+ title: 'Safety Margin Matters',
117
+ html: '<p>A common mistake is assuming that if the furniture measures 80cm and the gap is 80cm, it will pass. It will not. The movers\' hands, fabric elasticity and wall imperfections all require a minimum clearance of <strong>2 to 5 cm</strong>. Without this margin, the piece will be scratched or wedged in by pressure.</p>',
118
+ },
119
+ {
120
+ type: 'card',
121
+ icon: 'mdi:tools',
122
+ title: 'Disassemble to Win',
123
+ html: '<p>Before giving up because a piece does not fit, check the legs. Removing sofa legs often reduces the critical height by 10 to 15cm — the difference between success and leaving it in the lobby. Fridge doors and wardrobe handles also add critical centimetres.</p>',
124
+ },
125
+ { type: 'title', text: '3 Mistakes That Ruin Every Move', level: 3 },
126
+ {
127
+ type: 'paragraph',
128
+ html: 'Even with correct measurements, these invisible factors cause disasters: <strong>The Ceiling Light</strong> — forgotten during the diagonal tilt, it can be hit and smashed. <strong>Furniture Turning Radius</strong> — a rigid piece does not bend; even if it fits width-wise in a narrow corridor, it cannot complete the corner turn. <strong>Packaging</strong> — bubble wrap and cardboard protection can add 1 to 3 cm on every side.',
129
+ },
130
+ ],
131
+ ui: {
132
+ conTitle: 'Space Dimensions',
133
+ conHint: 'E.g.: Standard lift, door frame or van interior.',
134
+ objTitle: 'Furniture Dimensions',
135
+ labelWidth: 'Width (cm)',
136
+ labelHeight: 'Height (cm)',
137
+ labelDepth: 'Depth (cm)',
138
+ labelLength: 'Length (cm)',
139
+ labelMargin: 'Safety Margin (cm)',
140
+ vizLabel: 'Simplified Spatial View',
141
+ verdictDefault: 'Will it fit?',
142
+ verdictHint: 'Enter the measurements to check spatial compatibility.',
143
+ verdictYes: 'YES, IT FITS!',
144
+ verdictNo: 'DOES NOT FIT',
145
+ fitDirect: 'The furniture fits directly without any tilting.',
146
+ fitDiagonal3d: 'Fits when tilted diagonally (3D Pythagorean theorem).',
147
+ fitDiagonalPlane: 'Fits when tilted in one of the lateral planes.',
148
+ fitNope: 'The furniture is too large even when tilted diagonally.',
149
+ diagLabel: 'Maximum Diagonal (3D Pythagoras):',
150
+ objLabel: 'Furniture',
151
+ },
152
+ };
@@ -0,0 +1,152 @@
1
+ import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+ import type { FurnitureFitUI } from '../ui';
4
+
5
+ const slug = 'calculadora-espacio-muebles';
6
+ const title = 'Calculadora de Espacio para Mudanzas y Muebles';
7
+ const description =
8
+ 'Comprueba si tu sofá, armario o mesa cabe en el ascensor o por la puerta. Usa el teorema de Pitágoras 3D para calcular inclinaciones y evitar desastres en tu mudanza.';
9
+
10
+ const faqData = [
11
+ {
12
+ question: '¿Por qué un sofá puede no caber aunque sea más pequeño que la puerta?',
13
+ answer:
14
+ 'Debido al ángulo de giro. Si el pasillo es estrecho, el sofá debe entrar de lado o inclinado. El factor limitante no es solo el ancho de la puerta, sino el radio de giro disponible en el recibidor.',
15
+ },
16
+ {
17
+ question: '¿Qué es la diagonal de un mueble y por qué importa?',
18
+ answer:
19
+ 'Es la distancia más larga entre dos esquinas opuestas. Es vital para saber si un mueble alto puede ser levantado en una habitación con techo bajo después de haber sido montado en el suelo.',
20
+ },
21
+ {
22
+ question: '¿Cómo medir un ascensor correctamente?',
23
+ answer:
24
+ 'No midas solo el suelo. Mide el ancho de la puerta abierta, la profundidad libre y la altura total. La diagonal desde la base de la puerta hasta la esquina superior trasera es el dato más importante.',
25
+ },
26
+ {
27
+ question: '¿Qué piezas se deben desmontar primero?',
28
+ answer:
29
+ 'Patas de sofás, tiradores de armarios y puertas de neveras suelen ganar entre 5 y 10 cm críticos que marcan la diferencia entre que un mueble quepa o se quede en la calle.',
30
+ },
31
+ ];
32
+
33
+ const howToData = [
34
+ {
35
+ name: 'Medir el mueble (Largo, Ancho, Alto)',
36
+ text: 'Toma las medidas máximas del objeto, incluyendo cualquier saliente como reposabrazos o tiradores.',
37
+ },
38
+ {
39
+ name: 'Medir los pasos críticos',
40
+ text: 'Mide el hueco libre de la puerta (de marco a marco), el interior del ascensor y el ancho de los pasillos.',
41
+ },
42
+ {
43
+ name: 'Introducir datos en el simulador',
44
+ text: 'Escribe las dimensiones en la herramienta para ver si el volumen del mueble es compatible con el espacio de paso.',
45
+ },
46
+ {
47
+ name: 'Calcular inclinaciones',
48
+ text: 'Si el mueble es muy alto, usa la diagonal calculada para verificar si podrás girarlo en el descanso de la escalera o dentro del ascensor.',
49
+ },
50
+ ];
51
+
52
+ const faqSchema: WithContext<FAQPage> = {
53
+ '@context': 'https://schema.org',
54
+ '@type': 'FAQPage',
55
+ mainEntity: faqData.map((item) => ({
56
+ '@type': 'Question',
57
+ name: item.question,
58
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
59
+ })),
60
+ };
61
+
62
+ const howToSchema: WithContext<HowToThing> = {
63
+ '@context': 'https://schema.org',
64
+ '@type': 'HowTo',
65
+ name: title,
66
+ description,
67
+ step: howToData.map((step, i) => ({
68
+ '@type': 'HowToStep',
69
+ position: i + 1,
70
+ name: step.name,
71
+ text: step.text,
72
+ })),
73
+ };
74
+
75
+ const appSchema: WithContext<SoftwareApplication> = {
76
+ '@context': 'https://schema.org',
77
+ '@type': 'SoftwareApplication',
78
+ name: title,
79
+ description,
80
+ applicationCategory: 'UtilityApplication',
81
+ operatingSystem: 'All',
82
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
83
+ inLanguage: 'es',
84
+ };
85
+
86
+ export const content: ToolLocaleContent<FurnitureFitUI> = {
87
+ slug,
88
+ title,
89
+ description,
90
+ faqTitle: 'Preguntas Frecuentes',
91
+ faq: faqData,
92
+ bibliographyTitle: 'Referencias Técnicas',
93
+ bibliography: [
94
+ { name: 'Geometric Fit in Confined Spaces (MDPI Buildings)', url: 'https://www.mdpi.com/2075-5309/15/2/157' },
95
+ { name: 'Moving Sofa Problem: Wolfram MathWorld', url: 'https://mathworld.wolfram.com/MovingSofaProblem.html' },
96
+ ],
97
+ howTo: howToData,
98
+ schemas: [faqSchema, howToSchema, appSchema],
99
+ seo: [
100
+ { type: 'title', text: 'La Ciencia de las Mudanzas y el Teorema de Pitágoras', level: 2 },
101
+ {
102
+ type: 'paragraph',
103
+ html: 'Las mudanzas no son solo una prueba de fuerza física; son un complejo puzzle geométrico. El espacio aparente de una habitación o un ascensor engaña al ojo humano, especialmente cuando ignoramos la tercera dimensión. La matemática puede ahorrarte cientos de euros en devoluciones y transportes fallidos.',
104
+ },
105
+ { type: 'title', text: 'El Truco de la Diagonal 3D', level: 3 },
106
+ {
107
+ type: 'card',
108
+ icon: 'mdi:math-log',
109
+ title: 'Regla de Oro',
110
+ html: '<p>Nunca midas solo el mueble. Mide siempre los <strong>puntos críticos de acceso</strong>: el ancho del marco de la puerta (restando el grosor de la propia puerta si no abre 180°), el punto más bajo del techo en el rellano y la profundidad real del ascensor con las puertas cerradas. La fórmula <code>d = √(w² + h² + z²)</code> te revela si cabe inclinado.</p>',
111
+ },
112
+ { type: 'title', text: 'El Problema del Sofá en el Pasillo', level: 3 },
113
+ {
114
+ type: 'card',
115
+ icon: 'mdi:sofa',
116
+ title: 'Margen de Maniobra',
117
+ html: '<p>Un error común es asumir que si el mueble mide 80cm y el hueco 80cm, pasará. No es así. Las manos de los transportistas, la elasticidad del tejido y las imperfecciones de las paredes requieren un margen mínimo de <strong>2 a 5 cm</strong>. Sin este margen, el mueble se rayará o quedará encajado por presión.</p>',
118
+ },
119
+ {
120
+ type: 'card',
121
+ icon: 'mdi:tools',
122
+ title: 'Desmontar es Ganar',
123
+ html: '<p>Antes de rendirte porque el mueble no cabe, verifica las patas. Muchas veces, quitar las patas de un sofá reduce su altura crítica en 10 a 15cm, lo que marca la diferencia entre entrar triunfalmente o quedarse en el portal. Las puertas de nevera y los tiradores de armario también suman centímetros críticos.</p>',
124
+ },
125
+ { type: 'title', text: 'Los 3 Errores que Arruinan una Mudanza', level: 3 },
126
+ {
127
+ type: 'paragraph',
128
+ html: 'Incluso con medidas correctas, estos factores invisibles suelen causar desastres: <strong>La Lámpara del Techo</strong> — olvidada durante el giro diagonal, puede ser golpeada y destruida. <strong>El Radio de Giro del Mueble</strong> — un mueble rígido no se dobla; si el pasillo es estrecho y el mueble largo, aunque quepa de ancho, no podrá realizar el giro de esquina. <strong>El Embalaje</strong> — el papel burbuja y el cartón protector pueden añadir de 1 a 3 cm a cada lado.',
129
+ },
130
+ ],
131
+ ui: {
132
+ conTitle: 'Dimensiones del Espacio',
133
+ conHint: 'Ej: Ascensor estándar, marco de puerta o furgoneta.',
134
+ objTitle: 'Dimensiones del Mueble',
135
+ labelWidth: 'Ancho (cm)',
136
+ labelHeight: 'Alto (cm)',
137
+ labelDepth: 'Fondo (cm)',
138
+ labelLength: 'Largo (cm)',
139
+ labelMargin: 'Margen de Error (cm)',
140
+ vizLabel: 'Vista Espacial Simplificada',
141
+ verdictDefault: '¿Cabe?',
142
+ verdictHint: 'Introduce las medidas para comprobar la compatibilidad espacial.',
143
+ verdictYes: '¡SÍ, CABE!',
144
+ verdictNo: 'NO CABE',
145
+ fitDirect: 'El mueble cabe perfectamente de forma directa.',
146
+ fitDiagonal3d: 'Cabe inclinado diagonalmente (Pitágoras 3D).',
147
+ fitDiagonalPlane: 'Cabe inclinado en uno de los planos laterales.',
148
+ fitNope: 'El mueble es demasiado grande incluso para entrar en diagonal.',
149
+ diagLabel: 'Diagonal Máxima (Pitágoras 3D):',
150
+ objLabel: 'Mueble',
151
+ },
152
+ };
@@ -0,0 +1,152 @@
1
+ import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+ import type { FurnitureFitUI } from '../ui';
4
+
5
+ const slug = 'calculateur-encombrement-meubles';
6
+ const title = 'Calculateur de Place pour Meubles et Déménagement';
7
+ const description =
8
+ 'Vérifiez si votre canapé, armoire ou table passe dans l\'ascenseur ou par la porte. Utilisez le théorème de Pythagore 3D pour calculer les inclinaisons et éviter les catastrophes de déménagement.';
9
+
10
+ const faqData = [
11
+ {
12
+ question: 'Pourquoi un canapé peut ne pas passer même s\'il est plus petit que la porte?',
13
+ answer:
14
+ 'À cause de l\'angle de rotation. Si le couloir est étroit, le canapé doit entrer de côté ou incliné. Le facteur limitant n\'est pas seulement la largeur de la porte, mais le rayon de giration disponible dans l\'entrée.',
15
+ },
16
+ {
17
+ question: 'Qu\'est-ce que la diagonale d\'un meuble et pourquoi est-elle importante?',
18
+ answer:
19
+ 'C\'est la plus grande distance entre deux coins opposés. Elle est essentielle pour savoir si un meuble haut peut être redressé dans une pièce à plafond bas après avoir été assemblé au sol.',
20
+ },
21
+ {
22
+ question: 'Comment mesurer un ascenseur correctement?',
23
+ answer:
24
+ 'Ne mesurez pas seulement le sol. Mesurez la largeur de la porte ouverte, la profondeur libre et la hauteur totale. La diagonale depuis la base de la porte jusqu\'au coin supérieur arrière est la donnée la plus importante.',
25
+ },
26
+ {
27
+ question: 'Quelles pièces démonter en premier?',
28
+ answer:
29
+ 'Les pieds de canapés, poignées d\'armoires et portes de réfrigérateurs permettent souvent de gagner 5 à 10 cm critiques qui font la différence entre un meuble qui passe ou qui reste dans la rue.',
30
+ },
31
+ ];
32
+
33
+ const howToData = [
34
+ {
35
+ name: 'Mesurer le meuble (Longueur, Largeur, Hauteur)',
36
+ text: 'Prenez les dimensions maximales de l\'objet, y compris les saillies comme les accoudoirs ou les poignées.',
37
+ },
38
+ {
39
+ name: 'Mesurer les passages critiques',
40
+ text: 'Mesurez le dégagement de la porte (de cadre à cadre), l\'intérieur de l\'ascenseur et la largeur des couloirs.',
41
+ },
42
+ {
43
+ name: 'Saisir les données dans le simulateur',
44
+ text: 'Entrez les dimensions dans l\'outil pour vérifier si le volume du meuble est compatible avec l\'espace de passage.',
45
+ },
46
+ {
47
+ name: 'Calculer les inclinaisons',
48
+ text: 'Si le meuble est très haut, utilisez la diagonale calculée pour vérifier si vous pouvez le faire pivoter sur le palier ou dans l\'ascenseur.',
49
+ },
50
+ ];
51
+
52
+ const faqSchema: WithContext<FAQPage> = {
53
+ '@context': 'https://schema.org',
54
+ '@type': 'FAQPage',
55
+ mainEntity: faqData.map((item) => ({
56
+ '@type': 'Question',
57
+ name: item.question,
58
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
59
+ })),
60
+ };
61
+
62
+ const howToSchema: WithContext<HowToThing> = {
63
+ '@context': 'https://schema.org',
64
+ '@type': 'HowTo',
65
+ name: title,
66
+ description,
67
+ step: howToData.map((step, i) => ({
68
+ '@type': 'HowToStep',
69
+ position: i + 1,
70
+ name: step.name,
71
+ text: step.text,
72
+ })),
73
+ };
74
+
75
+ const appSchema: WithContext<SoftwareApplication> = {
76
+ '@context': 'https://schema.org',
77
+ '@type': 'SoftwareApplication',
78
+ name: title,
79
+ description,
80
+ applicationCategory: 'UtilityApplication',
81
+ operatingSystem: 'All',
82
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
83
+ inLanguage: 'fr',
84
+ };
85
+
86
+ export const content: ToolLocaleContent<FurnitureFitUI> = {
87
+ slug,
88
+ title,
89
+ description,
90
+ faqTitle: 'Questions Fréquentes',
91
+ faq: faqData,
92
+ bibliographyTitle: 'Références Techniques',
93
+ bibliography: [
94
+ { name: 'Geometric Fit in Confined Spaces (MDPI Buildings)', url: 'https://www.mdpi.com/2075-5309/15/2/157' },
95
+ { name: 'Moving Sofa Problem: Wolfram MathWorld', url: 'https://mathworld.wolfram.com/MovingSofaProblem.html' },
96
+ ],
97
+ howTo: howToData,
98
+ schemas: [faqSchema, howToSchema, appSchema],
99
+ seo: [
100
+ { type: 'title', text: 'La Science du Déménagement et le Théorème de Pythagore', level: 2 },
101
+ {
102
+ type: 'paragraph',
103
+ html: 'Un déménagement n\'est pas seulement une épreuve physique — c\'est un puzzle géométrique complexe. L\'espace apparent d\'une pièce ou d\'un ascenseur trompe l\'œil humain, surtout lorsqu\'on ignore la troisième dimension. Les mathématiques peuvent vous faire économiser des centaines d\'euros en retours et transports ratés.',
104
+ },
105
+ { type: 'title', text: 'L\'Astuce de la Diagonale 3D', level: 3 },
106
+ {
107
+ type: 'card',
108
+ icon: 'mdi:math-log',
109
+ title: 'La Règle d\'Or de la Mesure',
110
+ html: '<p>Ne mesurez jamais seulement le meuble. Mesurez toujours les <strong>points d\'accès critiques</strong>: la largeur nette du cadre de porte (soustrayez l\'épaisseur de la porte si elle n\'ouvre pas à 180°), le point le plus bas du plafond sur le palier et la profondeur réelle de l\'ascenseur portes fermées. La formule <code>d = √(l² + h² + p²)</code> révèle si le meuble passe incliné.</p>',
111
+ },
112
+ { type: 'title', text: 'Le Problème du Canapé dans le Couloir', level: 3 },
113
+ {
114
+ type: 'card',
115
+ icon: 'mdi:sofa',
116
+ title: 'La Marge de Manœuvre',
117
+ html: '<p>Une erreur courante est de supposer que si le meuble fait 80cm et l\'ouverture 80cm, il passera. Non. Les mains des déménageurs, l\'élasticité du tissu et les imperfections des murs nécessitent une marge minimale de <strong>2 à 5 cm</strong>. Sans cette marge, le meuble sera rayé ou coincé par pression.</p>',
118
+ },
119
+ {
120
+ type: 'card',
121
+ icon: 'mdi:tools',
122
+ title: 'Démonter pour Gagner',
123
+ html: '<p>Avant d\'abandonner parce que le meuble ne passe pas, vérifiez les pieds. Retirer les pieds d\'un canapé réduit souvent sa hauteur critique de 10 à 15cm, la différence entre entrer triomphalement ou rester dans le hall. Les portes de réfrigérateur et les poignées d\'armoire ajoutent aussi des centimètres critiques.</p>',
124
+ },
125
+ { type: 'title', text: '3 Erreurs Fatales lors d\'un Déménagement', level: 3 },
126
+ {
127
+ type: 'paragraph',
128
+ html: 'Même avec des mesures correctes, ces facteurs invisibles provoquent des catastrophes: <strong>Le Luminaire au Plafond</strong> — oublié pendant l\'inclinaison diagonale, il peut être heurté et brisé. <strong>Le Rayon de Giration du Meuble</strong> — un meuble rigide ne se plie pas; même s\'il passe en largeur dans un couloir étroit, il ne pourra pas effectuer le virage. <strong>L\'Emballage</strong> — le papier bulle et le carton de protection peuvent ajouter 1 à 3 cm de chaque côté.',
129
+ },
130
+ ],
131
+ ui: {
132
+ conTitle: 'Dimensions de l\'Espace',
133
+ conHint: 'Ex: Ascenseur standard, encadrement de porte ou fourgonnette.',
134
+ objTitle: 'Dimensions du Meuble',
135
+ labelWidth: 'Largeur (cm)',
136
+ labelHeight: 'Hauteur (cm)',
137
+ labelDepth: 'Profondeur (cm)',
138
+ labelLength: 'Longueur (cm)',
139
+ labelMargin: 'Marge d\'Erreur (cm)',
140
+ vizLabel: 'Vue Spatiale Simplifiée',
141
+ verdictDefault: 'Ça rentre?',
142
+ verdictHint: 'Entrez les mesures pour vérifier la compatibilité spatiale.',
143
+ verdictYes: 'OUI, ÇA RENTRE!',
144
+ verdictNo: 'ÇA NE RENTRE PAS',
145
+ fitDirect: 'Le meuble rentre parfaitement de façon directe.',
146
+ fitDiagonal3d: 'Rentre incliné en diagonale (Pythagore 3D).',
147
+ fitDiagonalPlane: 'Rentre incliné dans l\'un des plans latéraux.',
148
+ fitNope: 'Le meuble est trop grand même incliné en diagonale.',
149
+ diagLabel: 'Diagonale Maximale (Pythagore 3D):',
150
+ objLabel: 'Meuble',
151
+ },
152
+ };
@@ -0,0 +1,28 @@
1
+ import FurnitureFitComponent from './component.astro';
2
+ import FurnitureFitSEO from './seo.astro';
3
+ import FurnitureFitBibliography from './bibliography.astro';
4
+ import type { DiyToolEntry, ToolDefinition } from '../../types';
5
+ import type { FurnitureFitUI } from './ui';
6
+
7
+ export {
8
+ FurnitureFitComponent,
9
+ FurnitureFitSEO,
10
+ FurnitureFitBibliography,
11
+ };
12
+
13
+ const es = async () => (await import('./i18n/es')).content;
14
+ const en = async () => (await import('./i18n/en')).content;
15
+ const fr = async () => (await import('./i18n/fr')).content;
16
+
17
+ export const furnitureFit: DiyToolEntry<FurnitureFitUI> = {
18
+ id: 'furniture-fit-calculator',
19
+ icons: { bg: 'mdi:sofa', fg: 'mdi:ruler-square' },
20
+ i18n: { es, en, fr },
21
+ };
22
+
23
+ export const FURNITURE_FIT_TOOL: ToolDefinition = {
24
+ entry: furnitureFit,
25
+ Component: FurnitureFitComponent,
26
+ SEOComponent: FurnitureFitSEO,
27
+ BibliographyComponent: FurnitureFitBibliography,
28
+ };
@@ -0,0 +1,14 @@
1
+ ---
2
+ import { SEORenderer } from '@jjlmoya/utils-shared';
3
+ import { furnitureFit } from './index';
4
+ import type { KnownLocale } from '../../types';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ }
9
+ const { locale = 'es' } = Astro.props;
10
+ const content = await furnitureFit.i18n[locale]?.();
11
+ if (!content) return null;
12
+ ---
13
+
14
+ <SEORenderer content={{ locale: locale as string, sections: content.seo }} />
@@ -0,0 +1,21 @@
1
+ export interface FurnitureFitUI extends Record<string, string> {
2
+ conTitle: string;
3
+ conHint: string;
4
+ objTitle: string;
5
+ labelWidth: string;
6
+ labelHeight: string;
7
+ labelDepth: string;
8
+ labelLength: string;
9
+ labelMargin: string;
10
+ vizLabel: string;
11
+ verdictDefault: string;
12
+ verdictHint: string;
13
+ verdictYes: string;
14
+ verdictNo: string;
15
+ fitDirect: string;
16
+ fitDiagonal3d: string;
17
+ fitDiagonalPlane: string;
18
+ fitNope: string;
19
+ diagLabel: string;
20
+ objLabel: string;
21
+ }
@@ -0,0 +1,13 @@
1
+ ---
2
+ import { Bibliography as SharedBibliography } from '@jjlmoya/utils-shared';
3
+ import { mortarCalculator } from './index';
4
+ import type { KnownLocale } from '../../types';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ }
9
+ const { locale = 'es' } = Astro.props;
10
+ const content = await mortarCalculator.i18n[locale]?.();
11
+ ---
12
+
13
+ {content && <SharedBibliography links={content.bibliography} />}