├── CHANGELOG.md ├── ROADMAP.md ├── .nvmrc ├── .babelrc ├── src ├── views │ ├── mixins │ │ ├── mixins.pug │ │ ├── m-icon.pug │ │ └── m-checklist-section.pug │ ├── components │ │ ├── c-sponsor.pug │ │ ├── c-top-alert.pug │ │ ├── c-search.pug │ │ ├── c-progress.pug │ │ ├── svg │ │ │ ├── bullet.pug │ │ │ ├── checkbox.pug │ │ │ ├── collapse.pug │ │ │ ├── expand.pug │ │ │ ├── arrow.pug │ │ │ ├── check.pug │ │ │ ├── checked.pug │ │ │ ├── eye.pug │ │ │ ├── code.pug │ │ │ ├── print.pug │ │ │ └── reset.pug │ │ ├── c-nav.pug │ │ ├── checklist │ │ │ ├── checkbox.pug │ │ │ ├── dropdown.pug │ │ │ ├── priority.pug │ │ │ ├── class.pug │ │ │ └── label.pug │ │ ├── s-section-top.pug │ │ ├── s-section-bottom.pug │ │ ├── c-tools.pug │ │ ├── c-new-form.pug │ │ ├── c-newsletter.pug │ │ ├── c-corner.pug │ │ ├── c-tag-filter.pug │ │ ├── c-checklist.pug │ │ └── c-notation.pug │ ├── base │ │ ├── before-scripts.pug │ │ ├── after-scripts.pug │ │ ├── layout.pug │ │ ├── social.pug │ │ ├── footer.pug │ │ └── header.pug │ ├── index-en.pug │ └── index-jp.pug ├── favicon.ico ├── favicon-16x16.png ├── favicon-32x32.png ├── img │ ├── icons │ │ └── 1x1.png │ ├── social │ │ └── facebook-banner.jpg │ ├── logos │ │ ├── logo-front-end-checklist.jpg │ │ └── logo-front-end-checklist.webp │ ├── banners │ │ ├── logo-front-end-checklist.jpg │ │ ├── front-end-checklist-banner-dark.jpg │ │ └── front-end-checklist-banner-light.jpg │ └── flags │ │ ├── ru.svg │ │ ├── fr.svg │ │ ├── jp.svg │ │ ├── vn.svg │ │ ├── tr.svg │ │ ├── cn.svg │ │ └── kr.svg ├── mstile-150x150.png ├── robots.txt ├── apple-touch-icon.png ├── styles │ ├── base │ │ ├── _typography.scss │ │ ├── _media.scss │ │ ├── _headings.scss │ │ ├── _form.scss │ │ ├── _generic.scss │ │ ├── _fonts.scss │ │ ├── _links.scss │ │ ├── _print.scss │ │ └── _icons.scss │ ├── utilities │ │ ├── functions │ │ │ └── _functions.scss │ │ ├── _utilities.scss │ │ └── mixins │ │ │ ├── _mixins.scss │ │ │ └── _m-breakpoints.scss │ ├── components │ │ ├── _c-sponsor.scss │ │ ├── _c-dropdown.scss │ │ ├── _c-tools.scss │ │ ├── _c-top-alert.scss │ │ ├── _c-tags.scss │ │ ├── _c-github.scss │ │ ├── _c-progress.scss │ │ ├── _c-notation.scss │ │ ├── _c-newsletter.scss │ │ ├── _c-list.scss │ │ ├── _c-nav.scss │ │ └── _c-button.scss │ ├── config │ │ ├── _variables.scss │ │ ├── _v-namespaces.scss │ │ ├── _v-typography.scss │ │ └── _v-colors.scss │ ├── layout │ │ ├── _s-footer.scss │ │ ├── _page.scss │ │ ├── _s-main.scss │ │ ├── _s-checklist.scss │ │ ├── _s-aside.scss │ │ └── _s-header.scss │ └── main.scss ├── android-chrome-192x192.png ├── scripts │ ├── main.js │ ├── components │ │ ├── Analytics.js │ │ ├── ProgressBar.js │ │ ├── Notation.js │ │ ├── Filter.js │ │ ├── Report.js │ │ ├── Init.js │ │ ├── Checkboxes.js │ │ ├── Ui.js │ │ ├── Dropdown.js │ │ ├── Tools.js │ │ └── Storage.js │ └── Utils.js ├── browserconfig.xml ├── humans.txt ├── sitemap.xml ├── manifest.json ├── _headers ├── safari-pinned-tab.svg ├── service-worker.js ├── precache-config.js └── modernizr-custom.min.js ├── test ├── notation.test.js ├── localstorage.test.js └── reports.test.js ├── data ├── jp │ ├── project │ │ ├── introductions.json │ │ └── translation.json │ ├── _items.json │ ├── items │ │ └── 利用方法.json │ └── _project.json └── en │ ├── project │ ├── introductions.json │ └── translation.json │ └── items │ ├── webfonts.json │ ├── images.json │ ├── html.json │ ├── javascript.json │ ├── accessibility.json │ ├── seo.json │ ├── performance.json │ └── css.json ├── .github ├── ISSUE_TEMPLATE.md ├── stale.yml ├── PULL_REQUEST_TEMPLATE.md └── CONTRIBUTING.md ├── .editorconfig ├── .prettierrc ├── wallaby.js ├── .codeclimate.yml ├── .gitignore ├── modernizr-config.json ├── .travis.yml ├── webpack.config.js ├── .stylelintrc ├── .eslintrc.js ├── package.json ├── CODE_OF_CONDUCT.md └── README_APP.md /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ROADMAP.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 8.11.3 2 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["env"] 3 | } 4 | -------------------------------------------------------------------------------- /src/views/mixins/mixins.pug: -------------------------------------------------------------------------------- 1 | include m-checklist-section 2 | include m-icon 3 | -------------------------------------------------------------------------------- /src/views/components/c-sponsor.pug: -------------------------------------------------------------------------------- 1 | .c-sponsor 2 | .cs__wrapper 3 | #codefund_ad 4 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheLarkInn/Front-End-Checklist/HEAD/src/favicon.ico -------------------------------------------------------------------------------- /test/notation.test.js: -------------------------------------------------------------------------------- 1 | let expect = require('chai').expect; 2 | let assert = require('assert'); 3 | -------------------------------------------------------------------------------- /data/jp/project/introductions.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "head": { 3 | "introduction": "" 4 | } 5 | }] 6 | -------------------------------------------------------------------------------- /test/localstorage.test.js: -------------------------------------------------------------------------------- 1 | let expect = require('chai').expect; 2 | let assert = require('assert'); 3 | -------------------------------------------------------------------------------- /src/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheLarkInn/Front-End-Checklist/HEAD/src/favicon-16x16.png -------------------------------------------------------------------------------- /src/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheLarkInn/Front-End-Checklist/HEAD/src/favicon-32x32.png -------------------------------------------------------------------------------- /src/img/icons/1x1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheLarkInn/Front-End-Checklist/HEAD/src/img/icons/1x1.png -------------------------------------------------------------------------------- /src/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheLarkInn/Front-End-Checklist/HEAD/src/mstile-150x150.png -------------------------------------------------------------------------------- /src/robots.txt: -------------------------------------------------------------------------------- 1 | # www.robotstxt.org/ 2 | 3 | # Allow crawling of all content 4 | User-agent: * 5 | Disallow: 6 | -------------------------------------------------------------------------------- /src/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheLarkInn/Front-End-Checklist/HEAD/src/apple-touch-icon.png -------------------------------------------------------------------------------- /src/styles/base/_typography.scss: -------------------------------------------------------------------------------- 1 | p { 2 | font-size: 1.2rem; 3 | line-height: 1.5; 4 | margin-top: 0; 5 | } 6 | -------------------------------------------------------------------------------- /src/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheLarkInn/Front-End-Checklist/HEAD/src/android-chrome-192x192.png -------------------------------------------------------------------------------- /src/views/components/c-top-alert.pug: -------------------------------------------------------------------------------- 1 | .c-top-alert 2 | .c-top-alert--alert 3 | p= translation.alert.JAVASCRIPT_DESACTIVATE 4 | -------------------------------------------------------------------------------- /src/img/social/facebook-banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheLarkInn/Front-End-Checklist/HEAD/src/img/social/facebook-banner.jpg -------------------------------------------------------------------------------- /data/en/project/introductions.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "head": { 3 | "introduction": "" 4 | }, 5 | "html": { 6 | "introduction": "" 7 | } 8 | }] 9 | -------------------------------------------------------------------------------- /src/img/logos/logo-front-end-checklist.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheLarkInn/Front-End-Checklist/HEAD/src/img/logos/logo-front-end-checklist.jpg -------------------------------------------------------------------------------- /src/img/logos/logo-front-end-checklist.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheLarkInn/Front-End-Checklist/HEAD/src/img/logos/logo-front-end-checklist.webp -------------------------------------------------------------------------------- /src/img/banners/logo-front-end-checklist.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheLarkInn/Front-End-Checklist/HEAD/src/img/banners/logo-front-end-checklist.jpg -------------------------------------------------------------------------------- /src/scripts/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import Init from './components/Init'; 4 | 5 | document.addEventListener('DOMContentLoaded', () => new Init()); 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/img/banners/front-end-checklist-banner-dark.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheLarkInn/Front-End-Checklist/HEAD/src/img/banners/front-end-checklist-banner-dark.jpg -------------------------------------------------------------------------------- /src/img/banners/front-end-checklist-banner-light.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheLarkInn/Front-End-Checklist/HEAD/src/img/banners/front-end-checklist-banner-light.jpg -------------------------------------------------------------------------------- /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/components/_c-sponsor.scss: -------------------------------------------------------------------------------- 1 | .c-sponsor { 2 | width: 100%; 3 | } 4 | 5 | .cs { 6 | &__wrapper { 7 | min-width: 320px; 8 | overflow: hidden; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | --- 2 | engines: 3 | eslint: 4 | enabled: true 5 | channel: eslint-3 6 | stylelint: 7 | enabled: true 8 | ratings: 9 | paths: 10 | - src/** 11 | - "**.scss" 12 | - "**.js" 13 | exclude_paths: 14 | - "test" 15 | - "data" 16 | - "dist" 17 | - "gulpfile.babel.js" 18 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/humans.txt: -------------------------------------------------------------------------------- 1 | # humanstxt.org/ 2 | # The humans responsible & technology colophon 3 | 4 | # TEAM 5 | 6 | David Dias -- Front-End Developer -- @thedaviddias 7 | 8 | # THANKS 9 | 10 | 11 | 12 | # TECHNOLOGY COLOPHON 13 | 14 | CSS3, HTML5, Pug, Git, ES6, Webpack, Gulp, Modernizr, Normalize.css 15 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/img/flags/ru.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/img/flags/fr.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /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/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | https://frontendchecklist.io/ 5 | 6 | 7 | -------------------------------------------------------------------------------- /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 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/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 | -------------------------------------------------------------------------------- /data/jp/_items.json: -------------------------------------------------------------------------------- 1 | {"利用方法":[{"title":"Doctype","priority":"High","description":"The Doctype is HTML5 and is at the top of all your HTML pages.","code":"https://gist.github.com/thedaviddias/bccee9f4dfa728830cf38bb83838d2d3.js","documentation":[{"title":"Determining the character encoding - HTML5 W3C","url":"https://www.w3.org/TR/html5/syntax.html#determining-the-character-encoding"}],"tags":["all","Meta tag"]}]} -------------------------------------------------------------------------------- /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/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "FE Checklist", 3 | "name": "Front-End Checklist", 4 | "start_url": "http://frontendchecklist.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/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/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 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | sudo: false 3 | node_js: 4 | - "7.1.0" 5 | cache: 6 | directories: 7 | - node_modules 8 | install: 9 | - npm install 10 | script: 11 | - gulp build 12 | notifications: 13 | email: 14 | recipients: 15 | - thedaviddias@gmail.com 16 | branches: 17 | only: 18 | - master 19 | - /^greenkeeper/.*$/ 20 | deploy: 21 | local_dir: dist 22 | provider: pages 23 | skip_cleanup: true 24 | github_token: $GITHUB_TOKEN 25 | on: 26 | branch: master 27 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | daysUntilStale: 60 2 | daysUntilClose: 15 3 | exemptLabels: 4 | - pinned 5 | - security 6 | staleLabel: wontfix 7 | markComment: > 8 | This issue has been automatically marked as stale because it has not had 9 | recent activity. It will be closed if no further activity occurs. If you have any question, please contact me directly at thedaviddias@gmail.com. Thank you 10 | for your contributions to that project! 11 | # Comment to post when closing a stale issue. Set to `false` to disable 12 | closeComment: false 13 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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-sponsor 12 | //- include c-search 13 | 14 | //- Section with tag filter 15 | .s-main__section.s-main__filter 16 | 17 | include c-tag-filter 18 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/img/flags/jp.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /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/img/flags/vn.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /src/img/flags/tr.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /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/_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' everywhere-8a59.kxcdn.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://frontendchecklist.report-uri.io/r/default/csp/enforce; 11 | -------------------------------------------------------------------------------- /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/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 | link.setAttribute('href', link.href + '?ref=frontendchecklist'); 23 | }); 24 | }); 25 | } 26 | 27 | enableAnalytics() { 28 | instance.addRef(); 29 | } 30 | } 31 | 32 | const Instance = new Analytics(); 33 | Object.freeze(Instance); 34 | export default Analytics; 35 | -------------------------------------------------------------------------------- /src/views/components/s-section-bottom.pug: -------------------------------------------------------------------------------- 1 | .s-main__section.s-main__newsletter 2 | 3 | include c-newsletter 4 | 5 | //- Form and navigation anchors 6 | //- Navigation is at the bottom of the page because of the `listSections` generated by each +section present in the article. 7 | header.s-main__section.s-main__header 8 | 9 | .s-header__checklist 10 | 11 | h2.s-header__checklist__title Report and navigation 12 | //- Form to create new checklist 13 | .s-header__checklist__el 14 | include c-new-form 15 | 16 | //- Navigation with anchors based on the sections 17 | .s-header__checklist__el 18 | include c-nav 19 | 20 | //- Letter notation based on number of items checked 21 | .s-header__checklist__el 22 | include c-notation 23 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 3 | 4 | **Fixes**: # 5 | 6 | 🚨 Please review the [guidelines for contributing](CONTRIBUTING.md) and our [code of conduct](../CODE_OF_CONDUCT.md) to this repository. 🚨 7 | **Please complete these steps and check these boxes (by putting an x inside the brackets) before filing your PR:** 8 | 9 | - [ ] Check the commit's or even all commits' message styles matches our requested structure. 10 | - [ ] Check your code additions will fail neither code linting checks nor unit test. 11 | 12 | #### Short description of what this resolves: 13 | 14 | 15 | #### Proposed changes: 16 | 17 | - 18 | - 19 | - 20 | 21 | 👍 Thank you! 22 | -------------------------------------------------------------------------------- /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/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/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/img/flags/cn.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /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/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/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/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="Front-End 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 Front-End 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="@thedaviddias") 15 | meta(name="twitter:creator" content="@thedaviddias") 16 | meta(name="twitter:image" content="https://everywhere-8a59.kxcdn.com/img/social/facebook-banner.jpg") 17 | -------------------------------------------------------------------------------- /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/views/components/c-newsletter.pug: -------------------------------------------------------------------------------- 1 | #mc_embed_signup 2 | h2 Don't miss the Front-End Checklist news! 3 | 4 | p Time to time I'll send you an email with all new evolutions and projects related to the Front-End Checklist. No spam, no cheese! 5 | 6 | form#mc-embedded-subscribe-form.validate(action='https://frontendchecklist.us4.list-manage.com/subscribe/post?u=766ec606ec124252ef84eae4e&id=ef844c4ec4', method='post', name='mc-embedded-subscribe-form', target='_blank', novalidate='') 7 | #mc_embed_signup_scroll 8 | input#mce-EMAIL.email(type='email', value='', name='EMAIL', placeholder='Enter your Email address', required='', aria-label="Email for newsletter") 9 | //- real people should not fill this in and expect good things - do not remove this or risk form bot signups 10 | div(style='position: absolute; left: -5000px;', aria-hidden='true') 11 | input(type='text', name='b_766ec606ec124252ef84eae4e_ef844c4ec4', tabindex='-1', value='') 12 | .clear 13 | input#mc-embedded-subscribe.button(type='submit', value='Subscribe', name='subscribe') 14 | -------------------------------------------------------------------------------- /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-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/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.11, written by Peter Selinger 2001-2013 9 | 10 | 12 | 16 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /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/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/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/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/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-sponsor'; 34 | @import 'components/c-button'; 35 | @import 'components/c-checklist'; 36 | @import 'components/c-dropdown'; 37 | @import 'components/c-newsletter'; 38 | @import 'components/c-github'; 39 | @import 'components/c-tools'; 40 | @import 'components/c-list'; 41 | @import 'components/c-nav'; 42 | @import 'components/c-progress'; 43 | @import 'components/c-notation'; 44 | @import 'components/c-tags'; 45 | -------------------------------------------------------------------------------- /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/views/base/footer.pug: -------------------------------------------------------------------------------- 1 | footer.page-footer 2 | .s-footer 3 | 4 | .s-footer__badges 5 | 6 | p 7 | a(href="https://github.com/thedaviddias/Front-End-Checklist/") 8 | img(src="https://camo.githubusercontent.com/05034eed0515ee94cb8c8829dad9ace1f4e7d79e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f46726f6e74254532253830253931456e645f436865636b6c6973742d666f6c6c6f7765642d627269676874677265656e2e737667" alt="Front‑End_Checklist followed" data-canonical-src="https://img.shields.io/badge/Front%E2%80%91End_Checklist-followed-brightgreen.svg") 9 | 10 | .s-footer__grateful 11 | 12 | p Accelerated by #[a(href="https://www.keycdn.com/" target='_blank', rel="noopener noreferrer") KeyCDN] 13 | 14 | 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] 15 | 16 | .s-footer__made 17 | p Made with ❤️ by #[a(href="https://thedaviddias.me") David Dias ("The")] #[a.twitter-follow-button(href="https://twitter.com/TwitterDev" data-show-count="false" data-show-screen-name="false") Follow @thedaviddias] for the Open-Source Community. 18 | -------------------------------------------------------------------------------- /data/en/items/webfonts.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "title": "Webfont format", 4 | "priority": "High", 5 | "description": "WOFF, WOFF2 and TTF are supported by all modern browsers.", 6 | "documentation": [ 7 | { 8 | "title": "WOFF - Web Open Font Format - Caniuse", 9 | "url": "https://caniuse.com/#feat=woff" 10 | }, 11 | { 12 | "title": "WOFF 2.0 - Web Open Font Format - Caniuse", 13 | "url": "https://caniuse.com/#feat=woff2" 14 | }, 15 | { 16 | "title": "TTF/OTF - TrueType and OpenType font support", 17 | "url": "https://caniuse.com/#feat=ttf" 18 | }, 19 | { 20 | "title": "Using @font-face - CSS-Tricks", 21 | "url": "https://css-tricks.com/snippets/css/using-font-face/" 22 | } 23 | ], 24 | "tags": ["all", "webfont"] 25 | }, 26 | { 27 | "title": "Webfont size", 28 | "priority": "High", 29 | "description": "Webfont sizes don't exceed 2 MB (all variants included).", 30 | "tags": ["all", "webfont"] 31 | }, 32 | { 33 | "title": "Webfont loader", 34 | "priority": "Low", 35 | "description": "Control loading behavior with a webfont loader.", 36 | "documentation": [ 37 | { 38 | "title": "Typekit Web Font Loader", 39 | "url": "https://github.com/typekit/webfontloader" 40 | } 41 | ], 42 | "tags": ["all", "webfont"] 43 | } 44 | ] 45 | -------------------------------------------------------------------------------- /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-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/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/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.head, 16 | sectionTitle: "Head" 17 | }) 18 | 19 | +checklist-section({ 20 | dataSection: _items.html, 21 | sectionTitle: "HTML" 22 | }) 23 | 24 | +checklist-section({ 25 | dataSection: _items.webfonts, 26 | sectionTitle: "Webfonts" 27 | }) 28 | 29 | +checklist-section({ 30 | dataSection: _items.css, 31 | sectionTitle: "CSS" 32 | }) 33 | 34 | +checklist-section({ 35 | dataSection: _items.javascript, 36 | sectionTitle: "JavaScript" 37 | }) 38 | 39 | +checklist-section({ 40 | dataSection: _items.images, 41 | sectionTitle: "Images" 42 | }) 43 | 44 | +checklist-section({ 45 | dataSection: _items.accessibility, 46 | sectionTitle: "Accessibility" 47 | }) 48 | 49 | +checklist-section({ 50 | dataSection: _items.performance, 51 | sectionTitle: "Performance" 52 | }) 53 | 54 | +checklist-section({ 55 | dataSection: _items.seo, 56 | sectionTitle: "SEO" 57 | }) 58 | 59 | include components/s-section-bottom 60 | -------------------------------------------------------------------------------- /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/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/views/index-jp.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.利用方法, 16 | sectionTitle: "利用方法" 17 | }) 18 | 19 | //- +checklist-section({ 20 | //- dataSection: _items.html, 21 | //- sectionTitle: "HTML" 22 | //- }) 23 | 24 | //- +checklist-section({ 25 | //- dataSection: _items.webfonts, 26 | //- sectionTitle: "Webfonts" 27 | //- }) 28 | 29 | //- +checklist-section({ 30 | //- dataSection: _items.css, 31 | //- sectionTitle: "CSS" 32 | //- }) 33 | 34 | //- +checklist-section({ 35 | //- dataSection: _items.javascript, 36 | //- sectionTitle: "JavaScript" 37 | //- }) 38 | 39 | //- +checklist-section({ 40 | //- dataSection: _items.images, 41 | //- sectionTitle: "Images" 42 | //- }) 43 | 44 | //- +checklist-section({ 45 | //- dataSection: _items.accessibility, 46 | //- sectionTitle: "Accessibility" 47 | //- }) 48 | 49 | //- +checklist-section({ 50 | //- dataSection: _items.performance, 51 | //- sectionTitle: "Performance" 52 | //- }) 53 | 54 | //- +checklist-section({ 55 | //- dataSection: _items.seo, 56 | //- sectionTitle: "SEO" 57 | //- }) 58 | 59 | include components/s-section-bottom 60 | -------------------------------------------------------------------------------- /src/views/base/header.pug: -------------------------------------------------------------------------------- 1 | header.s-header 2 | 3 | include ../components/c-corner 4 | 5 | .s-header__banner 6 | .text-center 7 | picture 8 | source(srcset="/img/logos/logo-front-end-checklist.webp" type="image/webp") 9 | source(srcset="/img/logos/logo-front-end-checklist.jpg" type="image/jpeg") 10 | img.img-logo(src="/img/logos/logo-front-end-checklist.jpg" alt="Front-End Checklist Logo" width="100" height="100") 11 | h1.font-weight-bold= translation.SITE_NAME 12 | p.sub-heading= translation.SITE_TAGLINE 13 | 14 | .s-header__media 15 | ul.s-header__media__list 16 | li.s-header__media__item 17 | .fb-like(data-href=translation.URL_WEBSITE data-layout="button_count" data-action="like" data-size="small" data-show-faces="true" data-share="true") 18 | li.s-header__media__item 19 | 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 20 | li.s-header__media__item 21 | 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 22 | 23 | //- Add new language manually 24 | .s-header__lang 25 | ul.s-header__lang__list 26 | li.s-header__lang__item 27 | a(href="/") 28 | img(src="/img/flags/en.svg" width="20" height="15" alt="English language") 29 | li.s-header__lang__item 30 | a(href="/jp") 31 | img(src="/img/flags/jp.svg" width="20" height="15" alt="Japanese language") 32 | -------------------------------------------------------------------------------- /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/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/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-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-newsletter.scss: -------------------------------------------------------------------------------- 1 | /* MailChimp Form Embed Code - Horizontal Super Slim - 12/16/2015 v10.7 2 | Adapted from: http://blog.heyimcat.com/universal-signup-form/ */ 3 | 4 | .mc-field-group { 5 | display: inline-block; 6 | } 7 | 8 | #mc_embed_signup { 9 | @include mq('print') { 10 | display: none; 11 | } 12 | 13 | 14 | form { 15 | text-align: center; 16 | padding: 10px 0; 17 | } 18 | 19 | input.email { 20 | font-size: 15px; 21 | border: 1px solid #abb0b2; 22 | -webkit-border-radius: 3px; 23 | -moz-border-radius: 3px; 24 | border-radius: 3px; 25 | color: #343434; 26 | background-color: white; 27 | box-sizing: border-box; 28 | height: 32px; 29 | padding: 0 5px; 30 | display: inline-block; 31 | margin: 0; 32 | width: 350px; 33 | vertical-align: top; 34 | } 35 | 36 | label { 37 | display: block; 38 | font-size: 16px; 39 | padding-bottom: 10px; 40 | font-weight: bold; 41 | } 42 | 43 | .clear { 44 | display: inline-block; 45 | } 46 | 47 | /* positions button horizontally in line with input */ 48 | .button { 49 | font-size: 13px; 50 | border: none; 51 | border-radius: 3px; 52 | letter-spacing: 1px; 53 | color: white; 54 | background-color: #aaaaaa; 55 | box-sizing: border-box; 56 | height: 32px; 57 | line-height: 32px; 58 | padding: 0 18px; 59 | display: inline-block; 60 | margin: 0; 61 | transition: all .23s ease-in-out 0s; 62 | } 63 | 64 | .button:hover { 65 | background-color: #777777; 66 | cursor: pointer; 67 | } 68 | } 69 | 70 | @media (max-width: 768px) { 71 | #mc_embed_signup { 72 | input.email { 73 | width: 100%; 74 | margin-bottom: 5px; 75 | } 76 | 77 | .clear { 78 | display: block; 79 | width: 100%; 80 | } 81 | 82 | .button { 83 | width: 100%; 84 | margin: 0; 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /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/precache-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | staticFileGlobs: [ 3 | 'index.html', 4 | 'manifest.json', 5 | 'favicon-32x32.png', 6 | 'android-chrome-192x192.png', 7 | 'favicon-16x16.png', 8 | 'safari-pinned-tab.svg', 9 | 'mstile-144x144.png', 10 | 'browserconfig.xml', 11 | 'apple-touch-icon.png' 12 | ], 13 | navigateFallback: '/index.html', 14 | navigateFallbackWhitelist: [/^\/user\//], 15 | skipWaiting: true, 16 | runtimeCaching: [ 17 | { 18 | urlPattern: '/', 19 | handler: 'networkFirst', 20 | options: { 21 | cache: { 22 | name: 'src' 23 | } 24 | } 25 | }, 26 | { 27 | urlPattern: /src/, 28 | handler: 'networkFirst', 29 | options: { 30 | cache: { 31 | name: 'src' 32 | } 33 | } 34 | }, 35 | { 36 | urlPattern: /^https:\/\/api\.github\.com\/users\/[^\/]*\?/, 37 | handler: 'cacheFirst', 38 | options: { 39 | cache: { 40 | maxAgeSeconds: 60 * 60 * 4, 41 | name: 'users' 42 | } 43 | } 44 | }, 45 | { 46 | urlPattern: /^https:\/\/api\.github\.com\/users\/[^\/]*\/repos\?.*$/, 47 | handler: 'cacheFirst', 48 | options: { 49 | cache: { 50 | maxAgeSeconds: 60 * 60 * 4, 51 | name: 'repos' 52 | } 53 | } 54 | }, 55 | { 56 | urlPattern: /^https:\/\/api\.github\.com\/repos/, 57 | handler: 'cacheFirst', 58 | options: { 59 | cache: { 60 | maxAgeSeconds: 60 * 60 * 4, 61 | name: 'contributors' 62 | } 63 | } 64 | }, 65 | { 66 | urlPattern: /^https:\/\/.*\.githubusercontent\.com\//, 67 | handler: 'cacheFirst', 68 | options: { 69 | cache: { 70 | maxAgeSeconds: 60 * 60 * 24, 71 | name: 'user-images' 72 | } 73 | } 74 | } 75 | ] 76 | }; 77 | -------------------------------------------------------------------------------- /data/en/project/translation.json: -------------------------------------------------------------------------------- 1 | { 2 | "SITE_NAME": "The Front-End Checklist", 3 | "INDEX_TITLE": "✨ Your best Front-End Tool ✨", 4 | "URL_WEBSITE": "https://frontendchecklist.io", 5 | "SITE_TAGLINE": "🗂 The Front-End Checklist Application is perfect for modern websites and meticulous developers!", 6 | "SITE_DESCRIPTION": "🗂 The Front-End Checklist Application is perfect for modern websites and meticulous developers! 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/thedaviddias/Front-End-Checklist", 10 | "URL_GITHUB_REPO": "https://github.com/thedaviddias/Front-End-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 desactivated. Please enable your JavaScript to use all functionnalities of the Front-End 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 ✨ Front-End Checklist Application ✨ for modern websites and meticulous developers! With more than 28 000 🌟 on #Github, now you can use it on your daily workflow and generate reports 📑!", 36 | "TWITTER_VIA": "thedaviddias", 37 | "TWITTER_HASHTAGS": "FrontEndChecklist #FrontEnd #Tool #Web", 38 | "STAR": "Star", 39 | "GITHUB_STAR_MSG": "Star thedaviddias/Front-End-Checklist on GitHub" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /data/jp/project/translation.json: -------------------------------------------------------------------------------- 1 | { 2 | "SITE_NAME": "フロントエンドチェックリスト日本語訳 ", 3 | "INDEX_TITLE": "🔥 Your NEW Front-End Tool 🔥", 4 | "URL_WEBSITE": "https://frontendchecklist.io", 5 | "URL_PAGE": "https://frontendchecklist.io/jp/", 6 | "SITE_TAGLINE": "🗂 The Front-End Checklist Application is perfect for modern websites and meticulous developers!", 7 | "SITE_DESCRIPTION": "🗂 The Front-End Checklist Application is perfect for modern websites and meticulous developers! Follow the rules and deliver the best of your work in a generated report!", 8 | "SITE_LANGUAGE": "jp", 9 | "SITE_DIRECTION": "ltr", 10 | "URL_GITHUB_ROOT": "https://github.com/thedaviddias/Front-End-Checklist", 11 | "URL_GITHUB_REPO": "https://github.com/thedaviddias/Front-End-Checklist/tree/gh-pages", 12 | "HIGH_CHECKED": "✓ high priority", 13 | "MEDIUM_CHECKED": "✓ medium priority", 14 | "LOW_CHECKED": "✓ low priority", 15 | "PERCENTAGE_CHECKED": "items are ✓", 16 | "SECTION_DOCUMENTATION": "Documentation", 17 | "SECTION_TOOL": "Tools", 18 | "SECTION_VIDEO": "Videos", 19 | "SECTION_TAG": "Filter by tags", 20 | "alert": { 21 | "JAVASCRIPT_DESACTIVATE": "Your JavaScript seems to be desactivate. Please enable your JavaScript to use all functionnalities of the Front-End Checklist." 22 | }, 23 | "form": { 24 | "LABEL_PROJECT_NAME": "Project Name", 25 | "TITLE_PROJECT_NAME": "Type the name of your project", 26 | "LABEL_PAGE_TITLE": "Page title or URL", 27 | "TITLE_PAGE_TITLE": "Type the name of your page or URL", 28 | "LABEL_DEVELOPER_NAME": "Developer's name or team", 29 | "TITLE_DEVELOPER_NAME": "Type your name or the name of your team", 30 | "LABEL_SEARCH": "Search", 31 | "BUTTON_START_NEW": "Start new checklist", 32 | "BUTTON_GENERATE_PRINT": "Generate report" 33 | }, 34 | "social": { 35 | "TWEET": "Tweet", 36 | "TWITTER_MSG": "Check the 🔥 NEW Front-End Checklist Application 🔥 for modern websites and meticulous developers! With more than 15 000 🌟 on Github, now you can use it on your daily workflow and generate reports 📑!", 37 | "TWITTER_VIA": "thedaviddias", 38 | "TWITTER_HASHTAGS": "FrontEndChecklist #FrontEnd #Tool", 39 | "STAR": "Star", 40 | "GITHUB_STAR_MSG": "Star thedaviddias/Front-End-Checklist on GitHub" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /data/jp/_project.json: -------------------------------------------------------------------------------- 1 | {"_items":{"利用方法":[{"title":"Doctype","priority":"High","description":"The Doctype is HTML5 and is at the top of all your HTML pages.","code":"https://gist.github.com/thedaviddias/bccee9f4dfa728830cf38bb83838d2d3.js","documentation":[{"title":"Determining the character encoding - HTML5 W3C","url":"https://www.w3.org/TR/html5/syntax.html#determining-the-character-encoding"}],"tags":["all","Meta tag"]}]},"introductions":[{"head":{"introduction":""}}],"translation":{"SITE_NAME":"フロントエンドチェックリスト日本語訳 ","INDEX_TITLE":"🔥 Your NEW Front-End Tool 🔥","URL_WEBSITE":"https://frontendchecklist.io","URL_PAGE":"https://frontendchecklist.io/jp/","SITE_TAGLINE":"🗂 The Front-End Checklist Application is perfect for modern websites and meticulous developers!","SITE_DESCRIPTION":"🗂 The Front-End Checklist Application is perfect for modern websites and meticulous developers! Follow the rules and deliver the best of your work in a generated report!","SITE_LANGUAGE":"jp","SITE_DIRECTION":"ltr","URL_GITHUB_ROOT":"https://github.com/thedaviddias/Front-End-Checklist","URL_GITHUB_REPO":"https://github.com/thedaviddias/Front-End-Checklist/tree/gh-pages","HIGH_CHECKED":"✓ high priority","MEDIUM_CHECKED":"✓ medium priority","LOW_CHECKED":"✓ low priority","PERCENTAGE_CHECKED":"items are ✓","SECTION_DOCUMENTATION":"Documentation","SECTION_TOOL":"Tools","SECTION_VIDEO":"Videos","SECTION_TAG":"Filter by tags","alert":{"JAVASCRIPT_DESACTIVATE":"Your JavaScript seems to be desactivate. Please enable your JavaScript to use all functionnalities of the Front-End Checklist."},"form":{"LABEL_PROJECT_NAME":"Project Name","TITLE_PROJECT_NAME":"Type the name of your project","LABEL_PAGE_TITLE":"Page title or URL","TITLE_PAGE_TITLE":"Type the name of your page or URL","LABEL_DEVELOPER_NAME":"Developer's name or team","TITLE_DEVELOPER_NAME":"Type your name or the name of your team","LABEL_SEARCH":"Search","BUTTON_START_NEW":"Start new checklist","BUTTON_GENERATE_PRINT":"Generate report"},"social":{"TWEET":"Tweet","TWITTER_MSG":"Check the 🔥 NEW Front-End Checklist Application 🔥 for modern websites and meticulous developers! With more than 15 000 🌟 on Github, now you can use it on your daily workflow and generate reports 📑!","TWITTER_VIA":"thedaviddias","TWITTER_HASHTAGS":"FrontEndChecklist #FrontEnd #Tool","STAR":"Star","GITHUB_STAR_MSG":"Star thedaviddias/Front-End-Checklist on GitHub"}}} -------------------------------------------------------------------------------- /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/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/img/flags/kr.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /data/en/items/images.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "title": "Optimization", 4 | "priority": "High", 5 | "description": "All images are optimized to be rendered in the browser. WebP format could be used for critical pages (like Homepage)", 6 | "tools": [ 7 | { 8 | "title": "Imagemin", 9 | "url": "https://github.com/imagemin/imagemin" 10 | }, 11 | { 12 | "title": "Use ImageOptim to optimise your images for free.", 13 | "url": "https://imageoptim.com/" 14 | }, 15 | { 16 | "title": "Use Kraken.io awesome alternative for both png and jpg optimization. Up to 1mb per files on free plan.", 17 | "url": "https://kraken.io/web-interface" 18 | } 19 | ], 20 | "tags": ["all", "images", "best practices"] 21 | }, 22 | { 23 | "title": "Picture/Srcset", 24 | "priority": "Medium", 25 | "description": "You use picture/srcset to provide the most appropriate image for the current viewport of the user.", 26 | "documentation": [ 27 | { 28 | "title": "How to Build Responsive Images with srcset", 29 | "url": "https://www.sitepoint.com/how-to-build-responsive-images-with-srcset/" 30 | } 31 | ], 32 | "tags": ["all", "images"] 33 | }, 34 | { 35 | "title": "Retina", 36 | "priority": "Low", 37 | "description": "You provide layout images 2x or 3x, support retina display.", 38 | "tags": ["all", "images"] 39 | }, 40 | { 41 | "title": "Sprite", 42 | "priority": "Medium", 43 | "description": "Small images are in a sprite file (in the case of icons, they can be in an SVG sprite image).", 44 | "tags": ["all", "images"] 45 | }, 46 | { 47 | "title": "Width and Height", 48 | "priority": "High", 49 | "description": "Set width and height attributes on if the final rendered image size is known (can be omitted for CSS sizing).", 50 | "tags": ["all", "images"] 51 | }, 52 | { 53 | "title": "Alternative text", 54 | "priority": "High", 55 | "description": "All have an alternative text which describe the image visually.", 56 | "documentation": [ 57 | { 58 | "title": "Alt-texts: The Ultimate Guide", 59 | "url": "https://axesslab.com/alt-texts/" 60 | } 61 | ], 62 | "tags": ["all", "images"] 63 | }, 64 | { 65 | "title": "Lazy loading", 66 | "priority": "Medium", 67 | "description": "Images are lazyloaded (A noscript fallback is always provided).", 68 | "tags": ["all", "images", "performance"] 69 | } 70 | ] 71 | -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "front-end-checklist", 3 | "version": "0.0.1", 4 | "description": "The perfect Front-End Checklist for modern websites and meticulous developers", 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://thedaviddias@github.com/thedaviddias/Front-End-Checklist-App.git" 14 | }, 15 | "author": "David Dias (thedaviddias@gmail.com)", 16 | "license": "MIT", 17 | "bugs": { 18 | "url": "https://github.com/thedaviddias/Front-End-Checklist-App/issues" 19 | }, 20 | "homepage": "https://github.com/thedaviddias/Front-End-Checklist-App#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 | "eslint-config-airbnb-base": "^13.0.0", 32 | "eslint-config-prettier": "^3.0.0", 33 | "eslint-plugin-flowtype": "^2.46.1", 34 | "eslint-plugin-import": "^2.9.0", 35 | "eslint-plugin-prettier": "^2.6.0", 36 | "flow-bin": "^0.76.0", 37 | "gulp": "^3.9.1", 38 | "gulp-autoprefixer": "^6.0.0", 39 | "gulp-cached": "^1.1.1", 40 | "gulp-cdnizer": "^2.0.0", 41 | "gulp-changed": "^3.2.0", 42 | "gulp-cssnano": "^2.1.2", 43 | "gulp-data": "^1.3.1", 44 | "gulp-eslint": "^5.0.0", 45 | "gulp-group-css-media-queries": "^1.2.2", 46 | "gulp-html-replace": "^1.6.2", 47 | "gulp-htmlmin": "^5.0.0", 48 | "gulp-if": "^2.0.2", 49 | "gulp-imagemin": "^4.1.0", 50 | "gulp-istanbul": "^1.1.3", 51 | "gulp-json-concat": "^0.1.1", 52 | "gulp-mocha": "^6.0.0", 53 | "gulp-newer": "^1.4.0", 54 | "gulp-plumber": "^1.2.0", 55 | "gulp-pug": "^4.0.1", 56 | "gulp-rename": "^1.2.2", 57 | "gulp-sass": "^4.0.1", 58 | "gulp-sourcemaps": "^2.6.4", 59 | "gulp-stylelint": "^7.0.0", 60 | "gulp-util": "^3.0.8", 61 | "gulp-webpack": "^1.5.0", 62 | "html-webpack-plugin": "^3.0.0", 63 | "imagemin-webp": "^4.1.0", 64 | "jsdom": "^12.0.0", 65 | "jsdom-global": "3.0.2", 66 | "modernizr": "^3.6.0", 67 | "postscribe": "^2.0.8", 68 | "prettier": "^1.11.1", 69 | "run-sequence": "^2.2.1", 70 | "sinon": "^6.1.3", 71 | "stylelint": "^9.1.1", 72 | "stylelint-config-standard": "^18.2.0", 73 | "stylelint-scss": "^3.1.3", 74 | "uglifyjs-webpack-plugin": "^1.2.3", 75 | "url-loader": "^1.0.1", 76 | "webpack": "^4.16.1", 77 | "webpack-stream": "^5.0.0", 78 | "yargs": "^12.0.1" 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /data/en/items/html.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "title": "HTML5 Semantic Elements", 4 | "priority": "High", 5 | "description": "HTML5 Semantic Elements are used appropriately (header, section, footer, main...).", 6 | "tools": [ 7 | { 8 | "title": "HTML Reference", 9 | "url": "http://htmlreference.io/" 10 | } 11 | ], 12 | "tags": ["all", "html", "best practices"] 13 | }, 14 | { 15 | "title": "Error pages", 16 | "priority": "High", 17 | "description": "Error 404 page and 5xx exist", 18 | "detail": "Remember that the 5xx error pages need to have their CSS integrated (no external call on the current server).", 19 | "tags": ["all", "html", "best practices"] 20 | }, 21 | { 22 | "title": "Noopener", 23 | "priority": "Medium", 24 | "description": "In case you are using external links with target=\"_blank\", your link should have a rel=\"noopener\" attribute to prevent tab nabbing. If you need to support older versions of Firefox, use rel=\"noopener noreferrer\"", 25 | "documentation": [ 26 | { 27 | "title": "About rel=noopener", 28 | "url": "https://mathiasbynens.github.io/rel-noopener/" 29 | } 30 | ], 31 | "tags": ["all", "html", "best practices", "security"] 32 | }, 33 | { 34 | "title": "Clean up comments", 35 | "priority": "Low", 36 | "description": "Unnecessary code needs to be removed before sending the page to production.", 37 | "tags": ["all", "html", "best practices"] 38 | }, 39 | { 40 | "title": "W3C compliant", 41 | "priority": "High", 42 | "description": "All pages need to be tested with the W3C validator to identify possible issues in the HTML code.", 43 | "tools": [ 44 | { 45 | "title": "W3C validator", 46 | "url": "https://validator.w3.org/" 47 | } 48 | ], 49 | "tags": ["all", "html", "testing"] 50 | }, 51 | { 52 | "title": "HTML Lint", 53 | "priority": "High", 54 | "description": "I use tools to help me analyze any issues I could have on my HTML code.", 55 | "tools": [ 56 | { 57 | "title": "Dirty markup", 58 | "url": "https://dirtymarkup.com/" 59 | }, 60 | { 61 | "title": "webhint", 62 | "url": "https://webhint.io/" 63 | } 64 | ], 65 | "tags": ["all", "html", "testing"] 66 | }, 67 | { 68 | "title": "Link checker", 69 | "priority": "High", 70 | "description": "There are no broken links in my page, verify that you don't have any 404 error.", 71 | "tools": [ 72 | { 73 | "title": "W3C Link Checker", 74 | "url": "https://validator.w3.org/checklink" 75 | } 76 | ], 77 | "tags": ["all", "html", "testing"] 78 | }, 79 | { 80 | "title": "Adblockers test", 81 | "priority": "Medium", 82 | "description": "Your website shows your content correctly with adblockers enabled", 83 | "detail": "(You can provide a message encouraging people to disable their adblocker)", 84 | "tags": ["all", "html", "testing"] 85 | } 86 | 87 | 88 | ] 89 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /data/en/items/javascript.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "title": "JavaScript Inline", 4 | "priority": "High", 5 | "description": "You don't have any JavaScript code inline (mixed with your HTML code).", 6 | "tags": ["all", "javascript"] 7 | }, 8 | { 9 | "title": "Concatenation", 10 | "priority": "High", 11 | "description": "JavaScript files are concatenated.", 12 | "tags": ["all", "javascript"] 13 | }, 14 | { 15 | "title": "Minification", 16 | "priority": "High", 17 | "description": "JavaScript files are minified (you can add the .min suffix).", 18 | "documentation": [ 19 | { 20 | "title": "Minify Resources (HTML, CSS, and JavaScript)", 21 | "url": "https://developers.google.com/speed/docs/insights/MinifyResources" 22 | } 23 | ], 24 | "tags": ["all", "javascript"] 25 | }, 26 | { 27 | "title": "JavaScript security", 28 | "priority": "High", 29 | "description": "", 30 | "documentation": [ 31 | { 32 | "title": "Guidelines for Developing Secure Applications Utilizing JavaScript", 33 | "url": "https://www.owasp.org/index.php/DOM_based_XSS_Prevention_Cheat_Sheet#Guidelines_for_Developing_Secure_Applications_Utilizing_JavaScript" 34 | } 35 | ], 36 | "tags": ["all", "javascript", "security"] 37 | }, 38 | { 39 | "title": "noscript tag", 40 | "priority": "Medium", 41 | "description": "Use `