@data-visuals/create 7.6.6 → 7.6.7

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@data-visuals/create",
3
- "version": "7.6.6",
3
+ "version": "7.6.7",
4
4
  "description": "Create graphics and features the Data Visuals way.",
5
5
  "scripts": {
6
6
  "build:docs": "doctoc README.md --github",
@@ -1,113 +1,191 @@
1
- {% extends 'base.html' %}
2
- {% from 'macros/prose-queso.html' import prose %}
3
- {% from 'macros/processors-queso.html' import ad %}
4
-
5
- {% set jsPackName = 'main' %}
6
- {% set context = data.text %}
7
- {% set graphicTags = context.guten_tags %}
8
- {% set authorComma = joiner() %}
9
-
10
- {% block google_fonts %}{# queso fonts found in CSS #}{% endblock google_fonts %}
11
- {% block css_file %}
12
- <link rel="stylesheet" href="{{ static('styles/min/main-queso.css') }}">
13
- {% endblock css_file %}
14
-
15
- {% block nav %}{% include 'components/navbar.html' %}{% endblock %}
16
-
17
- {% block content_wrap %}
18
- <main data-feature>
19
- <article class="has-giant-btm-marg">
20
- {% block content %}
21
- <div class="has-page-padding has-giant-btm-marg">
22
- <header class="t-align-center">
23
- <h1 class="l-container l-container--m t-headline t-serif t-lh-s has-s-btm-marg" data-title>{{ context.headline | widont or 'The only member-supported, digital-first, nonpartisan media organization' | widont }}</h1>
24
- <p class="t-byline t-links t-uppercase t-lsp-m t-size-xs has-text-gray-dark has-b-btm-marg">
25
- <span class="t-byline__item">By <span data-credit>{%- for author in context.authors or ['Texas Tribune Staff'] -%}
26
- {% if not loop.last %}{{ authorComma() }}{% elif not loop.first %} and{% endif %} <span class="l-display-ib">{{ author }}</span>
27
- {%- endfor -%}</span>
28
- </span>
29
-
30
- {% if context.update_date %}
31
- <span class="l-display-block">
32
- <span class="t-byline__item">Published: <time datetime="{{ context.pub_date }}">{{ apFormatDate(context.pub_date) }}</time></span>
33
- <span class="t-byline__item">Updated: <time datetime="{{ context.update_date }}">{{ apFormatDate(context.update_date) }}</time></span>
34
- </span>
35
- {% else %}
36
- <span class="t-byline__item"><time datetime="{{ context.pub_date }}">{{ apFormatDate(context.pub_date) }}</time></span>
37
- {% endif %}
38
- </p>
39
- </header>
40
-
41
- <div class="c-details t-size-xs t-uppercase t-lsp-m t-lh-b has-text-black-off has-text-vert-padding has-s-btm-marg t-byline t-links t-uppercase t-lsp-m t-size-xs has-text-gray-dark has-page-padding t-align-center">
42
- {% include 'components/share.html' %}
43
- </div>
44
- </div>
45
-
46
- <div class="t-serif t-links-underlined has-page-padding">
47
- {{ prose(context.prose, context, data) }}
48
-
49
- {# graphics are attached to this container #}
50
- <div id="graphic"></div>
51
-
52
- <p class="t-copy">Duis mattis orci a porta maximus. Pellentesque vel pellentesque augue, a condimentum nibh. Integer eget feugiat turpis, at vehicula metus. Vestibulum arcu dui, hendrerit sed purus sed, vulputate aliquam est. Duis quis metus sed odio commodo dapibus. Maecenas pulvinar elit sit amet lorem iaculis blandit. Aliquam vitae sollicitudin urna. Sed viverra tincidunt felis.</p>
53
-
54
- {# Brief promo #}
55
- {% include "includes/brief-promo.html" %}
56
-
57
- <p class="t-copy">Duis mattis orci a porta maximus. Pellentesque vel pellentesque augue, a condimentum nibh. Integer eget feugiat turpis, at vehicula metus. Vestibulum arcu dui, hendrerit sed purus sed, vulputate aliquam est. Duis quis metus sed odio commodo dapibus. Maecenas pulvinar elit sit amet lorem iaculis blandit. Aliquam vitae sollicitudin urna. Sed viverra tincidunt felis.</p>
58
-
59
- <h2 class="t-copy t-copy--subheader">{{ 'A cool subhead here' | widont }}</h2>
60
-
61
- <p class="t-copy">Curabitur vestibulum sagittis diam, vitae pulvinar lorem accumsan ut. Mauris enim massa, vestibulum sed sollicitudin dapibus, ultrices eget ligula. Aenean tempor mi urna, eu porta tortor vehicula quis. Morbi hendrerit, eros nec interdum tempus, sem purus fringilla leo, ut iaculis urna tortor id diam. Duis laoreet maximus sapien, sed scelerisque sapien volutpat vel. Sed est lacus, sollicitudin nec euismod eu, placerat eget turpis. Quisque ultricies urna et mollis bibendum. Quisque tempus, elit ut faucibus hendrerit, augue enim faucibus massa, eu scelerisque dui eros at dolor. Sed rutrum, ipsum id convallis facilisis, justo ex rhoncus ex, in ultrices nisi augue vitae erat. Donec consequat ipsum ac nunc aliquam, eu porttitor quam viverra. Praesent ultrices, diam eget placerat sodales, magna magna porttitor urna, nec mollis ipsum odio at magna. Nulla ac consectetur turpis. Cras non ligula elementum, aliquet arcu ut, interdum nulla.</p>
62
-
63
- <p class="t-copy">Nam ornare ante eget erat egestas, eget pulvinar diam tincidunt. Nunc eget ligula ac mi facilisis tempus. Proin molestie nisl at urna pharetra commodo. Praesent tincidunt vestibulum purus, id dictum tortor aliquet ac. Pellentesque semper scelerisque justo ac luctus. Nullam malesuada urna a magna fringilla bibendum. Mauris quis hendrerit nisl, a lacinia lectus.</p>
64
- </div>
65
-
66
- {# use 'none' as the value if the ad should not have a gray background #}
67
- {# do not put ads inside a container div #}
68
- {{ ad('gray') }}
69
-
70
- {# create another container for more prose if the text needs to be split by an ad #}
71
- <div class="t-serif t-links-underlined has-page-padding">
72
- <p class="t-copy">Curabitur vestibulum sagittis diam, vitae pulvinar lorem accumsan ut. Mauris enim massa, vestibulum sed sollicitudin dapibus, ultrices eget ligula. Aenean tempor mi urna, eu porta tortor vehicula quis. Morbi hendrerit, eros nec interdum tempus, sem purus fringilla leo, ut iaculis urna tortor id diam. Duis laoreet maximus sapien, sed scelerisque sapien volutpat vel. Sed est lacus, sollicitudin nec euismod eu, placerat eget turpis. Quisque ultricies urna et mollis bibendum. Quisque tempus, elit ut faucibus hendrerit, augue enim faucibus massa, eu scelerisque dui eros at dolor. Sed rutrum, ipsum id convallis facilisis, justo ex rhoncus ex, in ultrices nisi augue vitae erat. Donec consequat ipsum ac nunc aliquam, eu porttitor quam viverra. Praesent ultrices, diam eget placerat sodales, magna magna porttitor urna, nec mollis ipsum odio at magna. Nulla ac consectetur turpis. Cras non ligula elementum, aliquet arcu ut, interdum nulla.</p>
1
+ {% extends 'base.html' %} {% from 'macros/prose-queso.html' import prose %} {%
2
+ from 'macros/processors-queso.html' import ad %} {% set jsPackName = 'main' %}
3
+ {% set context = data.text %} {% set graphicTags = context.guten_tag %} {% set
4
+ authorComma = joiner() %} {% block google_fonts %}{# queso fonts found in CSS
5
+ #}{% endblock google_fonts %} {% block css_file %}
6
+ <link rel="stylesheet" href="{{ static('styles/min/main-queso.css') }}" />
7
+ {% endblock css_file %} {% block nav %}{% include 'components/navbar.html' %}{%
8
+ endblock %} {% block content_wrap %}
9
+ <main data-feature>
10
+ <article class="has-giant-btm-marg">
11
+ {% block content %}
12
+ <div class="has-page-padding has-giant-btm-marg">
13
+ <header class="t-align-center">
14
+ <h1
15
+ class="l-container l-container--m t-headline t-serif t-lh-s has-s-btm-marg"
16
+ data-title
17
+ >
18
+ {{ context.headline | widont or 'The only member-supported,
19
+ digital-first, nonpartisan media organization' | widont }}
20
+ </h1>
21
+ <p
22
+ class="t-byline t-links t-uppercase t-lsp-m t-size-xs has-text-gray-dark has-b-btm-marg"
23
+ >
24
+ <span class="t-byline__item"
25
+ >By
26
+ <span data-credit
27
+ >{%- for author in context.authors or ['Texas Tribune Staff'] -%}
28
+ {% if not loop.last %}{{ authorComma() }}{% elif not loop.first %}
29
+ and{% endif %} <span class="l-display-ib">{{ author }}</span> {%-
30
+ endfor -%}</span
31
+ >
32
+ </span>
33
+
34
+ {% if context.update_date %}
35
+ <span class="l-display-block">
36
+ <span class="t-byline__item"
37
+ >Published:
38
+ <time datetime="{{ context.pub_date }}"
39
+ >{{ apFormatDate(context.pub_date) }}</time
40
+ ></span
41
+ >
42
+ <span class="t-byline__item"
43
+ >Updated:
44
+ <time datetime="{{ context.update_date }}"
45
+ >{{ apFormatDate(context.update_date) }}</time
46
+ ></span
47
+ >
48
+ </span>
49
+ {% else %}
50
+ <span class="t-byline__item"
51
+ ><time datetime="{{ context.pub_date }}"
52
+ >{{ apFormatDate(context.pub_date) }}</time
53
+ ></span
54
+ >
55
+ {% endif %}
56
+ </p>
57
+ </header>
58
+
59
+ <div
60
+ class="c-details t-size-xs t-uppercase t-lsp-m t-lh-b has-text-black-off has-text-vert-padding has-s-btm-marg t-byline t-links t-uppercase t-lsp-m t-size-xs has-text-gray-dark has-page-padding t-align-center"
61
+ >
62
+ {% include 'components/share.html' %}
63
+ </div>
64
+ </div>
65
+
66
+ <div class="t-serif t-links-underlined has-page-padding">
67
+ {{ prose(context.prose, context, data) }} {# graphics are attached to this
68
+ container #}
69
+ <div id="graphic"></div>
70
+
71
+ <p class="t-copy">
72
+ Duis mattis orci a porta maximus. Pellentesque vel pellentesque augue, a
73
+ condimentum nibh. Integer eget feugiat turpis, at vehicula metus.
74
+ Vestibulum arcu dui, hendrerit sed purus sed, vulputate aliquam est.
75
+ Duis quis metus sed odio commodo dapibus. Maecenas pulvinar elit sit
76
+ amet lorem iaculis blandit. Aliquam vitae sollicitudin urna. Sed viverra
77
+ tincidunt felis.
78
+ </p>
73
79
 
74
- <p class="t-copy">Nam ornare ante eget erat egestas, eget pulvinar diam tincidunt. Nunc eget ligula ac mi facilisis tempus. Proin molestie nisl at urna pharetra commodo. Praesent tincidunt vestibulum purus, id dictum tortor aliquet ac. Pellentesque semper scelerisque justo ac luctus. Nullam malesuada urna a magna fringilla bibendum. Mauris quis hendrerit nisl, a lacinia lectus.</p>
75
- </div>
80
+ {# Brief promo #} {% include "includes/brief-promo.html" %}
76
81
 
77
- {{ ad('gray', 'footer') }}
78
-
79
- {# Authors and contributors #}
80
- {% include "includes/authors.html" %}
81
- {% if context['contributors'] %}
82
- {% include "includes/contributors.html" %}
83
- {% endif %}
82
+ <p class="t-copy">
83
+ Duis mattis orci a porta maximus. Pellentesque vel pellentesque augue, a
84
+ condimentum nibh. Integer eget feugiat turpis, at vehicula metus.
85
+ Vestibulum arcu dui, hendrerit sed purus sed, vulputate aliquam est.
86
+ Duis quis metus sed odio commodo dapibus. Maecenas pulvinar elit sit
87
+ amet lorem iaculis blandit. Aliquam vitae sollicitudin urna. Sed viverra
88
+ tincidunt felis.
89
+ </p>
84
90
 
85
- {# Trust project #}
86
- {% include "includes/trust-project.html" %}
87
- {% endblock content %}
88
- </article>
89
- </main>
90
- <aside>
91
- {# Related story topics #}
92
- <section id="related-story-topics" class="c-plugin c-plugin--default c-plugin--narrow is-hidden-print">
93
- <h2 class="t-size-s has-xs-btm-marg">Explore related story topics</h2>
94
- <p class="c-tags l-flex">
95
- {% for topic in context['related_story_topics'] %}
96
- <a href="{{ topic['topic_link'] }}" ga-event-category="article-tag" class="c-tag c-tag__inner has-bg-white-off is-rounded-b">{{ topic['topic_title'] }}</a>
97
- {% endfor %}
91
+ <h2 class="t-copy t-copy--subheader">
92
+ {{ 'A cool subhead here' | widont }}
93
+ </h2>
94
+
95
+ <p class="t-copy">
96
+ Curabitur vestibulum sagittis diam, vitae pulvinar lorem accumsan ut.
97
+ Mauris enim massa, vestibulum sed sollicitudin dapibus, ultrices eget
98
+ ligula. Aenean tempor mi urna, eu porta tortor vehicula quis. Morbi
99
+ hendrerit, eros nec interdum tempus, sem purus fringilla leo, ut iaculis
100
+ urna tortor id diam. Duis laoreet maximus sapien, sed scelerisque sapien
101
+ volutpat vel. Sed est lacus, sollicitudin nec euismod eu, placerat eget
102
+ turpis. Quisque ultricies urna et mollis bibendum. Quisque tempus, elit
103
+ ut faucibus hendrerit, augue enim faucibus massa, eu scelerisque dui
104
+ eros at dolor. Sed rutrum, ipsum id convallis facilisis, justo ex
105
+ rhoncus ex, in ultrices nisi augue vitae erat. Donec consequat ipsum ac
106
+ nunc aliquam, eu porttitor quam viverra. Praesent ultrices, diam eget
107
+ placerat sodales, magna magna porttitor urna, nec mollis ipsum odio at
108
+ magna. Nulla ac consectetur turpis. Cras non ligula elementum, aliquet
109
+ arcu ut, interdum nulla.
98
110
  </p>
99
- </section>
100
111
 
101
- {# Related stories #}
102
- <div class="related-content l-container has-page-padding" id="related-content-container"></div>
103
- <div id="ribbon-container"></div>
104
- </aside>
105
- {% endblock content_wrap %}
112
+ <p class="t-copy">
113
+ Nam ornare ante eget erat egestas, eget pulvinar diam tincidunt. Nunc
114
+ eget ligula ac mi facilisis tempus. Proin molestie nisl at urna pharetra
115
+ commodo. Praesent tincidunt vestibulum purus, id dictum tortor aliquet
116
+ ac. Pellentesque semper scelerisque justo ac luctus. Nullam malesuada
117
+ urna a magna fringilla bibendum. Mauris quis hendrerit nisl, a lacinia
118
+ lectus.
119
+ </p>
120
+ </div>
121
+
122
+ {# use 'none' as the value if the ad should not have a gray background #} {#
123
+ do not put ads inside a container div #} {{ ad('gray') }} {# create another
124
+ container for more prose if the text needs to be split by an ad #}
125
+ <div class="t-serif t-links-underlined has-page-padding">
126
+ <p class="t-copy">
127
+ Curabitur vestibulum sagittis diam, vitae pulvinar lorem accumsan ut.
128
+ Mauris enim massa, vestibulum sed sollicitudin dapibus, ultrices eget
129
+ ligula. Aenean tempor mi urna, eu porta tortor vehicula quis. Morbi
130
+ hendrerit, eros nec interdum tempus, sem purus fringilla leo, ut iaculis
131
+ urna tortor id diam. Duis laoreet maximus sapien, sed scelerisque sapien
132
+ volutpat vel. Sed est lacus, sollicitudin nec euismod eu, placerat eget
133
+ turpis. Quisque ultricies urna et mollis bibendum. Quisque tempus, elit
134
+ ut faucibus hendrerit, augue enim faucibus massa, eu scelerisque dui
135
+ eros at dolor. Sed rutrum, ipsum id convallis facilisis, justo ex
136
+ rhoncus ex, in ultrices nisi augue vitae erat. Donec consequat ipsum ac
137
+ nunc aliquam, eu porttitor quam viverra. Praesent ultrices, diam eget
138
+ placerat sodales, magna magna porttitor urna, nec mollis ipsum odio at
139
+ magna. Nulla ac consectetur turpis. Cras non ligula elementum, aliquet
140
+ arcu ut, interdum nulla.
141
+ </p>
106
142
 
107
- {% block inline_data %}
143
+ <p class="t-copy">
144
+ Nam ornare ante eget erat egestas, eget pulvinar diam tincidunt. Nunc
145
+ eget ligula ac mi facilisis tempus. Proin molestie nisl at urna pharetra
146
+ commodo. Praesent tincidunt vestibulum purus, id dictum tortor aliquet
147
+ ac. Pellentesque semper scelerisque justo ac luctus. Nullam malesuada
148
+ urna a magna fringilla bibendum. Mauris quis hendrerit nisl, a lacinia
149
+ lectus.
150
+ </p>
151
+ </div>
152
+
153
+ {{ ad('gray', 'footer') }} {# Authors and contributors #} {% include
154
+ "includes/authors.html" %} {% if context['contributors'] %} {% include
155
+ "includes/contributors.html" %} {% endif %} {# Trust project #} {% include
156
+ "includes/trust-project.html" %} {% endblock content %}
157
+ </article>
158
+ </main>
159
+ <aside>
160
+ {# Related story topics #}
161
+ <section
162
+ id="related-story-topics"
163
+ class="c-plugin c-plugin--default c-plugin--narrow is-hidden-print"
164
+ >
165
+ <h2 class="t-size-s has-xs-btm-marg">Explore related story topics</h2>
166
+ <p class="c-tags l-flex">
167
+ {% for topic in context['related_story_topics'] %}
168
+ <a
169
+ href="{{ topic['topic_link'] }}"
170
+ ga-event-category="article-tag"
171
+ class="c-tag c-tag__inner has-bg-white-off is-rounded-b"
172
+ >{{ topic['topic_title'] }}</a
173
+ >
174
+ {% endfor %}
175
+ </p>
176
+ </section>
177
+
178
+ {# Related stories #}
179
+ <div
180
+ class="related-content l-container has-page-padding"
181
+ id="related-content-container"
182
+ ></div>
183
+ <div id="ribbon-container"></div>
184
+ </aside>
185
+ {% endblock content_wrap %} {% block inline_data %}
108
186
  <script>
109
187
  window.ttData = {
110
- gutenTag: '{{ context.related_tag or "subject-politics" }}'
188
+ related_category: '{{ context.related_category or "politics" }}',
111
189
  };
112
190
  </script>
113
191
  {% endblock inline_data %}
@@ -1,24 +1,44 @@
1
1
  import { Component, h } from 'preact';
2
-
3
2
  import Story from './Story';
4
-
5
- import { BUILD_RELATED_CONTENT_URL } from '../utils/feeds';
3
+ import {
4
+ BUILD_RELATED_CONTENT_URL_NEWSPACK,
5
+ mappingTaxonomy,
6
+ } from '../utils/feeds';
6
7
 
7
8
  class RelatedContent extends Component {
8
9
  constructor() {
9
10
  super();
10
-
11
11
  this.state = {
12
12
  stories: [],
13
13
  };
14
14
  }
15
15
 
16
16
  componentDidMount() {
17
- const { gutenTag, numberOfStories } = this.props;
17
+ const { related_category, numberOfStories, taxonomy } = this.props;
18
+
19
+ mappingTaxonomy(taxonomy, related_category)
20
+ .then(term => {
21
+ if (!term) {
22
+ console.warn('No term found for tag or category');
23
+ return;
24
+ }
25
+
26
+ const itemId = term['fetched']['id'];
27
+ const taxonomyParam = taxonomy;
28
+
29
+ const url = BUILD_RELATED_CONTENT_URL_NEWSPACK({
30
+ taxonomy: taxonomyParam,
31
+ item: itemId,
32
+ numberOfStories,
33
+ });
18
34
 
19
- fetch(BUILD_RELATED_CONTENT_URL({ gutenTag, numberOfStories }))
20
- .then(res => res.json())
21
- .then(({ results: stories }) => this.setState({ stories }));
35
+ return fetch(url)
36
+ .then(res => res.json())
37
+ .then(posts => {
38
+ this.setState({ stories: posts });
39
+ });
40
+ })
41
+ .catch(err => console.error('related content error:', err));
22
42
  }
23
43
 
24
44
  render({ title }, { stories }) {
@@ -40,6 +60,8 @@ class RelatedContent extends Component {
40
60
  RelatedContent.defaultProps = {
41
61
  numberOfStories: 4,
42
62
  title: 'Read more',
63
+ // either categories or tags
64
+ taxonomy: 'categories',
43
65
  };
44
66
 
45
67
  export default RelatedContent;
@@ -1,39 +1,76 @@
1
- import { h } from 'preact';
1
+ import { h, Component } from 'preact';
2
2
  import { apdate } from 'journalize';
3
3
 
4
- const Story = ({ headline, url, pub_date, sitewide_image }) => {
5
- return (
6
- <article class="story">
7
- <a
8
- class="story-link dim"
9
- href={url}
10
- target="_blank"
11
- ga-event-category="read more"
12
- ga-event-action="automated by tag"
13
- ga-event-label="apps page"
14
- >
15
- <div class="story-media c-story-block">
16
- <div class="story-art c-story-block__image-wrap">
17
- <img
18
- src={sitewide_image.thumbnails.letterbox}
19
- alt={sitewide_image.description}
20
- class="l-width-full"
21
- />
22
- </div>
23
- <div class="story-text c-story-block__text">
24
- <header class="story-header">
25
- <h4 class="story-headline t-serif t-size-b t-lh-s has-xxxs-btm-marg">
26
- {headline}
27
- </h4>
28
- <p class="story-byline t-byline t-links t-uppercase t-lsp-m t-size-xs has-text-gray-dark">
29
- {apdate(new Date(pub_date))}
30
- </p>
31
- </header>
4
+ class Story extends Component {
5
+ constructor(props) {
6
+ super(props);
7
+ this.state = {
8
+ altText: '',
9
+ };
10
+ }
11
+
12
+ componentDidMount() {
13
+ const { _links } = this.props;
14
+ const href = _links['wp:featuredmedia'][0].href;
15
+ if (!href) return;
16
+
17
+ fetch(href)
18
+ .then(res => res.json())
19
+ .then(images => {
20
+ let finalAlt = '';
21
+
22
+ if (images.alt_text) {
23
+ finalAlt = images.alt_text;
24
+ } else if (images.media_details.image_meta.caption) {
25
+ finalAlt = images.media_details.image_meta.caption;
26
+ } else if (typeof images.caption.rendered == 'string') {
27
+ finalAlt = images.caption.rendered.replace(/<[^>]+>/g, '');
28
+ } else {
29
+ finalAlt = 'Image for article';
30
+ }
31
+
32
+ this.setState({ altText: finalAlt });
33
+ })
34
+ .catch(err => {
35
+ console.error('Error fetching media:', err);
36
+ this.setState({ altText: 'Image for article' });
37
+ });
38
+ }
39
+
40
+ render({ title, link, date, jetpack_featured_media_url }, { altText }) {
41
+ return (
42
+ <article class="story">
43
+ <a
44
+ class="story-link dim"
45
+ href={link}
46
+ target="_blank"
47
+ ga-event-category="read more"
48
+ ga-event-action="automated by tag"
49
+ ga-event-label="apps page"
50
+ >
51
+ <div class="story-media c-story-block">
52
+ <div class="story-art c-story-block__image-wrap">
53
+ <img
54
+ src={jetpack_featured_media_url}
55
+ alt={altText}
56
+ class="l-width-full"
57
+ />
58
+ </div>
59
+ <div class="story-text c-story-block__text">
60
+ <header class="story-header">
61
+ <h4 class="story-headline t-serif t-size-b t-lh-s has-xxxs-btm-marg">
62
+ {title['rendered']}
63
+ </h4>
64
+ <p class="story-byline t-byline t-links t-uppercase t-lsp-m t-size-xs has-text-gray-dark">
65
+ {apdate(new Date(date))}
66
+ </p>
67
+ </header>
68
+ </div>
32
69
  </div>
33
- </div>
34
- </a>
35
- </article>
36
- );
37
- };
70
+ </a>
71
+ </article>
72
+ );
73
+ }
74
+ }
38
75
 
39
76
  export default Story;
@@ -8,12 +8,15 @@ const relatedContentContainer = document.getElementById(
8
8
  'related-content-container'
9
9
  );
10
10
 
11
- if (relatedContentContainer && window.ttData.gutenTag) {
11
+ if (relatedContentContainer && window.ttData.related_category) {
12
12
  import(
13
13
  /* webpackChunkName: "RelatedContent" */ './components/RelatedContent'
14
14
  ).then(({ default: RelatedContent }) =>
15
15
  render(
16
- <RelatedContent title={'Read more'} gutenTag={window.ttData.gutenTag} />,
16
+ <RelatedContent
17
+ title={'Read more'}
18
+ related_category={window.ttData.related_category}
19
+ />,
17
20
  relatedContentContainer
18
21
  )
19
22
  );
@@ -31,7 +34,10 @@ if (relatedContentContainer && window.ttData.gutenTag) {
31
34
  // ads
32
35
  import(/* webpackChunkName: "ads" */ './utils/ad-loader').then(
33
36
  ({ default: AdLoader }) => {
34
- const ads = new AdLoader();
37
+ const ads = new AdLoader({
38
+ targetingKey: 'tribpedia',
39
+ targetingValue: window.ttData.targetingValue,
40
+ });
35
41
  ads.init();
36
42
  }
37
43
  );
@@ -3,4 +3,54 @@ const TRENDING_STORIES_URL =
3
3
  const BUILD_RELATED_CONTENT_URL = ({ gutenTag, numberOfStories = 4 }) =>
4
4
  `https://www.texastribune.org/api/v2/articles/?content_type=story,audio,video,pointer&tag=${gutenTag}&tag!=object-tribcast&fields=id,url,pub_date,headline,summary,sitewide_image&limit=${numberOfStories}&format=json`;
5
5
 
6
- export { BUILD_RELATED_CONTENT_URL, TRENDING_STORIES_URL };
6
+ // Newspack API base URL
7
+ let BASE_NEWSPACK_API = 'https://www.texastribune.org/wp-json/wp/v2/';
8
+
9
+ const BUILD_RELATED_CONTENT_URL_NEWSPACK = ({
10
+ taxonomy,
11
+ item,
12
+ numberOfStories = 4,
13
+ }) =>
14
+ `${BASE_NEWSPACK_API}posts?
15
+ ${taxonomy}=${item}&per_page=${numberOfStories}&orderby=date&order=desc`;
16
+
17
+ // Function to map taxonomy (categories or tags) to get the item ID
18
+ export async function mappingTaxonomy(type, string) {
19
+ // pick either categories or tags
20
+ const perPage = 100;
21
+
22
+ const base = `${BASE_NEWSPACK_API}${type}`;
23
+
24
+ // We get the total number of pages, total entries and first page
25
+ const firstRes = await fetch(`${base}?per_page=${perPage}&page=1`);
26
+
27
+ const total = Number(firstRes.headers.get('X-WP-Total'));
28
+ const totalPages = Number(firstRes.headers.get('X-WP-TotalPages'));
29
+
30
+ const firstPage = await firstRes.json();
31
+
32
+ const pageNums = Array.from(
33
+ { length: Math.max(totalPages - 1, 0) },
34
+ (_, i) => i + 2
35
+ );
36
+
37
+ const promises = pageNums.map(p =>
38
+ fetch(`${base}?per_page=${perPage}&page=${p}`).then(r => r.json())
39
+ );
40
+
41
+ const restPages = await Promise.all(promises);
42
+
43
+ // put all of rest together
44
+ const all = firstPage.concat(...restPages);
45
+
46
+ // Find the category or tag we want
47
+ const item = all.find(item => item.slug === string);
48
+
49
+ return { total, totalPages, fetched: item, type };
50
+ }
51
+
52
+ export {
53
+ BUILD_RELATED_CONTENT_URL,
54
+ BUILD_RELATED_CONTENT_URL_NEWSPACK,
55
+ TRENDING_STORIES_URL,
56
+ };
@@ -6,6 +6,12 @@
6
6
 
7
7
  .c-author-info__trib-author-container {
8
8
  gap: 0.92rem;
9
+
10
+ img {
11
+ width: 90px;
12
+ height: auto; // Let height adjust to maintain aspect ratio
13
+ object-fit: cover; // Crop to fit if needed
14
+ }
9
15
  }
10
16
 
11
17
  #nonstaff-author {
@@ -1,102 +1,103 @@
1
- <!doctype html>
1
+ <!DOCTYPE html>
2
2
  <html lang="en">
3
- <head>
4
- <title>{% if context.seo_headline %}{{ context.seo_headline + ' | ' }}{% elif context.headline %}{{ context.headline + ' | ' }}{% endif %}The Texas Tribune</title>
5
- {% include 'includes/metas.html' %}
3
+ <head>
4
+ <title>
5
+ {% if context.seo_headline %}{{ context.seo_headline + ' | ' }}{% elif
6
+ context.headline %}{{ context.headline + ' | ' }}{% endif %}The Texas
7
+ Tribune
8
+ </title>
9
+ {% include 'includes/metas.html' %}
6
10
 
7
- <meta name="tt-graphic-tags" content="{{ graphicTags or ['subject-politics'] }}" />
11
+ <meta name="tt-graphic-tags" content="{{ context.tags or ['politics'] }}" />
8
12
 
9
- <link rel="dns-prefetch" href="https://www.google-analytics.com">
10
- <link rel="dns-prefetch" href="https://www.googletagmanager.com">
11
- {% block google_fonts %}
12
- <link rel="dns-prefetch" href="https://fonts.googleapis.com">
13
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
13
+ <link rel="dns-prefetch" href="https://www.google-analytics.com" />
14
+ <link rel="dns-prefetch" href="https://www.googletagmanager.com" />
15
+ {% block google_fonts %}
16
+ <link rel="dns-prefetch" href="https://fonts.googleapis.com" />
17
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
14
18
 
15
19
  <!-- Start fonts -->
16
20
  <script>
17
- window.WebFontConfig = {
18
- google: { families: ['Open Sans:300,400,700', 'PT Serif:400,700'] },
19
- timeout: 10000,
20
- };
21
+ window.WebFontConfig = {
22
+ google: { families: ['Open Sans:300,400,700', 'PT Serif:400,700'] },
23
+ timeout: 10000,
24
+ };
21
25
  </script>
22
- <script async src="https://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js"></script>
23
- <!-- End fonts -->
24
- {% endblock google_fonts %}
25
-
26
- {% block css_file %}<link rel="stylesheet" href="{{ static('styles/main.css') }}">{% endblock css_file %}
27
- {% include 'includes/ldjson.html' %}
28
- {% block head_scripts %}
29
- {{ javascriptPack(jsPackName, { mjs: true }) }}
30
- {% endblock head_scripts %}
31
- </head>
32
- <body>
33
-
34
- {% include 'includes/svg-defs.html' %}
35
-
36
- {% block nav %}{% include 'components/simple-masthead.html' %}{% endblock nav %}
37
-
38
- {% block content_wrap %}
39
- <main role="main">
40
- {% block content %}{% endblock content %}
41
- </main>
42
- {% endblock content_wrap %}
43
-
44
- {% include 'components/footer.html' %}
45
-
46
- {% block inline_data %}{% endblock inline_data %}
47
-
48
- {% include 'includes/nomodule-shim.html' %}
49
-
50
- {% block scripts %}
51
- {{ javascriptPack(jsPackName) }}
52
- {% endblock scripts %}
53
-
54
- {% if ENV == 'production' %}
55
- <!-- Google Tag Manager -->
56
- <script>
57
- (function(w, d, s, l, i) {
58
- w[l] = w[l] || [];
59
- w[l].push({
60
- 'gtm.start': new Date().getTime(),
61
- event: 'gtm.js',
62
- });
63
- var f = d.getElementsByTagName(s)[0],
64
- j = d.createElement(s),
65
- dl = l != 'dataLayer' ? '&l=' + l : '';
66
- j.async = true;
67
- j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
68
- f.parentNode.insertBefore(j, f);
69
- })(window, document, 'script', 'dataLayer', 'GTM-P5L2Z5Z');
70
- </script>
71
- <!-- End Google Tag Manager -->
26
+ <script
27
+ async
28
+ src="https://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js"
29
+ ></script>
30
+ <!-- End fonts -->
31
+ {% endblock google_fonts %} {% block css_file %}
32
+ <link rel="stylesheet" href="{{ static('styles/main.css') }}" />
33
+ {% endblock css_file %} {% include 'includes/ldjson.html' %} {% block
34
+ head_scripts %} {{ javascriptPack(jsPackName, { mjs: true }) }} {% endblock
35
+ head_scripts %}
36
+ </head>
37
+ <body>
38
+ {% include 'includes/svg-defs.html' %} {% block nav %}{% include
39
+ 'components/simple-masthead.html' %}{% endblock nav %} {% block content_wrap
40
+ %}
41
+ <main role="main">
42
+ {% block content %}{% endblock content %}
43
+ </main>
44
+ {% endblock content_wrap %} {% include 'components/footer.html' %} {% block
45
+ inline_data %}{% endblock inline_data %} {% include
46
+ 'includes/nomodule-shim.html' %} {% block scripts %} {{
47
+ javascriptPack(jsPackName) }} {% endblock scripts %} {% if ENV ==
48
+ 'production' %}
49
+ <!-- Google Tag Manager -->
50
+ <script>
51
+ (function(w, d, s, l, i) {
52
+ w[l] = w[l] || [];
53
+ w[l].push({
54
+ 'gtm.start': new Date().getTime(),
55
+ event: 'gtm.js',
56
+ });
57
+ var f = d.getElementsByTagName(s)[0],
58
+ j = d.createElement(s),
59
+ dl = l != 'dataLayer' ? '&l=' + l : '';
60
+ j.async = true;
61
+ j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
62
+ f.parentNode.insertBefore(j, f);
63
+ })(window, document, 'script', 'dataLayer', 'GTM-P5L2Z5Z');
64
+ </script>
65
+ <!-- End Google Tag Manager -->
72
66
 
73
- <!-- Google Tag Manager (noscript) -->
74
- <noscript>
75
- <iframe src="https://www.googletagmanager.com/ns.html?id=GTM-P5L2Z5Z" height="0" width="0" style="display:none;visibility:hidden"></iframe>
76
- </noscript>
77
- <!-- End Google Tag Manager (noscript) -->
67
+ <!-- Google Tag Manager (noscript) -->
68
+ <noscript>
69
+ <iframe
70
+ src="https://www.googletagmanager.com/ns.html?id=GTM-P5L2Z5Z"
71
+ height="0"
72
+ width="0"
73
+ style="display:none;visibility:hidden"
74
+ ></iframe>
75
+ </noscript>
76
+ <!-- End Google Tag Manager (noscript) -->
78
77
 
79
- <!-- START Parse.ly Include: Standard -->
80
- <div id="parsely-root" style="display: none">
81
- <span id="parsely-cfg" data-parsely-site="texastribune.org"></span>
82
- </div>
83
- <script>
84
- (function(s, p, d) {
85
- var h = d.location.protocol,
86
- i = p + '-' + s,
87
- e = d.getElementById(i),
88
- r = d.getElementById(p + '-root'),
89
- u =
90
- h === 'https:' ? 'd1z2jf7jlzjs58.cloudfront.net' : 'static.' + p + '.com';
91
- if (e) return;
92
- e = d.createElement(s);
93
- e.id = i;
94
- e.async = true;
95
- e.src = h + '//' + u + '/p.js';
96
- r.appendChild(e);
97
- })('script', 'parsely', document);
98
- </script>
99
- <!-- END Parse.ly Include: Standard -->
100
- {% endif %}
101
- </body>
78
+ <!-- START Parse.ly Include: Standard -->
79
+ <div id="parsely-root" style="display: none">
80
+ <span id="parsely-cfg" data-parsely-site="texastribune.org"></span>
81
+ </div>
82
+ <script>
83
+ (function(s, p, d) {
84
+ var h = d.location.protocol,
85
+ i = p + '-' + s,
86
+ e = d.getElementById(i),
87
+ r = d.getElementById(p + '-root'),
88
+ u =
89
+ h === 'https:'
90
+ ? 'd1z2jf7jlzjs58.cloudfront.net'
91
+ : 'static.' + p + '.com';
92
+ if (e) return;
93
+ e = d.createElement(s);
94
+ e.id = i;
95
+ e.async = true;
96
+ e.src = h + '//' + u + '/p.js';
97
+ r.appendChild(e);
98
+ })('script', 'parsely', document);
99
+ </script>
100
+ <!-- END Parse.ly Include: Standard -->
101
+ {% endif %}
102
+ </body>
102
103
  </html>