{"id":14971611,"url":"https://github.com/suhay/exothermicjs","last_synced_at":"2025-10-26T16:31:04.186Z","repository":{"id":30696212,"uuid":"125744694","full_name":"suhay/exothermicjs","owner":"suhay","description":"YAML-based template engine for React","archived":false,"fork":false,"pushed_at":"2023-07-20T00:50:21.000Z","size":141505,"stargazers_count":3,"open_issues_count":10,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-21T22:39:54.209Z","etag":null,"topics":["frontend","hacktoberfest","reactjs","template","template-engine","yaml"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/suhay.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","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-03-18T16:25:20.000Z","updated_at":"2023-02-26T04:56:48.000Z","dependencies_parsed_at":"2024-09-23T09:40:59.823Z","dependency_job_id":null,"html_url":"https://github.com/suhay/exothermicjs","commit_stats":{"total_commits":230,"total_committers":3,"mean_commits":76.66666666666667,"dds":"0.21304347826086956","last_synced_commit":"956001925c74c354c0b83b80f88bf0418aeccdcf"},"previous_names":["suhay/reacty"],"tags_count":51,"template":false,"template_full_name":null,"purl":"pkg:github/suhay/exothermicjs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/suhay%2Fexothermicjs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/suhay%2Fexothermicjs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/suhay%2Fexothermicjs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/suhay%2Fexothermicjs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/suhay","download_url":"https://codeload.github.com/suhay/exothermicjs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/suhay%2Fexothermicjs/sbom","scorecard":{"id":857661,"data":{"date":"2025-08-18","repo":{"name":"github.com/suhay/exothermicjs","commit":"956001925c74c354c0b83b80f88bf0418aeccdcf"},"scorecard":{"version":"v5.2.1-41-g40576783","commit":"40576783fda6698350fcbbeaea760ff827433034"},"score":2,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 0/27 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#packaging"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#security-policy"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#binary-artifacts"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#branch-protection"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#fuzzing"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#pinned-dependencies"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 7 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"25 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-wf5p-g6vw-rhxx","Warn: Project is vulnerable to: GHSA-jr5f-v2jv-69x6","Warn: Project is vulnerable to: GHSA-8hc4-vh64-cxmj","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-ghr5-ch3p-vcr6","Warn: Project is vulnerable to: GHSA-jchw-25xp-jwwc","Warn: Project is vulnerable to: GHSA-cxjh-pqwp-8mfp","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-78xj-cgh5-2h22","Warn: Project is vulnerable to: GHSA-2p57-rm9w-gvfp","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-76c9-3jph-rj3q","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-m6fv-jmcg-4jfg","Warn: Project is vulnerable to: GHSA-76p7-773f-r4q5","Warn: Project is vulnerable to: GHSA-f5x3-32g6-xq36","Warn: Project is vulnerable to: GHSA-52f5-9888-hmc6","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3","Warn: Project is vulnerable to: GHSA-4vvj-4cpr-p986","Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7","Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-24T00:19:48.749Z","repository_id":30696212,"created_at":"2025-08-24T00:19:48.750Z","updated_at":"2025-08-24T00:19:48.750Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280865095,"owners_count":26404443,"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","status":"online","status_checked_at":"2025-10-24T02:00:06.418Z","response_time":73,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["frontend","hacktoberfest","reactjs","template","template-engine","yaml"],"created_at":"2024-09-24T13:45:32.847Z","updated_at":"2025-10-26T16:30:59.377Z","avatar_url":"https://github.com/suhay.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ExothermicJS\n## YAML-based template engine for React\n\n[![https://www.npmjs.com/package/@exothermic/core](https://img.shields.io/npm/v/@exothermic/core.svg)](https://www.npmjs.com/package/@exothermic/core)\n\n---\n\n## YAML-based, what kind of engine?\n\nI wanted to address a couple of issues I started noticing in almost every CMS I used over the years. I wrote a series of [blog articles](https://suhay.dev/blog/what-i-learned-from-15-years-of-content-management-systems-1) to outline what I wanted to achieve, but the TLDR; is that I wanted to have the benefits of using React on the front-end but I got tired of having to bootstrap *every, single* React application the same way. Writing out the same basic components, connecting it up to the same bundlers, and so on when I just wanted to put an idea on a site somewhere.\n\nI also hated that as the project grew, so did the bundle size. With ExothermicJS, the user only downloads the core file. All the page content, images, and layouts are abstracted away.\n\n## Installation\n\nThis is a purely client based library so all you'll need to do is add the core library to an `index.html` file, set `id=\"_exothermic\"` to a binding `\u003cdiv\u003e`, and you're done. Plus a bit of configuration, of course.\n\n```html\n\u003c!doctype html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n  \u003cmeta charset=\"UTF-8\"\u003e\n  \u003ctitle\u003eExothermicJS Page\u003c/title\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n  \u003cdiv id=\"__exothermic\"\u003e\u003c/div\u003e\n  \u003cscript src=\"https://unpkg.com/@exothermic/core@2.0.0/dist/exothermic-core.js\"\u003e\u003c/script\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n## Basic usage\n\n### Folder structure\n\n```\n└── example.com/\n    ├── index.html\n    ├── exothermic.config.json\n    (...)\n    ├── css/\n    │   └── styles.css\n    ├── js/\n    │   └── bootstrap.min.js\n    ├── pages/\n    │   ├── fragments/\n    │   │   └── top-nav.exo\n    │   ├── markdown/\n    │   │   └── page2.md\n    │   ├── about/\n    │   │   ├── contact-us.exo\n    │   │   └── index.exo\n    │   ├── index.exo\n    │   └── page2.exo\n    └── templates/\n         └── base.exo\n```\n\n- `index.html`: ***Required*** - Main entry point for the web browser. Loads the application.\n- `exothermic.config.json`: ***Required*** - Basic configurations for the application ([see below for an example]()).\n- `templates/base.exo`: ***Required*** - The base shared template used by all pages within the application (see below for an example).\n- `pages/`: ***Required-ish*** - This directory is required, but the naming is whatever you'd like as long as it matches the value entered for `\"pagePath\"` in the `exothermic.config.json` file.\n    - `index.exo`: ***Required*** - The main entry page. This file will be used when a user navigates to `https://example.com/`.\n    - `fragments/`: Optional, and only for organizational purposes, a fragment within the application is any part of a page that could be reused on many pages such as top navigation or footer.\n    - `markdown/`: Optional, and only for organizational purposes. It's good to keep your markdown files together, but you don't have to, nor do you have to put them here.\n- `css/`: Optional, directory you can put your static CSS files, can be named whatever you want.\n- `js/`: Optional, directory you can put your static JavaScript files, can be named whatever you want.\n\n---\n\n### `exothermic.config.json`\n\nThis is where the main configuration goes. Since we eliminated server-side rendering, you'll need to hand off a few things to the client before the app is able to load. As of v2.0.0, a basic configuration will look like this:\n\n```json\n{\n  \"pagePath\": \"/pages\",\n  \"plugins\": [\n    {\n      \"resolve\": \"@exothermic/plugin-blog\",\n      \"url\": \"https://unpkg.com/@exothermic/plugin-blog@2.0.0/dist/plugin-blog.js\",\n      \"options\": {\n        \"path\": \"blog\"\n      }\n    }\n  ]\n}\n```\n\n- `pagePath`: ***Required*** - The relative path to the home of all your pages.\n- `plugins`: Optional, but when you want to include more plugins as they become available, this is where you'll tell ExothermicJS about them and any configurations they need.\n    - `resolve`: The name of the plugin.\n    - `url`: Path to where the code is. This can be an external URL or a relative URL if the file is on your webserver.\n    - `options`: This will usually be a collection of values the plugin needs in order to run. They can range from being just about anything. You'll need to consult the individual plugin's  README to determine what is needed.\n  \n---\n\n### `base.exo`\n  ```yaml\n  ---\n  title: '' # Title of the page\n\n  # Meta data objects. A single key value pair will set the key as the value for 'name='\n  # and the value will be used as the value for 'content='.\n  # Multiple key value pairs will follow the key=value pattern\n  meta:\n    - httpEquiv: 'X-UA-Compatible'\n      content: 'IE=edge'\n    - charSet: 'UTF-8'\n    - viewport: 'width=device-width, initial-scale=1, shrink-to-fit=no'\n\n  # meta description of page, content will be used if left blank\n  description: ''\n\n  $main: []\n\n  # Single string will load the value as the script's src.\n  #  - 'https://example.com/script.js'\n  #\n  # Adding 'async' or 'defer' to the scripts will output the attribute\n  #  - 'https://example.com/script.js'\n  #    - async\n  #    - defer\n\n  scripts: []\n\n  headScripts:\n    - src: 'https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/js/bootstrap.bundle.js'\n      crossorigin: 'anonymous'\n\n  links:\n    - rel: \"preconnect\"\n      href: \"https://fonts.googleapis.com\"\n    - rel: \"preconnect\"\n      href: \"https://fonts.gstatic.com\"\n      crossorigin: \"crossorigin\"\n    - 'https://fonts.googleapis.com/css2?family=Noto+Serif+TC\u0026family=Yantramanav:wght@400;500;700\u0026display=swap'\n    # For complex links, the key is used as the attribute name and the value is its value\n    # \u003clink key=\"value\" /\u003e\n    - href: 'https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css' \n      integrity: \"sha384-+0n0xVW2eSR5OomGNYDnhzAbDsOXxcvSN1TPprVMTNDbiYZCxYbOOl7+AMvyTG2x\"\n      crossOrigin: \"anonymous\"\n      rel: \"stylesheet\"\n    - '/css/all.min.css'\n    - '/css/style@2.0.0.css'\n    - rel: 'icon' \n      type: \"image/svg\"\n      href: \"/images/mono.svg\"\n  ```\n\n- `title`: Page title used for SEO.\n- `meta`: Creates `\u003cmeta\u003e` tags that appear in the `\u003chead\u003e`.\n    - A single key-value pair will set the key as the value for 'name=' and the value will be used as the value for 'content='.\n\n      ```yaml\n      meta:\n        - viewport: 'width=device-width, initial-scale=1, shrink-to-fit=no'\n      ```\n\n      Renders as\n\n      ```html\n      \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\"\u003e\n      ```\n\n    - Multiple key value pairs will follow the key=value pattern\n\n      ```yaml\n      - httpEquiv: 'X-UA-Compatible'\n        content: 'IE=edge'\n      ```\n\n      Renders as\n\n      ```html\n      \u003cmeta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"\u003e\n      ```\n\n- `description`: SEO description of the page\n- `$main`: A list of modules displayed in the order they are listed.\n\n  ```yaml\n  $main:\n    - !header\n      content: The greatest site ever\n    - !section\n      id: what-im-doing\n      class: container mt-5 mb-5\n      items:\n        - !fragment\n          class: row\n          items:\n            - !col\n              class: col col-12 mb-5\n              content: |\n                ## What I'm working on\u003cspan\u003e\u0026#8226;\u003c/span\u003e  \n            - !col\n              class: col col-12\n              items:\n                - !get 'fragments/projects'\n  ```\n\n- `scripts`: Creates `\u003cscript\u003e` tags that appear at the bottom of the `\u003cbody\u003e`.\n    - A single string will load the value as the script's `src`.\n\n      ```yaml\n      scripts:\n        - 'https://example.com/script.js'\n      ```\n\n        Renders as\n      \n      ```html\n      \u003cscript src=\"https://example.com/script.js\"\u003e\u003c/script\u003e\n      ```\n\n    - Multiple key value pairs will follow the key=value pattern\n\n      ```yaml\n      scripts:\n        - src: 'https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/js/bootstrap.bundle.js'\n          crossorigin: 'anonymous'\n      ```\n\n        Renders as\n\n      ```html\n      \u003cscript src=\"https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/js/bootstrap.bundle.js\"\n        crossorigin=\"anonymous\"\u003e\u003c/script\u003e\n      ```\n\n- `headScripts`: Like `scripts`, but appear in the `\u003chead\u003e` instead of at the bottom of the `\u003cbody\u003e`.\n- `links`: Creates `\u003clink\u003e` tags that appear in the `\u003chead\u003e`.\n    - A single string will load the value as the link's `href`.\n\n      ```yaml\n      links:\n        - '/css/all.min.css'\n      ```\n\n        Renders as\n\n      ```html\n      \u003clink href=\"/css/all.min.css\" rel=\"stylesheet\" type=\"text/css\"\u003e\n      ```\n\n    - Multiple key value pairs will follow the key=value pattern\n\n      ```yaml\n      links:\n        - rel: 'icon' \n          type: \"image/svg\"\n          href: \"/images/mono.svg\"\n      ```\n\n        Renders as\n\n      ```html\n      \u003clink rel=\"icon\" type=\"image/svg\" href=\"/images/mono.svg\"\u003e\n      ```\n\n---\n\n### `index.exo`\n\n  ```yaml\n  ---\n  title: 'Page title!!'\n  description: 'Beep boop description.'\n  $top: !get 'fragments/header'\n  $bottom: !get 'fragments/footer'\n  $main:\n    - !main\n      items:\n        - !section\n          class: container-fluid\n          id: landing-section\n          content: |\n            Page content!!\n  ```\n\n- All options from `base.exo`. All values changed within a page template will replace the value set on the base with the exception of `headScripts`, those will be combined.\n- `$top`: A `!get` fragment that will appear above the `$main` rendering. This is used to inject content into the page.\n\n  ```yaml\n  $top: !get 'fragments/header'\n  ```\n\n- `$bottom`: A `!get` fragment that will appear below the `$main` rendering. This is used to inject content into the page.\n\n  ```yaml\n  $bottom: !get 'fragments/footer'\n  ```\n\n- `$[variable name]`: Will inject the listed module into a child fragment with the same variable name listed as a part of its `items`.\n\n  ```yaml\n  my-blog-post.exo\n  ---\n  title: 'My page title'\n  $content:\n    !markdown blog/markdown/article-name\n  $top: !get 'fragments/header'\n  $bottom: !get 'fragments/footer'\n  $main:\n    - !get fragments/blog-article\n\n  fragments/blog-article.exo\n  ---\n  items:\n    - !main\n      class: container blog-article\n      items:\n        - !section\n          class: row justify-content-center m-md-5\n          items:\n            - !col\n              class: col col-10 col-lg-7\n              items:\n                - $content # $content from the parent file will end up here during rendering\n  ```\n\n## Default modules\n\n### `!fragment`\n\nAll-purpose module that renders a `\u003cdiv\u003e` by default, but can be any HTML element by including an `as: something` key. Has several shortcut modules that include some out of the box configurations\n\n- `!article`: Renders an `\u003carticle\u003e` with room for a header and content.\n- `!col`: Renders a `\u003cdiv\u003e` with some predefined `col-` classes.\n- `!footer`: Renders a `\u003cfooter\u003e`.\n- `!header`: Renders a `\u003cheader\u003e`.\n- `!main`: Renders a `\u003cmain\u003e`.\n\n```yaml\n---\nitems:\n  - !fragment\n    as: section\n    items:\n      - !col\n        content: 'Stuff and things!'\n      - !fragment\n        content: 'Fragment content'\n```\n\nRenders as:\n\n```html\n\u003csection\u003e\n  \u003cdiv class=\"col\"\u003e\n    \u003cp\u003eStuff and things!\u003c/p\u003e\n  \u003c/div\u003e\n  \u003cdiv\u003e\n    \u003cp\u003eFragment content\u003c/p\u003e\n  \u003c/div\u003e\n\u003c/section\u003e\n```\n\n---\n\n### `!get`\n\nDynamically renders the specified fragment file into that location. Must be a `.exo` file, but can be anywhere relative to the document root. Think portals.\n\n```yaml\ncontent: !get 'fragments/nav-bar.exo'\n```\n\n---\n\n### `!markdown`\n\nDynamically loads and renders a markdown file.\n\n```yaml\ncontent: !markdown 'markdown/page-1-content.md'\n\npage-1-content.md\n---\n# Page title\n\nMy content [with a link](https://example.com/link)\n```\n\nRenders as:\n\n```html\n\u003cdiv\u003e\n  \u003ch1\u003ePage title\u003c/h1\u003e\n  \u003cp\u003eMy content \u003ca href=\"https://example.com/link\"\u003ewith a link\u003c/a\u003e\u003c/p\u003e\n\u003c/div\u003e\n```\n\n---\n\n### `!navbar`\n\n```yaml\n- !navbar\n  items:\n    - \"Home\": '/'\n    - \"All kinds of links\": 'https://example.com'\n    - \"Here's a link\": '#on-page-link'\n```\n\nRenders as:\n\n```html\n\u003cnav aria-label=\"Top navigation\"\u003e\n  \u003cul role=\"menubar\"\u003e\n    \u003cli role=\"none\"\u003e\n      \u003ca href=\"/\" role=\"menuitem\"\u003eHome\u003c/a\u003e\n    \u003c/li\u003e\n    \u003cli role=\"none\"\u003e\n      \u003ca href=\"https://example.com\" role=\"menuitem\"\u003e\n        All kinds of links\n      \u003c/a\u003e\n    \u003c/li\u003e\n    \u003cli role=\"none\"\u003e\n      \u003ca href=\"#on-page-link\" role=\"menuitem\"\u003e\n        Here's a link\n      \u003c/a\u003e\n    \u003c/li\u003e\n  \u003cul\u003e\n\u003c/nav\u003e\n```\n\n---\n\n### `!section`\n\n```yaml\n- !section\n  id: first\n  title: '# First!'\n  class: row\n  items:\n    - !col\n      content: |\n        ## Here is a column\n\n    - !col\n      content: |\n        ## Here is another column\n\n        You can add images and tables in here, too.\n\n        | Tables        | Are           | Cool  |\n        | ------------- |:-------------:| -----:|\n        | col 3 is      | right-aligned | $1600 |\n```\n\nRenders as:\n\n```html\n\u003csection class=”row” id=\"first\"\u003e\n  \u003ch1\u003eFirst!\u003c/h1\u003e\n  \u003cdiv class=\"col\"\u003e\n    \u003ch2\u003eHere is a column\u003c/h2\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"col\"\u003e\n    \u003ch2\u003eHere is another column\u003c/h2\u003e\n    \u003cp\u003eYou can add images and tables in here, too.\u003c/p\u003e\n    \u003ctable\u003e\n      ...\n    \u003c/table\u003e\n  \u003c/div\u003e\n\u003c/section\u003e\n```\n\n## What's next?\n\n\n\n---\n\n## Breaking changes from v1.0 to v2.0\n\n1. SSR is gone, don't ask me to bring it back\n\n    This means you will need to have a base `index.html` file in your document root that looks like this:\n\n    ```html\n    \u003c!doctype html\u003e\n    \u003chtml\u003e\n    \u003chead\u003e\n      \u003cmeta charset=\"UTF-8\"\u003e\n      \u003ctitle\u003eExothermicJS Page\u003c/title\u003e\n    \u003c/head\u003e\n    \u003cbody\u003e\n      \u003cdiv id=\"__exothermic\"\u003e\u003c/div\u003e\n      \u003cscript src=\"https://unpkg.com/@exothermic/core@2.0.0/dist/exothermic-core.js\"\u003e\u003c/script\u003e\n    \u003c/body\u003e\n    \u003c/html\u003e\n    ```\n\n1. We must now ship some configurations client side\n\n    You will need to include an `exothermic.config.json` file in your document root that has this, as a minimum:\n\n    ```json\n    {\n      \"path\": \"/pages\"\n    }\n    ```\n\n    The `path` is the relative path to where all your pages live.\n\n1. To lower confusion, templates are now separated from pages. What this means is you'll need to move your `base.exo` file into its own `/templates` directory off of the document root.\n\n1. Move everything out of `/static` into the document root. I didn't like it anyway.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsuhay%2Fexothermicjs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsuhay%2Fexothermicjs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsuhay%2Fexothermicjs/lists"}