@crtobiasdelsud/portal-ui 1.0.21 → 1.0.23

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 (49) hide show
  1. package/package.json +1 -1
  2. package/src/components/ArticleHero/ArticleHero.jsx +3 -8
  3. package/src/components/ArticleHero/variants/V0/V0.jsx +4 -1
  4. package/src/components/ArticleHero/variants/V0Desktop/V0Desktop.jsx +4 -1
  5. package/src/components/ArticleHero/variants/V1/V1.jsx +4 -1
  6. package/src/components/ArticleHero/variants/V2/V2.jsx +1 -5
  7. package/src/components/AuthorBlock/AuthorBlock.jsx +1 -4
  8. package/src/components/Breadcrumb/Breadcrumb.jsx +1 -5
  9. package/src/components/Cards/Bajada/Bajada.jsx +1 -2
  10. package/src/components/Cards/Bajada/variants/V1/V1.jsx +2 -1
  11. package/src/components/Cards/Bajada/variants/V2/V2.jsx +1 -2
  12. package/src/components/DolarTickerOriginal/DolarTickerOriginal.module.scss +1 -4
  13. package/src/components/Feed/FeedView.jsx +1 -2
  14. package/src/components/Footers/FooterSimple/FooterSimple.module.scss +11 -1
  15. package/src/components/Hero/HeroView.jsx +14 -38
  16. package/src/components/Hero/variants/V1/V1.jsx +33 -0
  17. package/src/components/Hero/variants/V2/V2.jsx +37 -0
  18. package/src/components/Hero/variants/V2/V2.module.scss +168 -0
  19. package/src/components/Hero/variants/V3/V3.jsx +36 -0
  20. package/src/components/Hero/variants/V3/V3.module.scss +164 -0
  21. package/src/components/ShareBlock/ShareBlock.jsx +1 -2
  22. package/src/utils/stripHtml.js +13 -0
  23. package/src/components/ArticleHero/variants/V1/V1.module.scss +0 -40
  24. package/src/components/ArticleHero/variants/V2/V2.module.scss +0 -44
  25. package/src/components/ArticleHero/variants/V3/V3.jsx +0 -25
  26. package/src/components/ArticleHero/variants/V3/V3.module.scss +0 -41
  27. package/src/components/ArticleHero/variants/V4/V4.jsx +0 -25
  28. package/src/components/ArticleHero/variants/V4/V4.module.scss +0 -36
  29. package/src/components/ArticleHero/variants/V5/V5.jsx +0 -25
  30. package/src/components/ArticleHero/variants/V5/V5.module.scss +0 -33
  31. package/src/components/AuthorBlock/variants/V2/V2.jsx +0 -38
  32. package/src/components/AuthorBlock/variants/V2/V2.module.scss +0 -10
  33. package/src/components/AuthorBlock/variants/V3/V3.jsx +0 -30
  34. package/src/components/AuthorBlock/variants/V3/V3.module.scss +0 -10
  35. package/src/components/AuthorBlock/variants/V4/V4.jsx +0 -30
  36. package/src/components/AuthorBlock/variants/V4/V4.module.scss +0 -10
  37. package/src/components/Breadcrumb/variants/V2/V2.jsx +0 -28
  38. package/src/components/Breadcrumb/variants/V2/V2.module.scss +0 -3
  39. package/src/components/Breadcrumb/variants/V3/V3.jsx +0 -28
  40. package/src/components/Breadcrumb/variants/V3/V3.module.scss +0 -3
  41. package/src/components/Breadcrumb/variants/V4/V4.jsx +0 -28
  42. package/src/components/Breadcrumb/variants/V4/V4.module.scss +0 -3
  43. package/src/components/Breadcrumb/variants/V5/V5.jsx +0 -28
  44. package/src/components/Breadcrumb/variants/V5/V5.module.scss +0 -4
  45. package/src/components/Cards/Bajada/variants/V2/V2.module.scss +0 -2
  46. package/src/components/Feed/variants/V2/V2.jsx +0 -36
  47. package/src/components/Feed/variants/V2/V2.module.scss +0 -72
  48. package/src/components/ShareBlock/variants/V2/V2.jsx +0 -37
  49. package/src/components/ShareBlock/variants/V2/V2.module.scss +0 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crtobiasdelsud/portal-ui",
3
- "version": "1.0.21",
3
+ "version": "1.0.23",
4
4
  "description": "Componentes compartidos entre el portal (Next) y el CMS (Vite) — widgets, views, providers para adapters y article pool.",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
@@ -5,19 +5,14 @@ import { useTheme } from '../../context/SiteConfigContext.jsx'
5
5
  import AspectImage from '../../components/UI/AspectImage/AspectImage.jsx'
6
6
  import Carousel from '../Carousel/Carousel.jsx'
7
7
  import V0 from './variants/V0/V0'
8
- import V1 from './variants/V1/V1'
9
- import V2 from './variants/V2/V2'
10
- import V3 from './variants/V3/V3'
11
- import V4 from './variants/V4/V4'
12
- import V5 from './variants/V5/V5'
13
8
  import V0Tablet from './variants/V0Tablet/V0Tablet'
14
9
  import V0Desktop from './variants/V0Desktop/V0Desktop'
15
10
 
16
- const VARIANTS = { '0': V0, '1': V1, '2': V2, '3': V3, '4': V4, '5': V5 }
11
+ const VARIANTS = { '0': V0 }
17
12
 
18
13
  export default function ArticleHero({ titulo, volanta, copete, imagen, imagenes, imagenEpigrafe, focalPoint, isAmp = false, extras = null, hideImageOnDesktop = false }) {
19
14
  const theme = useTheme()
20
- const variant = String(theme.articleHero ?? 1)
15
+ const variant = String(theme.articleHero ?? 0)
21
16
 
22
17
  const inlineStyle = isAmp ? {} : {
23
18
  fontFamily: theme.fontFamily,
@@ -80,7 +75,7 @@ export default function ArticleHero({ titulo, volanta, copete, imagen, imagenes,
80
75
  const imgOnlyClass = (!isAmp && hideImageOnDesktop) ? styles.imgHiddenDesktop : undefined
81
76
  const noImgMod = (!isAmp && hideImageOnDesktop) ? ` ${styles.noImgDesktop}` : ''
82
77
 
83
- const MobileVariant = VARIANTS[variant] ?? V1
78
+ const MobileVariant = VARIANTS[variant] ?? V0
84
79
 
85
80
  const sharedProps = {
86
81
  isAmp,
@@ -7,7 +7,10 @@ export default function V0({ isAmp, inlineStyle, titulo, volanta, copete, ImgEl,
7
7
  : null
8
8
  const TituloEl = <h1 className={isAmp ? 'article-hero__titulo' : `${shared.titulo} ${s.titulo}`}>{titulo}</h1>
9
9
  const CopeteEl = copete
10
- ? <p className={isAmp ? 'article-hero__copete' : `${shared.copete} ${s.copete}`}>{copete}</p>
10
+ ? <p
11
+ className={isAmp ? 'article-hero__copete' : `${shared.copete} ${s.copete}`}
12
+ dangerouslySetInnerHTML={{ __html: copete }}
13
+ />
11
14
  : null
12
15
 
13
16
  return (
@@ -7,7 +7,10 @@ export default function V0Desktop({ isAmp, inlineStyle, titulo, volanta, copete,
7
7
  : null
8
8
  const TituloEl = <h1 className={isAmp ? 'article-hero__titulo' : `${shared.titulo} ${s.titulo}`}>{titulo}</h1>
9
9
  const CopeteEl = copete
10
- ? <p className={isAmp ? 'article-hero__copete' : `${shared.copete} ${s.copete}`}>{copete}</p>
10
+ ? <p
11
+ className={isAmp ? 'article-hero__copete' : `${shared.copete} ${s.copete}`}
12
+ dangerouslySetInnerHTML={{ __html: copete }}
13
+ />
11
14
  : null
12
15
 
13
16
  return (
@@ -7,7 +7,10 @@ export default function V1({ isAmp, inlineStyle, titulo, volanta, copete, ImgEl,
7
7
  : null
8
8
  const TituloEl = <h1 className={isAmp ? 'article-hero__titulo' : `${shared.titulo} ${s.titulo}`}>{titulo}</h1>
9
9
  const CopeteEl = copete
10
- ? <p className={isAmp ? 'article-hero__copete' : `${shared.copete} ${s.copete}`}>{copete}</p>
10
+ ? <p
11
+ className={isAmp ? 'article-hero__copete' : `${shared.copete} ${s.copete}`}
12
+ dangerouslySetInnerHTML={{ __html: copete }}
13
+ />
11
14
  : null
12
15
 
13
16
  return (
@@ -1,14 +1,11 @@
1
1
  import shared from '../../ArticleHero.module.scss'
2
2
  import s from './V2.module.scss'
3
3
 
4
- export default function V2({ isAmp, inlineStyle, titulo, volanta, copete, ImgEl, ExtrasEl, imgWrapClass, noImgMod }) {
4
+ export default function V2({ isAmp, inlineStyle, titulo, volanta, ImgEl, ExtrasEl, imgWrapClass, noImgMod }) {
5
5
  const VolantaEl = volanta
6
6
  ? <span className={isAmp ? 'article-hero__volanta' : `${shared.volanta} ${s.volanta}`}>{volanta}</span>
7
7
  : null
8
8
  const TituloEl = <h1 className={isAmp ? 'article-hero__titulo' : `${shared.titulo} ${s.titulo}`}>{titulo}</h1>
9
- const CopeteEl = copete
10
- ? <p className={isAmp ? 'article-hero__copete' : `${shared.copete} ${s.copete}`}>{copete}</p>
11
- : null
12
9
 
13
10
  return (
14
11
  <article
@@ -21,7 +18,6 @@ export default function V2({ isAmp, inlineStyle, titulo, volanta, copete, ImgEl,
21
18
  </div>
22
19
  <div className={isAmp ? 'article-hero__panel' : s.panel}>
23
20
  {TituloEl}
24
- {CopeteEl}
25
21
  </div>
26
22
  {ExtrasEl}
27
23
  </article>
@@ -3,11 +3,8 @@
3
3
  import { useState, useEffect } from 'react'
4
4
  import { useTheme, useSiteConfig } from '../../context/SiteConfigContext.jsx'
5
5
  import V1 from './variants/V1/V1'
6
- import V2 from './variants/V2/V2'
7
- import V3 from './variants/V3/V3'
8
- import V4 from './variants/V4/V4'
9
6
 
10
- const VARIANTS = { '1': V1, '2': V2, '3': V3, '4': V4 }
7
+ const VARIANTS = { '1': V1 }
11
8
 
12
9
  function formatDate(fechaPublicacion, useLongDate) {
13
10
  if (!fechaPublicacion) return null
@@ -2,12 +2,8 @@
2
2
 
3
3
  import { useTheme } from '../../context/SiteConfigContext.jsx'
4
4
  import V1 from './variants/V1/V1'
5
- import V2 from './variants/V2/V2'
6
- import V3 from './variants/V3/V3'
7
- import V4 from './variants/V4/V4'
8
- import V5 from './variants/V5/V5'
9
5
 
10
- const VARIANTS = { '1': V1, '2': V2, '3': V3, '4': V4, '5': V5 }
6
+ const VARIANTS = { '1': V1 }
11
7
 
12
8
  export default function Breadcrumb({ items = [], isAmp = false }) {
13
9
  const theme = useTheme()
@@ -2,9 +2,8 @@
2
2
 
3
3
  import { useTheme } from "../../../context/SiteConfigContext.jsx"
4
4
  import V1 from './variants/V1/V1'
5
- import V2 from './variants/V2/V2'
6
5
 
7
- const VARIANTS = { '1': V1, '2': V2 }
6
+ const VARIANTS = { '1': V1 }
8
7
 
9
8
  export default function Bajada({ settings = {}, isAmp = false }) {
10
9
  const theme = useTheme()
@@ -1,4 +1,5 @@
1
1
  import shared from '../../Bajada.module.scss'
2
+ import { stripHtml } from '../../../../../utils/stripHtml'
2
3
  import s from './V1.module.scss'
3
4
 
4
5
  export default function V1({ isAmp, inlineStyle, volanta, title, copete, authorId, vDesktop }) {
@@ -13,7 +14,7 @@ export default function V1({ isAmp, inlineStyle, volanta, title, copete, authorI
13
14
  <span className={isAmp ? 'bajada__volanta' : shared.volanta}>{volanta}. </span>
14
15
  {title}
15
16
  </h2>
16
- {copete && <p className={isAmp ? 'bajada__copete' : shared.copete}>{copete}</p>}
17
+ {copete && <p className={isAmp ? 'bajada__copete' : shared.copete}>{stripHtml(copete)}</p>}
17
18
  {authorId && <span className={isAmp ? 'bajada__autor' : shared.autor}>Por {authorId}</span>}
18
19
  </div>
19
20
  )
@@ -1,7 +1,7 @@
1
1
  import shared from '../../Bajada.module.scss'
2
2
  import s from './V2.module.scss'
3
3
 
4
- export default function V2({ isAmp, inlineStyle, volanta, title, copete, authorId, vDesktop }) {
4
+ export default function V2({ isAmp, inlineStyle, volanta, title, authorId, vDesktop }) {
5
5
  const deskCls = shared[`vd${vDesktop}`] ?? ''
6
6
  const className = isAmp
7
7
  ? 'bajada__container'
@@ -13,7 +13,6 @@ export default function V2({ isAmp, inlineStyle, volanta, title, copete, authorI
13
13
  <span className={isAmp ? 'bajada__volanta' : shared.volanta}>{volanta}. </span>
14
14
  {title}
15
15
  </h2>
16
- {copete && <p className={isAmp ? 'bajada__copete' : shared.copete}>{copete}</p>}
17
16
  {authorId && <span className={isAmp ? 'bajada__autor' : shared.autor}>Por {authorId}</span>}
18
17
  </div>
19
18
  )
@@ -28,11 +28,8 @@ padding: 0 16px;
28
28
  width: 100%;
29
29
  box-sizing: border-box;
30
30
  margin: 20px 0 10px;
31
-
31
+
32
32
  background-color: #f5f5f5;
33
-
34
-
35
-
36
33
  }
37
34
 
38
35
  .mobile {
@@ -2,9 +2,8 @@
2
2
 
3
3
  import { useTheme } from "../../context/SiteConfigContext.jsx"
4
4
  import V1 from './variants/V1/V1'
5
- import V2 from './variants/V2/V2'
6
5
 
7
- const VARIANTS = { '1': V1, '2': V2 }
6
+ const VARIANTS = { '1': V1 }
8
7
 
9
8
  export default function FeedView({ articles = [] }) {
10
9
  const theme = useTheme()
@@ -26,7 +26,7 @@
26
26
 
27
27
  .container {
28
28
  width: 100%;
29
- padding: 20px 30px 20px 50px;
29
+ padding: 20px 30px;
30
30
  display: flex;
31
31
  flex-direction: column;
32
32
  gap: 16px;
@@ -35,6 +35,10 @@
35
35
  margin-top: auto;
36
36
  min-height: 268px;
37
37
  color: var(--text-color, #fff);
38
+
39
+ @media (min-width: $tablet) {
40
+ padding: 20px 50px;
41
+ }
38
42
  }
39
43
 
40
44
  // ── MAIN ROW (2 columns) ──────────────────────────────────────────────────────
@@ -58,9 +62,12 @@
58
62
  align-items: center;
59
63
  gap: 14px;
60
64
  flex-shrink: 0;
65
+ min-width: 0;
66
+ max-width: 100%;
61
67
 
62
68
  @media (min-width: $tablet) {
63
69
  align-items: flex-start;
70
+ max-width: 320px;
64
71
  }
65
72
  }
66
73
 
@@ -103,10 +110,13 @@
103
110
  .logoWrap {
104
111
  display: flex;
105
112
  justify-content: center;
113
+ max-width: 100%;
106
114
  }
107
115
 
108
116
  .logoImg {
109
117
  height: 53px;
118
+ width: auto;
119
+ max-width: 280px;
110
120
  object-fit: contain;
111
121
  }
112
122
 
@@ -1,49 +1,25 @@
1
1
  'use client'
2
2
 
3
- import styles from "./Hero.module.scss"
4
3
  import { useTheme } from "../../context/SiteConfigContext.jsx"
5
- import { useAdapters } from "../../adapters/AdaptersContext.jsx"
6
- import AspectImage from "../UI/AspectImage/AspectImage.jsx"
4
+ import V1 from './variants/V1/V1'
5
+ import V2 from './variants/V2/V2'
6
+ import V3 from './variants/V3/V3'
7
+
8
+ const VARIANTS = { '1': V1, '2': V2, '3': V3 }
7
9
 
8
10
  export default function HeroView({ article, important = false }) {
9
11
  const theme = useTheme()
10
- const { Link } = useAdapters()
11
- const surfaceColor = theme.surface
12
- const primaryColor = theme.primary
13
- const textColor = theme.textColor
14
- const fontFamily = theme.fontFamily
12
+ const v = String(theme.hero ?? 1)
15
13
 
16
14
  const inlineStyle = {
17
- backgroundColor: surfaceColor,
18
- fontFamily,
19
- '--primary-color': primaryColor,
20
- '--text-color': textColor,
21
- '--surface-color': surfaceColor,
15
+ backgroundColor: theme.surface,
16
+ fontFamily: theme.fontFamily,
17
+ '--primary-color': theme.primary,
18
+ '--text-color': theme.textColor,
19
+ '--surface-color': theme.surface,
22
20
  }
23
21
 
24
- return (
25
- <article style={inlineStyle} className={`${styles.container} ${important ? styles.important : ""}`}>
26
- <Link href={article.slug} className={styles.link}>
27
- {article.imagen?.url && (
28
- <AspectImage
29
- src={article.imagen.url}
30
- alt={article.imagen.alt ?? ''}
31
- aspect="16:9"
32
- focalPoint={article.focalPoint}
33
- className={styles.media}
34
- />
35
- )}
36
- <div className={styles.body}>
37
- <p className={styles.headline}>
38
- {article.volanta && <span className={styles.category}>{article.volanta}. </span>}
39
- {article.titulo}
40
- </p>
41
- <p className={styles.copete}> {article.copete}</p>
42
- {article.autor?.nombre && (
43
- <span className={styles.autor}>Por {article.autor.nombre}</span>
44
- )}
45
- </div>
46
- </Link>
47
- </article>
48
- )
22
+ const Variant = VARIANTS[v] ?? V1
23
+
24
+ return <Variant article={article} important={important} inlineStyle={inlineStyle} />
49
25
  }
@@ -0,0 +1,33 @@
1
+ import { useAdapters } from '../../../../adapters/AdaptersContext.jsx'
2
+ import AspectImage from '../../../UI/AspectImage/AspectImage.jsx'
3
+ import styles from '../../Hero.module.scss'
4
+
5
+ export default function V1({ article, important = false, inlineStyle }) {
6
+ const { Link } = useAdapters()
7
+
8
+ return (
9
+ <article style={inlineStyle} className={`${styles.container} ${important ? styles.important : ''}`}>
10
+ <Link href={article.slug} className={styles.link}>
11
+ {article.imagen?.url && (
12
+ <AspectImage
13
+ src={article.imagen.url}
14
+ alt={article.imagen.alt ?? ''}
15
+ aspect="16:9"
16
+ focalPoint={article.focalPoint}
17
+ className={styles.media}
18
+ />
19
+ )}
20
+ <div className={styles.body}>
21
+ <p className={styles.headline}>
22
+ {article.volanta && <span className={styles.category}>{article.volanta}. </span>}
23
+ {article.titulo}
24
+ </p>
25
+ <p className={styles.copete}> {article.copete}</p>
26
+ {article.autor?.nombre && (
27
+ <span className={styles.autor}>Por {article.autor.nombre}</span>
28
+ )}
29
+ </div>
30
+ </Link>
31
+ </article>
32
+ )
33
+ }
@@ -0,0 +1,37 @@
1
+ import { useAdapters } from '../../../../adapters/AdaptersContext.jsx'
2
+ import AspectImage from '../../../UI/AspectImage/AspectImage.jsx'
3
+ import s from './V2.module.scss'
4
+
5
+ export default function V2({ article, important = false, inlineStyle }) {
6
+ const { Link } = useAdapters()
7
+
8
+ return (
9
+ <article style={inlineStyle} className={`${s.container} ${important ? s.important : ''}`}>
10
+ <Link href={article.slug} className={s.link}>
11
+ <div className={s.imgWrap}>
12
+ {article.imagen?.url && (
13
+ <div className={s.mediaBox}>
14
+ <AspectImage
15
+ src={article.imagen.url}
16
+ alt={article.imagen.alt ?? ''}
17
+ fill
18
+ focalPoint={article.focalPoint}
19
+ priority
20
+ />
21
+ </div>
22
+ )}
23
+ <div className={s.overlay}>
24
+ {article.volanta && (
25
+ <span className={s.volantaWrap}><span className={s.volanta}>{article.volanta}.</span></span>
26
+ )}{' '}
27
+ <span className={s.headlineWrap}><span className={s.headline}>{article.titulo}</span></span>
28
+ </div>
29
+ </div>
30
+
31
+ {article.autor?.nombre && (
32
+ <span className={s.autor}>Por {article.autor.nombre}</span>
33
+ )}
34
+ </Link>
35
+ </article>
36
+ )
37
+ }
@@ -0,0 +1,168 @@
1
+ @use "../../../../styles/index.scss" as *;
2
+
3
+ .container {
4
+ background-color: var(--surface-color, transparent);
5
+ box-sizing: border-box;
6
+ height: 100%;
7
+ padding: 0; // full bleed: la imagen toca los bordes
8
+
9
+ @include respond(desktop) {
10
+ display: flex;
11
+ flex-direction: column;
12
+ }
13
+ }
14
+
15
+ .link {
16
+ display: block;
17
+ text-decoration: none;
18
+ color: inherit;
19
+
20
+ @include respond(desktop) {
21
+ flex: 1;
22
+ display: flex;
23
+ flex-direction: column;
24
+ min-height: 0;
25
+ }
26
+ }
27
+
28
+ .imgWrap {
29
+ position: relative;
30
+ width: 100%;
31
+
32
+ @include respond(desktop) {
33
+ flex: 1;
34
+ min-height: 0;
35
+ }
36
+ }
37
+
38
+ // Caja que define el tamaño de la imagen (AspectImage va en modo `fill`)
39
+ .mediaBox {
40
+ position: relative;
41
+ width: 100%;
42
+ height: 55vh; // mobile: imagen alta pero sin ocupar toda la pantalla
43
+
44
+ @include respond(tablet) {
45
+ height: auto;
46
+ aspect-ratio: 16 / 9;
47
+ }
48
+
49
+ @include respond(desktop) {
50
+ height: 100%;
51
+ aspect-ratio: unset;
52
+ }
53
+ }
54
+
55
+ // ── Overlay SOBRE la imagen en todos los anchos (cajas blancas por línea) ──
56
+ .overlay {
57
+ position: absolute;
58
+ left: 0;
59
+ right: 0;
60
+ bottom: 14px;
61
+ padding: 0 14px;
62
+ display: flex;
63
+ flex-direction: column;
64
+ align-items: flex-start;
65
+ font-family: var(--font-family);
66
+ }
67
+
68
+ .volantaWrap {
69
+ display: block;
70
+ margin-bottom: 5px;
71
+ max-width: 100%;
72
+ }
73
+
74
+ .headlineWrap {
75
+ display: block;
76
+ max-width: 100%;
77
+ }
78
+
79
+ // Cajas con fondo blanco que se clonan en cada línea de texto
80
+ .volanta,
81
+ .headline {
82
+ -webkit-box-decoration-break: clone;
83
+ box-decoration-break: clone;
84
+ background: #fff;
85
+ padding: 3px 7px;
86
+ }
87
+
88
+ .volanta {
89
+ color: var(--primary-color, #4bac48);
90
+ font-size: 18px;
91
+ font-weight: 700;
92
+ line-height: 1.5;
93
+
94
+ @include respond(tablet) {
95
+ font-size: 26px;
96
+ }
97
+
98
+ @include respond(desktop) {
99
+ font-size: 28px;
100
+ }
101
+ }
102
+
103
+ .headline {
104
+ color: var(--text-color, #252523);
105
+ font-size: 20px;
106
+ font-weight: 800;
107
+ line-height: 1.55;
108
+
109
+ @include respond(tablet) {
110
+ font-size: 30px;
111
+ line-height: 1.7;
112
+ }
113
+
114
+ @include respond(desktop) {
115
+ font-size: 32px;
116
+ }
117
+ }
118
+
119
+ // ── Copete debajo de la imagen (si existe) ───────────────────────────────
120
+ .copete {
121
+ font-size: 14px;
122
+ line-height: 1.4;
123
+ color: var(--text-color, #252523);
124
+ margin: 10px 0 0;
125
+ padding: 0 16px;
126
+
127
+ @include respond(tablet) {
128
+ padding: 0;
129
+ }
130
+
131
+ @include respond(desktop) {
132
+ flex: none;
133
+ }
134
+ }
135
+
136
+ .autor {
137
+ display: block;
138
+ font-size: 12px;
139
+ font-weight: 300;
140
+ color: var(--text-color, #252523);
141
+ padding: 8px 16px 0;
142
+
143
+ @include respond(tablet) {
144
+ padding-left: 0;
145
+ padding-right: 0;
146
+ }
147
+ }
148
+
149
+ // ── Hero importante ──────────────────────────────────────────────────────
150
+ .important {
151
+ .mediaBox {
152
+ @include respond(tablet) {
153
+ aspect-ratio: 16 / 7;
154
+ }
155
+ @include respond(desktop) {
156
+ aspect-ratio: unset;
157
+ }
158
+ }
159
+
160
+ .headline {
161
+ @include respond(tablet) {
162
+ font-size: 32px;
163
+ }
164
+ @include respond(desktop) {
165
+ font-size: 38px;
166
+ }
167
+ }
168
+ }
@@ -0,0 +1,36 @@
1
+ import { useAdapters } from '../../../../adapters/AdaptersContext.jsx'
2
+ import AspectImage from '../../../UI/AspectImage/AspectImage.jsx'
3
+ import s from './V3.module.scss'
4
+
5
+ export default function V3({ article, important = false, inlineStyle }) {
6
+ const { Link } = useAdapters()
7
+
8
+ return (
9
+ <article style={inlineStyle} className={`${s.container} ${important ? s.important : ''}`}>
10
+ <Link href={article.slug} className={s.link}>
11
+ <div className={s.imgWrap}>
12
+ {article.imagen?.url && (
13
+ <div className={s.mediaBox}>
14
+ <AspectImage
15
+ src={article.imagen.url}
16
+ alt={article.imagen.alt ?? ''}
17
+ fill
18
+ focalPoint={article.focalPoint}
19
+ priority
20
+ />
21
+ </div>
22
+ )}
23
+ <div className={s.gradient} aria-hidden="true" />
24
+ <div className={s.overlay}>
25
+ {article.volanta && <p className={s.volanta}>{article.volanta}</p>}
26
+ <h2 className={s.headline}>{article.titulo}</h2>
27
+ </div>
28
+ </div>
29
+
30
+ {article.autor?.nombre && (
31
+ <span className={s.autor}>Por {article.autor.nombre}</span>
32
+ )}
33
+ </Link>
34
+ </article>
35
+ )
36
+ }