@data-visuals/create 7.2.0 → 7.4.1

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 (25) hide show
  1. package/README.md +55 -32
  2. package/package.json +1 -1
  3. package/templates/__common__/_package.json +4 -4
  4. package/templates/{graphic → __common__}/app/scripts/embeds/frames.js +0 -0
  5. package/templates/__common__/app/scripts/utils/clamp.js +10 -0
  6. package/templates/__common__/app/scripts/utils/get-current-url.js +5 -0
  7. package/templates/__common__/app/scripts/utils/serialize-query-string.js +1 -1
  8. package/templates/__common__/app/scripts/utils/sum-values.js +7 -0
  9. package/templates/__common__/app/templates/macros/prose.html +2 -2
  10. package/templates/__common__/config/tasks/graphics-meta.js +10 -2
  11. package/templates/__common__/project-metadata.md +186 -0
  12. package/templates/__common__/utils/deployment/deploy.js +0 -27
  13. package/templates/__common__/utils/fetch/authorize.js +8 -4
  14. package/templates/feature/README.md +15 -7
  15. package/templates/feature/app/scripts/packs/graphic-embed.js +31 -0
  16. package/templates/feature/app/scripts/packs/main-embed.js +7 -0
  17. package/templates/feature/app/scripts/utils/ad-loader.js +7 -3
  18. package/templates/feature/app/templates/{base-graphic.html → base-embed.html} +3 -2
  19. package/templates/feature/app/templates/{graphic.html → embed.html} +6 -6
  20. package/templates/feature/app/templates/includes/metas.html +1 -1
  21. package/templates/feature/app/templates/macros/processors.html +6 -2
  22. package/templates/graphic/app/templates/base.html +3 -2
  23. package/templates/graphic/app/templates/graphic-static.html +4 -4
  24. package/templates/graphic/app/templates/graphic.html +4 -4
  25. package/templates/graphic/graphics-meta.md +0 -120
package/README.md CHANGED
@@ -36,16 +36,16 @@ npm start
36
36
  - [Usage](#usage)
37
37
  - [Development and testing](#development-and-testing)
38
38
  - [Folder structure](#folder-structure)
39
- - [config/](#config)
40
- - [data/](#data)
41
- - [workspace/](#workspace)
42
- - [project.config.js](#projectconfigjs)
43
- - [app/](#app)
44
- - [app/index.html, app/static.html](#appindexhtml-appstatichtml)
45
- - [app/templates/](#apptemplates)
46
- - [app/scripts/](#appscripts)
47
- - [app/styles/](#appstyles)
48
- - [app/assets/](#appassets)
39
+ - [config/](#config)
40
+ - [data/](#data)
41
+ - [workspace/](#workspace)
42
+ - [project.config.js](#projectconfigjs)
43
+ - [app/](#app)
44
+ - [app/index.html, app/static.html](#appindexhtml-appstatichtml)
45
+ - [app/templates/](#apptemplates)
46
+ - [app/scripts/](#appscripts)
47
+ - [app/styles/](#appstyles)
48
+ - [app/assets/](#appassets)
49
49
  - [Other directories you may see](#other-directories-you-may-see)
50
50
  - [.tmp/](#tmp)
51
51
  - [dist/](#dist)
@@ -57,13 +57,13 @@ npm start
57
57
  - [Creating a new entrypoint](#creating-a-new-entrypoint)
58
58
  - [Connecting an entrypoint to an HTML file](#connecting-an-entrypoint-to-an-html-file)
59
59
  - [Available commands](#available-commands)
60
- - [`npm start` or `npm run serve`](#npm-start-or-npm-run-serve)
61
- - [`npm run deploy`](#npm-run-deploy)
62
- - [`npm run data:fetch`](#npm-run-datafetch)
63
- - [`npm run assets:push`](#npm-run-assetspush)
64
- - [`npm run assets:pull`](#npm-run-assetspull)
65
- - [`npm run workspace:push`](#npm-run-workspacepush)
66
- - [`npm run workspace:pull`](#npm-run-workspacepull)
60
+ - [`npm start` or `npm run serve`](#npm-start-or-npm-run-serve)
61
+ - [`npm run deploy`](#npm-run-deploy)
62
+ - [`npm run data:fetch`](#npm-run-datafetch)
63
+ - [`npm run assets:push`](#npm-run-assetspush)
64
+ - [`npm run assets:pull`](#npm-run-assetspull)
65
+ - [`npm run workspace:push`](#npm-run-workspacepush)
66
+ - [`npm run workspace:pull`](#npm-run-workspacepull)
67
67
  - [Environment variables and authentication](#environment-variables-and-authentication)
68
68
  - [AWS](#aws)
69
69
  - [Google](#google)
@@ -87,13 +87,18 @@ npm install -g @data-visuals/create
87
87
  npx @data-visuals/create@latest <project-type> <project-name>
88
88
  ```
89
89
 
90
- Currently there are two project types available — `graphic` and `feature`. The project name should be passed in as a slug, i.e. `my-beautiful-project`.
90
+ Currently there are two project types available — `graphic` and `feature`.
91
+
92
+ `graphic` - embeddable graphics, like the [district race lookup embedded in this voter guide](https://www.texastribune.org/2022/01/17/texas-primary-election-2022-voter-guide/)
93
+ `features` - entire page projects, like this [2022 primary ballot page](https://apps.texastribune.org/features/2022/texas-election-results-2022-primary/)
94
+
95
+ The project name should be passed in as a slug, i.e. `my-beautiful-project`.
91
96
 
92
97
  ```sh
93
98
  npx @data-visuals/create@latest graphic school-funding
94
99
  ```
95
100
 
96
- This will create a directory for you, copy in the files, install the dependencies, and do your first `git commit`.
101
+ This will create a directory for you, copy in the files, install the dependencies and do your first `git commit`.
97
102
 
98
103
  The directory name will be formatted like this:
99
104
 
@@ -106,10 +111,6 @@ graphic-school-funding-2018-01
106
111
 
107
112
  This is to ensure consistent naming of our directories!
108
113
 
109
- ## Development and testing
110
-
111
- If you make changes locally to `@data-visuals/create` and want to test them, you can run `data-visuals-create/bin/data-visuals-create <project-type> <project-name>` to generate a graphic or feature and see if your changes were included. Run the command one level above this repo, or you'll create a graphic or feature within `data-visuals-create`.
112
-
113
114
  ## Folder structure
114
115
 
115
116
  After creation, your project directory should look something like this:
@@ -147,23 +148,37 @@ The `workspace` directory is for storing all of your analysis, production and ra
147
148
 
148
149
  #### project.config.js
149
150
 
150
- Where all the configuration for a project belongs. This is where you can change the S3 deploy parameters, manage the Google Drive documents that sync with this project, set up a bespoke API or add custom filters to Nunjucks.
151
+ Where all the configuration for a project belongs. This is where you can change the S3 deploy parameters, manage the Google Drive documents that sync with this project, format data pulled from Google Drive documents, set up a bespoke API or add custom filters to Nunjucks.
152
+
153
+ - `dataMutators` - Modify what's returned by the data fetch. This is a good place to restructure raw data, or to do joins with other data you may have. [Here's an example from our coronavirus tracker.](https://github.com/texastribune/feature-tx-coronavirus-tracker-2020-03/blob/master/project.config.js#L188)
154
+ - `createAPI` - Bake out a series of JSON files that get deployed with your project. This is a great way to partition data that users only need a small slice of based on how they interact with our project. The kit expects this to return an array of objects. Each object should have a "key" and a "value" - the "key" determines the URL, the "value" is what is saved at that URL. [Here's an example from our voter guide.](https://github.com/texastribune/newsapps-dailies/blob/master/2022/graphic-voter-guide-primaries-2022-01/project.config.js#L136)
155
+ - `customFilters` - Where custom filters for Nunjucks are added. Each key should be the name of the filter, and each value should be a function it will call. (journalize comes built in and does not need to be added manually.) [Here's an example from our voter guide.](https://github.com/texastribune/newsapps-dailies/blob/master/2022/graphic-voter-guide-primaries-2022-01/project.config.js#L405)
151
156
 
152
157
  #### app/
153
158
 
154
159
  Where you'll spend most of your time! Here are where all the assets that go into building your project live.
155
160
 
156
- #### app/index.html, app/static.html
161
+ #### app/index.html
157
162
 
158
- The starter HTML pages provided by the kit. `index.html` is for scripted graphics that require additional JavaScript, and `static.html` is for graphics that do not, like Illustrator embeds. Feel free to rename them!
163
+ This is the landing page for graphics and features. For features, this page provides a full-page template to start from. For embeddable graphics, this page has instructions on how to create embeddable graphics and which templates in `app/templates/` to clone.
159
164
 
160
- If your project is only a single page (or graphic), you can pick one of them where you do all your HTML work. No special configuration is required to create new HTML files - just creating a new `.html` file in in the `app` directory (but _not_ within `app/scripts/` or `/app/templates/` - HTML files have special meanings in those directories) is enough to tell the kit about new pages it should compile.
165
+ #### app/templates/
161
166
 
162
- When embedding graphics other than `index.html`, remember to add the name of the template to the end of the embed link. The default link points to `index`.
167
+ Where all the Nunjucks templates (including the `base.html` template that `app/index.html` inherits from), `includes` and `macros` live.
163
168
 
164
- #### app/templates/
169
+ ### Embeddable graphics
165
170
 
166
- Where all the Nunjucks templates (including the `base.html` template that `app/index.html` inherits from), includes and macros live.
171
+ - `base.html` - base template used across all graphics
172
+ - `graphic-static.html` - template for static graphics, like Illustrator embeds
173
+ - `graphic.html` - template for graphics using JS, like ones that require D3
174
+
175
+ ### Features
176
+
177
+ - `base.html` - base template used across all features
178
+ - `base-embed.html` - base template used across all embeddable graphics associated with the feature
179
+ - `embed.html` - template for embeddable graphics associated with the feature
180
+
181
+ If your project is only a single page (or graphic), you can pick one of them where you do all your HTML work. No special configuration is required to create new HTML files - just creating a new `.html` file in in the `app` directory (but _not_ within `app/scripts/` or `/app/templates/` - HTML files have special meanings in those directories) is enough to tell the kit about new pages it should compile.
167
182
 
168
183
  #### app/scripts/
169
184
 
@@ -231,7 +246,7 @@ ArchieML Google Docs work as documented on the [ArchieML](http://archieml.org/)
231
246
 
232
247
  Our kit can display variables pulled in from Google Docs in the template. This is helpful when we want to show data in our text that is in the `data/` folder. Nunjucks finds the variable syntax (anything in curly braces) in our Google Doc text and displays the corresponding value.
233
248
 
234
- By default, Nunjucks has access to every file in our `data/` folder as an object. For example, if there are two files in the `data/` folder named `data.json` and `text.json` respectively, it will be structured as:
249
+ By default, Nunjucks has access to every file in our `data/` folder as an object. For example, if there are two files in the `data/` folder named `data.json` and `text.json` respectively, it will be structured as:
235
250
 
236
251
  ```json
237
252
  {
@@ -291,7 +306,7 @@ touch app/scripts/packs/maps.js
291
306
 
292
307
  Because there's a lot more going on behind the scenes than just adding a `<script>` tag, you have to set a special variable in a template in order to get the right entrypoint into the right HTML file.
293
308
 
294
- Set `jsPackName` anywhere in the HTML file to the name of your entrypoint (__without__ the extension) to route the right JavaScript files to it.
309
+ Set `jsPackName` anywhere in the HTML file to the name of your entrypoint (**without** the extension) to route the right JavaScript files to it.
295
310
 
296
311
  ```html
297
312
  {% set jsPackName = 'map' %}
@@ -312,6 +327,14 @@ The main command for development. This will build your HTML pages, prepare your
312
327
 
313
328
  The main command for deployment. It will always run `npm run build` first to ensure the compiled version is up-to-date. Use this when you want to put your project online. This will use the `bucket` and `folder` values in the `project.config.js` file to determine where it should be deployed on S3. Make sure those are set the appropriate values!
314
329
 
330
+ #### `npm run build`
331
+
332
+ The main command for compiling files. Stores compiled files in the `dist/` folder. Also runs `npm run parse` which parses project for metadata.
333
+
334
+ #### `npm run parse`
335
+
336
+ The main command for parsing metadata from projects. Refer to `project-metadata.md` for more information.
337
+
315
338
  #### `npm run data:fetch`
316
339
 
317
340
  This command uses the array of files listed under the `files` key in `project.config.js` to download data to the project. This data will be processed and made available in the `data` folder in the root of the project.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@data-visuals/create",
3
- "version": "7.2.0",
3
+ "version": "7.4.1",
4
4
  "description": "Create graphics and features the Data Visuals way.",
5
5
  "scripts": {
6
6
  "build:docs": "doctoc README.md --github",
@@ -17,7 +17,7 @@
17
17
  "workspace:push": "node ./utils/deployment/push-workspace.js"
18
18
  },
19
19
  "devDependencies": {
20
- "@babel/core": "^7.0.0",
20
+ "@babel/core": "^7.17.8",
21
21
  "@babel/plugin-proposal-class-properties": "^7.1.0",
22
22
  "@babel/plugin-syntax-dynamic-import": "^7.0.0",
23
23
  "@babel/plugin-transform-react-jsx": "^7.0.0",
@@ -28,7 +28,7 @@
28
28
  "ansi-colors": "^3.2.3",
29
29
  "archieml": "^0.4.1",
30
30
  "assets-webpack-plugin": "^6.1.2",
31
- "autoprefixer": "^9.0.2",
31
+ "autoprefixer": "^10.4.2",
32
32
  "aws-sdk": "^2.372.0",
33
33
  "babel-eslint": "^10.0.1",
34
34
  "babel-loader": "^8.0.0",
@@ -50,7 +50,7 @@
50
50
  "fast-glob": "^2.2.2",
51
51
  "fs-extra": "^7.0.0",
52
52
  "glob-watcher": "^5.0.3",
53
- "googleapis": "^83.0.0",
53
+ "googleapis": "^99.0.0",
54
54
  "html-minifier": "^3.5.21",
55
55
  "imagemin": "^7.0.0",
56
56
  "imagemin-gifsicle": "^7.0.0",
@@ -60,7 +60,7 @@
60
60
  "journalize": "^2.1.0",
61
61
  "mime-types": "^2.1.17",
62
62
  "nunjucks": "^3.0.1",
63
- "postcss": "^7.0.2",
63
+ "postcss": "^8.4.12",
64
64
  "postcss-flexbugs-fixes": "^4.1.0",
65
65
  "prettier": "^1.12.1",
66
66
  "puppeteer": "^5.5.0",
@@ -1,3 +1,13 @@
1
+ /**
2
+ * Returns the minimum if n is less than the minimum.
3
+ * Returns the maximum if n is more than the maximum.
4
+ * Returns n if n is between the minimum and maximum.
5
+ *
6
+ * @param {Number} n
7
+ * @param {Number} min
8
+ * @param {Number} max
9
+ * @return {Number}
10
+ */
1
11
  export default function clamp(n, min, max) {
2
12
  return Math.min(Math.max(n, min), max);
3
13
  }
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Returns current URL as a String.
3
+ *
4
+ * @return {String}
5
+ */
1
6
  function getCurrentUrl() {
2
7
  const loc = window.location;
3
8
  return `${loc.protocol}//${loc.host}${loc.pathname}`;
@@ -7,7 +7,7 @@
7
7
  const encode = encodeURIComponent;
8
8
 
9
9
  /**
10
- * Converts an object of key/value pairs into a encoded query string.
10
+ * Converts an object of key/value pairs into an encoded query string.
11
11
  *
12
12
  * @param {Object} params The params of the query string
13
13
  * @return {String}
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Sums up values of a property across objects in an array.
3
+ *
4
+ * @param {Array} arr An array of objects.
5
+ * @param {String} key The property to sum across objects.
6
+ * @return {Number}
7
+ */
1
8
  export default function sumValues(arr, key) {
2
9
  return arr.reduce((acc, obj) => acc + obj[key], 0);
3
10
  }
@@ -1,9 +1,9 @@
1
1
  {% import 'macros/processors.html' as processors %}
2
2
 
3
- {% macro prose(content, context, data) %}
3
+ {% macro prose(content, context, data, type) %}
4
4
  {% for item in content %}
5
5
  {% if processors[item.type] %}
6
- {{ processors[item.type](item.value, context, data) }}
6
+ {{ processors[item.type](item.value, context, data, type) }}
7
7
  {% else %}
8
8
  {{ processors['raw'](item.value, context, data) }}
9
9
  {% endif %}
@@ -170,7 +170,7 @@ const parseGraphic = async (
170
170
  // create array from credits
171
171
  if (credits.length > 0) {
172
172
  // separate by commas or and
173
- credits = credits.replace('Credit: ', '').split(/, *| and */g);
173
+ credits = credits.split(/, *| and */g);
174
174
  } else {
175
175
  credits = [];
176
176
  }
@@ -180,7 +180,15 @@ const parseGraphic = async (
180
180
  const caption = await getText({ key: 'caption', page });
181
181
  const altText = await getText({ key: 'alt-text', page });
182
182
  const note = await getText({ key: 'note', page });
183
- const source = await getText({ key: 'source', page });
183
+ let source = await getText({ key: 'source', page });
184
+
185
+ // create array from source
186
+ if (source.length > 0) {
187
+ // separate by commas or and
188
+ source = source.split(/, *| and */g);
189
+ } else {
190
+ source = [];
191
+ }
184
192
 
185
193
  const links = await page.$$eval('a', links =>
186
194
  links.map(link => {
@@ -0,0 +1,186 @@
1
+ ## Graphics and features metadata
2
+
3
+ In order to keep track of our graphics and features, metadata is grabbed from each project when we deploy them! (Hooray!) Metadata is scraped via specific selectors present in the HTML. The values for these selectors are parsed and output into a `manifest.json` file.
4
+
5
+ The metadata from `manifest.json` is then pasted into our [work log](https://docs.google.com/spreadsheets/d/1hCP5zGx8dNxk59gI9wBSFY2juJVM8OFCDY45VnNb2nI/edit#gid=965603489), which powers the CMS graphics plugin. Only embeddable graphics are present in the plugin — full-page features are not. The plugin surfaces our graphics for editors to embed them into stories.
6
+
7
+ | Selector/Variable | Alt Text | Example | Output in manifest.json |
8
+ |--|--|--|--|
9
+ | `[data-graphic]` or `[data-feature]` | If present, the HTML of the page will be parsed for metadata and surfaced in the CMS | `<div class="app" data-graphic>` or `<main data-feature>` | N/A - If no `[data-graphic]` or `[data-feature]` selector is found, the project won't output in manifest. |
10
+ | `{{ graphicTitle }}` or `[data-title]` | The title of the project in the CMS. **If this is missing in an embeddable graphic, the graphic will not surface in the CMS.** | `{% set graphicTitle = 'Some title' %}` or `<h1 class="graphic-title" data-title>Some title</h1>` | `title: string` |
11
+ | `{{ graphicAltText }}` | The alt text of the graphic in the CMS. This will also be read by screenreaders in platforms like Apple News. | `{% set graphicAltText = 'This is a bar chart showing xyz' %}` | `altText: string` |
12
+ | `{{ graphicCaption }}` or `[data-caption]` | The caption of the graphic in the CMS. The text typically below the title. | `{% set graphicCaption = 'Summarizing statement about the values in the graphic.' %}` or `<span data-caption>{{ prose(context.prose, context, graphicData) }}</span>` | `caption: string` |
13
+ | `{{ graphicNote }}` or `[data-note]` | Note or disclaimer attached to the graphic. | `{% set graphicNote = 'Important disclaimer about this graphic.' %}` or `<li data-note>Note: Important disclaimer about this graphic.</li>` | `note: string` |
14
+ | `{{ graphicSource }}` or `[data-source]` | The source of the graphic in the CMS | `{% set graphicSource = 'TXDOT' %}` or `<li data-source>Source: TXDOT</li>` | `source: string` |
15
+ | `{{ graphicCredit }}` or `[data-credit]` | The author names for the project in the CMS. | `{% set graphicCredit = 'Texas Tribune Staff' %}` or `<li data-credit>Texas Tribune Staff</li>` | `credits: array` |
16
+ | `{{ graphicTags }}` | The tags for the project in the CMS. | `{% set graphicTags = context.guten_tags %}` | `tags: array` |
17
+
18
+ The metadata as a variable, i.e. `graphicTitle` and `graphicCaption`, takes precedent over metadata in selectors, i.e. `[data-title]` and `[data-caption]`.
19
+
20
+ ### Full example with an embeddable graphic
21
+
22
+ `context` is data from the project's ArchieML Google Doc.
23
+
24
+ ```html
25
+ {% extends 'base.html' %}
26
+ {% set context = data.text %}
27
+ {% set graphicAltText = context.alttext %}
28
+ {% set graphicTags = context.guten_tags %}
29
+ {% block content %}
30
+ <div class="app" data-graphic>
31
+ <h1 class="graphic-title" data-title>{{ context.headline }}</h1>
32
+ <span data-caption>{{ prose(context.prose, context, graphicData) }}</span>
33
+ <div id="graphic" class="graphic"></div>
34
+ <ul class="graphic-footer">
35
+ <li data-note>Note: {{ context.note }}</li>
36
+ <li data-source>Source: {{ context.source }}</li>
37
+ <li data-credit>Credit: {{ context.credit }}</li>
38
+ </ul>
39
+ </div>
40
+ {% endblock content %}
41
+ ```
42
+
43
+ ### Full example with a full-page feature
44
+
45
+ `context` is data from the project's ArchieML Google Doc.
46
+
47
+ ```html
48
+ {% set graphicTags = context.guten_tags %}
49
+ <main data-feature>
50
+ <article class="has-giant-btm-marg">
51
+ {% block content %}
52
+ <div class="has-page-padding has-giant-btm-marg">
53
+ <header class="t-align-center">
54
+ <h1 class="l-container l-container--m t-headline t-serif t-lh-s has-s-btm-marg" data-title>{{ context.headline | widont }}</h1>
55
+ <p class="t-byline t-links t-uppercase t-lsp-m t-size-xs has-text-gray-dark has-b-btm-marg">
56
+ <span class="t-byline__item">By <span data-credit>{%- for author in context.authors -%}
57
+ {% if not loop.last %}{{ authorComma() }}{% elif not loop.first %} and{% endif %} <span class="l-display-ib">{{ author }}</span>
58
+ {%- endfor -%}</span>
59
+ </span>
60
+ </p>
61
+ </header>
62
+ </div>
63
+ {% endblock content %}
64
+ </article>
65
+ </main>
66
+ ```
67
+
68
+ ### Full example with ai2html graphic
69
+
70
+ Sometimes in Illustrator graphics, we set the title and other info in the Illustrator file itself and not the HTML, so we'd need to add those as nunjucks variables to surface the metadata. `context` is data from the project's ArchieML Google Doc.
71
+
72
+ ```html
73
+ {% extends 'base.html' %}
74
+ {% set context = data.text %}
75
+ {% set graphicTitle = context.headline %}
76
+ {% set graphicCaption = context.prose %}
77
+ {% set graphicAltText = context.alttext %}
78
+ {% set graphicNote = context.note %}
79
+ {% set graphicSource = context.source %}
80
+ {% set graphicCredit = context.credit %}
81
+ {% set graphicTags = context.guten_tags %}
82
+ {% block content %}
83
+ <div class="app" data-graphic>
84
+ <h1 class="graphic-title" data-title>{{ context.headline | widont }}</h1>
85
+ <span data-caption>{{ prose(context.prose, context, graphicData) }}</span>
86
+ {% set ai2html = "border-map-full" %}
87
+ {% include "ai2html-output/" + ai2html + ".html" %}
88
+ <ul class="graphic-footer">
89
+ <li data-note>Note: {{ context.note }}</li>
90
+ <li data-source>Source: {{ context.source }}</li>
91
+ <li data-credit>Credit: {{ context.credit }}</li>
92
+ </ul>
93
+ </div>
94
+ {% endblock content %}
95
+ ```
96
+
97
+ ### Other metadata
98
+
99
+ Along with HTML selectors, we also get metadata about graphics through the `project.config.js`. These are global to the whole project.
100
+
101
+ Project config keys output in `manifest.json`
102
+
103
+ - `type`
104
+ - `bucket`
105
+ - `createMonth`
106
+ - `createYear`
107
+ - `lastBuildTime`
108
+ - `folder`
109
+ - `id`
110
+ - `parserOptions`
111
+ - `appleNewsIgnore` - **Only applies to embeddable graphics** This is an array of files or folders that should be flagged in the CMS as not compatible with Apple News. Use this for graphics that are too dynamic to be accurately captured in a screenshot.
112
+
113
+ ### Ignoring projects
114
+
115
+ If any projects should be ignored in `manifest.json`, add the paths in `metadataIgnore` in `project.config.js`.
116
+
117
+ - `parserOptions`
118
+ - `metadataIgnore` - This is an array of files or folders that should not be parsed for metadata and displayed in the CMS graphics plugin. For example, any graphics or features created for testing but are not publishable should be added here.
119
+
120
+ ### Sample `manifest.json` output for embeddable graphics
121
+
122
+ ```json
123
+ [
124
+ {
125
+ "type": "graphic",
126
+ "title": "Title of graphic",
127
+ "altText": "Alt text of graphic",
128
+ "bucket": "graphics.texastribune.org",
129
+ "projectPath": "graphics/new-test-2-2021-02/static",
130
+ "projectURL": "https://graphics.texastribune.org/graphics/new-test-2-2021-02/static/",
131
+ "caption": "Caption of graphic",
132
+ "createMonth": "02",
133
+ "createYear": "2021",
134
+ "credits": ["Mandi Cai", "Darla Cameron", "Carla Astudillo", "Chris Essig"],
135
+ "folder": "graphics/new-test-2-2021-02",
136
+ "id": "uniqueString",
137
+ "lastBuildTime": "2021-04-22T19:28:30.269Z",
138
+ "label": "static/index.html",
139
+ "links": [
140
+ {
141
+ "url": "https://www.texastribune.org/series/news-apps-graphics-databases/",
142
+ "text": "See more graphics like this",
143
+ "isCTA": true
144
+ }
145
+ ],
146
+ "note": "Note: Texas Department of State Health Services was missing data last year.",
147
+ "previews": {
148
+ "large": "https://graphics.texastribune.org/graphics/new-test-2-2021-02/static/preview-large.png",
149
+ "small": "https://graphics.texastribune.org/graphics/new-test-2-2021-02/static/preview-small.png"
150
+ },
151
+ "showInAppleNews": true,
152
+ "source": "Source: Texas Department of State Health Services and U.S. Census ACS 2018 population estimates",
153
+ "tags": ["subject-politics"]
154
+ }
155
+ ]
156
+ ```
157
+
158
+ ### Sample `manifest.json` output for full-page features
159
+
160
+ ```json
161
+ [
162
+ {
163
+ "type": "feature",
164
+ "title": "Title of the feature",
165
+ "bucket": "apps.texastribune.org",
166
+ "projectPath": "features/2022/new-test-2-2021-02",
167
+ "projectURL": "https://apps.texastribune.org/features/2022/new-test-2-2021-02/",
168
+ "createMonth": "04",
169
+ "createYear": "2022",
170
+ "credits": ["Texas Tribune Staff"],
171
+ "folder": "features/2022/new-test-2-2021-02",
172
+ "id": "uniqueString",
173
+ "lastBuildTime": "2022-04-21T15:49:19.130Z",
174
+ "label": "index.html",
175
+ "tags": ["subject-politics"]
176
+ }
177
+ ]
178
+ ```
179
+
180
+ ### How it works
181
+
182
+ The `npm run parse` step will use [Puppeteer](https://github.com/puppeteer/puppeteer) and a local Chrome install to emulate the project in a browser. This will help build metadata based on a project's HTML and, for embeddable graphics, export image-based previews of the graphic as well as a manifest of all the metadata (`manifest.json`).
183
+
184
+ #### Troubleshooting
185
+
186
+ By default, this process assumes you're using MacOS. To change this for other operating systems, rerun the command with the correct install path variable: `CHROME_INSTALL_PATH="local/path/to/chrome" npm run parse`.
@@ -35,31 +35,4 @@ ${colors.blue.underline(mainPath)} (This has been copied to your clipboard.)
35
35
  Did you run ${colors.yellow(
36
36
  `npm run data:fetch`
37
37
  )} before deploying to get the latest data?`);
38
-
39
- if (projectType === 'feature') {
40
- console.log(`
41
- If you are deploying a feature, check Facebook/Twitter/other social platforms to make sure the
42
- share image shows up.`);
43
- }
44
-
45
- if (projectType === 'graphic') {
46
- console.log(`
47
- If you are deploying a graphic in a CMS story, there are a few steps. First,
48
- add this in the Content section of the Raw Plugin:
49
- ${colors.yellow(
50
- `<div class="dv201808-graphic dv201808-graphic--centered dv201808-graphic--centered-narrow" data-frame-src="${mainPath}" data-frame-sandbox="allow-scripts allow-same-origin allow-top-navigation-by-user-activation allow-top-navigation"></div>`
51
- )}`);
52
-
53
- console.log(`
54
- Next, add the style code snippet found in ${colors.yellow(
55
- 'app/styles/raw-plugin-styles.html'
56
- )} to the CSS content section of the Raw Plugin`);
57
-
58
- console.log(`
59
- Then, add this line to the JavaScript content section of the Raw Plugin:
60
- ${colors.yellow(
61
- '<script src="https://cdn.texastribune.org/lib/@newswire/frames@0.3.1/index.umd.js"></script>'
62
- )}
63
- ${colors.yellow('<script>newswireFrames.autoInitFrames();</script>')}`);
64
- }
65
38
  });
@@ -79,8 +79,10 @@ async function getAuth() {
79
79
  function getGoogleToken(auth, googleTokenFile) {
80
80
  return new Promise((resolve, reject) => {
81
81
  const url = auth.generateAuthUrl({
82
- access_type: 'offline',
83
82
  scope: SCOPES,
83
+ response_type: "code",
84
+ redirect_uri: auth.redirectUri,
85
+ client_id: auth._clientId
84
86
  });
85
87
 
86
88
  console.log(
@@ -96,10 +98,12 @@ function getGoogleToken(auth, googleTokenFile) {
96
98
  });
97
99
 
98
100
  rl.question(
99
- colors.bold('Enter your success code from that page here:\n'),
100
- async code => {
101
+ colors.bold("Sign in with your @texastribune.org account and hit 'Allow' to grant access to News Apps Graphics Kit.\nAfter you are redirected, the page will look broken, but copy the URL and paste it here:\n"),
102
+ async url => {
101
103
  rl.close();
102
104
 
105
+ const code = url.split(/[?=&]+/)[2];
106
+
103
107
  let tokens;
104
108
 
105
109
  try {
@@ -118,4 +122,4 @@ function getGoogleToken(auth, googleTokenFile) {
118
122
  });
119
123
  }
120
124
 
121
- module.exports = { getAuth };
125
+ module.exports = { getAuth };
@@ -10,22 +10,30 @@ This is a running list of things you should do before you launch any project on
10
10
 
11
11
  Our process for pitching and executing projects (which should happen before all of this) can be found on [this doc](https://docs.google.com/document/d/1E7QE8gp29h20EAafzSui8VjQ_9TG5-XhR33tbAP0hBA/edit).
12
12
 
13
- ## Final editing checklist
13
+ ### Final editing checklist
14
14
  Before your embedded graphic or feature goes live, here's the editing steps you need to take:
15
15
 
16
+ #### Initial steps
16
17
  - [ ] Spell check and self-edit — does everything make sense?
17
- - [ ] Data visuals editor for a visual edit
18
- - [ ] Design feedback channel (optional for more complex graphics or apps)
19
18
  - [ ] Story reporter, if a collaboration
19
+
20
+ #### Editing
21
+ Copy editors have a deadline of 5 pm so all editing should be done early afternoon the day before publication (at the latest)
20
22
  - [ ] Story or beat editor for a line edit to check facts
21
- - [ ] DV team in the secret channel (for a final gut check)
22
- - [ ] Copy editor
23
+ - [ ] Data visuals editor for edits and/or fact check
24
+ - [ ] DV team in the secret channel (for a final gut check. Darla can also provide visual edits in this channel, if she's available)
25
+ - [ ] Optional: Design feedback channel (can provide design edits)
26
+
27
+ #### Final steps
28
+ - [ ] Copy editor — their deadline is 5 p.m.
23
29
  - [ ] Be available the night before publication for any last-minute changes, or let other DV teammates know how to make edits
24
30
 
25
- ### Headline
26
- - [ ] Get a headline by submitting the story's budget line to the Headline Hoedown Slack channel
31
+ ### Headline and pointer
32
+ - [ ] If it's an apps page, we need to get the page's headline, slug and summary all approved by an editor. This is done in the team-editors channel. As of June 2022, only the Data Visuals Editor has access to that channel so they will need to hoedown this information for you. Also, it's likely you will need to hoedown a SEO headline as well for the pointer inside the CMS. These are created so a link to the apps page can show up on our website. Here's [an example](https://www.texastribune.org/admin/articles/articlelink/40354/change/) of one we've done.
27
33
 
28
34
  ### Article
35
+ If you're creating an apps page, make sure you complete these.
36
+
29
37
  - [ ] Add ads (three is typically the minimum; add more if longer)
30
38
  - [ ] Make sure there's related articles (powered by the `guten_tag` property in the feature's ArchieML doc)
31
39
  - [ ] Add any sigs, icons, or lead art
@@ -0,0 +1,31 @@
1
+ /* eslint-disable no-unused-vars */
2
+ import * as d3 from 'd3';
3
+ import createBase from '../utils/d3-base';
4
+
5
+ // a reference to the default graphic container, change if needed
6
+ const container = d3.select('#graphic');
7
+
8
+ // a helper function to clear the container of its contents
9
+ const clearContainer = () => container.html('');
10
+
11
+ // a helper function to grab the container's width
12
+ const getFrameWidth = () => container.node().offsetWidth;
13
+
14
+ // import data by getting the window variable, OR by importing the filepath
15
+ // let data = window.DATA;
16
+ // import data from '../../../data/data.json';
17
+ // import data from 'Data/data.json';
18
+
19
+ /**
20
+ * This function is called to render a graphic, using d3 or a library of your choice.
21
+ *
22
+ * @return {void}
23
+ */
24
+ export default function renderGraphic() {
25
+ // pass the recalculated frameWidth to parts of your chart (like an axis) that change with resize!
26
+ clearContainer();
27
+ const frameWidth = getFrameWidth();
28
+ //
29
+ // rest of your code goes here
30
+ // use createBase() to create the base of an d3 chart
31
+ }
@@ -0,0 +1,7 @@
1
+ import { frameLoader } from '../embeds/frames';
2
+ import renderGraphic from './graphic-embed';
3
+
4
+ // included in index.html by default
5
+ // initiates frame so your graphic is wrapped in an AMP-compatible iframe
6
+ // renderGraphic() renders a coded graphic on load and on resize
7
+ frameLoader(renderGraphic);
@@ -99,9 +99,13 @@ class AdLoader {
99
99
  adElementId
100
100
  );
101
101
 
102
- // overwrites the default fixed size set above
103
- // if the ad is a banner ad
104
- gptAdUnit.defineSizeMapping(banner);
102
+ // make ad square if it includes the `dv-gpt-ad-square` class
103
+ if (attributes.class.includes('dv-gpt-ad-square')) {
104
+ gptAdUnit.defineSizeMapping([300, 250]);
105
+ } else {
106
+ // else use banner dimensions
107
+ gptAdUnit.defineSizeMapping(banner);
108
+ }
105
109
 
106
110
  if (options.targetingKey && options.targetingValue) {
107
111
  gptAdUnit.setTargeting(options.targetingKey, options.targetingValue);
@@ -22,8 +22,9 @@
22
22
  {% if graphicSource %}
23
23
  <meta name="tt-graphic-source" content="{{ graphicSource }}" />
24
24
  {% endif %}
25
-
26
- <meta name="tt-graphic-credit" content="{{ graphicCredit or 'Texas Tribune Staff'}}" />
25
+ {% if graphicCredit %}
26
+ <meta name="tt-graphic-credit" content="{{ graphicCredit }}" />
27
+ {% endif %}
27
28
  <meta name="tt-graphic-tags" content="{{ graphicTags or ['subject-politics'] }}" />
28
29
 
29
30
  <link rel="dns-prefetch" href="https://www.google-analytics.com">
@@ -1,9 +1,9 @@
1
1
  {# Template for any scripted graphics, i.e. D3 charts #}
2
- {% extends 'base-graphic.html' %}
2
+ {% extends 'base-embed.html' %}
3
3
  {% from 'macros/prose.html' import prose %}
4
4
 
5
5
  {# set pack that provides JS #}
6
- {% set jsPackName = 'main' %}
6
+ {% set jsPackName = 'main-embed' %}
7
7
 
8
8
  {# data.text --> data/text.json #}
9
9
  {% set context = data.text %}
@@ -23,16 +23,16 @@
23
23
  {# data-title is used to grab the title in the CMS #}
24
24
  <h1 class="graphic-title" data-title>{{ context.headline | widont }}</h1>
25
25
  {# data-caption is used to grab the caption in the CMS #}
26
- <span data-caption>{{ prose(context.graphic_prose, context, graphicData) }}</span>
26
+ <span data-caption>{{ prose(context.embed_prose, context, graphicData, 'embed') }}</span>
27
27
 
28
28
  {# container that JS is attached to #}
29
29
  <div id="graphic" class="graphic"></div>
30
30
 
31
31
  {# data-source, data-credit, and data-note are also used in the CMS #}
32
32
  <ul class="graphic-footer">
33
- {% if context.note %}<li data-note>Note: {{ context.note }}</li>{% endif %}
34
- {% if context.source %}<li data-source>Source: {{ context.source }}</li>{% endif %}
35
- {% if context.credit %}<li data-credit>Credit: {{ context.credit }}</li>{% endif %}
33
+ {% if context.embed_note %}<li>Note: <span data-note>{{ context.embed_note }}</span></li>{% endif %}
34
+ {% if context.embed_source %}<li>Source: <span data-source>{{ context.embed_source }}</span></li>{% endif %}
35
+ {% if context.embed_credit %}<li>Credit: <span data-credit>{{ context.embed_credit }}</span></li>{% endif %}
36
36
  </ul>
37
37
  </div>
38
38
  {% endblock content %}
@@ -19,7 +19,7 @@
19
19
  <meta property="og:site_name" content="The Texas Tribune">
20
20
  <meta property="og:image" content="{{ staticAbsolute('assets/images/share-art.jpg', true) }}">
21
21
  <meta property="fb:app_id" content="154122474650943">
22
- <meta name="parsely-title" content="{{ context.headline|escape }}" />
22
+ <meta name="parsely-title" content="{{ context.seo_headline|escape }}" />
23
23
  <meta name="parsely-link" content="{{ CURRENT_PAGE_URL }}" />
24
24
  <meta name="parsely-type" content="post" />
25
25
  <meta name="parsely-image-url" content="{{ staticAbsolute('assets/images/share-art.jpg', true) }}" />
@@ -4,8 +4,12 @@
4
4
  {{ value | renderStringWithNunjucks(data) }}
5
5
  {% endmacro %}
6
6
 
7
- {% macro text(value, context, data) %}
8
- <p class="copy">{{ value | renderStringWithNunjucks(data) }}</p>
7
+ {% macro text(value, context, data, type) %}
8
+ {% if type == 'embed' %}
9
+ <p class="graphic-prose">{{ value | renderStringWithNunjucks(data) }}</p>
10
+ {% else %}
11
+ <p class="copy">{{ value | renderStringWithNunjucks(data) }}</p>
12
+ {% endif %}
9
13
  {% endmacro %}
10
14
 
11
15
  {% macro list(value) %}
@@ -22,8 +22,9 @@
22
22
  {% if graphicSource %}
23
23
  <meta name="tt-graphic-source" content="{{ graphicSource }}" />
24
24
  {% endif %}
25
-
26
- <meta name="tt-graphic-credit" content="{{ graphicCredit or 'Texas Tribune Staff'}}" />
25
+ {% if graphicCredit %}
26
+ <meta name="tt-graphic-credit" content="{{ graphicCredit }}" />
27
+ {% endif %}
27
28
  <meta name="tt-graphic-tags" content="{{ graphicTags or ['subject-politics'] }}" />
28
29
 
29
30
  <link rel="dns-prefetch" href="https://www.google-analytics.com">
@@ -27,7 +27,7 @@
27
27
  {# data-graphic signifies that this can be embedded in the CMS #}
28
28
  <div class="app" data-graphic>
29
29
  {# data-title is used to grab the title in the CMS #}
30
- <h1 class="graphic-title" data-title>{{ context.headline | widont }}</h1>
30
+ <h1 class="graphic-title" data-title>{{ context.headline | widont or 'The only member-supported, digital-first, nonpartisan media organization' | widont }}</h1>
31
31
  {# data-caption is used to grab the caption in the CMS #}
32
32
  <span data-caption>{{ prose(context.prose, context, graphicData) }}</span>
33
33
 
@@ -37,9 +37,9 @@
37
37
 
38
38
  {# data-source and data-credit are also used in the CMS #}
39
39
  <ul class="graphic-footer">
40
- {% if context.note %}<li data-note>Note: {{ context.note }}</li>{% endif %}
41
- {% if context.source %}<li data-source>Source: {{ context.source }}</li>{% endif %}
42
- {% if context.credit %}<li data-credit>Credit: {{ context.credit }}</li>{% endif %}
40
+ {% if context.note %}<li>Note: <span data-note>{{ context.note }}</span></li>{% endif %}
41
+ {% if context.source %}<li>Source: <span data-source>{{ context.source }}</span></li>{% endif %}
42
+ {% if context.credit %}<li>Credit: <span data-credit>{{ context.credit }}</span></li>{% endif %}
43
43
  </ul>
44
44
  </div>
45
45
  {% endblock content %}
@@ -21,7 +21,7 @@
21
21
  {# data-graphic signifies that this can be embedded in the CMS #}
22
22
  <div class="app" data-graphic>
23
23
  {# data-title is used to grab the title in the CMS #}
24
- <h1 class="graphic-title" data-title>{{ context.headline | widont }}</h1>
24
+ <h1 class="graphic-title" data-title>{{ context.headline | widont or 'The only member-supported, digital-first, nonpartisan media organization' | widont }}</h1>
25
25
  {# data-caption is used to grab the caption in the CMS #}
26
26
  <span data-caption>{{ prose(context.prose, context, graphicData) }}</span>
27
27
 
@@ -30,9 +30,9 @@
30
30
 
31
31
  {# data-source, data-credit, and data-note are also used in the CMS #}
32
32
  <ul class="graphic-footer">
33
- {% if context.note %}<li data-note>Note: {{ context.note }}</li>{% endif %}
34
- {% if context.source %}<li data-source>Source: {{ context.source }}</li>{% endif %}
35
- {% if context.credit %}<li data-credit>Credit: {{ context.credit }}</li>{% endif %}
33
+ {% if context.note %}<li>Note: <span data-note>{{ context.note }}</span></li>{% endif %}
34
+ {% if context.source %}<li>Source: <span data-source>{{ context.source }}</span></li>{% endif %}
35
+ {% if context.credit %}<li>Credit: <span data-credit>{{ context.credit }}</span></li>{% endif %}
36
36
  </ul>
37
37
  </div>
38
38
  {% endblock content %}
@@ -1,120 +0,0 @@
1
- ## Graphics metadata
2
-
3
- Graphics intended to be used as embeds in the CMS should have specific selectors present in the HTML. The values for these selectors are parsed and output into a `manifest.json` file which is used by the graphics plugin to organize our graphics inventory.
4
-
5
-
6
- | Selector/Variable | Alt Text | Example | Output in manifest.json |
7
- |--|--|--|--|
8
- | `[data-graphic]` | If present, the HTML of the page will be parsed for metadata and surfaced in the CMS | `<div class="app" data-graphic>` | N/A - If no `[data-graphic]` selector is found, the graphic won't output in manifest. |
9
- | `{{ graphicTitle }}` or `[data-title]` | The title of the graphic in the CMS. **If this is missing, the graphic will not surface in the CMS.** | `{% set graphicTitle = 'Some title' %}` or `<h1 class="graphic-title" data-title>Some title</h1>` | `title: string` |
10
- | `{{ graphicAltText }}` | The alt text of the graphic in the CMS. This will also be read by screenreaders in platforms like Apple News. | `{% set graphicAltText = 'This is a bar chart showing xyz' %}` | `altText: string` |
11
- | `{{ graphicCaption }}` | The caption of the graphic in the CMS. The text typically below the title. | `{% set graphicCaption = 'Summarizing statement about the values in the graphic.' %}` | `caption: string` |
12
- | `{{ graphicNote }}` or `[data-note]` | Note or disclaimer attached to the graphic. | `{% set graphicNote = 'Important disclaimer about this graphic.' %}` or `<li data-note>Note: Important disclaimer about this graphic.</li>` | `note: string` |
13
- | `{{ graphicSource }}` or `[data-source]` | The source of the graphic in the CMS | `{% set graphicSource = 'TXDOT' %}` or `<li data-source>Source: TXDOT</li>` | `source: string` |
14
- | `{{ graphicCredit }}` or `[data-credit]` | The author names for the graphic in the CMS. | `{% set graphicCredit = 'Trib Tribington, Super Cool Corgi' %}` or `<li data-credit>Trib Tribington and Super Cool Corgi</li>` | `credits: array` |
15
-
16
- ### Full example
17
- ```html
18
- {% extends 'base.html' %}
19
- {% set context = data.text %}
20
- {% set graphicAltText = 'Alt text of graphic' %}
21
- {% block content %}
22
- <div class="app" data-graphic>
23
- <h1 class="graphic-title" data-title>{{ context.headline }}</h1>
24
- <span data-caption>{{ prose(context.prose, context, graphicData) }}</span>
25
- <div id="graphic" class="graphic"></div>
26
- <ul class="graphic-footer">
27
- <li data-note>Note: {{ context.note }}</li>
28
- <li data-source>Source: {{ context.source }}</li>
29
- <li data-credit>Credit: {{ context.credit }}</li>
30
- </ul>
31
- </div>
32
- {% endblock content %}
33
- ```
34
- ### Full example with ai2html graphic
35
-
36
- For Illustrator graphics, we typically set the title and other info in the Illustrator file itself and not the HTML, so we'd need to add those as nunjucks variables to surface the metadata.
37
-
38
- ```html
39
- {% extends 'base.html' %}
40
- {% set context = data.text %}
41
- {% set graphicTitle = 'Headline from AI graphic' %}
42
- {% set graphicAltText = 'Alt text of graphic' %}
43
- {% set graphicCaption = 'Chatter from AI graphic' %}
44
- {% set graphicNote = 'Note from AI graphic' %}
45
- {% set graphicSource = 'Source from AI graphic' %}
46
- {% set graphicCredit = 'Credit from AI graphic' %}
47
- {% block content %}
48
- <div class="app" data-graphic>
49
- <h1 class="graphic-title" data-title>{{ context.headline }}</h1>
50
- {{ prose(context.prose, context, graphicData) }}
51
- {% set ai2html = "border-map-full" %}
52
- {% include "ai2html-output/" + ai2html + ".html" %}
53
- <ul class="graphic-footer">
54
- <li data-note>Note: {{ context.note }}</li>
55
- <li data-source>Source: {{ context.source }}</li>
56
- <li data-credit>Credit: {{ context.credit }}</li>
57
- </ul>
58
- </div>
59
- {% endblock content %}
60
- ```
61
-
62
- ### Other metadata
63
-
64
- Along with HTML selectors, we also get metadata about graphics through the `project.config.js`. These are global to the whole project and the same for every graphic in the project.
65
-
66
- Project config keys output in `manifest.json`
67
- - `bucket`
68
- - `createMonth`
69
- - `createYear`
70
- - `lastBuildTime`
71
- - `folder`
72
- - `id`
73
- - `tags`
74
- - `parserOptions`
75
- - `metadataIgnore` - This is an array of files or folders that should not be parsed for metadata and displayed in the CMS graphics plugin. For example, any graphics or features created for testing but are not publishable should be added here.
76
- - `appleNewsIgnore` - This is an array of files or folders that should be flagged in the CMS as not compatible with Apple News. Use this for graphics that are too dynamic to be accurately captured in a screenshot.
77
-
78
- ### Sample `manifest.json` output
79
-
80
- ```json
81
- [
82
- {
83
- "title": "Title of graphic",
84
- "altText": "Alt text of graphic",
85
- "bucket": "graphics.texastribune.org",
86
- "graphicPath": "graphics/new-test-2-2021-02/static",
87
- "graphicURL": "https://graphics.texastribune.org/graphics/new-test-2-2021-02/static/",
88
- "createMonth": "02",
89
- "createYear": "2021",
90
- "credits": ["Mandi Cai", "Darla Cameron", "Carla Astudillo", "Chris Essig"],
91
- "folder": "graphics/new-test-2-2021-02",
92
- "id": "uniqueString",
93
- "label": "static/index.html",
94
- "lastBuild": "2021-04-22T19:28:30.269Z",
95
- "links": [
96
- {
97
- "url": "https://www.texastribune.org/series/news-apps-graphics-databases/",
98
- "text": "See more graphics like this",
99
- "isCTA": true
100
- }
101
- ],
102
- "note": "Note: Texas Department of State Health Services was missing data last year.",
103
- "previews": {
104
- "large": "https://graphics.texastribune.org/graphics/new-test-2-2021-02/static/preview-large.png",
105
- "small": "https://graphics.texastribune.org/graphics/new-test-2-2021-02/static/preview-small.png"
106
- },
107
- "showInAppleNews": true,
108
- "source": "Texas Department of State Health Services and U.S. Census ACS 2018 population estimates"
109
- }
110
- ]
111
-
112
- ```
113
-
114
-
115
- ### How it works
116
-
117
- The `npm run parse` step will use [Puppeteer](https://github.com/puppeteer/puppeteer) and a local Chrome install to emulate the project in a browser. This will help build metadata based on a graphic's HTML and export image-based previews of the graphic as well as a manifest of all the graphics in the project (`manifest.json`).
118
-
119
- #### Troubleshooting
120
- By default, this process assumes you're using MacOS. To change this for other operating systems, rerun the command with the correct install path variable: `CHROME_INSTALL_PATH="local/path/to/chrome" npm run parse`.