@@ -68,7 +68,11 @@ const TEMPLATE_SHOTS: Record<string, Shot> = {
6868 webp: tplLocalWebp ,
6969 png: tplLocalPng ,
7070 },
71- " local-business" : { avif: tplLocalAvif , webp: tplLocalWebp , png: tplLocalPng },
71+ " local-business" : {
72+ avif: tplLocalAvif ,
73+ webp: tplLocalWebp ,
74+ png: tplLocalPng ,
75+ },
7276 " startups-productos" : {
7377 avif: tplStartupAvif ,
7478 webp: tplStartupWebp ,
@@ -87,6 +91,7 @@ interface Props {
8791
8892const { lang } = Astro .props ;
8993const t = locales [lang ].projectsPage ;
94+ const t2 = locales [lang ].projects ;
9095const pj = locales [lang ].projects ;
9196const nav = locales [lang ].nav ;
9297const featured = pj .featured ;
@@ -208,7 +213,11 @@ const [idShipped, idHelio, idTemplates, idAutomations] = ids;
208213 </section >
209214
210215 <!-- ══ 01 · ENTREGADO ════════════════════════════════════════════════ -->
211- <section id ={ idShipped } class =" bt-shipped" aria-labelledby =" bt-shipped-title" >
216+ <section
217+ id ={ idShipped }
218+ class =" bt-shipped"
219+ aria-labelledby =" bt-shipped-title"
220+ >
212221 <div class =" bt-shipped-wrap" >
213222 <!-- Texto a babor: cabecera + ficha del proyecto, en una columna. -->
214223 <div class =" bt-shipped-text" data-reveal style =" --i:0" >
@@ -236,17 +245,57 @@ const [idShipped, idHelio, idTemplates, idAutomations] = ids;
236245
237246 <StackList items ={ featured .stack } />
238247
239- <dl class =" bt-metrics" >
240- {
241- featured .metrics .map ((m ) => (
242- <div class = " bt-metric" >
243- <dt class = " bt-metric-label" >{ m .label } </dt >
244- <dd class = " bt-metric-value" >{ m .value } </dd >
245- </div >
246- ))
247- }
248- </dl >
249- <p class =" bt-source" >{ pj .metricsSource } </p >
248+ <!-- Contenedor para alinear métricas y reseña lado a lado -->
249+ <div class =" bt-metrics-and-quote" >
250+ <div class =" bt-metrics-col" >
251+ <dl class =" bt-metrics" >
252+ {
253+ featured .metrics .map ((m ) => (
254+ <div class = " bt-metric" >
255+ <dt class = " bt-metric-label" >{ m .label } </dt >
256+ <dd class = " bt-metric-value" >{ m .value } </dd >
257+ </div >
258+ ))
259+ }
260+ </dl >
261+ <p class =" bt-source" >{ pj .metricsSource } </p >
262+ </div >
263+
264+ <figure class =" pj-quote" >
265+ <p class =" pj-quote-label" >{ t2 .testimonial .label } </p >
266+ <blockquote
267+ class =" pj-quote-text"
268+ cite ={ t2 .testimonial .sourceUrl || undefined }
269+ >
270+ { t2 .testimonial .quote }
271+ </blockquote >
272+
273+ <figcaption class =" pj-quote-by" >
274+ <span class =" pj-quote-author" >{ t2 .testimonial .author } </span >
275+ <span class =" pj-quote-source" >
276+ {
277+ t2 .testimonial .sourceUrl ? (
278+ <a
279+ href = { t2 .testimonial .sourceUrl }
280+ target = " _blank"
281+ rel = " noopener noreferrer nofollow"
282+ >
283+ { t2 .testimonial .source }
284+ </a >
285+ ) : (
286+ t2 .testimonial .source
287+ )
288+ }
289+ </span >
290+ </figcaption >
291+
292+ {
293+ t2 .testimonial .note && (
294+ <p class = " pj-quote-note" >{ t2 .testimonial .note } </p >
295+ )
296+ }
297+ </figure >
298+ </div >
250299
251300 <a
252301 class =" bt-visit"
@@ -292,33 +341,66 @@ const [idShipped, idHelio, idTemplates, idAutomations] = ids;
292341 solo) bajo una línea de escaneo. Es lo honesto para algo «en
293342 construcción» —aún no hay captura—. En móvil estorba: se oculta. -->
294343 <div class =" bt-blueprint" aria-hidden =" true" >
295- <span class =" bt-blueprint-tag" >wireframe · v0</span >
296- <svg viewBox =" 0 0 420 300" fill =" none" xmlns =" http://www.w3.org/2000/svg" >
297- <rect class =" bp-draw" x =" 8" y =" 8" width =" 404" height =" 284" rx =" 12" />
298- <line class =" bp-draw" x1 =" 8" y1 =" 44" x2 =" 412" y2 =" 44" />
299- <circle class =" bp-dot" cx =" 28" cy =" 26" r =" 4" />
300- <circle class =" bp-dot" cx =" 44" cy =" 26" r =" 4" />
301- <circle class =" bp-dot" cx =" 60" cy =" 26" r =" 4" />
302- <line class =" bp-draw" x1 =" 120" y1 =" 44" x2 =" 120" y2 =" 292" />
303- <rect class =" bp-soft" x =" 24" y =" 64" width =" 72" height =" 9" rx =" 4" />
304- <rect class =" bp-soft" x =" 24" y =" 88" width =" 60" height =" 9" rx =" 4" />
305- <rect class =" bp-soft" x =" 24" y =" 112" width =" 80" height =" 9" rx =" 4" />
306- <rect class =" bp-soft" x =" 24" y =" 136" width =" 54" height =" 9" rx =" 4" />
307- <rect class =" bp-soft" x =" 140" y =" 64" width =" 130" height =" 12" rx =" 5" />
308- <rect class =" bp-draw" x =" 140" y =" 96" width =" 120" height =" 60" rx =" 8" />
309- <rect class =" bp-draw" x =" 272" y =" 96" width =" 120" height =" 60" rx =" 8" />
310- <polyline
311- class =" bp-draw bp-chart"
312- points =" 152,140 176,120 200,132 224,108 248,124"
313- />
314- <rect class =" bp-soft" x =" 284" y =" 112" width =" 46" height =" 20" rx =" 4" />
315- <rect class =" bp-soft" x =" 284" y =" 138" width =" 80" height =" 8" rx =" 4" />
316- <line class =" bp-draw" x1 =" 140" y1 =" 180" x2 =" 392" y2 =" 180" />
317- <line class =" bp-draw" x1 =" 140" y1 =" 208" x2 =" 392" y2 =" 208" />
318- <line class =" bp-draw" x1 =" 140" y1 =" 236" x2 =" 392" y2 =" 236" />
319- <line class =" bp-draw" x1 =" 140" y1 =" 264" x2 =" 392" y2 =" 264" />
320- <rect class =" bp-scan" x =" 8" y =" 44" width =" 404" height =" 40" />
321- </svg >
344+ <span class =" bt-blueprint-tag" >wireframe · v0</span >
345+ <svg
346+ viewBox =" 0 0 420 300"
347+ fill =" none"
348+ xmlns =" http://www.w3.org/2000/svg"
349+ >
350+ <rect class =" bp-draw" x =" 8" y =" 8" width =" 404" height =" 284" rx =" 12"
351+ ></rect >
352+ <line class =" bp-draw" x1 =" 8" y1 =" 44" x2 =" 412" y2 =" 44" ></line >
353+ <circle class =" bp-dot" cx =" 28" cy =" 26" r =" 4" ></circle >
354+ <circle class =" bp-dot" cx =" 44" cy =" 26" r =" 4" ></circle >
355+ <circle class =" bp-dot" cx =" 60" cy =" 26" r =" 4" ></circle >
356+ <line class =" bp-draw" x1 =" 120" y1 =" 44" x2 =" 120" y2 =" 292" ></line >
357+ <rect class =" bp-soft" x =" 24" y =" 64" width =" 72" height =" 9" rx =" 4"
358+ ></rect >
359+ <rect class =" bp-soft" x =" 24" y =" 88" width =" 60" height =" 9" rx =" 4"
360+ ></rect >
361+ <rect class =" bp-soft" x =" 24" y =" 112" width =" 80" height =" 9" rx =" 4"
362+ ></rect >
363+ <rect class =" bp-soft" x =" 24" y =" 136" width =" 54" height =" 9" rx =" 4"
364+ ></rect >
365+ <rect
366+ class =" bp-soft"
367+ x =" 140"
368+ y =" 64"
369+ width =" 130"
370+ height =" 12"
371+ rx =" 5" ></rect >
372+ <rect
373+ class =" bp-draw"
374+ x =" 140"
375+ y =" 96"
376+ width =" 120"
377+ height =" 60"
378+ rx =" 8" ></rect >
379+ <rect
380+ class =" bp-draw"
381+ x =" 272"
382+ y =" 96"
383+ width =" 120"
384+ height =" 60"
385+ rx =" 8" ></rect >
386+ <polyline
387+ class =" bp-draw bp-chart"
388+ points =" 152,140 176,120 200,132 224,108 248,124" ></polyline >
389+ <rect
390+ class =" bp-soft"
391+ x =" 284"
392+ y =" 112"
393+ width =" 46"
394+ height =" 20"
395+ rx =" 4" ></rect >
396+ <rect class =" bp-soft" x =" 284" y =" 138" width =" 80" height =" 8" rx =" 4"
397+ ></rect >
398+ <line class =" bp-draw" x1 =" 140" y1 =" 180" x2 =" 392" y2 =" 180" ></line >
399+ <line class =" bp-draw" x1 =" 140" y1 =" 208" x2 =" 392" y2 =" 208" ></line >
400+ <line class =" bp-draw" x1 =" 140" y1 =" 236" x2 =" 392" y2 =" 236" ></line >
401+ <line class =" bp-draw" x1 =" 140" y1 =" 264" x2 =" 392" y2 =" 264" ></line >
402+ <rect class =" bp-scan" x =" 8" y =" 44" width =" 404" height =" 40" ></rect >
403+ </svg >
322404 </div >
323405
324406 <div class =" bt-helio-lead" >
@@ -397,7 +479,12 @@ const [idShipped, idHelio, idTemplates, idAutomations] = ids;
397479 t .templates .items .map ((item , i ) => {
398480 const shot = TEMPLATE_SHOTS [item .slug ];
399481 return (
400- <li class = " bt-tpl" id = { item .slug } data-reveal style = { ` --i:${i } ` } >
482+ <li
483+ class = " bt-tpl"
484+ id = { item .slug }
485+ data-reveal
486+ style = { ` --i:${i } ` }
487+ >
401488 { shot ? (
402489 <figure class = " bt-frame bt-frame--shot" >
403490 <picture >
@@ -465,31 +552,51 @@ const [idShipped, idHelio, idTemplates, idAutomations] = ids;
465552 salida, con los pulsos por los cables). Va al fondo, tenue, para no
466553 robarle el ancho al texto; se oculta en móvil. -->
467554 <div class =" bt-flow" aria-hidden =" true" >
468- <svg viewBox =" 0 0 300 240" fill =" none" xmlns =" http://www.w3.org/2000/svg" >
469- <path class =" bt-flow-wire" d =" M56 48 C 150 48 120 120 196 120" />
470- <path class =" bt-flow-wire" d =" M56 120 H 196" />
471- <path class =" bt-flow-wire" d =" M56 192 C 150 192 120 120 196 120" />
472- <path class =" bt-flow-wire" d =" M244 120 H 288" />
555+ <svg
556+ viewBox =" 0 0 300 240"
557+ fill =" none"
558+ xmlns =" http://www.w3.org/2000/svg"
559+ >
560+ <path class =" bt-flow-wire" d =" M56 48 C 150 48 120 120 196 120" ></path >
561+ <path class =" bt-flow-wire" d =" M56 120 H 196" ></path >
562+ <path class =" bt-flow-wire" d =" M56 192 C 150 192 120 120 196 120"
563+ ></path >
564+ <path class =" bt-flow-wire" d =" M244 120 H 288" ></path >
473565 <circle class =" bt-flow-pulse" r =" 3.5" >
474- <animateMotion dur =" 2.4s" repeatCount =" indefinite"
475- path =" M56 48 C 150 48 120 120 196 120" />
566+ <animateMotion
567+ dur =" 2.4s"
568+ repeatCount =" indefinite"
569+ path =" M56 48 C 150 48 120 120 196 120" ></animateMotion >
476570 </circle >
477571 <circle class =" bt-flow-pulse" r =" 3.5" >
478- <animateMotion dur =" 2.4s" begin =" 0.5s" repeatCount =" indefinite"
479- path =" M56 120 H 196" />
572+ <animateMotion
573+ dur =" 2.4s"
574+ begin =" 0.5s"
575+ repeatCount =" indefinite"
576+ path =" M56 120 H 196" ></animateMotion >
480577 </circle >
481578 <circle class =" bt-flow-pulse" r =" 3.5" >
482- <animateMotion dur =" 2.4s" begin =" 1s" repeatCount =" indefinite"
483- path =" M56 192 C 150 192 120 120 196 120" />
579+ <animateMotion
580+ dur =" 2.4s"
581+ begin =" 1s"
582+ repeatCount =" indefinite"
583+ path =" M56 192 C 150 192 120 120 196 120" ></animateMotion >
484584 </circle >
485- <circle class =" bt-flow-node" cx =" 40" cy =" 48" r =" 14" />
486- <circle class =" bt-flow-node" cx =" 40" cy =" 120" r =" 14" />
487- <circle class =" bt-flow-node" cx =" 40" cy =" 192" r =" 14" />
488- <rect class =" bt-flow-hub" x =" 196" y =" 98" width =" 48" height =" 44" rx =" 10" />
489- <path class =" bt-flow-gear"
490- d =" M220 108 v6 M220 126 v6 M210 120 h6 M224 120 h6" />
491- <circle class =" bt-flow-gear" cx =" 220" cy =" 120" r =" 5" />
492- <circle class =" bt-flow-out" cx =" 288" cy =" 120" r =" 6" />
585+ <circle class =" bt-flow-node" cx =" 40" cy =" 48" r =" 14" ></circle >
586+ <circle class =" bt-flow-node" cx =" 40" cy =" 120" r =" 14" ></circle >
587+ <circle class =" bt-flow-node" cx =" 40" cy =" 192" r =" 14" ></circle >
588+ <rect
589+ class =" bt-flow-hub"
590+ x =" 196"
591+ y =" 98"
592+ width =" 48"
593+ height =" 44"
594+ rx =" 10" ></rect >
595+ <path
596+ class =" bt-flow-gear"
597+ d =" M220 108 v6 M220 126 v6 M210 120 h6 M224 120 h6" ></path >
598+ <circle class =" bt-flow-gear" cx =" 220" cy =" 120" r =" 5" ></circle >
599+ <circle class =" bt-flow-out" cx =" 288" cy =" 120" r =" 6" ></circle >
493600 </svg >
494601 </div >
495602
@@ -511,7 +618,12 @@ const [idShipped, idHelio, idTemplates, idAutomations] = ids;
511618 <ul class =" bt-auto-list" role =" list" >
512619 {
513620 t .automations .items .map ((item , i ) => (
514- <li class = " bt-auto-item" id = { item .slug } data-reveal style = { ` --i:${i } ` } >
621+ <li
622+ class = " bt-auto-item"
623+ id = { item .slug }
624+ data-reveal
625+ style = { ` --i:${i } ` }
626+ >
515627 <p class = " bt-auto-code" aria-hidden = " true" >
516628 { item .code }
517629 </p >
@@ -554,10 +666,18 @@ const [idShipped, idHelio, idTemplates, idAutomations] = ids;
554666 babor y el texto con el CTA a estribor. El CTA NO va al Home: el
555667 formulario vive en el footer de ESTA página (#contact), así que baja
556668 hasta él (scroll suave, ya global) y la flecha lo anuncia. -->
557- <aside class =" bt-closing" data-reveal aria-labelledby =" bt-closing-title" >
669+ <aside
670+ class =" bt-closing"
671+ data-reveal
672+ aria-labelledby =" bt-closing-title"
673+ >
558674 <div class =" bt-closing-mark" aria-hidden =" true" >
559- <svg viewBox =" 0 0 120 120" fill =" none" xmlns =" http://www.w3.org/2000/svg" >
560- <circle class =" bt-closing-ring" cx =" 60" cy =" 60" r =" 50" />
675+ <svg
676+ viewBox =" 0 0 120 120"
677+ fill =" none"
678+ xmlns =" http://www.w3.org/2000/svg"
679+ >
680+ <circle class =" bt-closing-ring" cx =" 60" cy =" 60" r =" 50" ></circle >
561681 <g class =" bt-closing-ticks" >
562682 {
563683 Array .from ({ length: 24 }).map ((_ , i ) => (
@@ -571,8 +691,9 @@ const [idShipped, idHelio, idTemplates, idAutomations] = ids;
571691 ))
572692 }
573693 </g >
574- <path class =" bt-closing-needle" d =" M60 26 L70 78 L60 70 L50 78 Z" />
575- <circle class =" bt-closing-hub" cx =" 60" cy =" 60" r =" 3.5" />
694+ <path class =" bt-closing-needle" d =" M60 26 L70 78 L60 70 L50 78 Z"
695+ ></path >
696+ <circle class =" bt-closing-hub" cx =" 60" cy =" 60" r =" 3.5" ></circle >
576697 </svg >
577698 <span class =" bt-closing-coords" >10.4236° N · 75.5518° W</span >
578699 </div >
@@ -644,4 +765,4 @@ const [idShipped, idHelio, idTemplates, idAutomations] = ids;
644765 applyFlow();
645766 reduceMotion.addEventListener("change", applyFlow);
646767 }
647- </script >
768+ </script >
0 commit comments