{"id":22879269,"url":"https://github.com/utdata/icj-project-rig","last_synced_at":"2025-04-14T19:51:12.755Z","repository":{"id":40364366,"uuid":"155099548","full_name":"utdata/icj-project-rig","owner":"utdata","description":"A project scaffold for the Intro to Coding for Journalists class at the University of Texas at Austin, School of Journalism","archived":false,"fork":false,"pushed_at":"2025-02-20T21:38:03.000Z","size":9902,"stargazers_count":0,"open_issues_count":13,"forks_count":3,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-28T08:11:26.758Z","etag":null,"topics":["icj","template"],"latest_commit_sha":null,"homepage":"https://utdata.github.io/icj-project-rig/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/utdata.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-10-28T17:59:08.000Z","updated_at":"2025-02-20T21:38:06.000Z","dependencies_parsed_at":"2023-02-08T03:30:52.446Z","dependency_job_id":"b0542f04-2bd6-4b22-8658-236e56431edf","html_url":"https://github.com/utdata/icj-project-rig","commit_stats":null,"previous_names":[],"tags_count":0,"template":true,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/utdata%2Ficj-project-rig","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/utdata%2Ficj-project-rig/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/utdata%2Ficj-project-rig/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/utdata%2Ficj-project-rig/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/utdata","download_url":"https://codeload.github.com/utdata/icj-project-rig/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248951596,"owners_count":21188414,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["icj","template"],"created_at":"2024-12-13T16:38:38.819Z","updated_at":"2025-04-14T19:51:12.742Z","avatar_url":"https://github.com/utdata.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ICJ Project Rig\n\nThis project rig was developed for the [Intro to Coding for Journalists](https://github.com/utdata/icj-class) class taught at different times by two different professors in the School of Journalism and Media, Moody College of Communication, University of Texas at Austin:\n\n- [Christian McDonald](https://github.com/critmcdonald), Assistant Professor of Practice\n- [Jeff Linwood](https://github.com/jefflinwood), Lecturer\n\nThe development concepts used are similar to rigs used by news graphics teams in newsrooms like The Texas Tribune, Los Angeles Times and NPR.\n\n## Features\n\nThis Node-based rig uses a Gulp workflow configured for GitHub Pages publishing. Features include:\n\n- [Bootstrap](https://getbootstrap.com/) and [Sass](https://sass-lang.com/).\n- [Nunjucks Templating](https://mozilla.github.io/nunjucks/templating.html) with [`journalize`](https://www.npmjs.com/package/journalize) filters.\n- Ability to configure Google Sheets and Docs (with [ArchieML](http://archieml.org/)) to manage data and content.\n\n## Launching from codespaces\n\n1. From the [icj-project-rig repo](https://github.com/utdata/icj-project-rig), click on the green **Use this template** button and choose _Create a new repository_.\n    - This should allow you to create new repo based on icj-bootstrap-template.\n    - Leave all the other settings the same and click **Create repository**.\n    - It takes several seconds to create your repo.\n1. Click on the green **\u003c\u003e Code** button and then choose the **Codespaces** tab.\n    - Click **Create codespace on main**.\n    - This will take a bit more time, but should just be a couple of minutes. **It will pause at one point and give you a prompt, but wait until you see it say \"Detected Node.js\" and let it finish that setup.\n    - Once the Node installation finishes, your browser will look like you have a version of Visual Studio Code open, and you do!\n1. In the codespace's VS Code Terminal, run:\n    \n    ```bash\n    npm install -g gulp\n    ```\n\n1. In the Terminal, run `gulp dev`.\n\nIf you get errors, you might have to try `npm install` and then run `gulp dev` again.\n\n### Using on a local machine\n\n**IF you are using codespaces, skip to the next section!**\n\nIf you want to develop on your own machine vs Github codespaces, you have to set up your machine to run Node.js and have some other configurations. See the [ICJ Setting Up](https://utdata.github.io/icj-setting-up/) site on how to do that. Here we just have the steps.\n\nTo start a new project:\n\n- Create a project folder for all your code.\n- Open Visual Studio Code into that folder and open the integrated Terminal.\n- Run `degit utdata/icj-project-rig`.\n- Initialize your repo with `git init`, add and commit the files.\n- Create your GitHub repo and connect them. Your GitHub repo and local repo should have the same name. The instructions for pushing an existing local repo to your GitHub repo will appear after you create the repo on GitHub, but here are the instructions again:\n  - Run `git remote add origin https://github.com/\u003cgithub-username\u003e/\u003cgithub-repo-name\u003e` in your local repo\n  - `git branch -M main` (if your default branch is not already named main)\n  - `git push -u origin main`\n\nMake sure you run `degit` to get all your files _before_ you initialize your repo.\n\n## Understanding this project rig\n\nMost of the files you edit for this project are in the `src` directory. The Gulp production process will generate the publishable files into the `docs` folder, which you shouldn't touch.\n\n```pre\n├── src\n|  ├── _data (For data)\n|  |── _includes (For code snippets)\n|  ├── _macros (For reusable code)\n|  ├── _templates (For templates)\n|  ├── img (For image files)\n|  ├── js (For custom JavaScript)\n|  ├── scss (For Sass/CSS files)\n|  └── index.njk (Becomes an HTML page)\n```\n\nEach `.njk` (or `.html`) file inside `src/` or a nested folder is compiled as an HTML file in `docs/`. Folders inside `src` that start with `_` support the system and files inside do NOT become published files.\n\n## Sass/scss\n\nThe `src/scss/` folder holds all the SCSS files. It is configured for Bootstrap and the CSS gets compiled into the `docs/css` folder for docsation.\n\nThere is an example of a Sass partial with the `src/scss/_nav.scss` file, which is imported into `src/scss/main.scss`.\n\n## Nunjucks templates\n\n[Nunjucks](https://mozilla.github.io/nunjucks/templating.html) allows you to write and reuse code in templates so you don't have to repeat code for each page of your site. The Nunjucks community has adopted `.njk` as the standard file extension.\n\nTemplates work off several basic concepts:\n\n- _extends_ is used to specify template inheritance, meaning you can \"build upon\" templates to avoid repeating code.\n- _block_ defines a section in a template and identifies it with a name. Pages that extend a template can override or append to these reserved blocks with new content.\n- _include_ imports code from other files. It's useful to organize or share smaller chunks of code.\n- _macro_ allows you to define reusable chunks of content. It is similar to a function in other programming languages.\n\nWith these tools, you can build a site framework once as a template, and then _extend_ that template and use all its code, but swap out predefined _blocks_ specific to your new page.\n\n### Nunjucks template examples\n\nThis project organizes Nunjucks helper files into folders that start with `_` so their contents won't be complied into full pages on your site. There are examples of **templates**, **includes** and **macros**.\n\n- The file `src/_templates/base.njk` is an example base template for a website. The idea is to build the framework of the site only once, even though you might have many pages.\n- Files in `src/_includes/` are snippets of code used by other templates using the _include_ tag. You can see how the  `nav.njk` and `footer.njk` includes are pulled into the `base.njk` template.\n\nSome other files in those folders are discussed as advanced features later.\n\n### Pages\n\nAll **pages** are kept in the `src/` folder. Each `.njk` file (including those in a nested folder that don't start with `_`) will be processed and become an `.html` file in `docs/`, and therefore a webpage on your website.\n\nThis project includes the example `src/index.njk`, which is the homepage of the website. It _extends_ `src/_templates/base.njk`. Using the _block_ and _extend_ features allows you to worry about only main content of the page, as it inherits the nav and other framework from the base template. This example includes some loops to build content from the example library and bookstores data, described in detail below.\n\nTo create a new webpage, just add a new file in `src/` with the `.njk` extension. You'll want to _extend_ the `_templates/base.njk` template and put your content inside the `{% block content %}{% endblock %}` block.\n\n### Deployment\n\nThis project is designed to bundle the finished website into the `docs` folder, which can then be published anywhere you have a server. We use and commit our `docs` distribution folder to GitHub to take advantage of [GitHub Pages](https://help.github.com/categories/github-pages-basics/) for free hosting of the site.\n\nReview [GitHub Pages](https://help.github.com/articles/configuring-a-publishing-source-for-github-pages/#publishing-your-github-pages-site-from-a-docs-folder-on-your-master-branch) for specific directions on deployment using the `main/docs/` folder.\n\n## Advanced Nunjucks features\n\n### Using project data, loops\n\nNunjucks has special [tags to apply logic](https://mozilla.github.io/nunjucks/templating.html#tags), like looping through data.\n\nData used in the project must be saved as a JSON file in the `src/_data/` folder. There are some examples in the project, including `library.json`. While not the full file, this is an example of JSON array of key-value pairs:\n\n```json\n{\n  \"books\": [\n    {\n      \"slug\": \"the-clown\",\n      \"title\": \"The Clown\",\n      \"author\": \"Heinrich Böll\"\n    },\n    {\n      \"slug\": \"the-shipping-news\",\n      \"title\": \"The Shipping News\",\n      \"author\": \"Annie Proulx\"\n    }\n  ]\n}\n```\n\nThere is an example using a loop to access data in these files in `index.njk`.\n\n- You can add new `*.json` files into `src/_data/` and they will be added to the Nunjucks context as `filename.arrayname`. Data is accessed with a Nunjucks variable `{{ arrayname.key }}`.\n- Optionally, with the Google Drive authentication described below, you can store data in Google Sheets or Docs and \"fetch\" it as JSON arrays that will be downloaded and saved into the `src/_data` folder.\n- You can also create global variables in `project.config.json` as key-value pairs or arrays.\n\n\u003e IMPORTANT: If you add/change/delete data in JSON files, you must re-run the `gulp dev` command to make it available to Nunjucks.\n\n### \"Bake\" pages from data and a template\n\nIt is possible to generate (or \"bake\") multiple pages from data and a Nunjucks template. Combined with Google Sheets/Docs data management, this can be a powerful tool to create and manage multi-page websites from data collections, like voter guides, restaurant databases and investigative project case studies.\n\nThe example used in the project publishes a [webpage for each book](https://utdata.github.io/icj-project-template/books/the-shipping-news.html) in a library based on \"data\" in a Google Doc.\n\nThe process requires three things:\n\n- A Nunjucks template: The example in the project is: `src/_templates/bake-book.njk`. The template displays the data through Nunjucks variables `{{ keyvalue }}`.\n- Data: A JSON data file saved in the `src/_data/` folder.\n- Configuration to pair the layout with the data: This is set up in the `project.config.json` file, which has several requirements:\n\n```json\n{\n  \"to_bake\": [\n    {\n      \"template\": \"bake-book\",\n      \"data\": \"library\",\n      \"array\": \"books\",\n      \"slug\": \"slug\",\n      \"path\": \"books\"\n    }\n  ]\n}\n```\n\n- **`template`** is the name of the template file stored in `src/_templates` that will be used to build the pages. Note you don't need the extension in name.\n- **`data`** is the name of the data file to build from. You don't need `.json` in the name.\n- **`array`** is the name of the array you are using from the JSON file.\n- **`slug`** is a key required from the data that will become the filename of each file created. The field used in the data needs to be in a URL-friendly format with all lowercase letters with dashes instead of spaces.\n- **`path`** is an optional folder to save the files into. Use an empty string to save the files at the root of `docs/`.\n\nYou can configure more than one \"bake\" task by adding new configurations to the `to_bake` array.\n\nThe command to generate the files is `gulp bake`, but the task is also included in the default `gulp` and `gulp dev` commands.\n\n### Layouts and relative paths\n\nSince pages using layouts like `_templates/base.njk` and includes like `_includes/nav.njk` can come from nested directories on the site, the example pages in this project use a variable `{{ relative_path }}` to correct these paths.\n\nIf needed, set the variable to the path that would return you to the root/index of the site. For example, since layout `bake-book.njk` will create files inside a folder at `/books/filename.html` we set the `{{ relative_path }}` to come up one level to come out of that \"books\" folder.\n\n```html\n{% set relative_path = \"../\" %}\n```\n\nAny code written that includes `src` or `href` paths that could be called from a nested directory should include the variable `{{ relative_path }}` at the beginning of the url.\n\n```html\n\u003cscript src=\"{{ relative_path }}js/jquery.js\"\u003e\u003c/script\u003e\n```\n\n### More Nunjucks configuration\n\nA collection of functions useful for making prose reader friendly is already included with [`journalize`](https://www.npmjs.com/package/journalize).\n\nYou can add [custom filters](https://mozilla.github.io/nunjucks/api.html#custom-filters) and [global variables](https://mozilla.github.io/nunjucks/api.html#addglobal) in the `manageEnv` function inside `tasks/nunjucks.js`.\n\nIn addition to data in the `src/_data` folder, you can also configure data variables in the `project.config.json` file.\n\n## Using data from Google Drive\n\nTo use Google Drive to store and \"fetch\" data, you have to configure a service account key. See [icj-setting-up](https://utdata.github.io/icj-setting-up/setup-part-2.html) Part 2 to prepare this.\n\n`icj-project-template` projects support downloading ArchieML-formatted Google Docs and correctly-formatted Google Sheets directly from Google Drive for use within your project. All files you want to use in your projects should be listed in `project.config.json` under the `files` key. You are not limited to one of each.\n\n```js\n{\n  files: [\n    {\n      fileId: '\u003cthe-document-id-from-the-url\u003e',\n      type: 'doc',\n      name: 'text',\n    },\n    {\n      fileId: '\u003cthe-sheet-id-from-the-url\u003e',\n      type: 'sheet',\n      name: 'data',\n    }\n  ]\n}\n```\n\nEach object representing a Google Drive file needs three things:\n\n- The `fileId` key represents the ID of a Google Doc or Google Sheet. This is most easily found in the URL of a document when you have it open in your browser.\n- The `type` key is used to denote whether this is a Google Doc (`doc`) or a Google Sheet (`sheet`). This controls how it gets processed.\n- The `name` key controls what filename it will receive as it is downloaded into the `_data/` directory. So if the `name` is set as `hello`, it'll be saved to `src/_data/hello.json`.\n\n### Gulp fetch downloads the data\n\nOnce your Google Sheet or Docs are set up and entered into `project.config.json`, you can run `gulp fetch` to download the data. You must then run `gulp dev` to load that data into the Nunjucks context. If you are already running gulp dev, be sure to kill the process with Control-c, then run `gulp fetch` and restart `gulp dev` again to get the new data.\n\n### Google Sheets\n\nFor more information about how the Google Sheets processor works, check out the [sheet-to-data library](https://github.com/rdmurphy/sheet-to-data). The example Sheet used in this project is at [Bookstores data](https://docs.google.com/spreadsheets/d/1gDwO-32cgpBDn_0niV0iu6TqQTaRDr4nmSqnT53magY/edit#gid=0).\n\nGoogle Sheets used may potentially require some additional configuration. Each sheet (or tab) in a Google Sheet is converted separately by the kit, and keyed-off in the output object by the _name of the sheet_.\n\nBy default, it treats every sheet in a Google Sheet as being formatted as a `table`. In other words, every _row_ is considered an item, and the _header row_ determines the key of each value in a _column_.\n\nThe Google Sheets processor also supports a `key-value` format as popularized by [`copytext`](https://github.com/nprapps/copytext) ([and its Node.js counterpart](https://github.com/rdmurphy/node-copytext)). This treats everything in the _first column_ as the key, and everything in the _second column_ as the value matched to its key. Every other column is _ignored_.\n\nTo activate the `key-value` format, add `:kv` to the end of a sheet's filename. (For consistency you can also use `:table` to tell the processor to treat a sheet as a `table`, but it is not required due to it being the default.)\n\nIf there are any sheets you want to exclude from being processed, you can do it via two ways: hide them using the native _hide_ mechanism in Google Sheets, or add `:skip` to the end of the sheet name.\n\n### Google Docs\n\nArchieML Google Docs work as documented on the [ArchieML](http://archieml.org/) site. This includes the automatic conversion of links to `\u003ca\u003e` tags! You can use the [Archie Sandbox](http://archieml.org/sandbox.html) to see what the outputted json will look like.\n\n- The Docs example used in this project is at [Books data](https://docs.google.com/document/d/1RgMhjtkXlbbf9uzSzy_xPRKwxcVZIZqVytgM_JoU4E4/edit).\n- See [@newswire/doc-to-archieml](https://www.npmjs.com/package/@newswire/doc-to-archieml) and [ArchieML](http://archieml.org/) for more information on preparing these Google Docs as data.\n\n### Prose macro\n\nThere is a \"prose\" macro that can loop through multiple paragraphs of text that have been created using [freeform arrays in ArchieML](http://archieml.org/#freeform-arrays). To use this feature on a page, you need the following in your page:\n\n```html\n{% from '_macros/prose.njk' import prose %}\n\n{{ prose(filename.array_name) }}\n```\n\n- The first line imports the prose macro. This can near the top of the file after the template extend.\n- The second line goes where you want the paragraphs of text to go. Change \"filename\" to your data file name and  \"array_name\" to the name of your array in your data.\n\nSee the `[example_multigraph]`, `[+example_prose]` and `[+example_image]` arrays in the [Books data](https://docs.google.com/document/d/1RgMhjtkXlbbf9uzSzy_xPRKwxcVZIZqVytgM_JoU4E4/edit) for some examples of how to format the Google Doc.\n\nTo use the \"example_prose\" array, the code would be `{{ prose(library.example_prose) }}`.\n\nIt processes paragraphs, subheads, lists, images (though the image macro might need some work). You can add other elements in `src/_macros/processors.njk`.\n\n## Technical notes\n\nGulp is the task runner and is configured in `gulpfile.js`. Individual tasks live in the `tasks` folder.\n\n- The default `gulp` task runs the `styles`, `lint`, `scripts`, `images`, `nunjucks` and `bake` tasks to create the production files.\n- `gulp dev` runs the default tasks above plus `serve` for the BrowserSync server.\n- To run any specific gulp task use `gulp \u003cname of task\u003e`, e.g. `gulp clean`.\n\nGoogle authentication is handled via the Google Cloud Platform command line interface tool, [`gcloud`](https://cloud.google.com/sdk/gcloud).\n\n### Prettier\n\nIf there are errors with pull requests (or perhaps elsewhere) that suggest \"Forgot to run Prettier?\", then run it:\n\n```bash\nnpm run lint\n```\n\n### Tasks\n\n- `bake.js`: Generates detail pages from a layout and data as noted above.\n- `clean.js`: Deletes the contents of the `docs` directory using [`del`](https://www.npmjs.com/package/del).\n- `clear.js`: Clears out the gulp cache. Useful to reprocess images of the same name stuck in cache. Run `gulp clear` then re-run `gulp`.\n- `copy.js`: Used to copy production-necessary JavaScript files from `node_modules` into `docs/js`.\n- `fetch.js`: Downloads Google Drive files as data as configured in `project.config.json`.\n- `format.js`: Formats various `json`, `html`, and `js` files within the `src` and `data` folders.\n- `images.js`: Optimize images using [`gulp-imagemin`](https://www.npmjs.com/package/gulp-imagemin) and [`imagemin-mozjpeg`](https://www.npmjs.com/package/imagemin-mozjpeg) packages.\n- `lint.js`: Checks syntax of your (optionally ES6) javascript in `/src/js/` using [`gulp-eslint`](https://www.npmjs.com/package/gulp-eslint) -- it's a good idea to have an eslint package installed in your text editor of choice, as well.\n- `nunjucks.js`: Builds out html pages using [`gulp-nunjucks-render`](https://github.com/carlosl/gulp-nunjucks-render) (see notes below).\n- `scripts.js`: Babel/concat/uglify javascript in `/src/js/` using [`gulp-babel`](https://www.npmjs.com/package/gulp-babel), [`gulp-concat`](https://www.npmjs.com/package/gulp-concat) and [`gulp-uglify`](https://www.npmjs.com/package/gulp-uglify).\n- `serve.js`: Spins up a [BrowserSync](https://browsersync.io/docs/gulp) server at `localhost:3000`. Bundled with watch tasks for css/js/template changes.\n- `styles.js`: Processes Sass files from `/src/scss/` into minified css using [`gulp-sass`](https://www.npmjs.com/package/gulp-sass), [`gulp-sourcemaps`](https://www.npmjs.com/package/gulp-sourcemaps), [`gulp-autoprefixer`](https://www.npmjs.com/package/gulp-autoprefixer) and [`gulp-cssnano`](https://www.npmjs.com/package/gulp-cssnano).\n\nMany thanks to [Elbert Wang](https://github.com/elbertwang3) for developing the `bake` and `fetch` tasks, and to [Michael Plunkett](https://github.com/michplunkett) for other awesome updates.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Futdata%2Ficj-project-rig","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Futdata%2Ficj-project-rig","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Futdata%2Ficj-project-rig/lists"}