├── .babelrc
├── .editorconfig
├── .eslintrc.js
├── .github
├── CONTRIBUTING.md
└── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── .nvmrc
├── .prettierrc
├── .stylelintrc
├── CHANGELOG.md
├── Dockerfile
├── LICENSE
├── README.md
├── README_APP.md
├── ROADMAP.md
├── config
└── main
│ ├── app.yaml
│ ├── config.yaml
│ └── deployment.yaml
├── data
├── en
│ ├── items
│ │ ├── authoring.json
│ │ ├── before.json
│ │ ├── best_practices.json
│ │ ├── management.json
│ │ ├── security.json
│ │ ├── team.json
│ │ └── testing.json
│ └── project
│ │ ├── introductions.json
│ │ └── translation.json
└── jp
│ └── items
│ └── 利用方法.json
├── diagram-app.png
├── diagram-deployment.png
├── docker-compose.yml
├── gulpfile.babel.js
├── modernizr-config.json
├── package-lock.json
├── package.json
├── src
├── _headers
├── android-chrome-192x192.png
├── apple-touch-icon.png
├── browserconfig.xml
├── favicon-16x16.png
├── favicon-32x32.png
├── favicon.ico
├── humans.txt
├── img
│ └── icons
│ │ └── 1x1.png
├── manifest.json
├── modernizr-custom.min.js
├── mstile-150x150.png
├── precache-config.js
├── robots.txt
├── safari-pinned-tab.svg
├── scripts
│ ├── Utils.js
│ ├── components
│ │ ├── Analytics.js
│ │ ├── Checkboxes.js
│ │ ├── Dropdown.js
│ │ ├── Filter.js
│ │ ├── Init.js
│ │ ├── Notation.js
│ │ ├── ProgressBar.js
│ │ ├── Report.js
│ │ ├── Storage.js
│ │ ├── Tools.js
│ │ └── Ui.js
│ └── main.js
├── service-worker.js
├── sitemap.xml
├── styles
│ ├── base
│ │ ├── _fonts.scss
│ │ ├── _form.scss
│ │ ├── _generic.scss
│ │ ├── _headings.scss
│ │ ├── _icons.scss
│ │ ├── _links.scss
│ │ ├── _media.scss
│ │ ├── _print.scss
│ │ └── _typography.scss
│ ├── components
│ │ ├── _c-button.scss
│ │ ├── _c-checklist.scss
│ │ ├── _c-dropdown.scss
│ │ ├── _c-github.scss
│ │ ├── _c-list.scss
│ │ ├── _c-nav.scss
│ │ ├── _c-notation.scss
│ │ ├── _c-progress.scss
│ │ ├── _c-tags.scss
│ │ ├── _c-tools.scss
│ │ └── _c-top-alert.scss
│ ├── config
│ │ ├── _v-colors.scss
│ │ ├── _v-namespaces.scss
│ │ ├── _v-typography.scss
│ │ └── _variables.scss
│ ├── layout
│ │ ├── _page.scss
│ │ ├── _s-aside.scss
│ │ ├── _s-checklist.scss
│ │ ├── _s-footer.scss
│ │ ├── _s-header.scss
│ │ └── _s-main.scss
│ ├── main.scss
│ └── utilities
│ │ ├── _utilities.scss
│ │ ├── functions
│ │ └── _functions.scss
│ │ └── mixins
│ │ ├── _m-breakpoints.scss
│ │ └── _mixins.scss
└── views
│ ├── base
│ ├── after-scripts.pug
│ ├── before-scripts.pug
│ ├── footer.pug
│ ├── head.pug
│ ├── header.pug
│ ├── layout.pug
│ └── social.pug
│ ├── components
│ ├── c-checklist.pug
│ ├── c-corner.pug
│ ├── c-nav.pug
│ ├── c-new-form.pug
│ ├── c-notation.pug
│ ├── c-progress.pug
│ ├── c-search.pug
│ ├── c-tag-filter.pug
│ ├── c-tools.pug
│ ├── c-top-alert.pug
│ ├── checklist
│ │ ├── checkbox.pug
│ │ ├── class.pug
│ │ ├── dropdown.pug
│ │ ├── label.pug
│ │ └── priority.pug
│ ├── s-section-bottom.pug
│ ├── s-section-top.pug
│ └── svg
│ │ ├── arrow.pug
│ │ ├── bullet.pug
│ │ ├── check.pug
│ │ ├── checkbox.pug
│ │ ├── checked.pug
│ │ ├── code.pug
│ │ ├── collapse.pug
│ │ ├── expand.pug
│ │ ├── eye.pug
│ │ ├── print.pug
│ │ └── reset.pug
│ ├── index-en.pug
│ └── mixins
│ ├── m-checklist-section.pug
│ ├── m-icon.pug
│ └── mixins.pug
├── templates
├── app.yaml
└── deployment.yaml
├── test
├── localstorage.test.js
├── notation.test.js
└── reports.test.js
├── wallaby.js
└── webpack.config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["env"]
3 | }
4 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // https://eslint.org/docs/user-guide/configuring
2 |
3 | module.exports = {
4 | root: true,
5 | parser: 'babel-eslint',
6 | env: {
7 | browser: true,
8 | es6: true,
9 | },
10 | // https://github.com/standard/standard/blob/master/docs/RULES-en.md
11 | extends: [
12 | 'airbnb-base/legacy',
13 | 'plugin:flowtype/recommended',
14 | 'prettier',
15 | 'prettier/flowtype'
16 | ],
17 | plugins: [
18 | 'flowtype',
19 | 'prettier'
20 | ],
21 | // add your custom rules here
22 | 'rules': {
23 | "class-methods-use-this": 0,
24 | // allow debugger during development
25 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
26 |
27 | 'prettier/prettier': ['error', {
28 | 'useTabs': false,
29 | 'printWidth': 80,
30 | 'tabWidth': 2,
31 | 'singleQuote': true,
32 | 'trailingComma': 'all',
33 | 'bracketSpacing': false
34 | }]
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contribute
2 |
3 | ## Introduction
4 |
5 | First, thank you for considering contributing to Cloudformation checklist! It's people like you that make the open source community such a great community! 😊
6 |
7 | We welcome any type of contribution, not only code. You can help with
8 | - **QA**: file bug reports, the more details you can give the better (e.g. screenshots with the console open)
9 | - **Marketing**: writing blog posts, howto's, printing stickers, ...
10 | - **Community**: presenting the project at meetups, organizing a dedicated meetup for the local community, ...
11 | - **Code**: take a look at the [open issues](issues). Even if you can't write code, commenting on them, showing that you care about a given issue matters. It helps us triage them.
12 |
13 | ## Your First Contribution
14 |
15 | Working on your first Pull Request? You can learn how from this *free* series, [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github).
16 |
17 | ## Submitting code
18 |
19 | Any code change should be submitted as a pull request. The description should explain what the code does and give steps to execute it. The pull request should also contain tests.
20 |
21 | ## Code review process
22 |
23 | The bigger the pull request, the longer it will take to review and merge. Try to break down large pull requests in smaller chunks that are easier to review and merge.
24 | It is also always helpful to have some context for your pull request. What was the purpose? Why does it matter to you?
25 |
26 | ## Questions
27 |
28 | If you have any questions, create an [issue](issue) (protip: do a quick search first to see if someone else didn't ask the same question before!).
29 |
30 | ## Credits
31 |
32 | Thanks to **[David Dias](https://github.com/thedaviddias)** for the original Front-End Checklist on which this one is based.
33 |
34 | ### Sponsors
35 |
36 |
37 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
2 | **Fixes**: #
3 |
4 | 🚨 Please review the [guidelines for contributing](CONTRIBUTING.md) to this repository. 🚨
5 | **Please complete these steps and check these boxes (by putting an x inside the brackets) before filing your PR:**
6 |
7 | - [ ] Check the commits' message styles.
8 | - [ ] Check your code additions will fail neither code linting checks nor unit test.
9 |
10 | #### Short description of what this resolves:
11 |
12 |
13 | #### Proposed changes:
14 |
15 | -
16 | -
17 | -
18 |
19 | 👍 Thank you!
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | npm-debug.log*
4 | yarn-debug.log*
5 | yarn-error.log*
6 | test/unit/coverage
7 | test/e2e/reports
8 | selenium-debug.log
9 | dist/
10 | .tmp/
11 |
12 | # Editor directories and files
13 | .idea
14 | .vscode
15 | *.suo
16 | *.ntvs*
17 | *.njsproj
18 | *.sln
19 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | 8.12.0
2 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "flow",
3 | "useTabs": false,
4 | "printWidth": 80,
5 | "tabWidth": 2,
6 | "singleQuote": true,
7 | "trailingComma": "all",
8 | "bracketSpacing": false
9 | }
10 |
--------------------------------------------------------------------------------
/.stylelintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "stylelint-config-standard",
3 | "plugins": [
4 | "stylelint-scss"
5 | ],
6 | "rules": {
7 | "at-rule-no-unknown": null,
8 | "color-named": [
9 | "always-where-possible",
10 | ignore: ["inside-function"]
11 | ],
12 | "max-empty-lines": 4,
13 | "string-quotes": "single",
14 | "color-hex-length": "long",
15 | "declaration-colon-newline-after": null,
16 | "font-family-name-quotes": null,
17 | "number-leading-zero": "never",
18 | "value-list-comma-newline-after": null,
19 | "max-nesting-depth": 3,
20 | "unit-whitelist": ['%', 'px', 'rem', 's', 'deg', 'ms', 'fr', 'pt'],
21 | "no-descending-specificity": null
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeshan/cloudformation-checklist/99cb104f8a61a8aa9b40ccd5a90258678547efcb/CHANGELOG.md
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:8.16.0-slim
2 |
3 | RUN apt-get update && apt-get install -y git && rm -rf /var/cache/apt
4 |
5 | WORKDIR /app
6 |
7 | COPY package-lock.json .
8 | RUN npm install
9 |
10 | COPY package.json ./
11 | RUN npm install --only=dev
12 | RUN npm i -g gulp
13 |
14 | COPY src src
15 | COPY data data
16 | COPY *.js .babelrc modernizr-config.json package.json .stylelintrc ./
17 |
18 | ENTRYPOINT ["npm"]
19 | RUN gulp build
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | CC0 1.0 Universal
2 |
3 | Statement of Purpose
4 |
5 | The laws of most jurisdictions throughout the world automatically confer
6 | exclusive Copyright and Related Rights (defined below) upon the creator and
7 | subsequent owner(s) (each and all, an "owner") of an original work of
8 | authorship and/or a database (each, a "Work").
9 |
10 | Certain owners wish to permanently relinquish those rights to a Work for the
11 | purpose of contributing to a commons of creative, cultural and scientific
12 | works ("Commons") that the public can reliably and without fear of later
13 | claims of infringement build upon, modify, incorporate in other works, reuse
14 | and redistribute as freely as possible in any form whatsoever and for any
15 | purposes, including without limitation commercial purposes. These owners may
16 | contribute to the Commons to promote the ideal of a free culture and the
17 | further production of creative, cultural and scientific works, or to gain
18 | reputation or greater distribution for their Work in part through the use and
19 | efforts of others.
20 |
21 | For these and/or other purposes and motivations, and without any expectation
22 | of additional consideration or compensation, the person associating CC0 with a
23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
25 | and publicly distribute the Work under its terms, with knowledge of his or her
26 | Copyright and Related Rights in the Work and the meaning and intended legal
27 | effect of CC0 on those rights.
28 |
29 | 1. Copyright and Related Rights. A Work made available under CC0 may be
30 | protected by copyright and related or neighboring rights ("Copyright and
31 | Related Rights"). Copyright and Related Rights include, but are not limited
32 | to, the following:
33 |
34 | i. the right to reproduce, adapt, distribute, perform, display, communicate,
35 | and translate a Work;
36 |
37 | ii. moral rights retained by the original author(s) and/or performer(s);
38 |
39 | iii. publicity and privacy rights pertaining to a person's image or likeness
40 | depicted in a Work;
41 |
42 | iv. rights protecting against unfair competition in regards to a Work,
43 | subject to the limitations in paragraph 4(a), below;
44 |
45 | v. rights protecting the extraction, dissemination, use and reuse of data in
46 | a Work;
47 |
48 | vi. database rights (such as those arising under Directive 96/9/EC of the
49 | European Parliament and of the Council of 11 March 1996 on the legal
50 | protection of databases, and under any national implementation thereof,
51 | including any amended or successor version of such directive); and
52 |
53 | vii. other similar, equivalent or corresponding rights throughout the world
54 | based on applicable law or treaty, and any national implementations thereof.
55 |
56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of,
57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
59 | and Related Rights and associated claims and causes of action, whether now
60 | known or unknown (including existing as well as future claims and causes of
61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum
62 | duration provided by applicable law or treaty (including future time
63 | extensions), (iii) in any current or future medium and for any number of
64 | copies, and (iv) for any purpose whatsoever, including without limitation
65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
66 | the Waiver for the benefit of each member of the public at large and to the
67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver
68 | shall not be subject to revocation, rescission, cancellation, termination, or
69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work
70 | by the public as contemplated by Affirmer's express Statement of Purpose.
71 |
72 | 3. Public License Fallback. Should any part of the Waiver for any reason be
73 | judged legally invalid or ineffective under applicable law, then the Waiver
74 | shall be preserved to the maximum extent permitted taking into account
75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
76 | is so judged Affirmer hereby grants to each affected person a royalty-free,
77 | non transferable, non sublicensable, non exclusive, irrevocable and
78 | unconditional license to exercise Affirmer's Copyright and Related Rights in
79 | the Work (i) in all territories worldwide, (ii) for the maximum duration
80 | provided by applicable law or treaty (including future time extensions), (iii)
81 | in any current or future medium and for any number of copies, and (iv) for any
82 | purpose whatsoever, including without limitation commercial, advertising or
83 | promotional purposes (the "License"). The License shall be deemed effective as
84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the
85 | License for any reason be judged legally invalid or ineffective under
86 | applicable law, such partial invalidity or ineffectiveness shall not
87 | invalidate the remainder of the License, and in such case Affirmer hereby
88 | affirms that he or she will not (i) exercise any of his or her remaining
89 | Copyright and Related Rights in the Work or (ii) assert any associated claims
90 | and causes of action with respect to the Work, in either case contrary to
91 | Affirmer's express Statement of Purpose.
92 |
93 | 4. Limitations and Disclaimers.
94 |
95 | a. No trademark or patent rights held by Affirmer are waived, abandoned,
96 | surrendered, licensed or otherwise affected by this document.
97 |
98 | b. Affirmer offers the Work as-is and makes no representations or warranties
99 | of any kind concerning the Work, express, implied, statutory or otherwise,
100 | including without limitation warranties of title, merchantability, fitness
101 | for a particular purpose, non infringement, or the absence of latent or
102 | other defects, accuracy, or the present or absence of errors, whether or not
103 | discoverable, all to the greatest extent permissible under applicable law.
104 |
105 | c. Affirmer disclaims responsibility for clearing rights of other persons
106 | that may apply to the Work or any use thereof, including without limitation
107 | any person's Copyright and Related Rights in the Work. Further, Affirmer
108 | disclaims responsibility for obtaining any necessary consents, permissions
109 | or other rights required for any use of the Work.
110 |
111 | d. Affirmer understands and acknowledges that Creative Commons is not a
112 | party to this document and has no duty or obligation with respect to this
113 | CC0 or use of the Work.
114 |
115 | For more information, please see
116 |
117 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | CloudFormation Checklist
4 |
5 |
6 | The CloudFormation Checklist is a list of all elements you need to have / to test before launching your infra to production.
7 |
8 |
9 | How To Use • Contributing
10 |
11 |
12 | Sister project: Lambda Checklist
13 |
14 | 🎮 Lambda Checklist
15 |
16 |
17 | Inspired by the Front-end Checklist
18 |
19 | 🎮 Front-End Checklist
20 |
21 |
22 |
23 | ## Table of Contents
24 |
25 | See https://cfnchecklist.com
26 |
27 | ---
28 |
29 | ## How to use?
30 |
31 | All items in the **CloudFormation Checklist** are required for the majority of the projects, but some elements can be omitted or are not essential (in the case of an administration web app, you may not need RSS feed for example). We choose to use 3 levels of flexibility:
32 |
33 | * ![Low][low_img] means that the item is **recommended** but can be omitted in some particular situations.
34 | * ![Medium][medium_img] means that the item is **highly recommended** and can eventually be omitted in some really particular cases. Omitting these that engineers may not work at full speed.
35 | * ![High][high_img] means that the item **can't be omitted** by any reason. You may risk security issues in your infra. The testing priority needs to be on these elements first.
36 |
37 | Some resources possess an emoticon to help you understand which type of content / help you may find on the checklist:
38 |
39 | * 📖: documentation or article
40 | * 🛠: online tool / testing tool
41 | * 📹: media or video content
42 |
43 | > You can contribute to the ***CloudFormation Checklist App*** reading the [README_APP file](https://github.com/jeshan/cloudformation-checklist/blob/master/README_APP.md) which explains everything about the project.
44 |
45 | ## CloudFormation Checklist Badge
46 |
47 | If you want to show you are following the rules of the CloudFormation Checklist, put this badge on your README file!
48 |
49 | ➔ [](https://github.com/jeshan/cloudformation-checklist/)
50 |
51 | ```md
52 | [](https://github.com/jeshan/cloudformation-checklist/)
53 | ```
54 |
55 | ## Contributing
56 |
57 | **Open an issue or a pull request to suggest changes or additions.**
58 |
59 | ## Authors
60 |
61 | Original checklist application author:
62 | **[David Dias](https://github.com/thedaviddias)**
63 |
64 | Modified for AWS CloudFormation:
65 | **[Jeshan G. BABOOA](https://github.com/jeshan)**
66 |
67 | ## Infrastructure
68 | The website is a static one deployed on AWS. Contents are stored in Amazon S3 while CloudFront cdn is used to deliver the contents. This is how the stack is:
69 |
70 | 
71 |
72 | This is how the deployment pipeline has been set up:
73 |
74 | 
75 |
76 |
77 | *Images automatically generated with [cfnbuddy](https://www.cfnbuddy.com)*
78 |
79 |
80 | ## License
81 |
82 | [](https://creativecommons.org/publicdomain/zero/1.0/)
83 |
84 | [low_img]: https://front-end-checklist.now.sh/low.svg
85 | [medium_img]: https://front-end-checklist.now.sh/medium.svg
86 | [high_img]: https://front-end-checklist.now.sh/high.svg
87 |
--------------------------------------------------------------------------------
/README_APP.md:
--------------------------------------------------------------------------------
1 | # CloudFormation Checklist App
2 |
3 | ## Table of Contents
4 |
5 | - [Install](#install)
6 | - [Add new translation](#add-new-translation)
7 | - [Contribute](#contribute)
8 | - [License](#license)
9 |
10 |
11 |
12 | ## Install
13 |
14 | ### Docker
15 | To run site locally: `docker-compose up --build start`, then open `http://localhost:3000` in your browser.
16 |
17 | To build site: `docker-compose up --build dist`. Deploy `dist` directory to your web server.
18 |
19 | ### Other
20 |
21 | To install and run, open a terminal and use the following commands:
22 |
23 | ```shell
24 | npm install
25 | npm start or gulp dev
26 | ```
27 | ## Authors
28 |
29 | Original checklist application author:
30 | **[David Dias](https://github.com/thedaviddias)**
31 |
32 | Modified for AWS CloudFormation:
33 | **[Jeshan G. BABOOA](https://github.com/jeshan)**
34 |
35 | ## Contribute
36 |
37 | ## License
38 |
39 | [](https://creativecommons.org/publicdomain/zero/1.0/)
40 |
--------------------------------------------------------------------------------
/ROADMAP.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeshan/cloudformation-checklist/99cb104f8a61a8aa9b40ccd5a90258678547efcb/ROADMAP.md
--------------------------------------------------------------------------------
/config/main/app.yaml:
--------------------------------------------------------------------------------
1 | template_path: app.yaml
2 |
3 | parameters:
4 | DomainName: {{stack_group_config.domain_name}}
5 |
--------------------------------------------------------------------------------
/config/main/config.yaml:
--------------------------------------------------------------------------------
1 | project_code: cloudformation-checklist
2 |
3 | domain_name: cfnchecklist.com
4 | region: us-east-1
5 |
--------------------------------------------------------------------------------
/config/main/deployment.yaml:
--------------------------------------------------------------------------------
1 | template_path: deployment.yaml
2 |
3 | parameters:
4 | Cdn: !stack_output main/app.yaml::DistributionId
5 | DomainName: {{stack_group_config.domain_name}}
6 |
--------------------------------------------------------------------------------
/data/en/items/authoring.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "title": "Essential DevOps tools",
4 | "priority": "Medium",
5 | "description": "Install these to work faster locally",
6 | "tools": [
7 | {
8 | "title": "Typeformation plugin for JetBrains IDEs",
9 | "url": "https://plugins.jetbrains.com/plugin/10653-typeformation"
10 | },
11 | {
12 | "title": "AWS CloudFormation plugin for JetBrains IDEs",
13 | "url": "https://plugins.jetbrains.com/plugin/7371-aws-cloudformation"
14 | },
15 | {
16 | "title": "CloudFormation support for Visual Studio Code",
17 | "url": "https://marketplace.visualstudio.com/items?itemName=aws-scripting-guy.cform"
18 | },
19 | {
20 | "title": "Cloudformation YAML Snippets for VS Code",
21 | "url": "https://marketplace.visualstudio.com/items?itemName=dsteenman.cloudformation-yaml-snippets"
22 | },
23 | {
24 | "title": "Snippets for other IDEs",
25 | "url": "https://github.com/search?q=cloudformation+snippets"
26 | },
27 | {
28 | "title": "cfn-python-lint IDE plugins",
29 | "url": "https://github.com/aws-cloudformation/cfn-python-lint#editor-plugins"
30 | }
31 | ],
32 | "tags": [
33 | "all",
34 | "tools",
35 | "ide",
36 | "medium"
37 | ]
38 | },
39 | {
40 | "title": "Prefer YAML over JSON",
41 | "priority": "Low",
42 | "description": "less verbosity, supports comments",
43 | "tools": [
44 | {
45 | "title": "Use aws-cfn-template-flip to migrate to YAML",
46 | "url": "https://github.com/awslabs/aws-cfn-template-flip"
47 | }
48 | ],
49 | "tags": [
50 | "all",
51 | "template",
52 | "low"
53 | ]
54 | },
55 | {
56 | "title": "Reuse snippets",
57 | "priority": "Medium",
58 | "description": "Reduce the guesswork; CloudFormation snippets available from AWS and on Github",
59 | "documentation": [
60 | {
61 | "title": "Template Snippets",
62 | "url": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/CHAP_TemplateQuickRef.html?shortFooter=true"
63 | },
64 | {
65 | "title": "Cloudformation samples/snippets",
66 | "url": "https://github.com/search?q=cloudformation+samples"
67 | }
68 | ],
69 | "tags": [
70 | "all",
71 | "authoring",
72 | "reuse",
73 | "medium"
74 | ]
75 | },
76 | {
77 | "title": "Organise Your Stacks By Lifecycle and Ownership",
78 | "priority": "High",
79 | "description": "Putting all resources in too few stacks can become cumbersome",
80 | "documentation": [
81 | {
82 | "title": "Explanation",
83 | "url": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/best-practices.html?shortFooter=true#organizingstacks"
84 | }
85 | ],
86 | "tags": [
87 | "all",
88 | "template",
89 | "team",
90 | "high"
91 | ]
92 | },
93 | {
94 | "title": "Use Cross-Stack References to Export Shared Resources",
95 | "priority": "Low",
96 | "description": "Decrease overhead to get a stack running",
97 | "documentation": [
98 | {
99 | "title": "Explanation",
100 | "url": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/best-practices.html?shortFooter=true#cross-stack"
101 | }
102 | ],
103 | "tags": [
104 | "all",
105 | "template",
106 | "low"
107 | ]
108 | },
109 | {
110 | "title": "Make templates reusable",
111 | "priority": "Medium",
112 | "description": "Reuse Templates to Replicate Stacks in Multiple Environments",
113 | "documentation": [
114 | {
115 | "title": "Explanation",
116 | "url": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/best-practices.html?shortFooter=true#reuse"
117 | }
118 | ],
119 | "tags": [
120 | "all",
121 | "template",
122 | "reuse",
123 | "medium"
124 | ]
125 | },
126 | {
127 | "title": "Use AWS-Specific Parameter Types",
128 | "priority": "Low",
129 | "description": "For basic validation and some variable lookups",
130 | "documentation": [
131 | {
132 | "title": "Explanation",
133 | "url": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/best-practices.html?shortFooter=true#parmtypes"
134 | }
135 | ],
136 | "tags": [
137 | "all",
138 | "template",
139 | "low"
140 | ]
141 | },
142 | {
143 | "title": "Use Parameter Constraints",
144 | "priority": "Low",
145 | "description": "So as to clarify what inputs the user should be entering",
146 | "documentation": [
147 | {
148 | "title": "Explanation",
149 | "url": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/best-practices.html?shortFooter=true#parmconstraints"
150 | }
151 | ],
152 | "tags": [
153 | "all",
154 | "template",
155 | "low"
156 | ]
157 | },
158 | {
159 | "title": "Use AWS::CloudFormation::Init to Deploy Software Applications on Amazon EC2 Instances",
160 | "priority": "Medium",
161 | "description": "To make it declarative instead of procedural",
162 | "documentation": [
163 | {
164 | "title": "Explanation",
165 | "url": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/best-practices.html?shortFooter=true#cfninit"
166 | }
167 | ],
168 | "tags": [
169 | "all",
170 | "template",
171 | "ec2",
172 | "medium"
173 | ]
174 | },
175 | {
176 | "title": "Experiment with the console first, then generate the templates/snippets",
177 | "priority": "Medium",
178 | "description": "To reduce the guesswork on how to get the resource definitions right, have a tool generate it accurately",
179 | "tools": [
180 | {
181 | "title": "AWS Console Recorder (Records actions made in the AWS Management Console and outputs the equivalent CLI/SDK commands and CloudFormation/Terraform templates in your browser)",
182 | "url": "https://github.com/iann0036/AWSConsoleRecorder"
183 | },
184 | {
185 | "title": "Former2 (Generate CloudFormation / Terraform / Troposphere templates from your existing AWS resources in your browser)",
186 | "url": "https://former2.com"
187 | }
188 | ],
189 | "tags": [
190 | "all",
191 | "code generator",
192 | "medium"
193 | ]
194 | },
195 | {
196 | "title": "Check resource lifecycle policies",
197 | "priority": "High",
198 | "description": "Be aware if/when your resources will get replaced by CFN to avoid surprises",
199 | "documentation": [
200 | {
201 | "title": "AWS Resource and Property Types Reference",
202 | "url": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html?shortFooter=true"
203 | }
204 | ],
205 | "tags": [
206 | "all",
207 | "docs",
208 | "high"
209 | ]
210 | },
211 | {
212 | "title": "Use custom resources to automate more of your infra",
213 | "priority": "Low",
214 | "description": "because AWS may not cover everything under CFN yet",
215 | "documentation": [
216 | {
217 | "title": "Docs",
218 | "url": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html?shortFooter=true"
219 | }
220 | ],
221 | "tags": [
222 | "all",
223 | "template",
224 | "low"
225 | ]
226 | },
227 | {
228 | "title": "Use macros",
229 | "priority": "Medium",
230 | "description": "to reduce duplication, custom lookups, or any arbitrary code to transform template, etc",
231 | "documentation": [
232 | {
233 | "title": "Docs",
234 | "url": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-macros.html?shortFooter=true"
235 | }
236 | ],
237 | "tags": [
238 | "all",
239 | "template",
240 | "medium"
241 | ]
242 | }
243 | ]
244 |
--------------------------------------------------------------------------------
/data/en/items/before.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "title": "Reuse templates",
4 | "priority": "High",
5 | "description": "Don't reinvent the wheel; check these tools for vetted open-source templates",
6 | "tools": [
7 | {
8 | "title": "widdix/aws-cf-templates",
9 | "url": "https://github.com/widdix/aws-cf-templates"
10 | },
11 | {
12 | "title": "awslabs/aws-cloudformation-templates",
13 | "url": "https://github.com/awslabs/aws-cloudformation-templates"
14 | },
15 | {
16 | "title": "stelligent/cloudformation_templates",
17 | "url": "https://github.com/stelligent/cloudformation_templates"
18 | },
19 | {
20 | "title": "AWS Quick Starts",
21 | "url": "https://aws.amazon.com/quickstart"
22 | },
23 | {
24 | "title": "Other templates on Github",
25 | "url": "https://github.com/search?q=cloudformation+template"
26 | }
27 | ],
28 | "tags": [
29 | "all",
30 | "before starting",
31 | "github",
32 | "reuse",
33 | "community",
34 | "high"
35 | ]
36 | }
37 | ]
38 |
--------------------------------------------------------------------------------
/data/en/items/best_practices.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "title": "High availability practices",
4 | "priority": "Medium",
5 | "description": "",
6 | "documentation": [
7 | {
8 | "title": "Link",
9 | "url": "https://aws-quickstart.github.io/best-practices.html#ha"
10 | }
11 | ],
12 | "tags": [
13 | "all",
14 | "medium"
15 | ]
16 | },
17 | {
18 | "title": "Security practices",
19 | "priority": "High",
20 | "description": "",
21 | "documentation": [
22 | {
23 | "title": "Link",
24 | "url": "https://aws-quickstart.github.io/best-practices.html#security"
25 | }
26 | ],
27 | "tags": [
28 | "all",
29 | "security",
30 | "high"
31 | ]
32 | },
33 | {
34 | "title": "Portability practices",
35 | "priority": "Low",
36 | "description": "",
37 | "documentation": [
38 | {
39 | "title": "Link",
40 | "url": "https://aws-quickstart.github.io/best-practices.html#port"
41 | }
42 | ],
43 | "tags": [
44 | "all",
45 | "low"
46 | ]
47 | },
48 | {
49 | "title": "Managed Services practices",
50 | "priority": "Low",
51 | "description": "Some managed services that you should be using",
52 | "documentation": [
53 | {
54 | "title": "Link",
55 | "url": "https://aws-quickstart.github.io/best-practices.html#managed"
56 | }
57 | ],
58 | "tags": [
59 | "all",
60 | "low"
61 | ]
62 | },
63 | {
64 | "title": "Custom Resources practices",
65 | "priority": "Medium",
66 | "description": "",
67 | "documentation": [
68 | {
69 | "title": "Link",
70 | "url": "https://aws-quickstart.github.io/best-practices.html#custom"
71 | }
72 | ],
73 | "tags": [
74 | "all",
75 | "custom resources",
76 | "medium"
77 | ]
78 | },
79 | {
80 | "title": "Linux practices",
81 | "priority": "Medium",
82 | "description": "",
83 | "documentation": [
84 | {
85 | "title": "Link",
86 | "url": "https://aws-quickstart.github.io/best-practices.html#linux"
87 | }
88 | ],
89 | "tags": [
90 | "all",
91 | "ec2",
92 | "medium"
93 | ]
94 | },
95 | {
96 | "title": "Windows practices",
97 | "priority": "Medium",
98 | "description": "",
99 | "documentation": [
100 | {
101 | "title": "Link",
102 | "url": "https://aws-quickstart.github.io/best-practices.html#windows"
103 | }
104 | ],
105 | "tags": [
106 | "all",
107 | "ec2",
108 | "medium"
109 | ]
110 | },
111 | {
112 | "title": "All platforms practices",
113 | "priority": "Low",
114 | "description": "",
115 | "documentation": [
116 | {
117 | "title": "Link",
118 | "url": "https://aws-quickstart.github.io/best-practices.html#all-plat"
119 | }
120 | ],
121 | "tags": [
122 | "all",
123 | "all platforms",
124 | "low"
125 | ]
126 | },
127 | {
128 | "title": "Template formatting practices",
129 | "priority": "Low",
130 | "description": "",
131 | "documentation": [
132 | {
133 | "title": "Link",
134 | "url": "https://aws-quickstart.github.io/best-practices.html#formatting"
135 | }
136 | ],
137 | "tags": [
138 | "all",
139 | "template",
140 | "low"
141 | ]
142 | },
143 | {
144 | "title": "Other practices (community)",
145 | "priority": "Low",
146 | "description": "Other practices that the community has come up with",
147 | "documentation": [
148 | {
149 | "title": "alexgibs/cfnstyle",
150 | "url": "https://github.com/alexgibs/cfnstyle"
151 | },
152 | {
153 | "title": "toddm92/aws (Wiki: CloudFormation Best Practices)",
154 | "url": "https://github.com/toddm92/aws/wiki/CloudFormation-Best-Practices"
155 | }
156 | ],
157 | "tags": [
158 | "all",
159 | "community",
160 | "low"
161 | ]
162 | }
163 | ]
164 |
--------------------------------------------------------------------------------
/data/en/items/management.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "title": "Manage All Stack Resources Through AWS CloudFormation",
4 | "priority": "High",
5 | "description": "Doing so can create a mismatch between your stack's template and the current state of your stack resources, which can cause errors if you update or delete the stack",
6 | "documentation": [
7 | {
8 | "title": "Reference",
9 | "url": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/best-practices.html?shortFooter=true#donttouch"
10 | }
11 | ],
12 | "tags": [
13 | "all",
14 | "management",
15 | "high"
16 | ]
17 | },
18 | {
19 | "title": "Create Change Sets Before Updating Your Stacks",
20 | "priority": "Low",
21 | "description": "See how proposed changes might impact your resources to avoid accidents",
22 | "documentation": [
23 | {
24 | "title": "Explanation",
25 | "url": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/best-practices.html?shortFooter=true#cfn-best-practices-changesets"
26 | }
27 | ],
28 | "tags": [
29 | "all",
30 | "management",
31 | "low"
32 | ]
33 | },
34 | {
35 | "title": "Use Stack Policies",
36 | "priority": "Medium",
37 | "description": "protect critical stack resources from unintentional updates",
38 | "documentation": [
39 | {
40 | "title": "Explanation",
41 | "url": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/best-practices.html?shortFooter=true#stackpolicy"
42 | }
43 | ],
44 | "tags": [
45 | "all",
46 | "management",
47 | "medium"
48 | ]
49 | },
50 | {
51 | "title": "Use AWS CloudTrail to Log AWS CloudFormation Calls",
52 | "priority": "Low",
53 | "description": "To track api calls for auditing",
54 | "documentation": [
55 | {
56 | "title": "Explanation",
57 | "url": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/best-practices.html?shortFooter=true#cloudtrail"
58 | }
59 | ],
60 | "tags": [
61 | "all",
62 | "management",
63 | "low"
64 | ]
65 | },
66 | {
67 | "title": "Use a CFN launcher like Sceptre",
68 | "priority": "Medium",
69 | "description": "Helps manage templates at scale with your multiple accounts and regions. Check docs for more useful features",
70 | "documentation": [
71 | {
72 | "title": "Sceptre docs",
73 | "url": "https://sceptre.cloudreach.com/latest/index.html"
74 | }
75 | ],
76 | "tags": [
77 | "all",
78 | "tools",
79 | "management",
80 | "medium"
81 | ]
82 | },
83 | {
84 | "title": "Automate drift detection",
85 | "priority": "Low",
86 | "description": "Important to catch unmanaged changes made outside of CloudFormation",
87 | "documentation": [
88 | {
89 | "title": "Detecting Unmanaged Configuration Changes to Stacks and Resources",
90 | "url": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-stack-drift.html?shortFooter=true"
91 | },
92 | {
93 | "title": "Automate drift detection with AWS Config",
94 | "url": "https://docs.aws.amazon.com/config/latest/developerguide/cloudformation-stack-drift-detection-check.html?shortFooter=true"
95 | }
96 | ],
97 | "tags": [
98 | "all",
99 | "management",
100 | "automation",
101 | "low"
102 | ]
103 | }
104 | ]
105 |
--------------------------------------------------------------------------------
/data/en/items/security.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "title": "Restrict IAM permissions",
4 | "priority": "High",
5 | "description": "Grant users only the permissions they need to work with CloudFormation",
6 | "documentation": [
7 | {
8 | "title": "Use IAM to Control Access",
9 | "url": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/best-practices.html?shortFooter=true#use-iam-to-control-access"
10 | }
11 | ],
12 | "tags": [
13 | "all",
14 | "security",
15 | "team",
16 | "management",
17 | "high"
18 | ]
19 | },
20 | {
21 | "title": "Do not embed credentials",
22 | "priority": "High",
23 | "description": "Use input parameters instead",
24 | "documentation": [
25 | {
26 | "title": "Do Not Embed Credentials in Your Templates",
27 | "url": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/best-practices.html?shortFooter=true#creds"
28 | }
29 | ],
30 | "tags": [
31 | "all",
32 | "security",
33 | "high"
34 | ]
35 | },
36 | {
37 | "title": "Statically analyse your templates with cfn_nag",
38 | "priority": "Medium",
39 | "description": "45+ rules to catch potential insecure infra and misconfiguration",
40 | "tools": [
41 | {
42 | "title": "stelligent/cfn_nag",
43 | "url": "https://github.com/stelligent/cfn_nag"
44 | },
45 | {
46 | "title": "List of rules",
47 | "url": "https://github.com/stelligent/cfn_nag/tree/master/lib/cfn-nag/custom_rules"
48 | }
49 | ],
50 | "tags": [
51 | "all",
52 | "tools",
53 | "security",
54 | "medium"
55 | ]
56 | }
57 | ]
58 |
--------------------------------------------------------------------------------
/data/en/items/team.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "title": "Use Code Reviews and Revision Controls to Manage Your Templates",
4 | "priority": "High",
5 | "description": "Share and ask feedback from your team",
6 | "documentation": [
7 | {
8 | "title": "Explanation",
9 | "url": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/best-practices.html?shortFooter=true#code"
10 | }
11 | ],
12 | "tags": [
13 | "all",
14 | "team",
15 | "high"
16 | ]
17 | },
18 | {
19 | "title": "Share this checklist",
20 | "priority": "Medium",
21 | "description": "Ask each team member to always have this template open",
22 | "tools": [
23 | {
24 | "title": "CloudFormation checklist",
25 | "url": "https://cfnchecklist.com"
26 | }
27 | ],
28 | "tags": [
29 | "all",
30 | "team",
31 | "medium"
32 | ]
33 | }
34 | ]
35 |
--------------------------------------------------------------------------------
/data/en/items/testing.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "title": "Verify Quotas for All Resource Types",
4 | "priority": "Low",
5 | "description": "To avoid hitting AWS api limits during CFN deployments",
6 | "documentation": [
7 | {
8 | "title": "Explanation",
9 | "url": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/best-practices.html?shortFooter=true#limits"
10 | }
11 | ],
12 | "tools": [
13 | {
14 | "title": "AWS Service Quotas",
15 | "url": "https://console.aws.amazon.com/servicequotas/home"
16 | }
17 | ],
18 | "tags": [
19 | "all",
20 | "testing",
21 | "low"
22 | ]
23 | },
24 | {
25 | "title": "Validate Templates Before Using Them",
26 | "priority": "Low",
27 | "description": "save time by catching syntax and semantic errors",
28 | "documentation": [
29 | {
30 | "title": "Explanation",
31 | "url": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/best-practices.html?shortFooter=true#validate"
32 | }
33 | ],
34 | "tags": [
35 | "all",
36 | "testing",
37 | "low"
38 | ]
39 | },
40 | {
41 | "title": "Lint your templates",
42 | "priority": "Low",
43 | "description": "To quickly catch typos, fast validations, if you're following certain best practices, etc",
44 | "tools": [
45 | {
46 | "title": "cfn-python-lint",
47 | "url": "https://github.com/aws-cloudformation/cfn-python-lint"
48 | }
49 | ],
50 | "tags": [
51 | "all",
52 | "testing",
53 | "low"
54 | ]
55 | },
56 | {
57 | "title": "Test your templates with TaskCat in your relevant regions",
58 | "priority": "Low",
59 | "description": "TaskCat deploys your AWS CloudFormation template in multiple AWS Regions and generates a report with a pass/fail grade for each region",
60 | "documentation": [
61 | {
62 | "title": "Automated testing with TaskCat",
63 | "url": "https://aws-quickstart.github.io/auto-testing.html"
64 | }
65 | ],
66 | "tags": [
67 | "all",
68 | "testing",
69 | "low"
70 | ]
71 | }
72 | ]
73 |
--------------------------------------------------------------------------------
/data/en/project/introductions.json:
--------------------------------------------------------------------------------
1 | [{
2 | "head": {
3 | "introduction": ""
4 | },
5 | "html": {
6 | "introduction": ""
7 | }
8 | }]
9 |
--------------------------------------------------------------------------------
/data/en/project/translation.json:
--------------------------------------------------------------------------------
1 | {
2 | "SITE_NAME": "The CloudFormation Checklist",
3 | "INDEX_TITLE": "✨ Your best cloud checklist Tool ✨",
4 | "URL_WEBSITE": "https://cfnchecklist.com",
5 | "SITE_TAGLINE": "🗂 The CloudFormation Checklist Application is perfect for meticulous AWS DevOps engineers!",
6 | "SITE_DESCRIPTION": "🗂 The CloudFormation Checklist Application is perfect for meticulous AWS DevOps engineers! Follow the rules and deliver the best of your work in a generated report!",
7 | "SITE_LANGUAGE": "en",
8 | "SITE_DIRECTION": "ltr",
9 | "URL_GITHUB_ROOT": "https://github.com/jeshan/cloudformation-checklist",
10 | "URL_GITHUB_REPO": "https://github.com/jeshan/cloudformation-checklist/tree/gh-pages",
11 | "HIGH_CHECKED": "✓ high priority",
12 | "MEDIUM_CHECKED": "✓ medium priority",
13 | "LOW_CHECKED": "✓ low priority",
14 | "PERCENTAGE_CHECKED": "items are ✓",
15 | "SECTION_DOCUMENTATION": "Documentation",
16 | "SECTION_TOOL": "Tools",
17 | "SECTION_VIDEO": "Videos",
18 | "SECTION_TAG": "Filter by tags",
19 | "alert": {
20 | "JAVASCRIPT_DESACTIVATE": "Your JavaScript seems to be deactivated. Please enable your JavaScript to use all features of the CloudFormation Checklist."
21 | },
22 | "form": {
23 | "LABEL_PROJECT_NAME": "Project Name",
24 | "TITLE_PROJECT_NAME": "Type the name of your project",
25 | "LABEL_PAGE_TITLE": "Page title or URL",
26 | "TITLE_PAGE_TITLE": "Type the name of your page or URL",
27 | "LABEL_DEVELOPER_NAME": "Developer's name or team",
28 | "TITLE_DEVELOPER_NAME": "Type your name or the name of your team",
29 | "LABEL_SEARCH": "Search",
30 | "BUTTON_START_NEW": "Start new checklist",
31 | "BUTTON_GENERATE_PRINT": "Generate report"
32 | },
33 | "social": {
34 | "TWEET": "Tweet",
35 | "TWITTER_MSG": "Check the ✨ CloudFormation Checklist Application ✨ for meticulous AWS DevOps engineers! Use it on your daily workflow and generate reports 📑!",
36 | "TWITTER_VIA": "jeshan25",
37 | "TWITTER_HASHTAGS": "cloudformation",
38 | "STAR": "Star",
39 | "GITHUB_STAR_MSG": "Star jeshan/cloudformation-checklist on GitHub"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/data/jp/items/利用方法.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "title": "Doctype",
4 | "priority": "High",
5 | "description": "The Doctype is HTML5 and is at the top of all your HTML pages.",
6 | "code": "https://gist.github.com/thedaviddias/bccee9f4dfa728830cf38bb83838d2d3.js",
7 | "documentation": [
8 | {
9 | "title": "Determining the character encoding - HTML5 W3C",
10 | "url": "https://www.w3.org/TR/html5/syntax.html#determining-the-character-encoding"
11 | }
12 | ],
13 | "tags": ["all", "Meta tag"]
14 | }
15 | ]
16 |
--------------------------------------------------------------------------------
/diagram-app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeshan/cloudformation-checklist/99cb104f8a61a8aa9b40ccd5a90258678547efcb/diagram-app.png
--------------------------------------------------------------------------------
/diagram-deployment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeshan/cloudformation-checklist/99cb104f8a61a8aa9b40ccd5a90258678547efcb/diagram-deployment.png
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.4'
2 |
3 | services:
4 | start:
5 | command: ['start']
6 | ports:
7 | - 3000:3000
8 | - 3001:3001
9 | build:
10 | context: .
11 | volumes:
12 | - ./data/en/items:/data/en/items
13 | - ./data/en/project:/data/en/project
14 | - ./src:/src
15 |
16 | dist:
17 | entrypoint: cp -r /app/dist /
18 | build:
19 | context: .
20 | volumes:
21 | - ./dist:/dist
22 |
--------------------------------------------------------------------------------
/modernizr-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "minify": true,
3 | "options": [
4 | "domPrefixes",
5 | "prefixes",
6 | "mq",
7 | "prefixedCSSValue",
8 | "testStyles",
9 | "setClasses"
10 | ],
11 | "feature-detects": [
12 | "test/history",
13 | "test/css/flexbox",
14 | "test/workers/webworkers"
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cloudformation-checklist",
3 | "version": "0.0.1",
4 | "description": "The checklist for meticulous AWS DevOps engineers",
5 | "scripts": {
6 | "start": "gulp dev",
7 | "build": "gulp build",
8 | "test": "gulp test",
9 | "eslint-check": "eslint --print-config .eslintrc.js | eslint-config-prettier-check"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git+https://jeshan@github.com/jeshan/cloudformation-checklist.git"
14 | },
15 | "author": "Jeshan G. Babooa (j@jeshan.co)",
16 | "license": "MIT",
17 | "bugs": {
18 | "url": "https://github.com/jeshan/cloudformation-checklist/issues"
19 | },
20 | "homepage": "https://github.com/jeshan/cloudformation-checklist#readme",
21 | "devDependencies": {
22 | "babel-cli": "^6.26.0",
23 | "babel-eslint": "^9.0.0",
24 | "babel-loader": "^7.1.4",
25 | "babel-polyfill": "^6.26.0",
26 | "babel-preset-env": "^1.6.1",
27 | "babel-register": "^6.26.0",
28 | "browser-sync": "^2.23.6",
29 | "chai": "^4.1.2",
30 | "critical": "^1.1.0",
31 | "del": "4.1.1",
32 | "eslint-config-airbnb-base": "^13.0.0",
33 | "eslint-config-prettier": "^3.0.0",
34 | "eslint-plugin-flowtype": "^2.46.1",
35 | "eslint-plugin-import": "^2.9.0",
36 | "eslint-plugin-prettier": "^2.6.0",
37 | "flow-bin": "^0.77.0",
38 | "gulp": "^3.9.1",
39 | "gulp-autoprefixer": "^6.0.0",
40 | "gulp-cached": "^1.1.1",
41 | "gulp-cdnizer": "^2.0.0",
42 | "gulp-changed": "^3.2.0",
43 | "gulp-cssnano": "^2.1.2",
44 | "gulp-data": "^1.3.1",
45 | "gulp-eslint": "^5.0.0",
46 | "gulp-group-css-media-queries": "^1.2.2",
47 | "gulp-html-replace": "^1.6.2",
48 | "gulp-htmlmin": "^5.0.0",
49 | "gulp-if": "^2.0.2",
50 | "gulp-imagemin": "^4.1.0",
51 | "gulp-istanbul": "^1.1.3",
52 | "gulp-json-concat": "^0.1.1",
53 | "gulp-mocha": "^6.0.0",
54 | "gulp-newer": "^1.4.0",
55 | "gulp-plumber": "^1.2.0",
56 | "gulp-pug": "^4.0.1",
57 | "gulp-rename": "^1.2.2",
58 | "gulp-sass": "^4.0.1",
59 | "gulp-sourcemaps": "^2.6.4",
60 | "gulp-stylelint": "^7.0.0",
61 | "gulp-util": "^3.0.8",
62 | "gulp-webpack": "^1.5.0",
63 | "html-webpack-plugin": "^3.0.0",
64 | "imagemin-webp": "^4.1.0",
65 | "jsdom": "^12.0.0",
66 | "jsdom-global": "3.0.2",
67 | "modernizr": "^3.6.0",
68 | "postscribe": "^2.0.8",
69 | "prettier": "^1.11.1",
70 | "run-sequence": "^2.2.1",
71 | "sinon": "^6.1.3",
72 | "stylelint": "^9.1.1",
73 | "stylelint-config-standard": "^18.2.0",
74 | "stylelint-scss": "^3.1.3",
75 | "uglifyjs-webpack-plugin": "^2.0.0",
76 | "url-loader": "^1.0.1",
77 | "webpack": "^4.16.1",
78 | "webpack-stream": "^5.0.0",
79 | "yargs": "^12.0.1"
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/_headers:
--------------------------------------------------------------------------------
1 | /*
2 | X-Frame-Options: DENY
3 | X-XSS-Protection: 1; mode=block
4 | # Prevent browsers from incorrectly detecting non-scripts as scripts
5 | X-Content-Type-Options: nosniff
6 | # Don't load any resource type not explicitly enabled
7 | # Disable plugins like Flash or Silverlight
8 | # Load images, scripts, stylesheets and fonts from self
9 | # Send reports to report-uri.io
10 | # Content-Security-Policy: default-src 'self' cfnchecklist.com; object-src 'none'; img-src https: app.codesponsor.io www.google.com; script-src https: www.google-analytics.com ajax.googleapis.com platform.twitter.com buttons.github.io; style-src https: ; font-src https: ; report-uri https://cfnchecklist.report-uri.io/r/default/csp/enforce;
11 |
--------------------------------------------------------------------------------
/src/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeshan/cloudformation-checklist/99cb104f8a61a8aa9b40ccd5a90258678547efcb/src/android-chrome-192x192.png
--------------------------------------------------------------------------------
/src/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeshan/cloudformation-checklist/99cb104f8a61a8aa9b40ccd5a90258678547efcb/src/apple-touch-icon.png
--------------------------------------------------------------------------------
/src/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #da532c
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeshan/cloudformation-checklist/99cb104f8a61a8aa9b40ccd5a90258678547efcb/src/favicon-16x16.png
--------------------------------------------------------------------------------
/src/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeshan/cloudformation-checklist/99cb104f8a61a8aa9b40ccd5a90258678547efcb/src/favicon-32x32.png
--------------------------------------------------------------------------------
/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeshan/cloudformation-checklist/99cb104f8a61a8aa9b40ccd5a90258678547efcb/src/favicon.ico
--------------------------------------------------------------------------------
/src/humans.txt:
--------------------------------------------------------------------------------
1 | # humanstxt.org/
2 | # The humans responsible & technology colophon
3 |
4 | # TEAM
5 |
6 | Jeshan G. BABOOA -- Cloudformation Nerd -- @jeshan25
7 |
8 | # THANKS
9 |
10 |
11 |
12 | # TECHNOLOGY COLOPHON
13 |
14 | CSS3, HTML5, Pug, Git, ES6, Webpack, Gulp, Modernizr, Normalize.css
15 |
--------------------------------------------------------------------------------
/src/img/icons/1x1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeshan/cloudformation-checklist/99cb104f8a61a8aa9b40ccd5a90258678547efcb/src/img/icons/1x1.png
--------------------------------------------------------------------------------
/src/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "CFN Checklist",
3 | "name": "CloudFormation Checklist",
4 | "start_url": "http://cfnchecklist.com/?utm_source=homescreen",
5 | "icons": [
6 | {
7 | "src": "/android-chrome-192x192.png",
8 | "sizes": "192x192",
9 | "type": "image/png"
10 | }
11 | ],
12 | "theme_color": "#ffffff",
13 | "background_color": "#ffffff",
14 | "display": "standalone"
15 | }
16 |
--------------------------------------------------------------------------------
/src/modernizr-custom.min.js:
--------------------------------------------------------------------------------
1 | /*! modernizr 3.6.0 (Custom Build) | MIT *
2 | * https://modernizr.com/download/?-flexbox-history-webworkers-domprefixes-mq-prefixedcssvalue-prefixes-setclasses-teststyles !*/
3 | !function(e,n,t){function r(e,n){return typeof e===n}function o(){var e,n,t,o,i,s,a;for(var l in C)if(C.hasOwnProperty(l)){if(e=[],n=C[l],n.name&&(e.push(n.name.toLowerCase()),n.options&&n.options.aliases&&n.options.aliases.length))for(t=0;td;d++)if(v=e[d],y=N.style[v],u(v,"-")&&(v=p(v)),N.style[v]!==t){if(i||r(o,"undefined"))return a(),"pfx"==n?v:!0;try{N.style[v]=o}catch(g){}if(N.style[v]!=y)return a(),"pfx"==n?v:!0}return a(),!1}function v(e,n){return function(){return e.apply(n,arguments)}}function y(e,n,t){var o;for(var i in e)if(e[i]in n)return t===!1?e[i]:(o=n[e[i]],r(o,"function")?v(o,t||n):o);return!1}function h(e,n,t,o,i){var s=e.charAt(0).toUpperCase()+e.slice(1),a=(e+" "+k.join(s+" ")+s).split(" ");return r(n,"string")||r(n,"undefined")?m(a,n,o,i):(a=(e+" "+P.join(s+" ")+s).split(" "),y(a,n,t))}function g(e,n,r){return h(e,t,t,n,r)}var C=[],S={_version:"3.6.0",_config:{classPrefix:"",enableClasses:!0,enableJSClass:!0,usePrefixes:!0},_q:[],on:function(e,n){var t=this;setTimeout(function(){n(t[e])},0)},addTest:function(e,n,t){C.push({name:e,fn:n,options:t})},addAsyncTest:function(e){C.push({name:null,fn:e})}},Modernizr=function(){};Modernizr.prototype=S,Modernizr=new Modernizr;var x=[],w=n.documentElement,_="svg"===w.nodeName.toLowerCase(),b="Moz O ms Webkit",P=S._config.usePrefixes?b.toLowerCase().split(" "):[];S._domPrefixes=P;var z=S._config.usePrefixes?" -webkit- -moz- -o- -ms- ".split(" "):["",""];S._prefixes=z;var E=function(){var n=e.matchMedia||e.msMatchMedia;return n?function(e){var t=n(e);return t&&t.matches||!1}:function(n){var t=!1;return l("@media "+n+" { #modernizr { position: absolute; } }",function(n){t="absolute"==(e.getComputedStyle?e.getComputedStyle(n,null):n.currentStyle).position}),t}}();S.mq=E;var T=function(e,n){var t=!1,r=s("div"),o=r.style;if(e in o){var i=P.length;for(o[e]=n,t=o[e];i--&&!t;)o[e]="-"+P[i]+"-"+n,t=o[e]}return""===t&&(t=!1),t};S.prefixedCSSValue=T;S.testStyles=l;Modernizr.addTest("history",function(){var n=navigator.userAgent;return-1===n.indexOf("Android 2.")&&-1===n.indexOf("Android 4.0")||-1===n.indexOf("Mobile Safari")||-1!==n.indexOf("Chrome")||-1!==n.indexOf("Windows Phone")||"file:"===location.protocol?e.history&&"pushState"in e.history:!1});var k=S._config.usePrefixes?b.split(" "):[];S._cssomPrefixes=k;var A={elem:s("modernizr")};Modernizr._q.push(function(){delete A.elem});var N={style:A.elem.style};Modernizr._q.unshift(function(){delete N.style}),S.testAllProps=h,S.testAllProps=g,Modernizr.addTest("flexbox",g("flexBasis","1px",!0)),Modernizr.addTest("webworkers","Worker"in e),o(),i(x),delete S.addTest,delete S.addAsyncTest;for(var O=0;O
2 |
4 |
7 |
8 | Created by potrace 1.11, written by Peter Selinger 2001-2013
9 |
10 |
12 |
16 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/scripts/Utils.js:
--------------------------------------------------------------------------------
1 | let instance = null;
2 |
3 | class Utils {
4 | constructor() {
5 | if (!instance) {
6 | instance = this;
7 | }
8 |
9 | return instance;
10 | }
11 |
12 | variableList(el) {
13 | const section = instance.getClosest(el, '.js-section');
14 | const sectionName = section.getAttribute('data-section');
15 | const sectionId = section.getAttribute('data-section-id');
16 |
17 | const item = instance.getClosest(el, '.js-item ');
18 |
19 | let itemId;
20 | let itemCheck;
21 | let itemDropdown;
22 |
23 | if (item !== null) {
24 | itemId = item.getAttribute('data-item-id');
25 | itemCheck = item.getAttribute('data-item-check');
26 | itemDropdown = item.getAttribute('data-item-dropdown');
27 | }
28 |
29 | return {
30 | sectionId,
31 | section,
32 | sectionName,
33 | item,
34 | itemId,
35 | itemCheck,
36 | itemDropdown,
37 | };
38 | }
39 |
40 | visibityEl(container, el, status) {
41 | const tags = container.querySelectorAll(el)[0];
42 |
43 | if (tags !== undefined) {
44 | if (status === 'hide') {
45 | tags.style.display = 'none';
46 | } else {
47 | tags.style.display = 'flex';
48 | }
49 | }
50 | }
51 |
52 | detailsContainer(section) {
53 | const sectionClass = section.classList[1];
54 | const sectionObj = document.querySelectorAll('.' + sectionClass);
55 | const detailsContainer = sectionObj[0].querySelectorAll('.js-details');
56 |
57 | return detailsContainer;
58 | }
59 |
60 | /* eslint-disable */
61 | getClosest(elem, selector) {
62 | if (!Element.prototype.matches) {
63 | Element.prototype.matches =
64 | Element.prototype.matchesSelector ||
65 | Element.prototype.mozMatchesSelector ||
66 | Element.prototype.msMatchesSelector ||
67 | Element.prototype.oMatchesSelector ||
68 | Element.prototype.webkitMatchesSelector ||
69 | function parse(s) {
70 | let matches = (this.document || this.ownerDocument).querySelectorAll(
71 | s);
72 | let i = matches.length;
73 | while ((--i >= 0 && matches.item(i) !== this)) {}
74 | return i > -1;
75 | };
76 | }
77 |
78 | // Get closest match
79 | for (; elem && elem !== document; elem = elem.parentNode) {
80 | if (elem.matches(selector)) return elem;
81 | }
82 |
83 | return null;
84 | }
85 | /* eslint-enable */
86 | }
87 |
88 | const Instance = new Utils();
89 | Object.freeze(Instance);
90 |
91 | export default Utils;
92 |
--------------------------------------------------------------------------------
/src/scripts/components/Analytics.js:
--------------------------------------------------------------------------------
1 | let instance = null;
2 | /**
3 | *
4 | *
5 | * @class Analytics
6 | */
7 | class Analytics {
8 | constructor() {
9 | if (!instance) {
10 | instance = this;
11 | }
12 |
13 | return instance;
14 | }
15 |
16 | addRef() {
17 | const details = document.querySelectorAll('.js-details');
18 |
19 | details.forEach(detail => {
20 | const links = detail.querySelectorAll('a');
21 | links.forEach(link => {
22 | const ref = 'ref=cloudformationchecklist';
23 | let append = '';
24 | let href = '';
25 |
26 | if (link.href.indexOf('?') > 0) {
27 | append = '&';
28 | } else {
29 | append = '?';
30 | }
31 | let hashAt = link.href.lastIndexOf('#');
32 | if (hashAt < 0) {
33 | href = link.href + append + ref;
34 | } else {
35 | href = link.href.substring(0, hashAt) + append + ref;
36 | href += link.href.substring(hashAt);
37 | }
38 | link.setAttribute('href', href);
39 | });
40 | });
41 | }
42 |
43 | enableAnalytics() {
44 | instance.addRef();
45 | }
46 | }
47 |
48 | const Instance = new Analytics();
49 | Object.freeze(Instance);
50 | export default Analytics;
51 |
--------------------------------------------------------------------------------
/src/scripts/components/Checkboxes.js:
--------------------------------------------------------------------------------
1 | import Utils from '../Utils';
2 | import ProgressBar from './ProgressBar';
3 | import Storage from './Storage';
4 | import Notation from './Notation';
5 | import Dropdown from './Dropdown';
6 |
7 | let instance = null;
8 | /**
9 | *
10 | *
11 | * @class Checkboxes
12 | */
13 | class Checkboxes {
14 | constructor() {
15 | if (!instance) {
16 | instance = this;
17 | }
18 |
19 | return instance;
20 | }
21 |
22 | checkItem(idNumber, section, sectionName, item, storage, type) {
23 |
24 | const storageData = storage;
25 |
26 | storageData.forEach(value => {
27 | const el = value;
28 |
29 | if (idNumber === el.id) {
30 | switch (type) {
31 | case 'state':
32 | el.state = 'checked';
33 | break;
34 |
35 | case 'dropdown':
36 | el.dropdown = 'open';
37 | break;
38 |
39 | case 'visible':
40 | el.visible = 'hide';
41 | break;
42 |
43 | default:
44 | break;
45 | }
46 | }
47 | });
48 |
49 | // Inject new array with new value
50 | storageData.forEach((el, i, arry) => {
51 | localStorage.setItem(sectionName, JSON.stringify(arry));
52 | });
53 |
54 | if (type !== 'visible') {
55 | // Count how many key in the localStorage array
56 | const nbrItemsChecked = JSON.parse(
57 | localStorage.getItem(sectionName),
58 | ).length;
59 |
60 | // Update progress bar
61 | new ProgressBar().updateProgressBar(section, nbrItemsChecked);
62 | item.setAttribute('data-item-check', 'true');
63 | new Notation().updateNotation();
64 |
65 | new Utils().visibityEl(item, '.c-tags', 'hide');
66 | new Utils().visibityEl(item, '.js-dropdown', 'hide');
67 |
68 |
69 | new Notation().updatePriority();
70 |
71 | gtag('event', 'check', {
72 | 'event_category': 'Click',
73 | 'event_label': 'Item checked'
74 | });
75 |
76 | if (item !== null) {
77 | const button = item.querySelector('.js-dropdown');
78 | if (item.getAttribute('data-item-dropdown') === 'open') {
79 | new Dropdown().moveDropdown({button});
80 | }
81 | }
82 |
83 |
84 | }
85 | // TODO: à refaire // const itemExpanded = new Utils().variableList(list.item); // if (itemExpanded.checklistItem.querySelectorAll('.c-checklist__details')[0].getAttribute('aria-expanded') === true) { // new Dropdown().moveDropdown({itemExpanded, force:true}); // }
86 |
87 |
88 | }
89 | uncheckItem(list) {
90 | let currentObj;
91 | if (list.itemId !== undefined) {
92 | const currentStorage = localStorage.getItem(list.sectionName);
93 | currentObj = JSON.parse(currentStorage);
94 | }
95 | currentObj.forEach((el, i) => {
96 | if (el.id === list.itemId) {
97 | // Remove element from current localStorage object
98 | currentObj.splice(i, 1);
99 | // Count how many key in the localStorage array
100 | localStorage.setItem(list.sectionName, JSON.stringify(currentObj));
101 |
102 | // Update the progress bar
103 | const nbrItemsChecked = JSON.parse(
104 | localStorage.getItem(list.sectionName),
105 | ).length;
106 |
107 | new ProgressBar().updateProgressBar(list.section, nbrItemsChecked);
108 | new Notation().updateNotation();
109 | new Utils().visibityEl(list.item, '.c-tags');
110 |
111 | // Change data-check attribute to uncheck item
112 | new Utils().visibityEl(list.item, '.js-dropdown');
113 |
114 | list.item.setAttribute('data-item-check', 'false');
115 |
116 | new Notation().updatePriority();
117 |
118 | gtag('event', 'uncheck', {
119 | 'event_category': 'Click',
120 | 'event_label': 'Item unchecked'
121 | });
122 | }
123 | });
124 | }
125 | checkboxDetection(el) {
126 | // List of all variables needed for checking item
127 | const list = new Utils().variableList(el);
128 | if (el.checked) {
129 | // Check item if unchecked
130 | new Storage().checkingItem(list);
131 | } else {
132 | // Uncheck item if checked
133 | instance.uncheckItem(list);
134 | }
135 | }
136 | enableCheckbox() {
137 | const allCheckboxes = document.querySelectorAll('input[type=checkbox]');
138 | allCheckboxes.forEach(el => {
139 | // Add a click event listener on all checkboxes
140 | el.addEventListener('click', () => instance.checkboxDetection(el));
141 | });
142 | }
143 | }
144 | const Instance = new Checkboxes();
145 | Object.freeze(Instance);
146 | export default Checkboxes;
147 |
--------------------------------------------------------------------------------
/src/scripts/components/Dropdown.js:
--------------------------------------------------------------------------------
1 | import Ui from './Ui';
2 | import Utils from '../Utils';
3 | import postscribe from 'postscribe';
4 |
5 | let instance = null;
6 | /**
7 | *
8 | *
9 | * @class Dropdown
10 | */
11 | class Dropdown {
12 | constructor() {
13 | if (!instance) {
14 | instance = this;
15 | }
16 |
17 | return instance;
18 | }
19 |
20 | // never called directly
21 | dropdownIcon(btn) {
22 | const item = new Utils().getClosest(btn, '.js-item');
23 | const ariaStatus = item.getAttribute('data-item-dropdown');
24 |
25 | if (ariaStatus === 'open') {
26 | item.querySelector('.icon-arrow').classList.add('icon-rotate');
27 | } else {
28 | item.querySelector('.icon-arrow').classList.remove('icon-rotate');
29 | }
30 | }
31 |
32 | allDropdown(options) {
33 |
34 | const el = options;
35 |
36 | const section = new Utils().getClosest(el.btn, '.js-section');
37 | const eachItem = section.querySelectorAll('.js-item[data-item-check="false"]');
38 |
39 | eachItem.forEach(item => {
40 | if (el.btn.classList.value.includes('js-collapse-all') === true) {
41 | item.setAttribute('data-item-dropdown', 'close');
42 | instance.removeCode(item);
43 | } else if (item.getAttributeNode('data-item-dropdown').value !== 'open') {
44 | item.setAttribute('data-item-dropdown', 'open');
45 | instance.loadCode(item);
46 |
47 | new Ui().lazyLoadImg(item);
48 | }
49 | });
50 | }
51 |
52 | removeCode(el) {
53 | const codeContainer = el.querySelector('.js-code');
54 | const loader = el.querySelector('.js-loader');
55 |
56 | if (codeContainer !== null) {
57 | while (codeContainer.hasChildNodes()) {
58 | codeContainer.removeChild(codeContainer.lastChild);
59 | }
60 | loader.style.display = 'inherit';
61 | }
62 | }
63 |
64 | loadCode(el) {
65 | const codeContainer = el.querySelector('.js-code');
66 |
67 | if (codeContainer !== null) {
68 | const scriptUrl = codeContainer.getAttribute('data-code-url');
69 |
70 | let script = document.createElement('script');
71 | script.src = scriptUrl;
72 |
73 | postscribe(codeContainer, script.outerHTML, {
74 | // eslint-disable-next-line func-names
75 | done: () => {
76 | const loader = el.querySelector('.js-loader');
77 | loader.style.display = 'none';
78 | },
79 | });
80 | }
81 |
82 | }
83 |
84 | moveDropdown(options) {
85 | const el = options;
86 |
87 | if (el.button !== null) {
88 | const eachItem = new Utils().getClosest(el.button, '.js-item');
89 | const ariaStatus = eachItem.getAttribute('data-item-dropdown');
90 |
91 | if (ariaStatus === 'open') {
92 | eachItem.setAttribute('data-item-dropdown', 'close');
93 | instance.removeCode(eachItem);
94 | instance.dropdownIcon(el.button);
95 | gtag('event', 'close-dropdown', {
96 | 'event_category': 'Click',
97 | 'event_label': 'Close dropdown'
98 | });
99 | } else if (ariaStatus === 'close') {
100 | eachItem.setAttribute('data-item-dropdown', 'open');
101 | instance.dropdownIcon(el.button);
102 | instance.loadCode(eachItem);
103 |
104 | new Ui().lazyLoadImg(eachItem);
105 |
106 | gtag('event', 'open-dropdown', {
107 | 'event_category': 'Click',
108 | 'event_label': 'Open dropdown'
109 | });
110 | }
111 | else {}
112 | }
113 | }
114 |
115 | collapseAllDropdown(options) {
116 | const el = options;
117 |
118 | const eachSection = new Utils().getClosest(el.button, '.js-section') ||
119 | el.section;
120 | const itemsBySection = eachSection.querySelectorAll('.js-item');
121 |
122 | itemsBySection.forEach(item => {
123 | item.setAttribute('data-item-dropdown', 'close');
124 | });
125 |
126 | // update local storage state dropdown hide
127 | }
128 |
129 | /**
130 | * Enable all dropdown buttons to be clickable
131 | *
132 | * @param {array} dropdownButtons
133 | * @memberof Dropdown
134 | */
135 | enableDropdown(dropdownButtons) {
136 | dropdownButtons.forEach(btn => {
137 | btn.addEventListener(
138 | 'click',
139 | e => {
140 | e.preventDefault();
141 |
142 | // If dropdown button clicked then close / open
143 | instance.moveDropdown({button: btn});
144 |
145 | e.stopImmediatePropagation();
146 | },
147 | false,
148 | );
149 | });
150 | }
151 | }
152 |
153 | const Instance = new Dropdown();
154 | Object.freeze(Instance);
155 |
156 | export default Dropdown;
157 |
--------------------------------------------------------------------------------
/src/scripts/components/Filter.js:
--------------------------------------------------------------------------------
1 | let instance = null;
2 | /**
3 | *
4 | *
5 | * @class Filter
6 | */
7 | class Filter {
8 | constructor() {
9 | if (!instance) {
10 | instance = this;
11 | }
12 |
13 | return instance;
14 | }
15 |
16 | highlightButton(nameFilter, type) {
17 |
18 | const button = document.querySelector(
19 | '[data-' + type + '="' + nameFilter + '"]',
20 | );
21 | const buttons = document.querySelectorAll('[data-' + type + ']');
22 |
23 | // Remove all filter-active class on all buttons
24 | buttons.forEach(el => {
25 | el.classList.remove('filter-active');
26 | })
27 |
28 | // Add class to highlight button
29 | button.classList.add('filter-active');
30 | }
31 |
32 | addFilter(el, storageName) {
33 | let storage = [];
34 | const name = storageName;
35 |
36 | if (localStorage.getItem(name) === null) {
37 | storage = [{'filter': 'all'}];
38 | } else {
39 | let item = {'filter': el};
40 | storage.push(item);
41 |
42 | instance.highlightButton(item.filter, storageName);
43 | }
44 |
45 | localStorage.setItem(name, JSON.stringify(storage));
46 | }
47 |
48 | selectBy(dataName) {
49 | let items = document.querySelectorAll('.js-item');
50 |
51 | items.forEach((el, i) => {
52 | if ((' ' + items[i].className + ' ').indexOf(' ' + dataName + ' ') < 0) {
53 | items[i].setAttribute('data-item-visible', false);
54 | items[i].setAttribute('aria-hidden', true);
55 | } else {
56 | items[i].setAttribute('data-item-visible', true);
57 | items[i].setAttribute('aria-hidden', false);
58 | }
59 | });
60 | }
61 |
62 | readFilterStorage(name) {
63 |
64 | let storage2 = [{'filter': 'all'}];
65 |
66 | if (localStorage.getItem(name) !== null) {
67 | const storage = JSON.parse(localStorage.getItem(name));
68 |
69 | storage.forEach(el => {
70 | instance.selectBy(el.filter);
71 | instance.highlightButton(el.filter, name);
72 | })
73 | }
74 | else {
75 | localStorage.setItem(name, JSON.stringify(storage2));
76 | instance.selectBy('all');
77 | instance.highlightButton('all', 'tag');
78 | }
79 | }
80 |
81 | enableFilter(name, dataName, filterClass) {
82 | const filterNames = document.querySelectorAll(filterClass);
83 |
84 | filterNames.forEach(el => {
85 | el.addEventListener(
86 | 'click',
87 | e => {
88 | e.preventDefault();
89 |
90 | instance.selectBy(e.target.getAttribute(dataName));
91 | instance.addFilter(e.target.getAttribute(dataName), name);
92 | },
93 | false,
94 | );
95 | });
96 | }
97 | }
98 |
99 | const Instance = new Filter();
100 | Object.freeze(Instance);
101 |
102 | export default Filter;
103 |
--------------------------------------------------------------------------------
/src/scripts/components/Init.js:
--------------------------------------------------------------------------------
1 | import Filter from './Filter';
2 | import Dropdown from './Dropdown';
3 | import Storage from './Storage';
4 | import Checkboxes from './Checkboxes';
5 | import Notation from './Notation';
6 | import Tools from './Tools';
7 | import Report from './Report';
8 | import Ui from './Ui';
9 | import Analytics from './Analytics';
10 |
11 | let instance = null;
12 | /**
13 | *
14 | *
15 | * @class Init
16 | */
17 | class Init {
18 | constructor() {
19 | if (!instance) {
20 | instance = this;
21 | }
22 |
23 | this.sections = document.querySelectorAll('.js-section');
24 | this.main = document.getElementById('js-main');
25 |
26 | this.checkboxesInit();
27 | this.dropdownInit(this.sections);
28 | this.filterInit();
29 | this.itemsInit(this.sections);
30 | this.notationInit();
31 | this.toolsInit();
32 | this.reportInit();
33 | this.uiInit();
34 | this.AnalyticsInit();
35 |
36 | return instance;
37 | }
38 |
39 | /**
40 | * Initialize all elements in the header which are used in the report
41 | *
42 | * @memberof Init
43 | */
44 | reportInit() {
45 | new Report().enableReport();
46 | }
47 |
48 | /**
49 | * Initialize Storage and load the content
50 | *
51 | * @memberof Init
52 | */
53 | itemsInit(sections) {
54 | // Load all items by each section based on localStorage
55 | sections.forEach((section, i) => {
56 | new Storage().readItems(section, i, sections);
57 | });
58 | // Hide sections based on the localStorage
59 | new Storage().readHideSections();
60 | }
61 |
62 | /**
63 | * Initialize the notation
64 | *
65 | * @memberof Init
66 | */
67 | notationInit() {
68 | // Initilize the progress bar for all sections
69 | new Notation().updateNotation();
70 |
71 | new Notation().readPriority();
72 | }
73 |
74 | /**
75 | * Initialize buttons
76 | *
77 | * @memberof Init
78 | */
79 | toolsInit() {
80 | // Enable all buttons in the option section bar
81 | new Tools().enableTools();
82 | }
83 |
84 | /**
85 | * Initialize Dropdown and collapse on load
86 | *
87 | * @memberof Init
88 | */
89 | dropdownInit(sections) {
90 | // Enable each dropdown buttons
91 | new Dropdown().enableDropdown(document.querySelectorAll('.js-dropdown'));
92 |
93 | // Collapse on loading each item (except which present into localStorage)
94 | sections.forEach(section => {
95 | new Dropdown().collapseAllDropdown({section});
96 | });
97 | }
98 |
99 | /**
100 | * Initialize Checkboxes class
101 | *
102 | * @memberof Init
103 | */
104 | checkboxesInit() {
105 | // Enable each checkboxe for all items
106 | new Checkboxes().enableCheckbox();
107 | }
108 |
109 | /**
110 | * Initialize Filters
111 | *
112 | * @memberof Init
113 | */
114 | filterInit() {
115 | new Filter().readFilterStorage('tag');
116 |
117 | new Filter().enableFilter('tag', 'data-tag', '.js-filter-tag');
118 | }
119 |
120 | /**
121 | * Initialize UI components
122 | *
123 | * @memberof Init
124 | */
125 | uiInit() {
126 | new Ui().enableUi();
127 | }
128 |
129 | /**
130 | * Add analytics utils
131 | *
132 | * @memberof Init
133 | */
134 | AnalyticsInit() {
135 | new Analytics().enableAnalytics();
136 | }
137 | }
138 |
139 | const Instance = new Init();
140 | Object.freeze(Instance);
141 |
142 | export default Init;
143 |
--------------------------------------------------------------------------------
/src/scripts/components/Notation.js:
--------------------------------------------------------------------------------
1 | let instance = null;
2 | /**
3 | *
4 | *
5 | * @class Notation
6 | */
7 | class Notation {
8 | constructor() {
9 | if (!instance) {
10 | instance = this;
11 | }
12 |
13 | this.main = document.getElementById('js-main');
14 | this.notationDetails = document.querySelector('.c-notation__details');
15 | this.items = document.querySelectorAll('.js-item');
16 | this.priority = [];
17 |
18 | return instance;
19 | }
20 |
21 | updatePriority() {
22 | this.priority.forEach((el, i) => {
23 | const checkedCounter = document.querySelectorAll(`[data-item-priority=${el}][data-item-check='true']`).length
24 | const number = document.querySelectorAll(`.js-detail-${el}`);
25 | number[0].querySelectorAll('.js-notation-checked')[0].innerHTML = checkedCounter
26 | });
27 | }
28 |
29 | /**
30 | * Read the localStorage about the number of items by priority
31 | *
32 | * @param {any} priorityId
33 | * @memberof Notation
34 | */
35 | readPriority(priorityId) {
36 | this.items.forEach((el, i) => {
37 | const currentPriority = el.getAttribute('data-item-priority');
38 | if (this.priority.indexOf(currentPriority) === -1) {
39 | this.priority.push(currentPriority);
40 | }
41 | })
42 | instance.updatePriority();
43 | }
44 |
45 | /**
46 | * Update the letter for the global notation
47 | *
48 | * @memberof Notation
49 | */
50 | updateNotation() {
51 | const items = this.main.querySelectorAll('.js-item').length;
52 | const mainCount = this.main.querySelectorAll('[data-item-check="true"]').length;
53 |
54 | const getPercent = parseInt(mainCount / items * 100, 10);
55 |
56 | const notation = document.getElementById('js-notation');
57 | const notationLetter = notation.getElementsByClassName('c-notation__letter')[0];
58 |
59 | notation.setAttribute('data-notation', getPercent);
60 |
61 | switch (true) {
62 | case getPercent <= 20:
63 | notationLetter.innerHTML = 'F';
64 | break;
65 |
66 | case getPercent <= 40:
67 | notationLetter.innerHTML = 'E';
68 | break;
69 |
70 | case getPercent <= 60:
71 | notationLetter.innerHTML = 'D';
72 | break;
73 |
74 | case getPercent <= 80:
75 | notationLetter.innerHTML = 'C';
76 | break;
77 |
78 | case getPercent < 100:
79 | notationLetter.innerHTML = 'B';
80 | break;
81 | case getPercent === 100:
82 | notationLetter.innerHTML = 'A';
83 | break;
84 | default:
85 | }
86 | }
87 |
88 | }
89 |
90 | const Instance = new Notation();
91 | Object.freeze(Instance);
92 |
93 | export default Notation;
94 |
--------------------------------------------------------------------------------
/src/scripts/components/ProgressBar.js:
--------------------------------------------------------------------------------
1 | let instance = null;
2 | /**
3 | *
4 | *
5 | * @class ProgressBar
6 | */
7 | class ProgressBar {
8 | constructor() {
9 | if (!instance) {
10 | instance = this;
11 | }
12 |
13 | this.main = document.getElementById('js-main');
14 |
15 | return instance;
16 | }
17 |
18 | /**
19 | * Count all items based on a section
20 | *
21 | * @param {any} el
22 | * @returns the number of items
23 | * @memberof ProgressBar
24 | */
25 | allItemsCounter(el) {
26 | const nbrItems = el.querySelectorAll('.js-item').length;
27 |
28 | return nbrItems;
29 | }
30 |
31 | /**
32 | * Update the main progress bar in the top of the page
33 | *
34 | * @depends updateProgressBar
35 | * @memberof ProgressBar
36 | */
37 | updateMainProgressBar() {
38 | const mainCount = this.main.querySelectorAll('[data-item-check="true"]').length;
39 | new ProgressBar().updateProgressBar(this.main, mainCount, 'main');
40 | }
41 |
42 | /**
43 | *
44 | *
45 | * @param {any} section
46 | * @param {any} checkedItems
47 | * @param {any} type
48 | * @memberof ProgressBar
49 | */
50 | updateProgressBar(section, checkedItems, type) {
51 | const currentSection = section;
52 | // Total items in the list
53 | // const checklistItem = section.querySelectorAll('.js-item');
54 | const totalItems = instance.allItemsCounter(section);
55 |
56 | let progressBar;
57 |
58 | switch (type) {
59 | // Main progress bar
60 | case 'main':
61 | progressBar = section.querySelector('.js-all-progress');
62 | break;
63 |
64 | default:
65 | progressBar = section.querySelector('.js-progress');
66 | break;
67 | }
68 |
69 | const getPercent = parseInt(checkedItems / totalItems * 100, 10);
70 |
71 | progressBar.setAttribute('value', getPercent);
72 |
73 | currentSection.querySelector('.c-progress__label',
74 | ).innerHTML = `${getPercent} %`;
75 |
76 | // section.getAttribute('data-section')
77 | document.querySelectorAll(
78 | '#js-nav-' + section.getAttribute('data-section'),
79 | )[0].setAttribute('data-notation', getPercent);
80 | }
81 |
82 | /**
83 | * Update all progress bar, the main and on each section
84 | *
85 | * @param {any} section
86 | * @param {number} items
87 | * @memberof ProgressBar
88 | */
89 | updateAllProgressBars(section, items) {
90 | new ProgressBar().updateProgressBar(section, items);
91 | // new ProgressBar().updateMainProgressBar();
92 | }
93 | }
94 |
95 | const Instance = new ProgressBar();
96 | Object.freeze(Instance);
97 |
98 | export default ProgressBar;
99 |
--------------------------------------------------------------------------------
/src/scripts/components/Report.js:
--------------------------------------------------------------------------------
1 | let instance = null;
2 | /**
3 | *
4 | *
5 | * @class Report
6 | */
7 | class Report {
8 | constructor() {
9 | if (!instance) {
10 | instance = this;
11 | }
12 |
13 | this.form = document.querySelector('.s-form');
14 | this.inputs = this.form.querySelectorAll('input');
15 |
16 | }
17 |
18 | readInputs() {
19 | this.inputs.forEach(el => {
20 | if (localStorage.getItem(el.name) !== null) {
21 | const storage = JSON.parse(localStorage.getItem(el.name));
22 | el.value = storage[0]
23 | }
24 | else {
25 | localStorage.getItem(el.name);
26 | }
27 | });
28 | }
29 |
30 | inputSave() {
31 |
32 |
33 | this.inputs.forEach(el => {
34 |
35 | // Save input value when the user reload the page
36 | window.addEventListener("beforeunload", e => {
37 |
38 | // let storage = [];
39 | // const valueInput = el.target.value;
40 | // const inputName = el.target.name;
41 | // // Push the input value to the storage array
42 | // storage.push(valueInput);
43 | // // Inject the new value typed in the localStorage
44 | // localStorage.setItem(inputName, JSON.stringify(storage));
45 | }, false);
46 |
47 | // Save input value when change focus
48 | el.addEventListener('blur', e => {
49 | let storage = [];
50 | const valueInput = e.target.value;
51 | const inputName = e.target.name;
52 | // Push the input value to the storage array
53 | storage.push(valueInput);
54 | // Inject the new value typed in the localStorage
55 | localStorage.setItem(inputName, JSON.stringify(storage));
56 | });
57 |
58 | });
59 | }
60 |
61 | resetAll() {
62 | document.querySelector('.js-reset-all').addEventListener('click', () => {
63 | const developerName = localStorage.getItem('developer-name');
64 | const projectName = localStorage.getItem('project-name');
65 | const pageTitle = localStorage.getItem('page-title');
66 | localStorage.clear();
67 | localStorage.setItem('developer-name', developerName);
68 | localStorage.setItem('project-name', projectName);
69 | localStorage.setItem('page-title', pageTitle);
70 | gtag('event', 'reset-all', {
71 | 'event_category': 'Click',
72 | 'event_label': 'Star new checklist'
73 | });
74 | window.location.reload(false);
75 | });
76 | }
77 |
78 | print() {
79 | document.querySelector('.js-print').addEventListener('click', () => {
80 | window.print();
81 | gtag('event', 'generate-reports', {
82 | 'event_category': 'Click',
83 | 'event_label': 'Generate reports'
84 | });
85 | });
86 | }
87 |
88 | enableReport() {
89 | instance.print();
90 | instance.resetAll();
91 | instance.inputSave();
92 | instance.readInputs(this.inputs);
93 |
94 | }
95 | }
96 | const Instance = new Report();
97 | Object.freeze(Instance);
98 |
99 | export default Report;
100 |
--------------------------------------------------------------------------------
/src/scripts/components/Storage.js:
--------------------------------------------------------------------------------
1 | import Utils from '../Utils';
2 | import ProgressBar from './ProgressBar';
3 | import Checkboxes from './Checkboxes';
4 |
5 | let instance = null;
6 | /**
7 | *
8 | *
9 | * @class Storage
10 | */
11 | class Storage {
12 | constructor() {
13 | if (!instance) {
14 | instance = this;
15 | }
16 |
17 | this.body = document.querySelectorAll('[data-section-id]');
18 |
19 | return instance;
20 | }
21 |
22 | checkingOption(list, keyName) {
23 | let storage = [];
24 |
25 | if (localStorage.getItem(keyName) === null) {
26 | storage = [];
27 | } else {
28 | // Parse the serialized data back into an aray of objects
29 | storage = JSON.parse(localStorage.getItem(keyName));
30 | }
31 |
32 | if (storage === []) {
33 | storage.forEach(el => {
34 | if (el.id === list.sectionId && list.itemId === null) {
35 | new Checkboxes().checkItem(
36 | list.sectionId,
37 | list.section,
38 | keyName,
39 | list.item,
40 | storage,
41 | 'visible',
42 | );
43 | } else {
44 | console.log('error');
45 | }
46 | });
47 | } else {
48 | if (list.itemId === undefined) {
49 | new Storage().addItemStorage(list.sectionId, storage, keyName);
50 |
51 | new Checkboxes().checkItem(
52 | list.sectionId,
53 | list.section,
54 | keyName,
55 | list.item,
56 | storage,
57 | 'visible',
58 | );
59 | } else {
60 | console.log('error');
61 | }
62 | }
63 | }
64 |
65 | checkingItem(list) {
66 | let storage = [];
67 |
68 | if (list.item !== null) {
69 | if (localStorage.getItem(list.sectionName) === null) {
70 | storage = [];
71 | } else {
72 | // Parse the serialized data back into an aray of objects
73 | storage = JSON.parse(localStorage.getItem(list.sectionName));
74 | }
75 | } else {
76 | console.log('error');
77 | }
78 |
79 | if (storage === []) {
80 | storage.forEach(el => {
81 | if (el.id === list.itemId) {
82 | new Checkboxes().checkItem(
83 | list.itemId,
84 | list.section,
85 | list.sectionName,
86 | list.item,
87 | storage,
88 | 'state',
89 | );
90 | } else {
91 | console.log('error');
92 | }
93 | });
94 | } else {
95 | if (list.itemId !== undefined) {
96 | new Storage().addItemStorage(list.itemId, storage, list.sectionName);
97 |
98 | new Checkboxes().checkItem(
99 | list.itemId,
100 | list.section,
101 | list.sectionName,
102 | list.item,
103 | storage,
104 | 'state',
105 | );
106 | } else {
107 | console.log('error');
108 | }
109 | }
110 | }
111 |
112 | loadItems(checklistItem, currentObj) {
113 | let listItem = checklistItem;
114 | let ids = [];
115 |
116 | currentObj.map(el => {
117 | return ids.push(el.id);
118 | });
119 |
120 | listItem.forEach(el => {
121 | if (ids.indexOf(el.getAttribute('data-item-id')) > -1) {
122 | el.setAttribute('data-item-check', 'true');
123 |
124 | const checkObj = el.querySelectorAll('input[type=checkbox]');
125 |
126 | document.getElementById(checkObj[0].id).checked = true;
127 |
128 | new Utils().visibityEl(el, '.c-tags', 'hide');
129 | new Utils().visibityEl(el, '.js-dropdown', 'hide');
130 | }
131 | });
132 | }
133 |
134 | readItems(el, i, sections) {
135 | const sectionName = el.getAttribute('data-section');
136 |
137 | if (
138 | localStorage.getItem(sectionName) !== null ||
139 | localStorage.getItem(sectionName) === undefined
140 | ) {
141 | const currentStorage = localStorage.getItem(sectionName);
142 | const currentObj = JSON.parse(currentStorage);
143 | const checkedItems = currentObj.length;
144 | const itemsBySection = el.querySelectorAll('.js-item');
145 |
146 | instance.loadItems(itemsBySection, currentObj);
147 |
148 | // Update progress bars
149 | new ProgressBar().updateProgressBar(sections[i], checkedItems);
150 | }
151 | }
152 |
153 | readHideSections() {
154 | let storage;
155 |
156 | if (localStorage.getItem('hide-sections') !== null) {
157 | // Parse the serialized data back into an aray of objects
158 | storage = JSON.parse(localStorage.getItem('hide-sections'));
159 |
160 | this.body.forEach(element => {
161 | storage.forEach(el => {
162 | if (element.getAttribute('data-section-id') === el.id) {
163 | element.querySelectorAll(
164 | '.js-checklist-body',
165 | )[0].setAttribute('data-body-visibility', 'hide');
166 | element.querySelectorAll(
167 | '.js-checklist-body',
168 | )[0].setAttribute('aria-hidden', 'true');
169 | element.querySelectorAll(
170 | '.js-hide-section',
171 | )[0].querySelector('.icon-eye').classList.add('icon-eye-hide');
172 |
173 | element.querySelectorAll(
174 | '.js-hide-section',
175 | )[0].classList.add('is-active');
176 | }
177 | });
178 | });
179 | }
180 | }
181 |
182 | /**
183 | * Add new item into the localStorage
184 | *
185 | * @param {number} itemId
186 | * @param {any} storage
187 | * @param {string} keyName
188 | * @memberof Storage
189 | */
190 | addItemStorage(itemId, storage, keyName) {
191 | for (let index = 0; index < storage.length; index+=1) {
192 | let value = storage[index];
193 | if (value.id === itemId) {
194 | return;
195 | }
196 | }
197 | const newItem = {id: itemId};
198 |
199 | storage.push(newItem);
200 |
201 | // Re-serialize the array back into a string and store it in localStorage
202 | localStorage.setItem(keyName, JSON.stringify(storage));
203 | }
204 | }
205 |
206 | const Instance = new Storage();
207 | Object.freeze(Instance);
208 |
209 | export default Storage;
210 |
--------------------------------------------------------------------------------
/src/scripts/components/Tools.js:
--------------------------------------------------------------------------------
1 | import Utils from '../Utils';
2 | import Dropdown from './Dropdown';
3 | import Checkboxes from './Checkboxes';
4 | import Storage from './Storage';
5 |
6 | let instance = null;
7 | /**
8 | *
9 | *
10 | * @class Tools
11 | */
12 | class Tools {
13 | constructor() {
14 | if (!instance) {
15 | instance = this;
16 | }
17 |
18 | this.checkAllButton = document.querySelectorAll('.js-check-all');
19 | this.uncheckAllButton = document.querySelectorAll('.js-uncheck-all');
20 |
21 | this.collapseAllButton = document.querySelectorAll('.js-collapse-all');
22 | this.expandAllButton = document.querySelectorAll('.js-expand-all');
23 |
24 | this.hideSectionButton = document.querySelectorAll('.js-hide-section');
25 |
26 | return instance;
27 | }
28 |
29 | /**
30 | * Chech or uncheck all items in a specific section
31 | *
32 | * @param {any} btn
33 | * @param {string} state
34 | * @memberof Tools
35 | */
36 | checkUncheckAll(btn, state) {
37 | const list = new Utils().variableList(btn);
38 | const checklistItem = list.section.querySelectorAll('.js-item');
39 |
40 | checklistItem.forEach(el => {
41 | if (state === 'true') {
42 | // if element is not already checked
43 | if (el.getAttribute('data-item-check') !== 'true') {
44 | // Change each item state
45 | el.setAttribute('data-item-check', state);
46 |
47 | const list2 = new Utils().variableList(el);
48 |
49 | new Storage().checkingItem(list2);
50 | }
51 | } else {
52 | // Change each item state
53 | el.setAttribute('data-item-check', state);
54 |
55 | const list2 = new Utils().variableList(el);
56 |
57 | new Checkboxes().uncheckItem(list2);
58 | }
59 | });
60 | }
61 |
62 | uncheckOption(list, keyName) {
63 | let currentObj;
64 |
65 | if (list.itemId === undefined) {
66 | const currentStorage = localStorage.getItem(keyName);
67 | currentObj = JSON.parse(currentStorage);
68 | }
69 |
70 | currentObj.forEach((el, i) => {
71 | if (el.id === list.sectionId) {
72 | // Remove element from current localStorage object
73 | currentObj.splice(i, 1);
74 |
75 | localStorage.setItem(keyName, JSON.stringify(currentObj));
76 | }
77 | });
78 | }
79 |
80 | /**
81 | * Hide the body
82 | *
83 | * @param {any} btn
84 | * @memberof Tools
85 | */
86 | hideShow(btn) {
87 | const list = new Utils().variableList(btn);
88 | const body = list.section.querySelectorAll('.js-checklist-body')[0];
89 |
90 | if (body !== undefined) {
91 | const status = body.getAttribute('data-body-visibility');
92 |
93 | if (status === 'visible') {
94 |
95 | btn.classList.add('is-active');
96 |
97 | btn.querySelector('.icon-eye').classList.add('icon-eye-hide');
98 |
99 | body.setAttribute('data-body-visibility', 'hide');
100 | body.setAttribute('aria-hidden', 'true');
101 |
102 | new Storage().checkingOption(list, 'hide-sections');
103 |
104 |
105 | } else {
106 |
107 | btn.classList.remove('is-active');
108 |
109 | btn.querySelector('.icon-eye').classList.remove('icon-eye-hide');
110 |
111 | body.setAttribute('data-body-visibility', 'visible');
112 | body.setAttribute('aria-hidden', 'false');
113 |
114 | instance.uncheckOption(list, 'hide-sections');
115 | }
116 | }
117 | }
118 |
119 | enableTools() {
120 | // Check all checkboxes
121 | this.checkAllButton.forEach(btn => {
122 | btn.addEventListener(
123 | 'click',
124 | () => {
125 | instance.checkUncheckAll(btn, 'true');
126 | }
127 | );
128 | });
129 |
130 | // Uncheck all checkboxes
131 | this.uncheckAllButton.forEach(btn => {
132 | btn.addEventListener(
133 | 'click',
134 | () => {
135 | instance.checkUncheckAll(btn, 'false');
136 | }
137 | );
138 | });
139 |
140 | // Collapse all dropdowns
141 | this.collapseAllButton.forEach(btn => {
142 | btn.addEventListener(
143 | 'click',
144 | () => {
145 | new Dropdown().allDropdown({btn});
146 | }
147 | );
148 | });
149 |
150 | // Expand all dropdowns
151 | this.expandAllButton.forEach(btn => {
152 | btn.addEventListener(
153 | 'click',
154 | () => {
155 | new Dropdown().allDropdown({btn});
156 | }
157 | );
158 | });
159 |
160 | // Hide section
161 | this.hideSectionButton.forEach(btn => {
162 | btn.addEventListener(
163 | 'click',
164 | () => {
165 | instance.hideShow(btn);
166 | }
167 | );
168 | });
169 | }
170 | }
171 |
172 | const Instance = new Tools();
173 | Object.freeze(Instance);
174 |
175 | export default Tools;
176 | // enableReset() {
177 | // const uncheckAll = document.querySelectorAll(".js-uncheck-section");
178 | // const checkAll = document.querySelectorAll(".js-check-section");
179 | // uncheckAll.forEach((el, i, array) => {
180 | // el.addEventListener('click', e => {
181 | // e.preventDefault();
182 | // const section = new Utils().getClosest(el, '.js-section');
183 | // const sectionName = section.getAttribute('data-section');
184 | // const checklistItem = new Utils().getClosest(el, '.js-item ');
185 | // localStorage.removeItem(sectionName);
186 | // instance.resetItems(section, sectionName);
187 | // });
188 | // });
189 | // checkAll.forEach((el, i, array) => {
190 | // el.addEventListener('click', e => {
191 | // e.preventDefault();
192 | // const section = new Utils().getClosest(el, '.js-section');
193 | // const sectionName = section.getAttribute('data-section');
194 | // const checklistItem = new Utils().getClosest(el, '.js-item ');
195 | // localStorage.addItem(sectionName);
196 | // });
197 | // });
198 | // }
199 |
--------------------------------------------------------------------------------
/src/scripts/components/Ui.js:
--------------------------------------------------------------------------------
1 | let instance = null;
2 |
3 | class Ui {
4 | constructor() {
5 | if (!instance) {
6 | instance = this;
7 | }
8 |
9 | this.nav = document.querySelector('.c-nav');
10 | this.scrollToggle = document.querySelectorAll('.js-scroll');
11 |
12 | return instance;
13 | }
14 |
15 | lazyLoadImg(item) {
16 | [].forEach.call(item.querySelectorAll('img[data-src]'), (img) => {
17 | img.setAttribute('src', img.getAttribute('data-src'));
18 | img.onload = function() {
19 | img.removeAttribute('data-src');
20 | };
21 | });
22 | }
23 |
24 | isScrolledIntoView(el) {
25 | var elemTop = el.getBoundingClientRect().top;
26 | var elemBottom = el.getBoundingClientRect().bottom;
27 |
28 | // Only completely visible elements return true:
29 | var isVisible = elemTop >= 0 && elemBottom <= window.innerHeight;
30 | // Partially visible elements return true:
31 | // isVisible = elemTop < window.innerHeight && elemBottom >= 0;
32 | return isVisible;
33 | }
34 |
35 | smoothScroll(anchor, duration) {
36 | // Calculate how far and how fast to scroll
37 | const startLocation = window.pageYOffset;
38 | const endLocation = anchor.offsetTop + 300;
39 | const distance = endLocation - startLocation;
40 | const increments = distance / (duration / 16);
41 | let stopAnimation;
42 |
43 | // Scroll the page by an increment, and check if it's time to stop
44 | const animateScroll = () => {
45 | window.scrollBy(0, increments);
46 | stopAnimation();
47 | };
48 |
49 | // Loop the animation function
50 | const runAnimation = setInterval(animateScroll, 16);
51 |
52 | // If scrolling down
53 | if (increments >= 0) {
54 | // Stop animation when you reach the anchor OR the bottom of the page
55 | stopAnimation = () => {
56 | const travelled = window.pageYOffset;
57 | if ( (travelled >= (endLocation - increments)) || ((window.innerHeight + travelled) >= document.body.offsetHeight) ) {
58 | clearInterval(runAnimation);
59 | }
60 | };
61 | }
62 | // If scrolling up
63 | else {
64 | // Stop animation when you reach the anchor OR the top of the page
65 | stopAnimation = () => {
66 | const travelled = window.pageYOffset;
67 | if ( travelled <= (endLocation || 0) ) {
68 | clearInterval(runAnimation);
69 | }
70 | };
71 | }
72 | }
73 |
74 | scrollAnchor() {
75 |
76 | // For each smooth scroll link
77 | this.scrollToggle.forEach(toggle => {
78 | // When the smooth scroll link is clicked
79 | toggle.addEventListener('click', e => {
80 | // Prevent the default link behavior
81 | e.preventDefault();
82 | // Get anchor link and calculate distance from the top
83 | const dataID = toggle.getAttribute('href');
84 | const dataTarget = document.querySelector(dataID);
85 | const dataSpeed = toggle.getAttribute('data-speed');
86 | // If the anchor exists
87 | if (dataTarget) {
88 | // Scroll to the anchor
89 | instance.smoothScroll(dataTarget, dataSpeed || 3000);
90 |
91 | // Push new state history to dynamically change the URL
92 | if(history.pushState) {
93 | history.pushState(null, null, '/'+dataID);
94 | }
95 | else {
96 | location.hash = '/'+dataID;
97 | }
98 | }
99 | }, false);
100 | });
101 | }
102 |
103 | navScroll() {
104 |
105 | let lastScrollPosition = 0;
106 | let ticking = false;
107 |
108 | window.addEventListener(
109 | 'scroll',
110 | () => {
111 |
112 | lastScrollPosition = window.scrollY;
113 |
114 | if (!ticking) {
115 |
116 | window.requestAnimationFrame(() => {
117 |
118 | // Execute only on desktop and when the menu is already on the side
119 | if (window.innerWidth > 1265) {
120 | if (
121 | instance.isScrolledIntoView(this.nav) ===
122 | false
123 | ) {
124 | this.nav.classList.add('c-nav__sidebar');
125 | } else {
126 | this.nav.classList.remove('c-nav__sidebar');
127 | }
128 | }
129 |
130 | ticking = false;
131 | });
132 |
133 | ticking = true;
134 | }
135 |
136 | }, {passive: true});
137 | }
138 |
139 | enableUi() {
140 | // instance.scrollAnchor();
141 | instance.navScroll();
142 | }
143 | }
144 |
145 | const Instance = new Ui();
146 | Object.freeze(Instance);
147 |
148 | export default Ui;
149 |
--------------------------------------------------------------------------------
/src/scripts/main.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import Init from './components/Init';
4 |
5 | document.addEventListener('DOMContentLoaded', () => new Init());
6 |
--------------------------------------------------------------------------------
/src/service-worker.js:
--------------------------------------------------------------------------------
1 | // importScripts('/cache-polyfill.js');
2 | 'use strict';
3 |
4 | var version = 'v1::';
5 |
6 | self.addEventListener("install", function(event) {
7 | // console.log('WORKER: install event in progress.');
8 | event.waitUntil(
9 | /* The caches built-in is a promise-based API that helps you cache responses,
10 | as well as finding and deleting them.
11 | */
12 | caches
13 | /* You can open a cache by name, and this method returns a promise. We use
14 | a versioned cache name here so that we can remove old cache entries in
15 | one fell swoop later, when phasing out an older service worker.
16 | */
17 | .open(version + 'fundamentals')
18 | .then(function(cache) {
19 | /* After the cache is opened, we can fill it with the offline fundamentals.
20 | The method below will add all resources we've indicated to the cache,
21 | after making HTTP requests for each of them.
22 | */
23 | return cache.addAll([
24 | '/',
25 | '/index.html',
26 | '/styles/main.min.css',
27 | '/scripts/app.bundle.js'
28 | ]);
29 | })
30 | .then(function() {
31 | // console.log('WORKER: install completed');
32 | })
33 | );
34 | });
35 |
--------------------------------------------------------------------------------
/src/sitemap.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | https://cfnchecklist.com/
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/styles/base/_fonts.scss:
--------------------------------------------------------------------------------
1 | // =============================================================================
2 | // String Replace
3 | // =============================================================================
4 |
5 | @function str-replace($string, $search, $replace: '') {
6 | $index: str-index($string, $search);
7 |
8 | @if $index {
9 | @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
10 | }
11 |
12 | @return $string;
13 | }
14 | // =============================================================================
15 | // Font Face
16 | // =============================================================================
17 | @mixin font-face($name, $path, $weight: null, $style: null, $exts: eot woff2 woff ttf svg) {
18 | $src: null;
19 | $extmods: (eot: '?', svg: '#' + str-replace($name, ' ', '_'));
20 | $formats: (otf: 'opentype', ttf: 'truetype');
21 |
22 | @each $ext in $exts {
23 | $extmod: if(map-has-key($extmods, $ext), $ext + map-get($extmods, $ext), $ext);
24 | $format: if(map-has-key($formats, $ext), map-get($formats, $ext), $ext);
25 | $src: append($src, url(quote($path + '.' + $extmod)) format(quote($format)), comma);
26 | }
27 |
28 | @font-face {
29 | font-family: quote($name);
30 | font-style: $style;
31 | font-weight: $weight;
32 | src: $src;
33 | }
34 | }
35 |
36 | // @include font-face(Samplinal, fonts/Samplinal, 500, normal, eot woff2 woff);
37 |
--------------------------------------------------------------------------------
/src/styles/base/_form.scss:
--------------------------------------------------------------------------------
1 | fieldset {
2 | border: 0;
3 | margin: 0;
4 | }
5 |
6 | label:hover {
7 | cursor: pointer;
8 | }
9 |
10 | .s-form {
11 | margin: 10px 0 20px;
12 |
13 | @include mq('handheld-and-up') {
14 | margin-bottom: 20px;
15 | }
16 | }
17 |
18 | .form {
19 | input {
20 | font-size: 1.5rem;
21 | padding: 5px;
22 | display: block;
23 | border: 0;
24 | width: 100%;
25 | border-radius: 0;
26 | border-bottom: 1px solid #757575;
27 |
28 | @include mq('handheld-and-up') {
29 | width: 300px;
30 | }
31 |
32 | &:focus {
33 | outline: none;
34 | }
35 |
36 | &:focus ~ label,
37 | &:valid ~ label {
38 | top: -15px;
39 | font-size: 12px;
40 | color: map-get($colors, $primary);
41 | }
42 | }
43 |
44 | label {
45 | color: #999999;
46 | font-size: 14px;
47 | font-weight: normal;
48 | position: absolute;
49 | pointer-events: none;
50 | left: 5px;
51 | top: 0;
52 | transition: .2s ease all;
53 | }
54 | }
55 |
56 | .form-group {
57 | position: relative;
58 | margin: 20px 0;
59 |
60 | &:last-of-type {
61 | margin: 20px 0 0;
62 | }
63 | }
64 |
65 | .label__title {
66 | font-weight: bold;
67 | display: inline;
68 | }
69 |
70 | label,
71 | .nav li a,
72 | .nav li input {
73 | transition: background-color .08s ease-in-out;
74 | }
75 |
--------------------------------------------------------------------------------
/src/styles/base/_generic.scss:
--------------------------------------------------------------------------------
1 | $body-background-color: #ededed !default;
2 | $body-size: 62.5% !default;
3 | $body-rendering: optimizeLegibility !default;
4 | $body-family: $family-sans-serif !default;
5 | $body-color: $text !default;
6 | $body-weight: $weight-normal !default;
7 | $body-line-height: 1.5 !default;
8 |
9 | // $hr-background-color: $border !default;
10 | $hr-height: 1px !default;
11 | $hr-margin: 1.5rem 0 !default;
12 | $strong-color: $text-strong !default;
13 | $strong-weight: $weight-bold !default;
14 |
15 | // Set box-sizing globally to handle padding and border widths
16 | *,
17 | *::after,
18 | *::before {
19 | box-sizing: inherit;
20 | }
21 |
22 | // The base font-size is set at 62.5% for having the convenience
23 | // of sizing rems in a way that is similar to using px: 1.6rem = 16px
24 | html {
25 | background-color: $body-background-color;
26 | min-width: 100%;
27 | overflow-x: hidden;
28 | overflow-y: scroll;
29 | box-sizing: border-box;
30 | font-size: $body-size;
31 | text-rendering: $body-rendering;
32 | -moz-osx-font-smoothing: grayscale;
33 | -webkit-font-smoothing: antialiased;
34 | scroll-behavior: smooth;
35 | }
36 |
37 | // Default body styles
38 | body {
39 | color: $body-color;
40 | font-size: 1rem;
41 | font-weight: $body-weight;
42 | line-height: $body-line-height;
43 | font-family: $family-sans-serif;
44 | margin: 0;
45 | }
46 |
--------------------------------------------------------------------------------
/src/styles/base/_headings.scss:
--------------------------------------------------------------------------------
1 | .h1,
2 | .h2,
3 | .h3,
4 | .h4,
5 | .h5,
6 | .h6,
7 | h1,
8 | h2,
9 | h3,
10 | h4,
11 | h5,
12 | h6 {
13 | margin-bottom: .5rem;
14 | font-family: inherit;
15 | font-weight: 500;
16 | line-height: 1.2;
17 | color: inherit;
18 | }
19 |
20 | h1,
21 | .h1 {
22 | margin: 0;
23 | padding: 15px 0 0;
24 | font-weight: 700;
25 | font-size: 2.5rem;
26 |
27 | @include mq('handheld-and-up') {
28 | font-size: 3rem;
29 | }
30 |
31 | @include mq('print') {
32 | font-size: 18pt;
33 | padding: 0 0 5px;
34 | }
35 | }
36 |
37 | h2,
38 | .h2 {
39 | font-size: 2rem;
40 | }
41 |
42 | h3,
43 | .h3 {
44 | font-size: 1.2rem;
45 | font-weight: 700;
46 |
47 | @include mq('handheld-and-up') {
48 | font-size: 1.3rem;
49 | }
50 | }
51 |
52 | h4,
53 | .h4 {
54 | font-size: 1.2rem;
55 | font-weight: 700;
56 |
57 | @include mq('handheld-and-up') {
58 | font-size: 1.3rem;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/styles/base/_icons.scss:
--------------------------------------------------------------------------------
1 | .icon {
2 | width: 18px;
3 | height: 18px;
4 | transition: all 200ms ease-in 0s;
5 | fill: map-get($colors, grey-light);
6 | display: inline-block;
7 | text-align: center;
8 | speak: none;
9 | backface-visibility: hidden;
10 | opacity: 1;
11 |
12 | @include mq('handheld-and-up') {
13 | width: 15px;
14 | height: 15px;
15 | }
16 | }
17 |
18 | button,
19 | .button {
20 | .icon {
21 | margin: 0 .7rem 0 -.2rem;
22 | }
23 | }
24 |
25 | .icon--small {
26 | width: 7px;
27 | height: 7px;
28 | }
29 |
30 | .icon-checkbox {
31 | .path-check {
32 | display: none;
33 | }
34 | }
35 |
36 | .icon-uncheck {
37 | .path-check {
38 | display: none;
39 | }
40 | }
41 |
42 | .icon-checkbox,
43 | .icon-checked {
44 | align-self: flex-start;
45 | width: 11px;
46 | height: 11px;
47 | fill: $primary;
48 | opacity: 1;
49 |
50 | @include mq('handheld-and-up') {
51 | width: 15px;
52 | height: 15px;
53 | }
54 |
55 | [data-item-check='false'] & {
56 | display: block;
57 | }
58 |
59 | [data-item-check='true'] & {
60 | display: none;
61 | }
62 | }
63 |
64 | .icon-checked {
65 | fill: map-get($colors, black);
66 | opacity: .1;
67 |
68 | [data-item-check='false'] & {
69 | display: none;
70 | }
71 |
72 | [data-item-check='true'] & {
73 | display: block;
74 | }
75 | }
76 |
77 | .icon-arrow {
78 | width: 15px;
79 | height: 15px;
80 | position: absolute;
81 | top: 10px;
82 | fill: map-get($colors, black);
83 | opacity: .2;
84 | }
85 |
86 | .icon-rotate {
87 | transform: rotate(180deg);
88 | transition: all 300ms ease-in 0s;
89 | }
90 |
91 | .icon-priority {
92 | &--high {
93 | fill: #f85f5f;
94 | align-self: flex-start;
95 | display: block;
96 | width: 7px;
97 | height: 7px;
98 |
99 | @include mq(lap-and-up) {
100 | margin-top: 0;
101 | width: 7px;
102 | height: 7px;
103 | }
104 | }
105 |
106 | &--medium {
107 | fill: #f2c741;
108 | align-self: flex-start;
109 | display: block;
110 | width: 7px;
111 | height: 7px;
112 |
113 | @include mq(lap-and-up) {
114 | margin-top: 0;
115 | width: 7px;
116 | height: 7px;
117 | }
118 | }
119 |
120 | &--low {
121 | fill: #62c547;
122 | align-self: flex-start;
123 | display: block;
124 | width: 7px;
125 | height: 7px;
126 |
127 | @include mq(lap-and-up) {
128 | margin-top: 0;
129 | width: 7px;
130 | height: 7px;
131 | }
132 | }
133 | }
134 |
135 | .btn--danger {
136 | border-color: #df5941;
137 | color: #df5941;
138 |
139 | .icon {
140 | fill: #df5941;
141 | }
142 | }
143 |
144 | @keyframes bounce {
145 | 0% {
146 | transform: scaleX(1);
147 | }
148 |
149 | 10% {
150 | transform: scaleX(1);
151 | }
152 |
153 | 20% {
154 | transform: scaleX(.8);
155 | }
156 |
157 | 35% {
158 | transform: scaleX(.8);
159 | }
160 |
161 | 45% {
162 | transform: scaleX(1);
163 | }
164 |
165 | 60% {
166 | transform: scaleX(1);
167 | }
168 |
169 | 75% {
170 | transform: scaleX(.8);
171 | }
172 |
173 | 85% {
174 | transform: scaleX(.8);
175 | }
176 |
177 | 100% {
178 | transform: scaleX(1);
179 | }
180 | }
181 |
182 | .code-icons {
183 |
184 | // height: 100%;
185 | margin: 0 auto;
186 | position: relative;
187 | width: 25px;
188 |
189 | &::after,
190 | &::before {
191 | box-sizing: content-box;
192 | content: '';
193 | height: 10px;
194 | position: absolute;
195 | top: 9px;
196 | transform: rotate(45deg);
197 | width: 10px;
198 | }
199 |
200 | &::before {
201 | border-bottom: 3px solid #cccccc;
202 | border-left: 3px solid #cccccc;
203 | left: 0;
204 | }
205 |
206 | &::after {
207 | border-right: 3px solid #cccccc;
208 | border-top: 3px solid #cccccc;
209 | right: 0;
210 | }
211 | }
212 |
213 | .icon-eye {
214 | path:nth-child(2),
215 | path:nth-child(3) {
216 | display: none;
217 | }
218 |
219 | &-hide {
220 | fill: #415257;
221 |
222 | path:nth-child(2),
223 | path:nth-child(3) {
224 | display: block;
225 | }
226 | }
227 | }
228 |
229 |
230 |
231 | .st0 {
232 | fill: map-get($colors, white);
233 | }
234 |
--------------------------------------------------------------------------------
/src/styles/base/_links.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Links
3 | //
4 |
5 | // Link colors
6 | $link: map-get($colors, primary) !default;
7 | $link-invert: map-get($colors, primary-invert) !default;
8 | $link-visited: map-get($colors, purple) !default;
9 | $link-hover: map-get($colors, grey-darker) !default;
10 | $link-hover-border: map-get($colors, grey-light) !default;
11 | $link-focus: map-get($colors, grey-darker) !default;
12 | $link-focus-border: map-get($colors, primary) !default;
13 | $link-active: map-get($colors, grey-darker) !default;
14 | $link-active-border: map-get($colors, grey-dark) !default;
15 | $link-color: $primary !default;
16 | $link-brand-color: #f40057 !default;
17 | $link-info-color: $info !default;
18 | $link-warning-color: $warning !default;
19 | $link-success-color: $success !default;
20 | $link-error-color: $danger !default;
21 | $link-text-decoration: none !default;
22 | $link-hover-text-decoration: underline !default;
23 |
24 | @mixin link--color($color: $link-color) {
25 | &:not(:disabled) {
26 | background-color: transparent;
27 | color: $link-color;
28 | // &:visited {
29 | // color: darken($color, $color-tint);
30 | // }
31 |
32 | &:hover {
33 | background-color: transparent;
34 | color: lighten($color, $color-tint);
35 | }
36 |
37 | &:active {
38 | background-color: transparent;
39 | color: lighten($color, $color-tint);
40 | }
41 | }
42 | }
43 |
44 | a,
45 | .c-link {
46 | @include link--color;
47 |
48 | text-decoration: $link-text-decoration;
49 | cursor: pointer;
50 |
51 | &:hover {
52 | text-decoration: $link-hover-text-decoration;
53 | }
54 | }
55 |
56 | .a-link--info {
57 | @include link--color($link-info-color);
58 | }
59 |
60 | .c-link--warning {
61 | @include link--color($link-warning-color);
62 | }
63 |
64 | .c-link--success {
65 | @include link--color($link-success-color);
66 | }
67 |
68 | .c-link--error {
69 | @include link--color($link-error-color);
70 | }
71 |
72 | // a:not( [href*='localhost:3000'] ):not( [href^='#'] ):not( [href^='/'] ):after {
73 | // content: " (external)";
74 | // }
75 |
--------------------------------------------------------------------------------
/src/styles/base/_media.scss:
--------------------------------------------------------------------------------
1 | .media {
2 | align-items: flex-start;
3 | display: flex;
4 | text-align: left;
5 | }
6 |
7 | .img-logo {
8 | width: 85px;
9 | height: 85px;
10 |
11 | @include mq('handheld-and-up') {
12 | width: 100px;
13 | height: 100px;
14 | }
15 | }
16 |
17 | // frameborder="0"
18 | // allowtransparency="true"
19 | // scrolling="no"
20 | iframe {
21 | background: transparent;
22 | margin: 0;
23 | padding: 0;
24 | border: 0;
25 | }
26 |
--------------------------------------------------------------------------------
/src/styles/base/_print.scss:
--------------------------------------------------------------------------------
1 | @media print {
2 | @page {
3 | margin: 20px 15px;
4 | }
5 |
6 | body {
7 | margin: 0;
8 | overflow: hidden;
9 | position: relative;
10 | box-sizing: border-box;
11 | page-break-after: always;
12 | font: 10pt Arial, 'Times New Roman', Times, serif;
13 | line-height: 1.3;
14 | background: map-get($colors, white) !important;
15 | color: map-get($colors, black) !important;
16 | -webkit-print-color-adjust: exact;
17 | }
18 |
19 | /* Defining all page breaks */
20 | a {
21 | page-break-inside: avoid;
22 | }
23 |
24 | h1,
25 | h2,
26 | h3,
27 | h4,
28 | h5,
29 | h6 {
30 | page-break-after: avoid;
31 | page-break-inside: avoid;
32 | }
33 |
34 | img {
35 | page-break-inside: avoid;
36 | page-break-after: avoid;
37 | }
38 |
39 | table,
40 | pre {
41 | page-break-inside: avoid;
42 | }
43 |
44 | ul,
45 | ol,
46 | dl {
47 | page-break-before: avoid;
48 | }
49 |
50 | /* Displaying link color and link behaviour */
51 | a:link,
52 | a:visited,
53 | a {
54 | background: transparent;
55 | color: map-get($colors, primary);
56 | font-weight: bold;
57 | text-decoration: underline;
58 | text-align: left;
59 | }
60 |
61 | a[href^='http']::after {
62 | content: initial;
63 | }
64 | $a: after >
65 |
66 | article a[href^='#']::after {
67 | content: '';
68 | }
69 |
70 | /* stylelint-disable selector-pseudo-class-no-unknown */
71 | a:not(:local-link)::after {
72 | content: ' < ' attr(href) '> ';
73 | }
74 | /* stylelint-enable */
75 |
76 | .icon-checkbox,
77 | .icon-checked {
78 | display: none !important;
79 | }
80 |
81 | .c-checklist__body input {
82 | height: auto !important;
83 | top: 4px !important;
84 | opacity: 1 !important;
85 | }
86 |
87 | .c-checklist__body label {
88 | text-decoration: none !important;
89 | opacity: 1 !important;
90 | }
91 |
92 | .c-tags,
93 | .c-github-corner,
94 | .s-header__media,
95 | .s-header__lang,
96 | .img-logo,
97 | .s-content__filter,
98 | .s-content__search,
99 | .s-content__meta,
100 | .s-section__meta,
101 | .s-meta,
102 | .c-notation__generate,
103 | .s-nav {
104 | display: none !important;
105 | }
106 |
107 | .page-main {
108 | display: block !important;
109 | }
110 |
111 | h2 {
112 | font-size: 20pt !important;
113 | }
114 |
115 | label {
116 | font-size: 9pt !important;
117 | }
118 |
119 |
120 | .s-header {
121 | text-align: left !important;
122 | }
123 |
124 | .s-header__banner {
125 | padding: 15px;
126 | }
127 |
128 | .sub-heading {
129 | font-size: 9pt !important;
130 | margin: 0 !important;
131 | }
132 |
133 | .c-checklist__item::before {
134 | display: none;
135 | }
136 |
137 | .label__description {
138 | line-height: 1.5;
139 | }
140 |
141 | .c-checklist__dropdown {
142 | display: none;
143 | }
144 |
145 | .sub-heading::after {
146 | content: ' ★ Generated on http://cfnchecklist.com ★ ';
147 | white-space: pre;
148 | }
149 |
150 | .s-header__checklist__el {
151 | padding: 0 !important;
152 | }
153 |
154 | .c-notation__item {
155 | width: 80px !important;
156 | height: 80px !important;
157 | }
158 |
159 | .c-progress {
160 | padding: 0 20px;
161 | }
162 |
163 | .c-progress__counter,
164 | .c-progress__label {
165 | font-size: 8pt !important;
166 | }
167 |
168 | .c-progress__bar {
169 | display: none !important;
170 | }
171 |
172 | .c-progress__label {
173 | position: relative !important;
174 | padding: 20pt 0 !important;
175 | left: auto !important;
176 | }
177 |
178 | .c-nav {
179 | margin: 0 !important;
180 | position: relative !important;
181 | right: auto !important;
182 | z-index: 10 !important;
183 | }
184 |
185 | .c-nav__list {
186 | position: relative !important;
187 | top: 0 !important;
188 | flex-direction: row !important;
189 | }
190 |
191 | .c-nav__item .c-button {
192 | font-size: 9pt !important;
193 | border: 0 !important;
194 | }
195 |
196 | .form input {
197 | font-size: 9pt !important;
198 | padding: 3px !important;
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/src/styles/base/_typography.scss:
--------------------------------------------------------------------------------
1 | p {
2 | font-size: 1.2rem;
3 | line-height: 1.5;
4 | margin-top: 0;
5 | }
6 |
--------------------------------------------------------------------------------
/src/styles/components/_c-button.scss:
--------------------------------------------------------------------------------
1 | // $control-radius: $radius !default;
2 | // $control-radius-small: $radius-small !default;
3 |
4 |
5 | $control-padding-vertical: calc(8px - 1px) !default;
6 | $control-padding-horizontal: calc(11px - 1px) !default;
7 | $control-padding-vertical-up: calc(6px - 1px) !default;
8 | $control-padding-horizontal-up: calc(10px - 1px) !default;
9 |
10 | @mixin control {
11 | -moz-appearance: none;
12 | -webkit-appearance: none;
13 | align-items: center;
14 | border: 1px solid transparent;
15 | border-radius: 3px;
16 | box-shadow: none;
17 | display: inline-flex;
18 | font-size: 1.3rem;
19 | padding: $control-padding-vertical $control-padding-horizontal;
20 | justify-content: flex-start;
21 | line-height: 1.4;
22 | position: relative;
23 | vertical-align: top;
24 |
25 | @include mq(lap-and-up) {
26 | font-size: $size-medium;
27 | height: 34px;
28 | padding: $control-padding-vertical-up $control-padding-horizontal-up;
29 | }
30 | // States
31 | &:focus,
32 | &.is-focused,
33 | &:active,
34 | &.is-active {
35 | outline: none;
36 | }
37 |
38 | &[disabled] {
39 | cursor: not-allowed;
40 | }
41 | }
42 |
43 | // The controls sizes use mixins so they can be used at different breakpoints
44 | @mixin control-small {
45 | // border-radius: $control-radius-small;
46 | font-size: $size-small;
47 | }
48 |
49 | @mixin control-medium {
50 | font-size: $size-medium;
51 | }
52 |
53 | @mixin control-large {
54 | font-size: $size-large;
55 | }
56 |
57 | $button-color: map-get($colors, grey-darker) !default;
58 | $button-background-color: map-get($colors, white) !default;
59 | $button-border-color: #999999 !default;
60 | $button-hover-color: $link-hover !default;
61 | $button-hover-border-color: $link-hover-border !default;
62 | $button-focus-color: $link-focus !default;
63 | $button-focus-border-color: $link-focus-border !default;
64 |
65 | // The button sizes use mixins so they can be used at different breakpoints
66 | @mixin button-small {
67 | // border-radius: $radius-small;
68 | font-size: $size-small;
69 | }
70 |
71 | @mixin button-medium {
72 | font-size: $size-medium;
73 | }
74 |
75 | @mixin button-large {
76 | font-size: $size-large;
77 | }
78 |
79 | // Declarations
80 | // =============================================================================
81 | #{$namespace-button},
82 | button {
83 | @include control;
84 | @include unselectable;
85 |
86 | background-color: $button-background-color;
87 | border-color: $button-border-color;
88 | color: $button-color;
89 | cursor: pointer;
90 | justify-content: center;
91 | text-align: center;
92 | white-space: nowrap;
93 |
94 | // States
95 | &:hover,
96 | &.--hovered {
97 | border-color: $button-hover-border-color;
98 | color: $button-hover-color;
99 | transition: all 200ms ease-in 0s;
100 | }
101 |
102 | &:focus,
103 | &.--focused {
104 | border-color: $button-focus-border-color;
105 | color: $button-focus-color;
106 | }
107 |
108 | &:active,
109 | &.--active {
110 | border-color: $button-focus-border-color;
111 | color: $button-focus-color;
112 | }
113 |
114 | // Sizes
115 | &.--small {
116 | @include button-small;
117 | }
118 |
119 | &.--medium {
120 | @include button-medium;
121 | }
122 |
123 | &.--large {
124 | @include button-large;
125 | }
126 |
127 | &.--fill {
128 | background-color: map-get($colors, green);
129 | color: map-get($colors, white);
130 | border-color: map-get($colors, green);
131 |
132 | & .icon {
133 | fill: map-get($colors, white);
134 | }
135 | }
136 |
137 | &-icon {
138 | border-color: map-get($colors, grey-light);
139 |
140 | .icon {
141 | margin: 0;
142 | }
143 |
144 | &:hover {
145 | border-color: $secondary;
146 |
147 | .icon {
148 | fill: $secondary;
149 | }
150 | }
151 | }
152 | }
153 |
154 | #{$namespace-button}__group {
155 | margin: 0 5px;
156 | }
157 |
158 | .s-section__meta .button-icon {
159 | .icon {
160 | margin: 0 !important;
161 | vertical-align: top;
162 | fill: map-get($colors, grey-light);
163 | }
164 |
165 | &:hover {
166 | .icon {
167 | fill: $button-hover-border-color;
168 | }
169 | }
170 |
171 | &.is-active {
172 | border-color: $secondary;
173 |
174 | svg {
175 | fill: $secondary;
176 | }
177 | }
178 | }
179 |
180 | button.filter-active {
181 | border: 2px $primary solid;
182 | color: $primary;
183 | }
184 |
185 |
186 |
187 |
--------------------------------------------------------------------------------
/src/styles/components/_c-checklist.scss:
--------------------------------------------------------------------------------
1 | @if $use-checklist == true {
2 |
3 | // Variables
4 | // =============================================================================
5 | $checklist-background-color: map-get($colors, white) !default;
6 | $checklist-box-shadow: null !default;
7 |
8 | // Declarations
9 | // =============================================================================
10 | #{$namespace-checklist} {
11 | & [data-item-visible='false'] {
12 | display: none;
13 | }
14 |
15 | &__list {
16 | margin: 0;
17 | padding: 0;
18 | list-style: none;
19 | }
20 |
21 | &__column {
22 | // padding: 8px 4px;
23 | padding: 0 0 10px;
24 |
25 | @include mq('handheld') {
26 | padding: 2px;
27 | }
28 |
29 | @include mq('handheld-and-up') {
30 | padding: 8px 4px;
31 | }
32 |
33 | @include mq('print') {
34 | padding: 0;
35 | }
36 |
37 | // Priority bullet
38 | &:nth-child(1) {
39 | padding-top: 12px;
40 |
41 | @include mq('handheld-and-up') {
42 | padding-top: 15px;
43 | }
44 |
45 | @include mq('print') {
46 | margin: 0 5px;
47 | padding-top: 5px;
48 | }
49 | }
50 |
51 | // Checkboxe
52 | &:nth-child(2) {
53 | padding-top: 11px;
54 |
55 | @include mq('handheld') {
56 | padding-top: 11px;
57 | }
58 | }
59 | }
60 |
61 | &__intro {
62 | font-size: 1.4rem;
63 | }
64 |
65 | &__body {
66 | display: flex;
67 | flex-flow: row nowrap;
68 | justify-content: space-between;
69 | align-items: stretch;
70 | flex: 1;
71 |
72 | label {
73 | font-weight: 400;
74 | line-height: 1;
75 | position: relative;
76 | display: block;
77 |
78 | @include mq('handheld-and-up') {
79 | font-size: 1.6rem;
80 | line-height: 1.4;
81 | }
82 |
83 | &::before {
84 | border-color: #bdc3c7;
85 | }
86 | }
87 |
88 | input {
89 | position: absolute;
90 | left: 0;
91 | top: 0;
92 | min-width: 15px;
93 | width: 100%;
94 | height: 100%;
95 | z-index: 2;
96 | opacity: 0;
97 | margin: 0;
98 | padding: 0;
99 | cursor: pointer;
100 | }
101 | }
102 |
103 | .label__title,
104 | .label__description {
105 | font-size: 1.3rem;
106 |
107 | @include mq('handheld-and-up') {
108 | font-size: 1.5rem;
109 | }
110 | }
111 |
112 | &__item {
113 | opacity: 1;
114 | height: auto;
115 | transition-timing-function: ease-in;
116 | font-size: 24px;
117 | line-height: 31px;
118 | display: block;
119 | background-color: $checklist-background-color;
120 | box-shadow: $checklist-box-shadow;
121 | overflow: hidden;
122 | width: 100%;
123 | position: relative;
124 |
125 | @include mq('print') {
126 | padding: 5px 0;
127 | }
128 |
129 | &::before {
130 | content: '';
131 | position: absolute;
132 | border-top: 1px solid #e4ebf0;
133 | width: 100%;
134 | }
135 |
136 | &__inner {
137 | display: flex;
138 | }
139 |
140 | &:nth-child(even) {
141 | background: #f8f7f6;
142 | }
143 |
144 | &:hover {
145 | background-color: rgb(241, 240, 237);
146 | }
147 | }
148 |
149 | &__priority {
150 | order: 1;
151 | flex-basis: 1%;
152 | }
153 |
154 | &__checkbox {
155 | order: 2;
156 | flex-basis: 30px;
157 | position: relative;
158 | display: flex;
159 | align-items: center;
160 | justify-content: center;
161 |
162 | @include mq('print') {
163 | flex-basis: 25px;
164 | }
165 |
166 | @include mq('handheld-and-up') {
167 | flex-basis: 40px;
168 | }
169 | }
170 |
171 | &__label {
172 | order: 3;
173 | flex: 1;
174 | }
175 |
176 | &__dropdown {
177 | order: 4;
178 | flex-basis: 35px;
179 | position: relative;
180 | background-color: #f1f0ed;
181 |
182 | @include mq('desk') {
183 | flex-basis: 3%;
184 | }
185 |
186 | &__button {
187 | position: absolute;
188 | left: 0;
189 | top: 0;
190 | min-width: 15px;
191 | width: 100%;
192 | height: 100%;
193 | z-index: 999;
194 | margin: 0;
195 | padding: 0;
196 | cursor: pointer;
197 | border: 0;
198 | background-color: transparent;
199 | display: flex;
200 | }
201 |
202 | [data-item-check='true'] & {
203 | cursor: not-allowed;
204 | }
205 | }
206 | }
207 | }
208 |
209 | #{$namespace-checklist} {
210 | &__introduction {
211 | font-size: 1.5rem;
212 | margin-top: 0;
213 | }
214 |
215 | &__details {
216 | padding: 10px 10px 0;
217 |
218 | @include mq('handheld-and-up') {
219 | padding: 15px 15px 0;
220 | width: 100%;
221 | }
222 |
223 | &[aria-expanded='false'] {
224 | overflow: hidden;
225 | max-height: 0;
226 | padding-top: 0;
227 | padding-bottom: 0;
228 | margin-top: 0;
229 | margin-bottom: 0;
230 | transition-duration: .3s;
231 | transition-timing-function: cubic-bezier(0, 1, .5, 1);
232 | opacity: 0;
233 | }
234 |
235 | &[aria-expanded='true'] {
236 | transition-duration: .3s;
237 | transition-timing-function: ease-in;
238 | max-height: 1000px;
239 | overflow: hidden;
240 | opacity: 1;
241 | }
242 |
243 | [data-item-check='true'] & {
244 | opacity: .3;
245 | }
246 | }
247 |
248 | &__text {
249 | font-size: 1.4rem;
250 | line-height: 1.5;
251 | margin-top: 0;
252 | }
253 |
254 | &__code {
255 | // TODO: fix the Github Iframe
256 | display: none;
257 |
258 | @include mq('desk') {
259 | display: block;
260 | border: 1px solid #cccccc;
261 | background-color: white;
262 | }
263 |
264 | @include mq('print') {
265 | display: block;
266 | }
267 |
268 | &__loader {
269 | padding: 10px 0;
270 | display: block;
271 | width: 50px;
272 | height: 50px;
273 | margin: 0 auto;
274 | }
275 | }
276 |
277 | &__favicon {
278 | margin-right: 5px;
279 | width: 14px;
280 | height: 14px;
281 | display: inline;
282 |
283 | &[data-src] {
284 | display: none;
285 | }
286 |
287 | .no-js & {
288 | display: none;
289 | }
290 | }
291 |
292 | .documentation__list {
293 | margin: 0;
294 | padding: 0 0 0 20px;
295 | list-style: circle;
296 |
297 | li {
298 | font-size: 1.2rem;
299 | line-height: 1.8;
300 |
301 | @include mq('handheld-and-up') {
302 | font-size: 1.5rem;
303 | line-height: 1.5;
304 | }
305 | }
306 | }
307 | }
308 |
309 | .c-checklist__documentation,
310 | .c-checklist__tools {
311 | padding: 0 0 5px;
312 | margin: 0;
313 | }
314 |
315 |
316 | [data-item-check='true'] label {
317 | text-decoration: line-through;
318 | opacity: .3;
319 | }
320 |
--------------------------------------------------------------------------------
/src/styles/components/_c-dropdown.scss:
--------------------------------------------------------------------------------
1 | @if $use-dropdown == true {
2 | [data-item-dropdown='open'] .c-checklist__details {
3 | display: block;
4 | }
5 |
6 | [data-item-dropdown='close'] .c-checklist__details {
7 | display: none;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/styles/components/_c-github.scss:
--------------------------------------------------------------------------------
1 | .github-corner:hover .octo-arm {
2 | animation: octocat-wave 560ms ease-in-out;
3 | }
4 |
5 | .github-corner {
6 | svg {
7 | fill: white;
8 | color: #151513;
9 | position: absolute;
10 | top: 0;
11 | border: 0;
12 | right: 0;
13 | }
14 |
15 | .octo-arm {
16 | transform-origin: 130px 106px;
17 | }
18 | }
19 |
20 | @keyframes octocat-wave {
21 | 0%,
22 | 100% {
23 | transform: rotate(0);
24 | }
25 |
26 | 20%,
27 | 60% {
28 | transform: rotate(-25deg);
29 | }
30 |
31 | 40%,
32 | 80% {
33 | transform: rotate(10deg);
34 | }
35 | }
36 |
37 | @media (max-width: 500px) {
38 | .github-corner:hover .octo-arm {
39 | animation: none;
40 | }
41 |
42 | .github-corner .octo-arm {
43 | animation: octocat-wave 560ms ease-in-out;
44 | }
45 | }
46 |
47 |
48 | .gist {
49 | display: block !important;
50 | position: relative !important;
51 | margin: 0 !important;
52 | width: calc(100%) !important; /* Fill 100% of the parent container with an extra 30px on each side */
53 | overflow: hidden !important;
54 | }
55 |
56 | .gist-file {
57 | margin: 0 !important;
58 | border: none !important;
59 | }
60 |
61 | .gist-data {
62 | padding: 5px !important;
63 | border: 0 !important;
64 | border-bottom: none !important;
65 | border-radius: 0;
66 | }
67 |
68 | .gist .gist-meta {
69 | color: map-get($colors, black) !important;
70 | border: 0 !important;
71 | border-radius: 0;
72 | padding: 3px !important;
73 | font-size: 8px !important;
74 |
75 | @include mq('handheld-and-up') {
76 | font-size: 10px !important;
77 | padding: 5px !important;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/styles/components/_c-list.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Lists
3 | //
4 |
5 |
6 | // Variables
7 | // =============================================================================
8 | $list-margin: 0 !default;
9 | $list-padding: 0 0 0 $spacing-medium !default;
10 | $list-unstyled-padding: 0 !default;
11 | $list-unstyled-list-style: none !default;
12 | $list-nested-padding: $list-padding !default;
13 | $list-item-padding: 0 !default;
14 | $list-item-unstyled-list-style: none !default;
15 | $list-ordered-item-padding: 0 $spacing-small 0 0 !default;
16 | $list-inline-padding: 0 !default;
17 | $list-inline-item-padding-right: $spacing-medium !default;
18 | $list-inline-item-bullet-content: '\2022' !default;
19 | $list-inline-item-bullet-padding: 0 $spacing-small 0 0 !default;
20 |
21 | @mixin list--unstyled {
22 | padding: $list-unstyled-padding;
23 | list-style: $list-unstyled-list-style;
24 | }
25 |
26 | @mixin list--inline {
27 | padding: $list-inline-padding;
28 | }
29 |
30 | // Declarations
31 | // =============================================================================
32 | #{$namespace-list} {
33 | display: block;
34 | margin: $list-margin;
35 | padding: $list-padding;
36 | list-style-position: outside;
37 |
38 | & .c-list {
39 | padding: $list-nested-padding;
40 | }
41 |
42 | &__item {
43 | padding: $list-item-padding;
44 | }
45 |
46 | &__item--unstyled {
47 | list-style: $list-item-unstyled-list-style;
48 | }
49 |
50 | &--unstyled {
51 | @include list--unstyled;
52 | }
53 |
54 | &--ordered {
55 | @include list--unstyled;
56 |
57 | counter-reset: ordered;
58 |
59 | .c-list__item {
60 | &::before {
61 | padding: $list-ordered-item-padding;
62 | content: counters(ordered, '.') ' ';
63 | counter-increment: ordered;
64 | }
65 | }
66 | }
67 |
68 | // &--inline {
69 | // @include list--inline;
70 |
71 | // .c-list--inline {
72 | // @include list--inline;
73 | // }
74 |
75 | // .c-list__item {
76 | // display: inline-block;
77 | // width: auto;
78 | // padding-right: $list-inline-item-padding-right;
79 | // }
80 |
81 | // &:not(.c-list--unstyled) {
82 | // .c-list__item {
83 | // &::before {
84 | // padding: $list-inline-item-bullet-padding;
85 | // content: $list-inline-item-bullet-content;
86 | // }
87 | // }
88 | // }
89 | // }
90 | }
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/src/styles/components/_c-nav.scss:
--------------------------------------------------------------------------------
1 | @if $use-nav == true {
2 |
3 | // Variables
4 | // =============================================================================
5 | $nav-height: 64px;
6 | $nav-background: map-get($colors, white);
7 | $nav-border: #dddddd;
8 | $nav-collapse-breakpoint: 768px;
9 | $nav-item-font-size: 14px;
10 | $nav-item-border-width: 4px;
11 | $nav-item-color: #555555;
12 | $nav-item-active-color: #333333;
13 | $nav-item-border: transparent;
14 | $nav-item-active-border: $primary;
15 |
16 | // Declarations
17 | // =============================================================================
18 | #{$namespace-nav} {
19 | display: flex;
20 | align-items: flex-start;
21 | justify-content: space-between;
22 | margin-top: 15px;
23 |
24 | @include mq(lap-and-up) {
25 | display: flex;
26 | margin: 15px 0;
27 | }
28 |
29 | &--inline {
30 | flex-direction: row;
31 | }
32 |
33 | &__inner {
34 | display: flex;
35 | align-content: center;
36 | justify-content: center;
37 | flex-direction: column;
38 | }
39 |
40 | &__list {
41 | width: 100%;
42 | margin: 0;
43 | padding: 0;
44 | flex-wrap: wrap;
45 | display: flex;
46 |
47 | @include mq(lap-and-up) {
48 | display: flex;
49 | flex-wrap: wrap;
50 | }
51 | }
52 |
53 | &__item {
54 | margin: 0 10px 10px 0;
55 |
56 | @include mq(lap-and-up) {
57 | margin: 0 5px 5px 0;
58 | }
59 | }
60 |
61 | &__status {
62 | padding-left: 3px;
63 | margin-right: 7px;
64 | }
65 |
66 | &__sidebar {
67 | position: absolute;
68 | right: -10px;
69 | // animation: navShow 1s normal;
70 | // z-index: -1;
71 |
72 | .c-nav__list {
73 | position: fixed;
74 | top: 50px;
75 | flex-direction: column;
76 | width: auto;
77 | will-change: transform;
78 | }
79 |
80 | .c-button {
81 | text-align: left;
82 | }
83 | }
84 |
85 | &__item a,
86 | &__item button {
87 | display: block;
88 | text-transform: uppercase;
89 | color: map-get($colors, black);
90 | padding: 5px 10px;
91 | font-size: 1.3rem;
92 | border: 1px solid #cccccc;
93 |
94 | @include mq('handheld-and-up') {
95 | font-size: 14px;
96 | }
97 |
98 | &:hover {
99 | text-decoration: none;
100 | font-weight: $weight-normal;
101 | border: 1px solid $nav-item-active-border;
102 | }
103 | }
104 | }
105 | }
106 |
107 |
108 | @keyframes navShow {
109 | 0% {
110 | right: 150px;
111 | opacity: 0;
112 | }
113 |
114 | 80% {
115 | opacity: .2;
116 | }
117 |
118 | 100% {
119 | right: -10px;
120 | z-index: 9;
121 | opacity: 1;
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/src/styles/components/_c-notation.scss:
--------------------------------------------------------------------------------
1 | .c-notation__details__list {
2 | margin: 0;
3 | padding: 5px 0;
4 | text-align: left;
5 | }
6 |
7 | .c-notation__details__item {
8 | font-size: 1.3rem;
9 |
10 | .icon {
11 | display: inline-block;
12 | margin-right: 5px;
13 | }
14 | }
15 |
16 | // Declarations
17 | // =============================================================================
18 | .c-notation {
19 | display: flex;
20 | align-content: space-between;
21 | justify-content: space-between;
22 | margin: 15px 0 0;
23 |
24 | &__box {
25 | position: relative;
26 | }
27 |
28 | &__letter {
29 | position: absolute;
30 | top: 50%;
31 | left: 50%;
32 | transform: translate(-50%, -50%);
33 | text-align: center;
34 | font-size: 45px;
35 | color: white;
36 | line-height: 1;
37 | }
38 |
39 | &__item {
40 | width: 75px;
41 | height: 75px;
42 | background: #f3f3f3;
43 | position: relative;
44 | }
45 |
46 | &__generate {
47 | text-align: right;
48 | margin-top: 15px;
49 | }
50 |
51 | &__details {
52 | font-size: 1.2rem;
53 | }
54 | }
55 | $notation: -1;
56 |
57 | @while $notation <= 100 {
58 | $notation: $notation + 1;
59 |
60 | [data-notation='#{$notation}'] {
61 | @if $notation <= 20 {
62 | background-color: $progress-0;
63 | }
64 |
65 | @else if $notation <= 40 {
66 | background-color: $progress-20;
67 | }
68 |
69 | @else if $notation <= 60 {
70 | background-color: $progress-40;
71 | }
72 |
73 | @else if $notation <= 80 {
74 | background-color: $progress-60;
75 | }
76 |
77 | @else if $notation < 100 {
78 | background-color: $progress-80;
79 | }
80 |
81 | @else if $notation == 100 {
82 | background-color: $progress-100;
83 | }
84 |
85 | @else {
86 | background-color: $progress-0;
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/styles/components/_c-progress.scss:
--------------------------------------------------------------------------------
1 | @if $use-progress == true {
2 |
3 | $i: 0;
4 |
5 | #{$namespace-progress} {
6 | position: relative;
7 | display: flex;
8 | padding: 10px 0;
9 |
10 | @include mq('handheld-and-up') {
11 | padding: 0;
12 | display: block;
13 | }
14 |
15 | &__counter {
16 | text-align: center;
17 | margin-left: 20px;
18 |
19 | @include mq('handheld-and-up') {
20 | margin: 0;
21 | }
22 | }
23 |
24 | &__label {
25 | font-size: 1.3rem;
26 | font-weight: 600;
27 |
28 | @include mq('handheld-and-up') {
29 | position: absolute;
30 | top: 28%;
31 | left: 50%;
32 | transform: translate(-50%, -50%);
33 | }
34 | }
35 |
36 | &__text {
37 | font-size: 1.3rem;
38 |
39 | @include mq('handheld-and-up') {
40 | font-size: 1.1rem;
41 | padding: 0 5px;
42 | }
43 | }
44 | }
45 |
46 | .c-progress__bar {
47 | background-color: map-get($shades, white-ter);
48 | border: 0;
49 | height: 19px;
50 | border-radius: 3px;
51 | width: 120px;
52 |
53 | @include mq('handheld-and-up') {
54 | height: 20px;
55 | margin: 0 20px;
56 | }
57 |
58 | .c-progress--big & {
59 | height: 30px;
60 | width: 150px;
61 | }
62 |
63 | &::-webkit-progress-value {
64 | border-radius: 2px;
65 | }
66 |
67 | @while $i < 100 {
68 | $i: $i + 1;
69 | $hue: round((65 / 100) * $i);
70 |
71 | &[value='#{$i}'] {
72 | &::-webkit-progress-value {
73 | background-color: adjust-hue($progress-20, $hue);
74 | }
75 | }
76 | }
77 |
78 | &::-webkit-progress-bar {
79 | background-color: map-get($shades, white-ter);
80 | transition: all 300ms ease-in 0s;
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/styles/components/_c-tags.scss:
--------------------------------------------------------------------------------
1 | .c-tags {
2 | &__list {
3 | padding: 0;
4 | list-style: none;
5 | position: relative;
6 | opacity: .7;
7 |
8 | [data-item-check='true'] & {
9 | opacity: .2;
10 | }
11 | }
12 |
13 | &__item {
14 | font-size: 1rem;
15 | display: inline;
16 | padding: 3px;
17 | white-space: nowrap;
18 | opacity: 1;
19 | overflow: hidden;
20 | border: .5px solid $border;
21 |
22 | @include mq('handheld-and-up') {
23 | font-size: 11px;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/styles/components/_c-tools.scss:
--------------------------------------------------------------------------------
1 | .c-tools {
2 | display: flex;
3 |
4 | @include mq('print') {
5 | display: none;
6 | }
7 |
8 | .is-active {
9 | border-color: #415257;
10 | }
11 |
12 | .c-button__group:first-child {
13 | margin-left: 0;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/styles/components/_c-top-alert.scss:
--------------------------------------------------------------------------------
1 | @if $use-top-alert == true {
2 | #{$namespace-top-alert} {
3 | display: none;
4 |
5 | .no-js & {
6 | &--alert {
7 | min-height: 35px;
8 | background: orange;
9 | width: 100%;
10 | text-align: center;
11 | font-weight: bold;
12 | color: white;
13 | font-size: 1.3rem;
14 | padding: 5px 0;
15 |
16 | p {
17 | margin: 0;
18 | }
19 | }
20 | }
21 | }
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/src/styles/config/_v-colors.scss:
--------------------------------------------------------------------------------
1 | // Colors
2 | $colors: (
3 | black: hsl(0, 0%, 4%),
4 | black-bis: hsl(0, 0%, 7%),
5 | black-ter: hsl(0, 0%, 14%),
6 | grey-darker: hsl(0, 0%, 21%),
7 | grey-dark: #212529,
8 | grey: hsl(0, 0%, 48%),
9 | grey-light: hsl(0, 0%, 71%),
10 | grey-lighter: hsl(0, 0%, 86%),
11 | white-ter: hsl(0, 0%, 96%),
12 | white-bis: hsl(0, 0%, 98%),
13 | white: hsl(0, 0%, 100%),
14 | orange: #d75637,
15 | yellow: hsl(48, 100%, 67%),
16 | green: hsl(141, 71%, 48%),
17 | blue: #415257,
18 | red: red
19 | );
20 |
21 | // :root {
22 | // // each item in color map
23 | // @each $name, $color in $colors {
24 | // --color-#{$name}: $color;
25 | // }
26 | // }
27 |
28 | // Lists and maps
29 | $colors: ('white': ($white, $black), 'black': ($black, $white), 'light': ($light, $light-invert), 'dark': ($dark, $dark-invert), 'primary': ($primary, $primary-invert), 'info': ($info, $info-invert), 'success': ($success, $success-invert), 'warning': ($warning, $warning-invert), 'danger': ($danger, $danger-invert)) !default;
30 |
31 | $shades: ('black-bis': map-get($colors, black-bis), 'black-ter': map-get($colors, black-ter), 'grey-darker': map-get($colors, grey-darker), 'grey-dark': map-get($colors, grey-dark), 'grey': map-get($colors, grey), 'grey-light': map-get($colors, grey-light), 'grey-lighter': map-get($colors, grey-lighter), 'white-ter': map-get($colors, white-ter), 'white-bis': map-get($colors, white-bis)) !default;
32 |
33 | $primary: map-get($colors, orange) !default;
34 | $secondary: map-get($colors, blue) !default;
35 |
36 | $info: map-get($colors, blue) !default;
37 | $success: map-get($colors, green) !default;
38 | $warning: map-get($colors, yellow) !default;
39 | $danger: map-get($colors, red) !default;
40 | $light: map-get($colors, white-ter) !default;
41 | $dark: map-get($colors, grey-darker) !default;
42 | $background: map-get($colors, white-ter) !default;
43 | $border: map-get($colors, grey-lighter) !default;
44 | $border-hover: map-get($colors, grey-light) !default;
45 |
46 | $color-tint: 9 !default;
47 | $color-tint-dark: $color-tint !default;
48 | $color-tint-darker: $color-tint * 2 !default;
49 | $color-tint-light: $color-tint !default;
50 | $color-tint-lighter: $color-tint * 2 !default;
51 |
52 |
53 | $progress-0: #6f2110;
54 | $progress-20: #f63a0f;
55 | $progress-40: #f27011;
56 | $progress-60: #f2b01e;
57 | $progress-80: #f2d31b;
58 | $progress-100: #86e01e;
59 |
--------------------------------------------------------------------------------
/src/styles/config/_v-namespaces.scss:
--------------------------------------------------------------------------------
1 |
2 | //
3 | $use-top-alert: true !default;
4 | $use-button: true !default;
5 | $use-checklist: true !default;
6 | $use-dropdown: true !default;
7 | $use-list: true !default;
8 | $use-modal: true !default;
9 | $use-nav: true !default;
10 | $use-progress: true !default;
11 | $use-tooltip: true !default;
12 | $use-aside: true !default;
13 |
14 | // Components
15 | $namespace-top-alert: '.c-top-alert' !default;
16 | $namespace-button: '.c-button' !default;
17 | $namespace-checklist: '.c-checklist' !default;
18 | $namespace-dropdown: '.c-dropdown' !default;
19 | $namespace-list: '.c-list' !default;
20 | $namespace-modal: '.c-modal' !default;
21 | $namespace-nav: '.c-nav' !default;
22 | $namespace-progress: '.c-progress' !default;
23 | $namespace-tooltip: '.c-tooltip' !default;
24 | $namespace-aside: '.c-tag-filter' !default;
25 |
--------------------------------------------------------------------------------
/src/styles/config/_v-typography.scss:
--------------------------------------------------------------------------------
1 |
2 | $text: map-get($colors, grey-dark) !default;
3 | $text-light: map-get($colors, grey) !default;
4 | $text-strong: map-get($colors, grey-darker) !default;
5 |
6 | // Typography
7 | $family-sans-serif: BlinkMacSystemFont, -apple-system, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif !default;
8 | $family-monospace: monospace !default;
9 | $render-mode: optimizeLegibility !default;
10 | $family-primary: $family-sans-serif !default;
11 | $family-code: $family-monospace !default;
12 | $weight-light: 300 !default;
13 | $weight-normal: 400 !default;
14 | $weight-semibold: 500 !default;
15 | $weight-bold: 700 !default;
16 | $size-1: 3rem !default;
17 | $size-2: 2.5rem !default;
18 | $size-3: 2rem !default;
19 | $size-4: 1.5rem !default;
20 | $size-5: 1.25rem !default;
21 | $size-6: 1rem !default;
22 | $size-7: .75rem !default;
23 | $size-small: $size-7 !default;
24 | $size-normal: $size-6 !default;
25 | $size-medium: $size-5 !default;
26 | $size-large: $size-4 !default;
27 | $sizes: $size-1 $size-2 $size-3 $size-4 $size-5 $size-6 $size-7 !default;
28 |
--------------------------------------------------------------------------------
/src/styles/config/_variables.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Spacing
3 | //
4 | $spacing-super: 24px !default;
5 | $spacing-xlarge: 18px !default;
6 | $spacing-large: 16px !default;
7 | $spacing-medium: 14px !default;
8 | $spacing-small: .7px !default;
9 | $spacing-xsmall: 3px !default;
10 | $spacing-tiny: 1px !default;
11 |
--------------------------------------------------------------------------------
/src/styles/layout/_page.scss:
--------------------------------------------------------------------------------
1 | $layout-width: '1140px' !default;
2 | $av-element-class-chain: '__' !default; // Chain characters between block and element
3 | $av-modifier-class-chain: '--' !default; // Chain characters between block and modifier
4 | $av-breakpoint-class-chain: '--' !default; // Chain characters between width and breakpoint
5 | $logo-width: 150px;
6 |
7 | .page-wrapper {
8 | display: grid;
9 | grid-template-columns: auto;
10 | grid-template-areas:
11 | 'header'
12 | 'main'
13 | 'footer';
14 |
15 | @include mq('lap-and-up') {
16 | grid-template-areas: 'header header header' 'main main main' 'footer footer footer';
17 | }
18 |
19 | .page-header {
20 | grid-area: header;
21 | }
22 |
23 | .page-main {
24 | grid-area: main;
25 |
26 | @include mq('lap-and-up') {
27 | display: grid;
28 | grid-template-columns: auto 150px 960px 150px auto;
29 | }
30 | }
31 |
32 | .page-footer {
33 | grid-area: footer;
34 | }
35 | }
36 |
37 |
38 | .page-header {
39 | &__logo {
40 | grid-area: header-left;
41 | align-self: center;
42 |
43 | .page-header__inner--centered & {
44 | grid-area: header-center;
45 | justify-self: center;
46 | }
47 | }
48 |
49 | &__nav {
50 | grid-area: header-right;
51 | align-self: center;
52 | display: flex;
53 |
54 | & .version-01 {
55 | grid-column-start: 3;
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/styles/layout/_s-aside.scss:
--------------------------------------------------------------------------------
1 | .s-aside {
2 | position: fixed;
3 | transform: translateX(960px);
4 | text-align: left;
5 | margin-top: 55px;
6 | font-size: 1.5rem;
7 | top: 300px;
8 |
9 | ul {
10 | margin: 0;
11 | padding: 0;
12 | }
13 | }
14 |
15 | @if $use-aside == true {
16 |
17 | // Variables
18 | // =============================================================================
19 | $aside-height: 64px;
20 | $aside-background: #f8f7f6;
21 | $aside-border: #dddddd;
22 | $aside-collapse-breakpoint: 768px;
23 | $aside-item-font-size: 14px;
24 | $aside-item-border-width: 4px;
25 | $aside-item-color: #555555;
26 | $aside-item-active-color: #333333;
27 | $aside-item-border: transparent;
28 | $aside-item-active-border: #673ab7;
29 |
30 | // Declarations
31 | // =============================================================================
32 | #{$namespace-aside} {
33 | display: flex;
34 | align-items: center;
35 | justify-content: space-between;
36 | align-self: center;
37 | flex-flow: wrap row;
38 |
39 | @include mq('print') {
40 | display: none;
41 | }
42 |
43 | @include mq(lap-and-up) {
44 | display: flex;
45 | flex-direction: row;
46 | }
47 |
48 | &__title {
49 | font-size: 1.2rem;
50 | font-weight: 700;
51 |
52 | @include mq('handheld-and-up') {
53 | font-size: 1.3rem;
54 | }
55 | }
56 |
57 | &__inner {
58 | display: flex;
59 | align-content: center;
60 | justify-content: center;
61 | flex-direction: column;
62 | }
63 |
64 | &__list {
65 | flex-direction: row;
66 | width: 100%;
67 | margin: 0;
68 | padding: 10px;
69 | background-color: $aside-background;
70 |
71 | @include mq(lap-and-up) {
72 | display: flex;
73 | flex-wrap: wrap;
74 | }
75 | }
76 |
77 | &__item {
78 | display: inline-block;
79 | }
80 |
81 | &__item a,
82 | &__item button {
83 | display: block;
84 | text-transform: uppercase;
85 | font-size: 1.3rem;
86 | line-height: 1;
87 | color: map-get($colors, black-bis);
88 | padding: 5px 10px;
89 | border: 2px solid transparent;
90 | background-color: transparent;
91 |
92 | &:hover {
93 | text-decoration: none;
94 | font-weight: $weight-normal;
95 | border: 2px solid #dbdbdb;
96 | }
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/styles/layout/_s-checklist.scss:
--------------------------------------------------------------------------------
1 | .s-checklist {
2 | position: relative;
3 | min-height: 1px;
4 |
5 | @include mq('handheld-and-up') {
6 | padding: 0 10px;
7 | }
8 |
9 | @include mq('print') {
10 | padding: 15px 0;
11 |
12 | &:first-child {
13 | padding: 0 0 15px;
14 | }
15 | }
16 |
17 | &::after {
18 | content: '';
19 | position: absolute;
20 | height: 2px;
21 | border-top: 1px solid #e4ebf0;
22 | bottom: 0;
23 | width: 98%;
24 | }
25 |
26 | &__inner {
27 | display: grid;
28 | }
29 |
30 | &__body {
31 | padding: 0;
32 |
33 | .introduction {
34 | text-align: center;
35 | }
36 |
37 | .slide {
38 | display: grid;
39 | }
40 | }
41 |
42 | &__header {
43 | padding: 15px 0;
44 | z-index: 58;
45 |
46 | @include mq('print') {
47 | padding: 0;
48 | }
49 |
50 | @include mq('handheld-and-up') {
51 | display: flex;
52 | align-items: center;
53 | justify-content: space-between;
54 | }
55 | }
56 |
57 | &__title {
58 | @include mq('print') {
59 | display: flex;
60 | }
61 |
62 | @include mq('handheld-and-up') {
63 | display: flex;
64 | align-items: center;
65 | justify-content: center;
66 | }
67 | }
68 |
69 | &__header__title {
70 | margin: 0;
71 | text-align: left;
72 | color: rgb(65, 82, 87);
73 | font-weight: bold;
74 | text-transform: uppercase;
75 | line-height: 1.2;
76 | font-size: 2.5rem;
77 |
78 | @include mq('handheld-and-up') {
79 | font-size: 4rem;
80 | margin: 0;
81 | }
82 | }
83 |
84 | &__progress {
85 | display: flex;
86 | }
87 |
88 | &__footer {
89 | text-align: center;
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/styles/layout/_s-footer.scss:
--------------------------------------------------------------------------------
1 | .s-footer {
2 | display: grid;
3 | text-align: center;
4 | padding: 20px;
5 |
6 | @include mq(lap-and-up) {
7 | padding: 50px 0;
8 | }
9 |
10 | @include mq('print') {
11 | padding: 10px;
12 | }
13 |
14 | &__badges {
15 | @include mq('print') {
16 | display: none;
17 | }
18 | }
19 |
20 | &__grateful {
21 | @include mq('print') {
22 | display: none;
23 | }
24 | }
25 |
26 | &__made {
27 | font-size: 1.4rem;
28 |
29 | @include mq('print') {
30 | font-size: 7pt;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/styles/layout/_s-header.scss:
--------------------------------------------------------------------------------
1 | .sub-heading {
2 | margin: 5px 15px;
3 | font-family: Montserrat, sans-serif;
4 | color: hsla(0, 0%, 100%, .6);
5 | font-size: 1.3rem;
6 | line-height: 1.5;
7 |
8 | @include mq('handheld-and-up') {
9 | font-size: 1.5rem;
10 | margin: 15px;
11 | }
12 | }
13 |
14 | .s-header {
15 | grid-row: 1;
16 | grid-column-start: 2;
17 | padding: 15px 0;
18 | background-color: #415257;
19 | background-image: linear-gradient(45deg, #415257, #292e49);
20 | color: map-get($colors, white);
21 | font-size: 1rem;
22 | text-align: center;
23 | position: relative;
24 |
25 | @include mq('handheld-and-up') {
26 | padding-top: 25px;
27 | padding-bottom: 60px;
28 | }
29 |
30 | @include mq('print') {
31 | padding: 0;
32 | }
33 |
34 | &__banner {
35 | @include mq('handheld-and-up') {
36 | width: 795px;
37 | margin: 0 auto;
38 | }
39 | }
40 |
41 | &__media__list {
42 | display: flex;
43 | align-items: flex-start;
44 | justify-content: center;
45 | align-self: center;
46 | padding: 0;
47 | }
48 |
49 | &__media__item {
50 | margin: 0 5px;
51 | }
52 |
53 | &__checklist {
54 | display: grid;
55 | grid-template-columns: auto;
56 |
57 | @include mq('print') {
58 | margin: 0;
59 | }
60 |
61 | @include mq('handheld-and-up') {
62 | grid-template-rows: auto auto;
63 | grid-template-columns: repeat(5, 1fr);
64 | padding: 10px;
65 | border: 1px solid lightgray;
66 | }
67 |
68 | &__title {
69 | display: none;
70 | }
71 |
72 | &__el {
73 | display: grid;
74 |
75 | @include mq('handheld-and-up') {
76 | padding: 0 20px 0 0;
77 | }
78 | }
79 | // Form
80 | &__el:nth-child(2) {
81 | grid-column: 6;
82 | grid-row: 1 / 2;
83 |
84 | @include mq('print') {
85 | grid-column: 1 / 4;
86 | grid-row: 1;
87 | }
88 |
89 | @include mq('handheld') {
90 | grid-column: 1 / 4;
91 | grid-row: 1 / 2;
92 | }
93 |
94 | @include mq('lap-and-up') {
95 | grid-column: 1 / 2;
96 | grid-row: 1 / 1;
97 | }
98 | }
99 | // Nav
100 | &__el:nth-child(3) {
101 | grid-column: 6;
102 | grid-row: 3 / 4;
103 |
104 | @include mq('print') {
105 | display: none;
106 | }
107 |
108 | @include mq('handheld') {
109 | grid-column: 1 / 6;
110 | grid-row: 2 / 2;
111 | }
112 |
113 | @include mq('lap-and-up') {
114 | grid-column: 2 / 4;
115 | grid-row: 1 / 1;
116 | }
117 | }
118 | // Notation
119 | &__el:nth-child(4) {
120 | grid-column: 6;
121 | grid-row: 2 / 3;
122 |
123 | @include mq('print') {
124 | grid-column: 5 / 6;
125 | grid-row: 1;
126 | }
127 |
128 | @include mq('handheld') {
129 | grid-column: 4 / 6;
130 | grid-row: 1 / 2;
131 | }
132 |
133 | @include mq('lap-and-up') {
134 | grid-column: 4 / 6;
135 | grid-row: 1 / 1;
136 | padding-right: 0;
137 | }
138 | }
139 | }
140 |
141 | &__lang__list {
142 | display: flex;
143 | flex-direction: row;
144 | align-items: flex-start;
145 | align-self: center;
146 | justify-content: center;
147 | margin-top: 20px;
148 | }
149 |
150 | &__lang__item {
151 | margin: 0 5px;
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/src/styles/layout/_s-main.scss:
--------------------------------------------------------------------------------
1 | .s-main {
2 | display: grid;
3 | grid-column-start: 1;
4 | position: relative;
5 | background-color: map-get($colors, white);
6 | text-align: left;
7 | padding: 0 10px;
8 |
9 | &__section {
10 | margin: 0 0 10px;
11 | }
12 |
13 | @include mq('handheld-and-up') {
14 | display: grid;
15 | grid-column-start: 3;
16 | margin-top: -50px;
17 | width: 100%;
18 | padding: 10px;
19 | border-radius: 5px;
20 | border-color: rgba(0, 0, 0, .1);
21 | border-style: solid;
22 | border-width: 1px;
23 | }
24 |
25 | &__section:nth-child(1) {
26 | order: 2;
27 |
28 | @include mq('handheld-and-up') {
29 | padding: 0 20px;
30 | }
31 | }
32 |
33 | &__section:nth-child(2) {
34 | order: 4;
35 |
36 | @include mq('handheld-and-up') {
37 | padding: 0 20px;
38 | }
39 | }
40 |
41 | &__section:nth-child(3) {
42 | order: 4;
43 | }
44 |
45 | &__section:nth-child(4) {
46 | text-align: center;
47 | order: 5;
48 | }
49 |
50 | &__section:nth-child(5) {
51 | order: 1;
52 | }
53 |
54 | &__item {
55 | background: #ff6600;
56 | }
57 |
58 | &__header {
59 | text-align: center;
60 | z-index: 99999;
61 | }
62 |
63 | &__meta {
64 | display: none;
65 |
66 | @include mq('handheld-and-up') {
67 | display: flex;
68 | justify-content: flex-end;
69 | }
70 | }
71 | }
72 |
73 |
74 | .s-meta {
75 | text-align: left;
76 | }
77 |
--------------------------------------------------------------------------------
/src/styles/main.scss:
--------------------------------------------------------------------------------
1 | @charset 'utf-8';
2 |
3 | // Config and utilities
4 | @import 'config/variables';
5 | @import 'config/v-namespaces';
6 | @import 'config/v-colors';
7 | @import 'config/v-typography';
8 | @import 'utilities/functions/functions';
9 | @import 'utilities/mixins/mixins';
10 | @import 'utilities/utilities';
11 |
12 | // General styling using DOM element selectors
13 | @import 'base/print';
14 | @import 'base/fonts';
15 | @import 'base/icons';
16 | @import 'base/generic';
17 | @import 'base/headings';
18 | @import 'base/form';
19 | @import 'base/media';
20 | @import 'base/links';
21 | @import 'base/typography';
22 |
23 | // Layout
24 | @import 'layout/page';
25 | @import 'layout/s-header';
26 | @import 'layout/s-aside';
27 | @import 'layout/s-main';
28 | @import 'layout/s-checklist';
29 | @import 'layout/s-footer';
30 |
31 | // Components
32 | @import 'components/c-top-alert';
33 | @import 'components/c-button';
34 | @import 'components/c-checklist';
35 | @import 'components/c-dropdown';
36 | @import 'components/c-github';
37 | @import 'components/c-tools';
38 | @import 'components/c-list';
39 | @import 'components/c-nav';
40 | @import 'components/c-progress';
41 | @import 'components/c-notation';
42 | @import 'components/c-tags';
43 |
--------------------------------------------------------------------------------
/src/styles/utilities/_utilities.scss:
--------------------------------------------------------------------------------
1 |
2 | main [data-body-visibility='hide'] * {
3 | display: none;
4 | }
5 |
6 |
7 | [data-body-visbility='hide'] {
8 | display: none;
9 | }
10 |
11 |
--------------------------------------------------------------------------------
/src/styles/utilities/functions/_functions.scss:
--------------------------------------------------------------------------------
1 | // Function to choose colors in CSS variables
2 | @function color($color-name) {
3 | @return var(--color-#{$color-name});
4 | }
5 |
--------------------------------------------------------------------------------
/src/styles/utilities/mixins/_m-breakpoints.scss:
--------------------------------------------------------------------------------
1 | $av-breakpoints: (
2 | 'print': 'print', 'thumb': 'screen and (max-width: 499px)', 'handheld': 'screen and (min-width: 500px) and (max-width: 800px)', 'handheld-and-up': 'screen and (min-width: 500px)', 'pocket': 'screen and (max-width: 800px)', 'lap': 'screen and (min-width: 801px) and (max-width: 1024px)', 'lap-and-up': 'screen and (min-width: 801px)', 'portable': 'screen and (max-width: 1024px)', 'desk': 'screen and (min-width: 1025px)', 'widescreen': 'screen and (min-width: 1160px)', 'retina': 'screen and (-webkit-min-device-pixel-ratio: 2), screen and (min-resolution: 192dpi), screen and (min-resolution: 2dppx)') !default; // Responsive breakpoints.
3 |
4 | @mixin mq($alias) {
5 | // Search breakpoint map for alias
6 | $query: map-get($av-breakpoints, $alias);
7 | // If alias exists, print out media query
8 | @if $query {
9 | @media #{$query} {
10 | @content;
11 | }
12 | }
13 |
14 | @else {
15 | @error 'No breakpoint found for #{$alias}';
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/styles/utilities/mixins/_mixins.scss:
--------------------------------------------------------------------------------
1 | @import 'm-breakpoints';
2 |
3 | @mixin unselectable {
4 | -webkit-touch-callout: none;
5 | -webkit-user-select: none;
6 | -moz-user-select: none;
7 | -ms-user-select: none;
8 | user-select: none;
9 | }
10 |
11 | ol,
12 | ul {
13 | list-style: none;
14 | }
15 |
16 | .sr-only {
17 | display: none;
18 | }
19 |
--------------------------------------------------------------------------------
/src/views/base/after-scripts.pug:
--------------------------------------------------------------------------------
1 | script(src="/scripts/app.bundle.js" async)
2 | script.
3 |
4 | if ('serviceWorker' in navigator) {
5 | //- console.log('CLIENT: service worker registration in progress.');
6 | navigator.serviceWorker.register('/service-worker.js').then(function() {
7 | //- console.log('CLIENT: service worker registration complete.');
8 | }, function() {
9 | //- console.log('CLIENT: service worker registration failure.');
10 | });
11 | }
12 | else {
13 | //- console.log('CLIENT: service worker is not supported.');
14 | }
15 | script(async defer data-domain="cfnchecklist.com" src="https://plausible.io/js/plausible.js" doctype)
16 |
--------------------------------------------------------------------------------
/src/views/base/before-scripts.pug:
--------------------------------------------------------------------------------
1 | script.
2 | (function(d, s, id) {
3 | var js, fjs = d.getElementsByTagName(s)[0];
4 | if (d.getElementById(id)) return;
5 | js = d.createElement(s); js.id = id;
6 | js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.10&appId=1824577741189279";
7 | fjs.parentNode.insertBefore(js, fjs);
8 | }(document, 'script', 'facebook-jssdk'));
9 |
--------------------------------------------------------------------------------
/src/views/base/footer.pug:
--------------------------------------------------------------------------------
1 | footer.page-footer
2 | .s-footer
3 | .s-footer__grateful
4 | p Icons made by #[a(href='http://www.freepik.com' target='_blank', rel="nofollow noopener noreferrer") Freepik] from #[a(href='https://www.flaticon.com/', title='Flaticon' rel="nofollow noopener noreferrer") www.flaticon.com] is licensed by #[a(href='http://creativecommons.org/licenses/by/3.0/', title='Creative Commons BY 3.0', target='_blank', rel="noopener noreferrer") CC 3.0 BY]
5 |
6 | .s-footer__made
7 | p Sister project: #[a(href='https://lambdachecklist.com') Lambda checklist]
8 | p Made with ❤️ by #[a(href="https://github.com/jeshan") Jeshan G. BABOOA] based on the original #[a(href='https://frontendchecklist.io') Front-End Checklist by David Dias].
9 |
--------------------------------------------------------------------------------
/src/views/base/head.pug:
--------------------------------------------------------------------------------
1 |
2 | script(async src="https://www.googletagmanager.com/gtag/js?id=UA-109578378-1")
3 | script.
4 | window.dataLayer = window.dataLayer || [];
5 | function gtag(){dataLayer.push(arguments);}
6 | gtag('js', new Date());
7 |
8 | gtag('config', 'UA-109578378-1');
9 | script(src="https://platform.twitter.com/widgets.js" async)
10 | script(src="https://buttons.github.io/buttons.js" async)
11 |
12 | meta(charset="utf-8")
13 |
14 |
15 | meta(name='viewport', content='width=device-width, initial-scale=1')
16 |
17 |
18 | title #[=translation.SITE_NAME] - #[=translation.INDEX_TITLE]
19 |
20 |
21 | meta(name='description', content=translation.SITE_DESCRIPTION)
22 | meta(name='google-site-verification', content='vRDgryN3FdAjofpwH1OtdCb9c8VHscUG8VQ6jjnjlb4')
23 |
24 | style.
25 | @charset "UTF-8";ul{list-style:none}*,:after,:before{box-sizing:inherit}html{background-color:#ededed;min-width:100%;overflow-x:hidden;overflow-y:scroll;box-sizing:border-box;font-size:62.5%;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;scroll-behavior:smooth}body{color:#212529;font-size:1rem;font-weight:400;line-height:1.5;font-family:BlinkMacSystemFont,-apple-system,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,Helvetica,Arial,sans-serif;margin:0}h1,h2{margin-bottom:.5rem;font-family:inherit;font-weight:500;line-height:1.2;color:inherit}h1{margin:0;padding:15px 0 0;font-weight:700;font-size:2.5rem}h2{font-size:2rem}.img-logo{width:85px;height:85px}a{text-decoration:none}a:not(:disabled){background-color:transparent;color:#d75637}p{font-size:1.2rem;line-height:1.5;margin-top:0}.icon{width:18px;height:18px;fill:#b5b5b5;display:inline-block;text-align:center;speak:none;-webkit-backface-visibility:hidden;backface-visibility:hidden;opacity:1}button .icon{margin:0 .7rem 0 -.2rem}.page-wrapper{display:grid;grid-template-columns:auto;grid-template-areas:"a" "b" "c"}.page-wrapper .page-header{grid-area:a}.page-wrapper .page-main{grid-area:b}.sub-heading{margin:5px 15px;font-family:Montserrat,sans-serif;color:hsla(0,0%,100%,.6);font-size:1.3rem;line-height:1.5}.s-header{grid-row:1;grid-column-start:2;padding:15px 0;background-color:#415257;background-image:linear-gradient(45deg,#415257,#292e49);color:#fff;font-size:1rem;text-align:center;position:relative}.s-header__media__list{display:flex;align-items:flex-start;justify-content:center;align-self:center;padding:0}.s-header__media__item{margin:0 5px}.s-header__lang__list{display:flex;flex-direction:row;align-items:flex-start;align-self:center;justify-content:center;margin-top:20px}.s-header__lang__item{margin:0 5px}.c-tag-filter{display:flex;align-items:center;justify-content:space-between;align-self:center;flex-flow:row wrap}.c-tag-filter__title{font-size:1.2rem;font-weight:700}.c-tag-filter__list{flex-direction:row;width:100%;margin:0;padding:10px;background-color:#f8f7f6}.c-tag-filter__item{display:inline-block}.c-tag-filter__item button{display:block;text-transform:uppercase;font-size:1.3rem;line-height:1;color:#121212;padding:5px 10px;border:2px solid transparent;background-color:transparent}.s-main{display:grid;grid-column-start:1;position:relative;background-color:#fff;text-align:left;padding:0 10px}.s-main__section{margin:0 0 10px}.s-main__section:first-child{order:2}.s-main__section:nth-child(2),.s-main__section:nth-child(3){order:4}.s-main__meta{display:none}.s-checklist{position:relative;min-height:1px}.s-checklist:after{content:"";position:absolute;height:2px;border-top:1px solid #e4ebf0;bottom:0;width:98%}.s-checklist__inner{display:grid}.s-checklist__header{padding:15px 0;z-index:4}.s-checklist__header__title{margin:0;text-align:left;color:#415257;font-weight:700;text-transform:uppercase;line-height:1.2;font-size:2.5rem}.c-top-alert{display:none}.no-js .c-top-alert--alert{min-height:35px;background:orange;width:100%;text-align:center;font-weight:700;color:#fff;font-size:1.3rem;padding:5px 0}.no-js .c-top-alert--alert p{margin:0}button{-moz-appearance:none;-webkit-appearance:none;align-items:center;border:1px solid transparent;border-radius:3px;box-shadow:none;display:inline-flex;font-size:1.3rem;padding:7px 10px;justify-content:flex-start;line-height:1.4;position:relative;vertical-align:top;-webkit-touch-callout:none;background-color:#fff;border-color:#999;color:#363636;justify-content:center;text-align:center;white-space:nowrap}.c-button-icon{border-color:#b5b5b5}.c-button-icon .icon{margin:0}.c-button__group{margin:0 5px}.github-corner svg{fill:#fff;color:#151513;position:absolute;top:0;border:0;right:0}.github-corner .octo-arm{-webkit-transform-origin:130px 106px;transform-origin:130px 106px}@-webkit-keyframes a{0%,to{-webkit-transform:rotate(0);transform:rotate(0)}20%,60%{-webkit-transform:rotate(-25deg);transform:rotate(-25deg)}40%,80%{-webkit-transform:rotate(10deg);transform:rotate(10deg)}}@keyframes a{0%,to{-webkit-transform:rotate(0);transform:rotate(0)}20%,60%{-webkit-transform:rotate(-25deg);transform:rotate(-25deg)}40%,80%{-webkit-transform:rotate(10deg);transform:rotate(10deg)}}.c-tools{display:flex}.c-tools .c-button__group:first-child{margin-left:0}.c-progress{position:relative;display:flex;padding:10px 0}.c-progress__counter{text-align:center;margin-left:20px}.c-progress__label{font-size:1.3rem;font-weight:600}.c-progress__text{font-size:1.3rem}.c-progress__bar{background-color:#f5f5f5;border:0;height:19px;border-radius:3px;width:120px}.c-progress__bar::-webkit-progress-value{border-radius:2px}.c-progress__bar::-webkit-progress-bar{background-color:#f5f5f5}@media screen and (min-width:500px){h1{font-size:3rem}.img-logo{width:100px;height:100px}.icon{width:15px;height:15px}.sub-heading{font-size:1.5rem;margin:15px}.s-header{padding-top:25px;padding-bottom:60px}.s-header__banner{width:795px;margin:0 auto}.c-tag-filter__title{font-size:1.3rem}.s-main{display:grid;grid-column-start:3;margin-top:-50px;width:100%;padding:10px;border-radius:5px;border:1px solid rgba(0,0,0,.1)}.s-main__section:first-child,.s-main__section:nth-child(2){padding:0 20px}.s-main__meta{display:flex;justify-content:flex-end}.s-checklist{padding:0 10px}.s-checklist__header{display:flex;align-items:center;justify-content:space-between}.s-checklist__title{display:flex;align-items:center;justify-content:center}.s-checklist__header__title{font-size:4rem;margin:0}.c-progress{padding:0;display:block}.c-progress__counter{margin:0}.c-progress__label{position:absolute;top:28%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.c-progress__text{font-size:1.1rem;padding:0 5px}.c-progress__bar{height:20px;margin:0 20px}}@media screen and (min-width:801px){.page-wrapper{grid-template-areas:"a a a" "b b b" "c c c"}.page-wrapper .page-main{display:grid;grid-template-columns:auto 150px 960px 150px auto}.c-tag-filter{display:flex;flex-direction:row}.c-tag-filter__list{display:flex;flex-wrap:wrap}button{font-size:1.25rem;height:34px;padding:5px 9px}}@media (max-width:500px){.github-corner .octo-arm{-webkit-animation:a .56s ease-in-out;animation:a .56s ease-in-out}}
26 |
27 | link(rel="preload" as="style" href="/styles/main.min.css" onload="this.rel='stylesheet'")
28 |
29 | noscript
30 | link(rel="stylesheet" href="/styles/main.min.css")
31 |
32 | script.
33 | /*! loadCSS. [c]2017 Filament Group, Inc. MIT License */
34 | !function(a){"use strict";var b=function(b,c,d){function j(a){if(e.body)return a();setTimeout(function(){j(a)})}function l(){f.addEventListener&&f.removeEventListener("load",l),f.media=d||"all"}var g,e=a.document,f=e.createElement("link");if(c)g=c;else{var h=(e.body||e.getElementsByTagName("head")[0]).childNodes;g=h[h.length-1]}var i=e.styleSheets;f.rel="stylesheet",f.href=b,f.media="only x",j(function(){g.parentNode.insertBefore(f,c?g:g.nextSibling)});var k=function(a){for(var b=f.href,c=i.length;c--;)if(i[c].href===b)return a();setTimeout(function(){k(a)})};return f.addEventListener&&f.addEventListener("load",l),f.onloadcssdefined=k,k(l),f};"undefined"!=typeof exports?exports.loadCSS=b:a.loadCSS=b}("undefined"!=typeof global?global:this);
35 | /*! loadCSS rel=preload polyfill. [c]2017 Filament Group, Inc. MIT License */
36 | !function(a){if(a.loadCSS){var b=loadCSS.relpreload={};if(b.support=function(){try{return a.document.createElement("link").relList.supports("preload")}catch(a){return!1}},b.poly=function(){for(var b=a.document.getElementsByTagName("link"),c=0;c
39 | link(rel="icon", type="image/png", sizes="32x32", href="/favicon-32x32.png")
40 | link(rel="icon", type="image/png", sizes="16x16", href="/favicon-16x16.png")
41 |
42 |
43 | link(rel="apple-touch-icon", sizes="180x180", href="/apple-touch-icon.png")
44 |
45 |
46 | meta(name="msapplication-config" content="/browserconfig.xml")
47 |
48 | link(rel="mask-icon", href="/safari-pinned-tab.svg", color="#5bbad5")
49 | meta(name="theme-color" content="#2b2b2b")
50 | meta(name="msapplication-TileColor" content="#2b2b2b")
51 | meta(name="msapplication-TileImage" content="/icons/mstile-144x144.png")
52 |
53 | link(rel="manifest" href="/manifest.json")
54 |
55 | include social
56 |
57 | script
58 | include ../../modernizr-custom.min.js
59 |
--------------------------------------------------------------------------------
/src/views/base/header.pug:
--------------------------------------------------------------------------------
1 | header.s-header
2 |
3 | include ../components/c-corner
4 |
5 | .s-header__banner
6 | .text-center
7 | h1.font-weight-bold= translation.SITE_NAME
8 | p.sub-heading= translation.SITE_TAGLINE
9 |
10 | .s-header__media
11 | ul.s-header__media__list
12 | li.s-header__media__item
13 | a(href="https://twitter.com/share?ref_src=twsrc%5Etfw" class="twitter-share-button" data-text=translation.social.TWITTER_MSG data-via=translation.social.TWITTER_VIA data-hashtags=translation.social.TWITTER_HASHTAGS data-show-count="false")= translation.social.TWEET
14 | li.s-header__media__item
15 | a.github-button(href=translation.URL_GITHUB_ROOT data-icon="octicon-star" data-show-count="true" aria-label=translation.social.GITHUB_STAR_MSG)= translation.social.STAR
16 |
--------------------------------------------------------------------------------
/src/views/base/layout.pug:
--------------------------------------------------------------------------------
1 | block vars
2 | - listSections = []
3 |
4 | //- Inject all mixins to be able to call these
5 | include ../mixins/mixins
6 |
7 |
8 | doctype html
9 |
10 | html.no-js(lang=translation.SITE_LANGUAGE, dir=translation.SITE_DIRECTION)
11 | head
12 |
13 | //- Include the HEAD of the page
14 | include head
15 | body
16 |
17 | //- Scripts needed to be load just after the body
18 | include before-scripts
19 |
20 | //- Website wrapper
21 | .page-wrapper
22 |
23 | .page-header
24 | //- Top banners with informations for the user
25 | include ../components/c-top-alert
26 |
27 | include header
28 |
29 | .page-main
30 |
31 | //- The main tag is not include in the block main because repeted
32 | main.s-main#js-main
33 | block main
34 |
35 | .page-footer
36 | include footer
37 |
38 | //- Scripts loading
39 | include after-scripts
40 |
--------------------------------------------------------------------------------
/src/views/base/social.pug:
--------------------------------------------------------------------------------
1 | meta(property="og:site_name" content="CloudFormation Checklist")
2 | meta(property="og:url" content=translation.URL_WEBSITE)
3 | meta(property="og:type" content="website")
4 | meta(property="og:title" content=translation.INDEX_TITLE)
5 | meta(property="og:description" content=translation.SITE_DESCRIPTION)
6 | meta(property="og:image" content="https://everywhere-8a59.kxcdn.com/img/social/facebook-banner.jpg")
7 | meta(property="og:image:type" content="image/jpeg")
8 | meta(property="og:image:width" content="1200")
9 | meta(property="og:image:height" content="630")
10 | meta(property="og:image:alt" content="The NEW CloudFormation Checklist - Start, Check, Generate and enjoy!")
11 | meta(property="og:locale" content="en_US")
12 |
13 | meta(name="twitter:card" content="summary_large_image")
14 | meta(name="twitter:site" content="@jeshan25")
15 | meta(name="twitter:creator" content="@jeshan25")
16 | meta(name="twitter:image" content="https://everywhere-8a59.kxcdn.com/img/social/facebook-banner.jpg")
17 |
--------------------------------------------------------------------------------
/src/views/components/c-checklist.pug:
--------------------------------------------------------------------------------
1 | .c-checklist
2 |
3 | //- Grab introduction based on the name of the section
4 | if introductions[0][sectionTitle.toLowerCase()]
5 |
6 | each el in introductions[0][sectionTitle.toLowerCase()]
7 |
8 | p.c-checklist__intro= el
9 |
10 | //- List of all items elements based on the dataSection variable
11 | ul.c-checklist__list
12 |
13 | each item, i in dataSection
14 |
15 | include ../components/checklist/class
16 |
17 | //- data-item-check (false or true) => Element is checked or not
18 | //- data-item-priority (high, medium or low) => The priority of the task
19 | //- data-item-id (number) => the ID of the elements based on dataSection array
20 | //- data-item-dropdown (open close or false) => State of the dropdown
21 | //- data-item-visible (true or false) => Visibility of the item used by the tag filter
22 | li.c-checklist__item.js-item(class=` ${allClass}`, data-item-priority=priorityClass ,data-item-id=i, data-item-check="false", data-item-dropdown=dataItemDropdown, data-item-visible="true" aria-hidden="false")
23 |
24 | .c-checklist__item__inner
25 |
26 | .c-checklist__body
27 |
28 | //- Columns of the item
29 |
30 | //- Priority column
31 | include ../components/checklist/priority
32 |
33 | //- Checkbox column
34 | include ../components/checklist/checkbox
35 |
36 | //- Label column
37 | include ../components/checklist/label
38 |
39 | //- Dropdown column
40 | include ../components/checklist/dropdown
41 |
--------------------------------------------------------------------------------
/src/views/components/c-corner.pug:
--------------------------------------------------------------------------------
1 | .c-github-corner
2 | a(href=translation.URL_GITHUB_ROOT class="github-corner" aria-label="View source on Github")
3 | svg(width="80" height="80" viewBox="0 0 250 250" aria-hidden="true")
4 | path(d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z")
5 | path(d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" class="octo-arm")
6 | path(d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body")
7 |
--------------------------------------------------------------------------------
/src/views/components/c-nav.pug:
--------------------------------------------------------------------------------
1 | nav.c-nav
2 | ul.c-nav__list.c-nav--inline
3 |
4 | each item, i in listSections
5 | li.c-nav__item
6 | a.c-button.js-scroll(href=`#section-${item}`)
7 | span.c-nav__status(id=`js-nav-${item}`, data-notation="0")
8 | span= item
9 |
--------------------------------------------------------------------------------
/src/views/components/c-new-form.pug:
--------------------------------------------------------------------------------
1 | .s-form
2 | .form
3 |
4 | .form-group
5 | input(type="text", id="project-name" name="project-name", title=translation.form.TITLE_PROJECT_NAME required)
6 | label(for="project-name")= translation.form.LABEL_PROJECT_NAME
7 |
8 | .form-group
9 | input(type="text", id="page-title" name="page-title", title=translation.form.TITLE_PAGE_TITLE required)
10 | label(for="page-title")= translation.form.LABEL_PAGE_TITLE
11 |
12 | .form-group
13 | input(type="text", id="developer-name" name="developer-name", title=translation.form.TITLE_DEVELOPER_NAME required)
14 | label(for="developer-name")= translation.form.LABEL_DEVELOPER_NAME
15 |
16 | span#generated-date
17 |
18 | .s-meta
19 |
20 | button.button.btn--danger.js-reset-all
21 | +svg-icon.icon.icon-reset(data-icon-name='reset')
22 | | #[=translation.form.BUTTON_START_NEW]
23 |
--------------------------------------------------------------------------------
/src/views/components/c-notation.pug:
--------------------------------------------------------------------------------
1 | .c-notation
2 |
3 | - priority = []
4 | - totalHigh = []
5 | - totalMedium = []
6 | - totalLow = []
7 |
8 | each item, i in locals._items
9 |
10 | each item2 in item
11 |
12 | - priority.push(item2.priority)
13 |
14 | each el, i in priority
15 |
16 | if (el == 'High')
17 | - totalHigh.push('1')
18 |
19 | else if (el == 'Medium')
20 | - totalMedium.push('1')
21 |
22 | else
23 | - totalLow.push('1')
24 |
25 | .c-notation__details
26 | ul.c-notation__details__list
27 | li.c-notation__details__item.js-detail-high
28 | +svg-icon.icon.icon--small.icon-priority--high(data-icon-name='bullet')
29 | span.js-notation-checked 0
30 | |/
31 | span.js-notation-total= totalHigh.length
32 | | #[=translation.HIGH_CHECKED]
33 | li.c-notation__details__item.js-detail-medium
34 | +svg-icon.icon.icon--small.icon-priority--medium(data-icon-name='bullet')
35 | span.js-notation-checked 0
36 | |/
37 | span.js-notation-total= totalMedium.length
38 | | #[=translation.MEDIUM_CHECKED]
39 | li.c-notation__details__item.js-detail-low
40 | +svg-icon.icon.icon--small.icon-priority--low(data-icon-name='bullet')
41 | span.js-notation-checked 0
42 | |/
43 | span.js-notation-total= totalLow.length
44 | | #[=translation.LOW_CHECKED]
45 |
46 | .c-notation__box
47 | #js-notation.c-notation__item(data-notation="0")
48 | span.c-notation__letter X
49 |
50 |
51 | .c-notation__generate
52 | button.button.--fill.--large.js-print
53 | +svg-icon.icon.icon-print(data-icon-name='print')
54 | | #[=translation.form.BUTTON_GENERATE_PRINT]
55 |
--------------------------------------------------------------------------------
/src/views/components/c-progress.pug:
--------------------------------------------------------------------------------
1 | .c-progress
2 | progress.c-progress__bar.js-progress(value="0", max="100")
3 | .c-progress__counter
4 | span.c-progress__label 0 %
5 | span.c-progress__text #[=sectionTitle] #[=translation.PERCENTAGE_CHECKED]
6 |
--------------------------------------------------------------------------------
/src/views/components/c-search.pug:
--------------------------------------------------------------------------------
1 | .c-search
2 | .form
3 | .form-group
4 | input.search(type="search" id="search")
5 | label(for="search")= translation.form.LABEL_SEARCH
6 |
--------------------------------------------------------------------------------
/src/views/components/c-tag-filter.pug:
--------------------------------------------------------------------------------
1 | //- Array container for each filters
2 | - tagFilter = []
3 |
4 | //- Loop to save each tags present in JSON into tagFilter
5 | each item, i in _items
6 |
7 | each tagList in item
8 |
9 | each tag in tagList.tags
10 |
11 | //- Check if the filter tag already exist in the tagFilter array
12 | - if (tagFilter.indexOf(tag) === -1)
13 | - tagFilter.push(tag)
14 |
15 | //- Filter code implementation
16 | aside.c-tag-filter
17 | h2.c-tag-filter__title= translation.SECTION_TAG
18 |
19 | ul.c-tag-filter__list
20 |
21 | //- Loop to grab each title in the tagFilter array
22 | each title in tagFilter
23 |
24 | //- Add uppercase in the first letter
25 | - titleFilter = title.charAt(0).toUpperCase() + title.slice(1)
26 |
27 | //- Slip and add a dash if the tag is more than 1 word
28 | - dataFilter = title.split(' ').join('-')
29 |
30 | //- Check if title is not empty before printing it
31 | if title != ''
32 | li.c-tag-filter__item
33 | button.js-filter-tag(data-tag=`${dataFilter}`)= titleFilter
34 |
--------------------------------------------------------------------------------
/src/views/components/c-tools.pug:
--------------------------------------------------------------------------------
1 | .c-tools
2 |
3 | .c-button__group
4 | button.c-button-icon.js-check-all(title="Check all items")
5 | +svg-icon.icon.icon-check(data-icon-name='check')
6 |
7 | button.c-button-icon.js-uncheck-all(title="Uncheck all items")
8 | +svg-icon.icon.icon-uncheck(data-icon-name='check')
9 |
10 | .c-button__group
11 | button.c-button-icon.js-expand-all(title="Expand all items")
12 | +svg-icon.icon.icon-check(data-icon-name='expand')
13 |
14 | button.c-button-icon.js-collapse-all(title="Collapse all items")
15 | +svg-icon.icon.icon-uncheck(data-icon-name='collapse')
16 |
17 | .c-button__group
18 | button.c-button-icon.js-hide-section(title="Hide current section")
19 | +svg-icon.icon.icon-eye(data-icon-name='eye')
20 |
--------------------------------------------------------------------------------
/src/views/components/c-top-alert.pug:
--------------------------------------------------------------------------------
1 | .c-top-alert
2 | .c-top-alert--alert
3 | p= translation.alert.JAVASCRIPT_DESACTIVATE
4 |
--------------------------------------------------------------------------------
/src/views/components/checklist/checkbox.pug:
--------------------------------------------------------------------------------
1 | .c-checklist__column.c-checklist__checkbox
2 | input.checkbox(type="checkbox" name=`c-checklist__item-${sectionTitle.toLowerCase()}-${i}` id=`c-checklist__item-${sectionTitle.toLowerCase()}-${i}`)
3 | +svg-icon.icon.icon-checkbox(data-icon-name='check')
4 | +svg-icon.icon.icon-checked(data-icon-name='check')
5 |
--------------------------------------------------------------------------------
/src/views/components/checklist/class.pug:
--------------------------------------------------------------------------------
1 | - allClass = ''
2 | - dataItemDropdown
3 | - priorityClass = item.priority.toLowerCase()
4 |
5 | //- Iteration over tags array
6 | each tag in item.tags
7 |
8 | //- Create an empty array to put all values from tags array
9 | - var tempClass = []
10 |
11 | //- Slip and add a dash if the tag is more than 1 word
12 | - tag = tag.toLowerCase().split(' ').join('-')
13 |
14 | //- Push array value into tempClass array
15 | - tempClass.push(tag)
16 |
17 | - for (var i = 0; i < tempClass.length; i++)
18 | - allClass += tempClass[i] + ' ';
19 |
20 | if item.tools || item.documentation || item.code || item.video
21 | - dataItemDropdown = "open"
22 | else
23 | - dataItemDropdown = "false"
24 |
--------------------------------------------------------------------------------
/src/views/components/checklist/dropdown.pug:
--------------------------------------------------------------------------------
1 | .c-checklist__column.c-checklist__dropdown
2 |
3 | //- Check if the item has content, if not hide the button
4 | if item.tools || item.documentation || item.code || item.video
5 | button.button-icon.js-dropdown.c-checklist__dropdown__button(aria-label="Open the description section")
6 | +svg-icon.icon.icon-arrow(data-icon-name='arrow')
7 |
--------------------------------------------------------------------------------
/src/views/components/checklist/label.pug:
--------------------------------------------------------------------------------
1 | .c-checklist__column.c-checklist__label
2 | label(for=`c-checklist__item-${sectionTitle.toLowerCase()}-${i}`)
3 |
4 | span.label__title= item.title + ': '
5 | span.label__description #{item.description}
6 |
7 | if item.tools || item.documentation || item.code || item.video
8 | .c-checklist__details.js-details
9 |
10 | if item.detail
11 | p.c-checklist__text= item.detail
12 |
13 | if item.code
14 | .c-checklist__code
15 | .c-checklist__code__loader.js-loader
16 | .code-icons
17 | .c-checklist__code__github.js-code(data-code-url=`${item.code}`)
18 |
19 | if item.documentation
20 | .c-checklist__documentation
21 | h4= translation.SECTION_DOCUMENTATION
22 | ul.documentation__list
23 | each documentation, i in item.documentation
24 | li
25 | if documentation.url && documentation.title
26 | img.c-checklist__favicon(src="/img/icons/1x1.png" data-src=`https://www.google.com/s2/favicons?domain_url=${documentation.url}`, alt="")
27 | a(href=`${documentation.url}`, target="_blank", rel="noopener noreferrer")= documentation.title
28 |
29 | if item.tools
30 | .c-checklist__tools
31 | h4= translation.SECTION_TOOL
32 | ul.documentation__list
33 | each tool, i in item.tools
34 | li
35 | img.c-checklist__favicon(src="/img/icons/1x1.png" data-src=`https://www.google.com/s2/favicons?domain_url=${tool.url}`, alt="")
36 | a(href=`${tool.url}`, target="_blank", rel="noopener noreferrer")= tool.title
37 |
38 | if item.video
39 | .c-checklist__video
40 | h4= translation.SECTION_VIDEO
41 | ul.video__list
42 | each video, i in item.video
43 | li
44 | img.c-checklist__favicon(src="/img/icons/1x1.png" data-src=`https://www.google.com/s2/favicons?domain_url=${video.url}`, alt="")
45 | a(href=`${video.url}`, target="_blank", rel="noopener noreferrer")= video.title
46 |
47 | .c-tags
48 | ul.c-tags__list
49 | each tag in item.tags
50 | if tag == 'all'
51 | else
52 | li.c-tags__item= tag.toUpperCase()
53 |
--------------------------------------------------------------------------------
/src/views/components/checklist/priority.pug:
--------------------------------------------------------------------------------
1 | .c-checklist__column.c-checklist__priority
2 |
3 | if item.priority == "High"
4 | +svg-icon.icon.icon--small.icon-priority--high(aria-label="High priority item" data-icon-name='bullet')
5 |
6 | else if item.priority == "Medium"
7 | +svg-icon.icon.icon--small.icon-priority--medium(aria-label="Medium priority item" data-icon-name='bullet')
8 |
9 | else
10 | +svg-icon.icon.icon--small.icon-priority--low(aria-label="Low priority item", data-icon-name='bullet')
11 |
--------------------------------------------------------------------------------
/src/views/components/s-section-bottom.pug:
--------------------------------------------------------------------------------
1 | .s-main__section.s-main__newsletter
2 |
3 | //- Form and navigation anchors
4 | //- Navigation is at the bottom of the page because of the `listSections` generated by each +section present in the article.
5 | header.s-main__section.s-main__header
6 |
7 | .s-header__checklist
8 |
9 | h2.s-header__checklist__title Report and navigation
10 | //- Form to create new checklist
11 | .s-header__checklist__el
12 | include c-new-form
13 |
14 | //- Navigation with anchors based on the sections
15 | .s-header__checklist__el
16 | include c-nav
17 |
18 | //- Letter notation based on number of items checked
19 | .s-header__checklist__el
20 | include c-notation
21 |
--------------------------------------------------------------------------------
/src/views/components/s-section-top.pug:
--------------------------------------------------------------------------------
1 | //- List of all sections in the order the mixin +section is called in the article section.
2 | //- Array is populate by
3 | - listSections = []
4 |
5 | //- Ids of each section generated by the mixin +section when called.
6 | - listSectionId = []
7 |
8 | //- Section with Ad and search (TODO: to enable after first launch)
9 | .s-main__section.s-main__meta
10 |
11 | //- include c-search
12 |
13 | //- Section with tag filter
14 | .s-main__section.s-main__filter
15 |
16 | include c-tag-filter
17 |
--------------------------------------------------------------------------------
/src/views/components/svg/arrow.pug:
--------------------------------------------------------------------------------
1 | svg(xmlns="http://www.w3.org/2000/svg" width='30', height='30' viewBox="0 0 98.148 98.149" aria-hidden="true")&attributes(attributes)
2 | title Arrow
3 | path(d="M97.562 64.692L50.49 17.618c-.75-.75-2.078-.75-2.828 0L.586 64.693C.21 65.068 0 65.577 0 66.106c0 .53.21 1.04.586 1.414l12.987 12.987c.39.39.902.586 1.414.586.512 0 1.023-.195 1.414-.586l32.675-32.674L81.75 80.506c.75.75 2.078.75 2.828 0L97.562 67.52c.782-.78.782-2.048 0-2.828z")
4 |
--------------------------------------------------------------------------------
/src/views/components/svg/bullet.pug:
--------------------------------------------------------------------------------
1 | svg(xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 510 510" aria-hidden="true")&attributes(attributes)
2 | path(d="M255 0C114.75 0 0 114.75 0 255s114.75 255 255 255 255-114.75 255-255S395.25 0 255 0z")
3 |
--------------------------------------------------------------------------------
/src/views/components/svg/check.pug:
--------------------------------------------------------------------------------
1 | svg(xmlns='http://www.w3.org/2000/svg', width='30', height='30' viewbox='-432 234 94 94' aria-hidden="true")&attributes(attributes)
2 | title Check
3 | path(d='M-349 245v72h-72v-72h72m5-11h-82c-3.3 0-6 2.7-6 6v82c0 3.3 2.7 6 6 6h82c3.3 0 6-2.7 6-6v-82c0-3.3-2.7-6-6-6z')
4 | path.path-check(d='M-349.2 261.1l-7.2-7.2c-.8-.8-2-.8-2.8 0l-37.3 37.3-13.3-13.3c-.8-.8-2-.8-2.8 0l-7.2 7.2c-.4.4-.6.9-.6 1.4s.2 1 .6 1.4l21.9 21.9c.4.4.9.6 1.4.6.5 0 1-.2 1.4-.6l45.9-45.9c.4-.4.6-.9.6-1.4 0-.5-.2-1-.6-1.4z')
5 |
--------------------------------------------------------------------------------
/src/views/components/svg/checkbox.pug:
--------------------------------------------------------------------------------
1 | svg(xmlns="http://www.w3.org/2000/svg" width='30', height='30' viewBox="0 0 94 94" aria-hidden="true")&attributes(attributes)
2 | path(d="M94 88c0 3.312-2.688 6-6 6H6c-3.314 0-6-2.688-6-6V6c0-3.313 2.686-6 6-6h82c3.312 0 6 2.687 6 6v82z")
3 |
--------------------------------------------------------------------------------
/src/views/components/svg/checked.pug:
--------------------------------------------------------------------------------
1 | svg(xmlns="http://www.w3.org/2000/svg" width='30', height='30' viewBox="0 0 330 330" aria-hidden="true")&attributes(attributes)
2 | path(d="M315 0H15C6.716 0 0 6.716 0 15v300c0 8.284 6.716 15 15 15h300c8.284 0 15-6.716 15-15V15c0-8.284-6.716-15-15-15zm-49.394 107.796l-135.62 135.62c-2.813 2.814-6.63 4.394-10.606 4.394-3.98 0-7.794-1.58-10.607-4.393l-44.38-44.38c-5.858-5.86-5.858-15.356 0-21.214 5.858-5.857 15.354-5.857 21.214 0l33.772 33.774L244.393 86.583c5.857-5.858 15.355-5.858 21.213 0 5.858 5.857 5.858 15.355 0 21.213z")
3 |
--------------------------------------------------------------------------------
/src/views/components/svg/code.pug:
--------------------------------------------------------------------------------
1 | svg(xmlns='http://www.w3.org/2000/svg', width='30', height='30', viewbox='0 0 92.812 92.812' aria-hidden="true")&attributes(attributes)
2 | path.code-path-left(d='M92.226 44.992L60.97 13.736c-.78-.78-2.047-.78-2.827 0l-6.73 6.728c-.374.375-.585.884-.585 1.414 0 .53.21 1.04.586 1.414L74.53 46.406 51.415 69.52c-.375.376-.586.885-.586 1.415s.21 1.04.586 1.415l6.73 6.728c.39.39.902.585 1.414.585s1.024-.195 1.415-.586L92.227 47.82c.78-.78.78-2.047 0-2.828z')
3 | path.code-path-right(d='M18.283 46.406l23.114-23.114c.375-.375.586-.884.586-1.414 0-.53-.21-1.04-.586-1.414l-6.728-6.728c-.782-.78-2.05-.78-2.83 0L.587 44.992C.21 45.367 0 45.876 0 46.406s.21 1.04.586 1.414l31.26 31.256c.375.375.884.586 1.415.586.53 0 1.04-.21 1.415-.586l6.724-6.728c.78-.78.78-2.05 0-2.828L18.282 46.406z')
4 |
--------------------------------------------------------------------------------
/src/views/components/svg/collapse.pug:
--------------------------------------------------------------------------------
1 | svg(xmlns='http://www.w3.org/2000/svg', width='30', height='30', viewbox='0 0 510 510' aria-hidden="true")&attributes(attributes)
2 | title Minus Collapse
3 | path(d='M255 0C114.75 0 0 114.75 0 255s114.75 255 255 255 255-114.75 255-255S395.25 0 255 0zm127.5 280.5h-255v-51h255v51z')
4 |
--------------------------------------------------------------------------------
/src/views/components/svg/expand.pug:
--------------------------------------------------------------------------------
1 | svg(xmlns='http://www.w3.org/2000/svg', width='30', height='30', viewbox='0 0 510 510' aria-hidden="true")&attributes(attributes)
2 | title Plus Expand
3 | path(d='M280.5 127.5h-51v102h-102v51h102v102h51v-102h102v-51h-102v-102zM255 0C114.75 0 0 114.75 0 255s114.75 255 255 255 255-114.75 255-255S395.25 0 255 0zm0 459c-112.2 0-204-91.8-204-204S142.8 51 255 51s204 91.8 204 204-91.8 204-204 204z')
4 |
--------------------------------------------------------------------------------
/src/views/components/svg/eye.pug:
--------------------------------------------------------------------------------
1 | svg(xmlns='http://www.w3.org/2000/svg', width='30', height='30' viewbox='-430 231.5 98.5 98.5' aria-hidden="true")&attributes(attributes)
2 | path(d='M-332.8 277.3c-.9-1-21.5-24.9-48-24.9-26.4 0-47.1 23.9-48 24.9-1.7 2-1.7 4.9 0 6.9.9 1 21.5 24.9 48 24.9 26.4 0 47.1-23.9 48-24.9 1.7-2 1.7-4.9 0-6.9zm-39.9-10.6c1.8-1 4.3.1 5.5 2.5 1.3 2.3.9 5-.9 6s-4.3-.1-5.5-2.5c-1.3-2.3-.9-5 .9-6zm-8.1 33.8c-18.5 0-34-14.2-39.4-19.7 3.6-3.8 11.9-11.4 22.6-16-2.1 3.2-3.3 6.9-3.3 11 0 11.1 9 20.1 20.1 20.1s20.1-9 20.1-20.1c0-4.1-1.2-7.9-3.3-11 10.7 4.6 18.9 12.3 22.6 16-5.4 5.5-20.9 19.7-39.4 19.7z')
3 | path(d='M-349.675 239.41l8.202 8.202-74.245 74.246-8.202-8.203z')
4 | path.st0(d='M-416.16 322.39l75.095-75.093 3.465 3.465-75.094 75.094z')
5 | title Eye
6 |
--------------------------------------------------------------------------------
/src/views/components/svg/print.pug:
--------------------------------------------------------------------------------
1 | svg(xmlns='http://www.w3.org/2000/svg', width='30', height='30', viewbox='0 0 94.168 94.168' aria-hidden="true")&attributes(attributes)
2 | title Printer
3 | path(d='M93.135 27.803H79.167v6.447c0 1.104-.896 2-2 2H17c-1.103 0-2-.896-2-2v-6.447H1.034c-.57 0-1.033.462-1.033 1.033v36.497c0 .57.462 1.033 1.033 1.033H15V59.92c0-1.105.897-2 2-2h60.167c1.104 0 2 .895 2 2v6.446h13.968c.57 0 1.033-.463 1.033-1.033V28.836c0-.57-.463-1.033-1.033-1.033zM82.98 52.625c-2.425 0-4.392-1.965-4.392-4.39 0-2.424 1.967-4.39 4.39-4.39s4.39 1.966 4.39 4.39c0 2.426-1.968 4.39-4.39 4.39z')
4 | path(d='M75.617 22.522c0-.55-.22-1.073-.605-1.46L61.57 7.62c-.39-.388-.913-.606-1.46-.606H20.615c-1.14 0-2.065.925-2.065 2.066v23.754h57.067V22.522zm-17.333 2.952c-.278 0-.546-.11-.742-.306-.196-.197-.308-.463-.308-.742l.002-12.498 13.546 13.546H58.284z')
5 | path(d='M18.55 85.088c0 1.14.926 2.065 2.066 2.065h52.936c1.142 0 2.065-.925 2.065-2.065v-23.42H18.55v23.42z')
6 |
--------------------------------------------------------------------------------
/src/views/components/svg/reset.pug:
--------------------------------------------------------------------------------
1 | svg(xmlns='http://www.w3.org/2000/svg', width='30', height='30', viewbox='0 0 94.073 94.072' aria-hidden="true")&attributes(attributes)
2 | title Two arrows turn around
3 | path(d='M91.465 5.49c-.748-.31-1.61-.138-2.18.435L80.97 14.24C72.045 5.058 60.124 0 47.4 0c-2.693 0-5.408.235-8.07.697C21.22 3.845 6.543 17.405 1.945 35.244c-.155.6-.023 1.235.355 1.724.378.49.96.775 1.58.775h12.738c.84 0 1.59-.524 1.878-1.313 3.73-10.193 12.992-17.97 23.598-19.814 1.747-.303 3.525-.456 5.288-.456 8.428 0 16.3 3.374 22.168 9.5l-8.445 8.444c-.57.572-.742 1.432-.434 2.18.312.747 1.04 1.234 1.85 1.234H90.7c1.104 0 2-.896 2-2V7.338c0-.808-.49-1.537-1.235-1.847z')
4 | path(d='M90.192 56.328H77.455c-.84 0-1.59.523-1.878 1.312-3.73 10.193-12.992 17.972-23.598 19.814-1.75.303-3.526.456-5.29.456-8.427 0-16.3-3.374-22.167-9.5l8.444-8.444c.572-.572.743-1.432.434-2.18-.31-.747-1.038-1.234-1.847-1.234H3.373c-1.103 0-2 .896-2 2v28.18c0 .81.488 1.54 1.236 1.85.745.31 1.606.137 2.178-.436l8.316-8.315c8.922 9.184 20.843 14.242 33.57 14.242 2.692 0 5.407-.235 8.068-.697 18.112-3.146 32.79-16.708 37.387-34.547.154-.6.022-1.234-.355-1.725-.38-.488-.964-.775-1.583-.775z')
5 |
--------------------------------------------------------------------------------
/src/views/index-en.pug:
--------------------------------------------------------------------------------
1 | extends base/layout
2 |
3 | //- Block main
4 | block main
5 |
6 | include components/s-section-top
7 |
8 | //- List each section (the order is linked to the order of the c-nav)
9 | //- _items is in the JSON injected in the view with gulp-data (called _project.json)
10 | .s-main__section.s-main__checklist
11 |
12 | if _items !== undefined
13 |
14 | +checklist-section({
15 | dataSection: _items.before,
16 | sectionTitle: "Before"
17 | })
18 |
19 | +checklist-section({
20 | dataSection: _items.authoring,
21 | sectionTitle: "Authoring"
22 | })
23 |
24 | +checklist-section({
25 | dataSection: _items.security,
26 | sectionTitle: "Security"
27 | })
28 |
29 | +checklist-section({
30 | dataSection: _items.best_practices,
31 | sectionTitle: "Practices"
32 | })
33 |
34 | +checklist-section({
35 | dataSection: _items.management,
36 | sectionTitle: "Management"
37 | })
38 |
39 | +checklist-section({
40 | dataSection: _items.team,
41 | sectionTitle: "Team"
42 | })
43 |
44 | +checklist-section({
45 | dataSection: _items.testing,
46 | sectionTitle: "Testing"
47 | })
48 |
49 | include components/s-section-bottom
50 |
--------------------------------------------------------------------------------
/src/views/mixins/m-checklist-section.pug:
--------------------------------------------------------------------------------
1 | mixin checklist-section(options)
2 |
3 | - sectionId = '0'; //- Start with 0 to have 1 as first section
4 | - sectionTitle = options.sectionTitle || '';
5 | - dataSection = options.dataSection || [];
6 | - filter = options.filter || 'all';
7 |
8 | //- Push each section title to build navigation bar
9 | - listSections.push(sectionTitle.toLowerCase())
10 |
11 | //- Add a 0 in the array everytime the mixin is called
12 | - listSectionId.push(sectionId++)
13 |
14 |
15 | //- Section
16 | section.s-checklist.js-section(class="s-checklist__" + sectionTitle.toLowerCase(), data-section=sectionTitle.toLowerCase(), data-section-id=`${listSectionId.length-1}`, id="section-" + sectionTitle.toLowerCase())
17 | .s-checklist__inner
18 | .s-checklist__header
19 |
20 | .s-checklist__title
21 |
22 | h2.s-checklist__header__title= sectionTitle
23 |
24 | include ../components/c-progress
25 |
26 | include ../components/c-tools
27 |
28 | .s-checklist__body.js-checklist-body(data-body-visibility="visible", aria-hidden="false")
29 |
30 | //- Include checklist component
31 | include ../components/c-checklist
32 |
--------------------------------------------------------------------------------
/src/views/mixins/m-icon.pug:
--------------------------------------------------------------------------------
1 | mixin svg-icon
2 | -
3 | var icon = attributes['data-icon-name']
4 |
5 | case icon
6 | when 'checkbox'
7 | include ../components/svg/checkbox
8 |
9 | when 'checked'
10 | include ../components/svg/checked
11 |
12 | when 'arrow'
13 | include ../components/svg/arrow
14 |
15 | when 'bullet'
16 | include ../components/svg/bullet
17 |
18 | when 'reset'
19 | include ../components/svg/reset
20 |
21 | when 'eye'
22 | include ../components/svg/eye
23 |
24 | when 'check'
25 | include ../components/svg/check
26 |
27 | when 'collapse'
28 | include ../components/svg/collapse
29 |
30 | when 'expand'
31 | include ../components/svg/expand
32 |
33 | when 'print'
34 | include ../components/svg/print
35 |
36 | when 'code'
37 | include ../components/svg/code
38 |
39 | default
40 | include ../components/svg/checkbox
41 |
--------------------------------------------------------------------------------
/src/views/mixins/mixins.pug:
--------------------------------------------------------------------------------
1 | include m-checklist-section
2 | include m-icon
3 |
--------------------------------------------------------------------------------
/templates/app.yaml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: '2010-09-09'
2 | Description: 'Deploys this website at cfnchecklist.com'
3 |
4 | Parameters:
5 | DomainName:
6 | Type: String
7 |
8 | Resources:
9 | Bucket:
10 | Properties:
11 | AccessControl: Private
12 | BucketName: !Ref DomainName
13 | WebsiteConfiguration:
14 | ErrorDocument: error.html
15 | IndexDocument: index.html
16 | Type: AWS::S3::Bucket
17 |
18 | BucketPolicy:
19 | Type: AWS::S3::BucketPolicy
20 | Properties:
21 | Bucket: !Ref Bucket
22 | PolicyDocument:
23 | Version: 2008-10-17
24 | Statement:
25 | - Sid: PublicReadWebsite
26 | Effect: Allow
27 | Principal:
28 | AWS: '*'
29 | Action: ['s3:GetObject']
30 | Resource: !Sub 'arn:aws:s3:::${Bucket}/*'
31 |
32 | Certificate:
33 | Properties:
34 | DomainName: !Sub '*.${DomainName}'
35 | DomainValidationOptions:
36 | - DomainName: !Sub '*.${DomainName}'
37 | ValidationDomain: !Ref Bucket
38 | SubjectAlternativeNames:
39 | - !Ref DomainName
40 | - !Sub '*.${DomainName}'
41 | ValidationMethod: DNS
42 | Type: AWS::CertificateManager::Certificate
43 |
44 | Cdn:
45 | Properties:
46 | DistributionConfig:
47 | Aliases:
48 | - !Ref Bucket
49 | DefaultCacheBehavior:
50 | AllowedMethods:
51 | - GET
52 | - HEAD
53 | CachedMethods:
54 | - GET
55 | - HEAD
56 | Compress: true
57 | DefaultTTL: 86400
58 | FieldLevelEncryptionId: ''
59 | ForwardedValues:
60 | Cookies:
61 | Forward: all
62 | QueryString: true
63 | MaxTTL: 31536000
64 | MinTTL: 86400
65 | SmoothStreaming: false
66 | TargetOriginId: !Sub ${DomainName}-S3-origin
67 | ViewerProtocolPolicy: redirect-to-https
68 | DefaultRootObject: index.html
69 | Enabled: true
70 | HttpVersion: http2
71 | IPV6Enabled: true
72 | Origins:
73 | - CustomOriginConfig:
74 | HTTPPort: 80
75 | HTTPSPort: 443
76 | OriginKeepaliveTimeout: 5
77 | OriginProtocolPolicy: http-only
78 | OriginReadTimeout: 30
79 | OriginSSLProtocols:
80 | - SSLv3
81 | - TLSv1
82 | DomainName: !Sub ${DomainName}.s3-website-us-east-1.amazonaws.com
83 | Id: !Sub ${DomainName}-S3-origin
84 | OriginPath: ''
85 | PriceClass: PriceClass_All
86 | Restrictions:
87 | GeoRestriction:
88 | RestrictionType: none
89 | ViewerCertificate:
90 | AcmCertificateArn: !Ref Certificate
91 | MinimumProtocolVersion: TLSv1
92 | SslSupportMethod: sni-only
93 | WebACLId: ''
94 | Type: AWS::CloudFront::Distribution
95 |
96 | Outputs:
97 | DistributionId:
98 | Value: !Ref Cdn
99 |
--------------------------------------------------------------------------------
/templates/deployment.yaml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: '2010-09-09'
2 | Description: 'Deploys this website at cfnchecklist.com'
3 |
4 | Parameters:
5 | Cdn:
6 | Type: String
7 | DomainName:
8 | Type: String
9 | GithubRepo:
10 | Type: String
11 | Default: jeshan/cloudformation-checklist
12 |
13 | Resources:
14 | DeployCfnChecklist:
15 | Properties:
16 | Artifacts:
17 | Type: NO_ARTIFACTS
18 | BadgeEnabled: false
19 | Cache:
20 | Modes:
21 | - LOCAL_DOCKER_LAYER_CACHE
22 | - LOCAL_SOURCE_CACHE
23 | Type: LOCAL
24 | EncryptionKey: !Sub 'arn:aws:kms:${AWS::Region}:${AWS::AccountId}:alias/aws/s3'
25 | Environment:
26 | ComputeType: BUILD_GENERAL1_SMALL
27 | Image: aws/codebuild/docker:18.09.0
28 | PrivilegedMode: true
29 | Type: LINUX_CONTAINER
30 | LogsConfig:
31 | CloudWatchLogs:
32 | GroupName: !Ref 'LogGroup'
33 | Status: ENABLED
34 | ServiceRole: !GetAtt 'Role.Arn'
35 | Source:
36 | BuildSpec: !Sub |-
37 | version: 0.2
38 |
39 | env:
40 | variables:
41 | LC_ALL: C.UTF-8
42 | LANG: C.UTF-8
43 |
44 | phases:
45 | pre_build:
46 | commands:
47 | - pip3 install sceptre
48 | build:
49 | commands:
50 | - docker-compose build
51 | - docker-compose up dist
52 | - aws s3 sync dist/ s3://${DomainName}
53 | - aws cloudfront create-invalidation --distribution-id ${Cdn} --paths "/*"
54 | - sceptre --no-colour launch -y main
55 | GitCloneDepth: 1
56 | InsecureSsl: false
57 | Location: !Sub https://github.com/${GithubRepo}
58 | Type: GITHUB
59 | TimeoutInMinutes: 10
60 | Triggers:
61 | Webhook: true
62 | FilterGroups:
63 | - - Type: EVENT
64 | Pattern: PUSH
65 | - Type: HEAD_REF
66 | Pattern: '^refs/heads/master$'
67 | Type: AWS::CodeBuild::Project
68 |
69 | LogGroup:
70 | Type: AWS::Logs::LogGroup
71 |
72 | Role:
73 | Properties:
74 | AssumeRolePolicyDocument:
75 | Statement:
76 | - Action: sts:AssumeRole
77 | Effect: Allow
78 | Principal:
79 | Service: codebuild.amazonaws.com
80 | Version: '2012-10-17'
81 | Policies:
82 | - PolicyDocument:
83 | Statement:
84 | - Action:
85 | - logs:CreateLogGroup
86 | - logs:CreateLogStream
87 | - logs:DeleteLogGroup
88 | - logs:DescribeLogGroups
89 | - logs:PutLogEvents
90 | Effect: Allow
91 | Resource:
92 | - !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:*'
93 | - Action:
94 | - s3:*
95 | Effect: Allow
96 | Resource:
97 | - !Sub arn:aws:s3:::${DomainName}
98 | - !Sub arn:aws:s3:::${DomainName}/*
99 | - Action:
100 | - cloudformation:*
101 | Effect: Allow
102 | Resource:
103 | - !Sub arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/cloudformation-checklist-*
104 | - Action:
105 | - cloudfront:CreateInvalidation
106 | Effect: Allow
107 | Resource: '*'
108 | Version: '2012-10-17'
109 | PolicyName: cfn-checklist-pol
110 | Type: AWS::IAM::Role
111 |
--------------------------------------------------------------------------------
/test/localstorage.test.js:
--------------------------------------------------------------------------------
1 | let expect = require('chai').expect;
2 | let assert = require('assert');
3 |
--------------------------------------------------------------------------------
/test/notation.test.js:
--------------------------------------------------------------------------------
1 | let expect = require('chai').expect;
2 | let assert = require('assert');
3 |
--------------------------------------------------------------------------------
/test/reports.test.js:
--------------------------------------------------------------------------------
1 | const chai = require('chai');
2 | const assert = chai.assert; // Using Assert style
3 | const expect = chai.expect; // Using Expect style
4 | const should = chai.should(); // Using Should style
5 |
6 | const sinon = require('sinon');
7 | const EventEmitter = require('events').EventEmitter;
8 |
--------------------------------------------------------------------------------
/wallaby.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = function (wallaby) {
3 | return {
4 | files: [
5 | './src/scripts/**/*.js'
6 | ],
7 |
8 | tests: [
9 | 'test/**/*.js'
10 | ]
11 | };
12 | };
13 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const path = require('path');
3 |
4 | const mainPath = path.resolve(__dirname, 'src/scripts', 'main.js');
5 | const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
6 |
7 | module.exports = {
8 | cache: true,
9 | mode: 'production',
10 | entry: {
11 | app: mainPath
12 | },
13 | output: {
14 | filename: '[name].bundle.js',
15 | },
16 | module: {
17 | rules: [
18 | {
19 | test: /\.js$/,
20 | exclude: /node_modules/,
21 | loader: 'babel-loader'
22 | }
23 | ]
24 | },
25 | optimization: {
26 | minimize: true
27 | }
28 | };
29 |
--------------------------------------------------------------------------------