├── web
├── CHANGELOG.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-notation.pug
│ │ │ └── c-checklist.pug
│ │ ├── base
│ │ │ ├── header.pug
│ │ │ ├── after-scripts.pug
│ │ │ ├── footer.pug
│ │ │ └── layout.pug
│ │ └── index-en.pug
│ ├── favicon.ico
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── img
│ │ ├── icons
│ │ │ └── 1x1.png
│ │ ├── 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
│ │ │ ├── Notation.js
│ │ │ ├── Filter.js
│ │ │ ├── ProgressBar.js
│ │ │ ├── Report.js
│ │ │ ├── Init.js
│ │ │ ├── Ui.js
│ │ │ ├── Dropdown.js
│ │ │ ├── Checkboxes.js
│ │ │ └── Tools.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
├── data
│ ├── jp
│ │ ├── project
│ │ │ ├── introductions.json
│ │ │ └── translation.json
│ │ ├── _items.json
│ │ ├── items
│ │ │ └── 利用方法.json
│ │ └── _project.json
│ └── en
│ │ ├── project
│ │ ├── introductions.json
│ │ └── translation.json
│ │ ├── items
│ │ ├── domain.json
│ │ ├── process.json
│ │ ├── people.json
│ │ └── technology.json
│ │ ├── _items.json
│ │ └── _project.json
├── test
│ ├── notation.test.js
│ ├── localstorage.test.js
│ └── reports.test.js
├── .github
│ ├── ISSUE_TEMPLATE.md
│ ├── stale.yml
│ ├── PULL_REQUEST_TEMPLATE.md
│ └── CONTRIBUTING.md
├── README.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
├── _config.yml
├── docs
└── adr
│ ├── README.md
│ ├── 0001-前端展示页面.md
│ └── 0001-frontend-page.md
├── .editorconfig
├── LICENSE
├── .gitignore
└── rating
├── assets
├── canvas-to-blob.min.js
└── FileSaver.min.js
├── index.html
└── src
├── main.js
└── utils.js
/web/CHANGELOG.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/.nvmrc:
--------------------------------------------------------------------------------
1 | 8.12.0
2 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | remote_theme: phodal/mifa-jekyll
2 |
3 |
--------------------------------------------------------------------------------
/web/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["env"]
3 | }
4 |
--------------------------------------------------------------------------------
/web/src/views/mixins/mixins.pug:
--------------------------------------------------------------------------------
1 | include m-checklist-section
2 | include m-icon
3 |
--------------------------------------------------------------------------------
/web/src/views/components/c-sponsor.pug:
--------------------------------------------------------------------------------
1 | .c-sponsor
2 | .cs__wrapper
3 | #codefund_ad
4 |
--------------------------------------------------------------------------------
/docs/adr/README.md:
--------------------------------------------------------------------------------
1 | # Architecture Decision Records
2 |
3 | * [1. frontend-page](0001-frontend-page.md)
--------------------------------------------------------------------------------
/web/data/jp/project/introductions.json:
--------------------------------------------------------------------------------
1 | [{
2 | "head": {
3 | "introduction": ""
4 | }
5 | }]
6 |
--------------------------------------------------------------------------------
/web/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phodal/new-project-checklist/HEAD/web/src/favicon.ico
--------------------------------------------------------------------------------
/web/test/notation.test.js:
--------------------------------------------------------------------------------
1 | let expect = require('chai').expect;
2 | let assert = require('assert');
3 |
--------------------------------------------------------------------------------
/web/test/localstorage.test.js:
--------------------------------------------------------------------------------
1 | let expect = require('chai').expect;
2 | let assert = require('assert');
3 |
--------------------------------------------------------------------------------
/web/src/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phodal/new-project-checklist/HEAD/web/src/favicon-16x16.png
--------------------------------------------------------------------------------
/web/src/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phodal/new-project-checklist/HEAD/web/src/favicon-32x32.png
--------------------------------------------------------------------------------
/web/src/img/icons/1x1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phodal/new-project-checklist/HEAD/web/src/img/icons/1x1.png
--------------------------------------------------------------------------------
/web/src/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phodal/new-project-checklist/HEAD/web/src/mstile-150x150.png
--------------------------------------------------------------------------------
/web/src/robots.txt:
--------------------------------------------------------------------------------
1 | # www.robotstxt.org/
2 |
3 | # Allow crawling of all content
4 | User-agent: *
5 | Disallow:
6 |
--------------------------------------------------------------------------------
/web/src/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phodal/new-project-checklist/HEAD/web/src/apple-touch-icon.png
--------------------------------------------------------------------------------
/web/src/styles/base/_typography.scss:
--------------------------------------------------------------------------------
1 | p {
2 | font-size: 1.2rem;
3 | line-height: 1.5;
4 | margin-top: 0;
5 | }
6 |
--------------------------------------------------------------------------------
/web/src/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phodal/new-project-checklist/HEAD/web/src/android-chrome-192x192.png
--------------------------------------------------------------------------------
/web/src/views/components/c-top-alert.pug:
--------------------------------------------------------------------------------
1 | .c-top-alert
2 | .c-top-alert--alert
3 | p= translation.alert.JAVASCRIPT_DESACTIVATE
4 |
--------------------------------------------------------------------------------
/web/data/en/project/introductions.json:
--------------------------------------------------------------------------------
1 | [{
2 | "head": {
3 | "introduction": ""
4 | },
5 | "html": {
6 | "introduction": ""
7 | }
8 | }]
9 |
--------------------------------------------------------------------------------
/web/src/img/logos/logo-front-end-checklist.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phodal/new-project-checklist/HEAD/web/src/img/logos/logo-front-end-checklist.jpg
--------------------------------------------------------------------------------
/web/src/img/logos/logo-front-end-checklist.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phodal/new-project-checklist/HEAD/web/src/img/logos/logo-front-end-checklist.webp
--------------------------------------------------------------------------------
/web/src/img/banners/logo-front-end-checklist.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phodal/new-project-checklist/HEAD/web/src/img/banners/logo-front-end-checklist.jpg
--------------------------------------------------------------------------------
/web/src/scripts/main.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import Init from './components/Init';
4 |
5 | document.addEventListener('DOMContentLoaded', () => new Init());
6 |
--------------------------------------------------------------------------------
/web/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/src/img/banners/front-end-checklist-banner-dark.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phodal/new-project-checklist/HEAD/web/src/img/banners/front-end-checklist-banner-dark.jpg
--------------------------------------------------------------------------------
/web/src/img/banners/front-end-checklist-banner-light.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phodal/new-project-checklist/HEAD/web/src/img/banners/front-end-checklist-banner-light.jpg
--------------------------------------------------------------------------------
/web/README.md:
--------------------------------------------------------------------------------
1 | # New Project Chechlists in Web
2 |
3 | Web based on [https://github.com/thedaviddias/Front-End-Checklist](https://github.com/thedaviddias/Front-End-Checklist)
4 |
5 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/.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 |
--------------------------------------------------------------------------------
/web/.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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/src/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #da532c
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/web/.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 |
--------------------------------------------------------------------------------
/web/.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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | max_line_length = off
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/src/img/flags/ru.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/web/src/img/flags/fr.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/docs/adr/0001-前端展示页面.md:
--------------------------------------------------------------------------------
1 | # 1. Frontend Page
2 |
3 | Date: 2019-03-05
4 |
5 | ## Status
6 |
7 | 2019-03-05 proposed
8 |
9 | ## Context
10 |
11 | A webpage will help user to do this.
12 |
13 | such as:
14 |
15 | - https://github.com/thedaviddias/Front-End-Checklist
16 |
17 | ## Decision
18 |
19 | Decision here...
20 |
21 | ## Consequences
22 |
23 | Consequences here...
24 |
--------------------------------------------------------------------------------
/docs/adr/0001-frontend-page.md:
--------------------------------------------------------------------------------
1 | # 1. Frontend Page
2 |
3 | Date: 2019-03-05
4 |
5 | ## Status
6 |
7 | 2019-03-05 proposed
8 |
9 | ## Context
10 |
11 | A webpage will help user to do this.
12 |
13 | such as:
14 |
15 | - https://github.com/thedaviddias/Front-End-Checklist
16 |
17 | ## Decision
18 |
19 | Decision here...
20 |
21 | ## Consequences
22 |
23 | Consequences here...
24 |
--------------------------------------------------------------------------------
/web/src/sitemap.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | https://phodal.github.io/new-project-checklist/
5 |
6 |
7 |
--------------------------------------------------------------------------------
/web/src/views/components/checklist/dropdown.pug:
--------------------------------------------------------------------------------
1 | .c-checklist__column.c-checklist__dropdown
2 |
3 | //- Check if the item has content, if not hide the button
4 | if item.tools || item.documentation || item.code || item.subitems
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 |
--------------------------------------------------------------------------------
/web/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"]}]}
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/src/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "NP Checklist",
3 | "name": "New Project Checklist",
4 | "start_url": "https://phodal.github.io/new-project-checklist/",
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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/src/views/base/header.pug:
--------------------------------------------------------------------------------
1 | header.s-header
2 |
3 | include ../components/c-corner
4 |
5 | .s-header__banner
6 | .text-center
7 | h1.font-weight-bold= translation.SITE_NAME
8 | p.sub-heading= translation.SITE_TAGLINE
9 |
10 | //- Add new language manually
11 | //.s-header__lang
12 | // ul.s-header__lang__list
13 | // li.s-header__lang__item
14 | // a(href="/")
15 | // img(src="/img/flags/en.svg" width="20" height="15" alt="English language")
16 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/.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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | sudo: false
3 | node_js:
4 | - "8.12.0"
5 | cache:
6 | directories:
7 | - node_modules
8 | before_install:
9 | - npm i -g npm@latest
10 | install:
11 | - npm install
12 | script:
13 | - gulp build
14 | notifications:
15 | email:
16 | recipients:
17 | - thedaviddias@gmail.com
18 | branches:
19 | only:
20 | - master
21 | - /^greenkeeper/.*$/
22 | deploy:
23 | local_dir: dist
24 | provider: pages
25 | skip_cleanup: true
26 | github_token: $GITHUB_TOKEN
27 | on:
28 | branch: master
29 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/src/img/flags/jp.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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'; object-src 'none'; img-src https:; script-src https: www.google-analytics.com ajax.googleapis.com buttons.github.io; style-src https: ; font-src https: ;
11 |
--------------------------------------------------------------------------------
/web/src/img/flags/vn.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/.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 |
--------------------------------------------------------------------------------
/web/src/img/flags/tr.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/src/views/base/footer.pug:
--------------------------------------------------------------------------------
1 | footer.page-footer
2 | .s-footer
3 |
4 | .s-footer__grateful
5 |
6 | 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]
7 |
8 | .s-footer__made
9 | p Origin 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.
10 |
--------------------------------------------------------------------------------
/web/.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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 | //- Website wrapper
18 | .page-wrapper
19 |
20 | .page-header
21 | //- Top banners with informations for the user
22 | include ../components/c-top-alert
23 |
24 | include header
25 |
26 | .page-main
27 |
28 | //- The main tag is not include in the block main because repeted
29 | main.s-main#js-main
30 | block main
31 |
32 | .page-footer
33 | include footer
34 |
35 | //- Scripts loading
36 | include after-scripts
37 |
--------------------------------------------------------------------------------
/web/src/img/flags/cn.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/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.technology,
16 | sectionTitle: "技术"
17 | })
18 |
19 | +checklist-section({
20 | dataSection: _items.people,
21 | sectionTitle: "人"
22 | })
23 |
24 | +checklist-section({
25 | dataSection: _items.process,
26 | sectionTitle: "流程"
27 | })
28 |
29 | +checklist-section({
30 | dataSection: _items.domain,
31 | sectionTitle: "业务"
32 | })
33 |
34 | include components/s-section-bottom
35 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/.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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/data/en/items/domain.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "title": "业务远景",
4 | "priority": "High",
5 | "description": "我们在做什么,我们要去哪里?",
6 | "tags": ["all", "domain"]
7 | },
8 | {
9 | "title": "业务需求",
10 | "priority": "Medium",
11 | "description": "",
12 | "subitems": [
13 | {
14 | "title": "需求列表",
15 | "description": "有没有接近全的需求列表?在一定的时间(如迭代内),需求应该是稳定的。"
16 | },
17 | {
18 | "title": "需求管理",
19 | "description": "需求是如何从口头到待办列表的?中间是不是存在不规范的问题"
20 | },
21 | {
22 | "title": " 业务是如何进行变更的?"
23 | }
24 | ],
25 | "tags": ["all", "domain"]
26 | },
27 | {
28 | "title": "跨功能需求",
29 | "priority": "High",
30 | "description": "在系统运作时观察到的质量,例如保安性及易用性等",
31 | "subitems": [
32 | {
33 | "title": "运行质量",
34 | "description": "在系统运作时观察到的质量,例如保安性及易用性等"
35 | },
36 | {
37 | "title": "演进质量",
38 | "description": "软件系统结构及开发过程有关的质量,例如软件可测试性、可维护性、可扩展性、可伸缩性(scalability)等"
39 | }
40 | ],
41 | "tags": ["all", "domain"]
42 | }
43 | ]
44 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Phodal Huang
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/web/src/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
22 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (https://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # TypeScript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 | # next.js build output
61 | .next
62 | .idea
63 |
--------------------------------------------------------------------------------
/web/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-" + encodeURI(sectionTitle))
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 |
--------------------------------------------------------------------------------
/rating/assets/canvas-to-blob.min.js:
--------------------------------------------------------------------------------
1 | !function(t){"use strict";var e=t.HTMLCanvasElement&&t.HTMLCanvasElement.prototype,o=t.Blob&&function(){try{return Boolean(new Blob)}catch(t){return!1}}(),n=o&&t.Uint8Array&&function(){try{return 100===new Blob([new Uint8Array(100)]).size}catch(t){return!1}}(),r=t.BlobBuilder||t.WebKitBlobBuilder||t.MozBlobBuilder||t.MSBlobBuilder,a=/^data:((.*?)(;charset=.*?)?)(;base64)?,/,i=(o||r)&&t.atob&&t.ArrayBuffer&&t.Uint8Array&&function(t){var e,i,l,u,c,f,b,d,B;if(!(e=t.match(a)))throw new Error("invalid data URI");for(i=e[2]?e[1]:"text/plain"+(e[3]||";charset=US-ASCII"),l=!!e[4],u=t.slice(e[0].length),c=l?atob(u):decodeURIComponent(u),f=new ArrayBuffer(c.length),b=new Uint8Array(f),d=0;d
2 |
3 |
4 |
5 | New Project Checklist
6 |
7 |
8 |
9 |
10 |
13 |
14 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/data/en/project/translation.json:
--------------------------------------------------------------------------------
1 | {
2 | "SITE_NAME": "New Project Checklist",
3 | "INDEX_TITLE": "✨ Your best Project Tool ✨",
4 | "URL_WEBSITE": "https://phodal.github.io/new-project-checklist/",
5 | "SITE_TAGLINE": "🗂 The checklist for new project setup for developer",
6 | "SITE_DESCRIPTION": "🗂 The checklist for new project setup for developer",
7 | "SITE_LANGUAGE": "en",
8 | "SITE_DIRECTION": "ltr",
9 | "URL_GITHUB_ROOT": "https://github.com/phodal/new-project-checklist",
10 | "URL_GITHUB_REPO": "https://github.com/phodal/new-project-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 | "SECTION_SUBITEMS": "Items",
20 | "alert": {
21 | "JAVASCRIPT_DESACTIVATE": "Your JavaScript seems to be desactivated. 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 ✨ 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 📑!",
37 | "TWITTER_VIA": "thedaviddias",
38 | "TWITTER_HASHTAGS": "FrontEndChecklist #FrontEnd #Tool #Web",
39 | "STAR": "Star",
40 | "GITHUB_STAR_MSG": "Star thedaviddias/Front-End-Checklist on GitHub"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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"}}}
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/src/img/flags/kr.svg:
--------------------------------------------------------------------------------
1 |
25 |
--------------------------------------------------------------------------------
/rating/assets/FileSaver.min.js:
--------------------------------------------------------------------------------
1 | (function(a,b){if("function"==typeof define&&define.amd)define([],b);else if("undefined"!=typeof exports)b();else{b(),a.FileSaver={exports:{}}.exports}})(this,function(){"use strict";function b(a,b){return"undefined"==typeof b?b={autoBom:!1}:"object"!=typeof b&&(console.warn("Depricated: Expected third argument to be a object"),b={autoBom:!b}),b.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(a.type)?new Blob(["\uFEFF",a],{type:a.type}):a}function c(b,c,d){var e=new XMLHttpRequest;e.open("GET",b),e.responseType="blob",e.onload=function(){a(e.response,c,d)},e.onerror=function(){console.error("could not download file")},e.send()}function d(a){var b=new XMLHttpRequest;return b.open("HEAD",a,!1),b.send(),200<=b.status&&299>=b.status}function e(a){try{a.dispatchEvent(new MouseEvent("click"))}catch(c){var b=document.createEvent("MouseEvents");b.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),a.dispatchEvent(b)}}var f="object"==typeof window&&window.window===window?window:"object"==typeof self&&self.self===self?self:"object"==typeof global&&global.global===global?global:void 0,a=f.saveAs||("object"!=typeof window||window!==f?function(){}:"download"in HTMLAnchorElement.prototype?function(b,g,h){var i=f.URL||f.webkitURL,j=document.createElement("a");g=g||b.name||"download",j.download=g,j.rel="noopener","string"==typeof b?(j.href=b,j.origin===location.origin?e(j):d(j.href)?c(b,g,h):e(j,j.target="_blank")):(j.href=i.createObjectURL(b),setTimeout(function(){i.revokeObjectURL(j.href)},4E4),setTimeout(function(){e(j)},0))}:"msSaveOrOpenBlob"in navigator?function(f,g,h){if(g=g||f.name||"download","string"!=typeof f)navigator.msSaveOrOpenBlob(b(f,h),g);else if(d(f))c(f,g,h);else{var i=document.createElement("a");i.href=f,i.target="_blank",setTimeout(function(){e(i)})}}:function(a,b,d,e){if(e=e||open("","_blank"),e&&(e.document.title=e.document.body.innerText="downloading..."),"string"==typeof a)return c(a,b,d);var g="application/octet-stream"===a.type,h=/constructor/i.test(f.HTMLElement)||f.safari,i=/CriOS\/[\d]+/.test(navigator.userAgent);if((i||g&&h)&&"object"==typeof FileReader){var j=new FileReader;j.onloadend=function(){var a=j.result;a=i?a:a.replace(/^data:[^;]*;/,"data:attachment/file;"),e?e.location.href=a:location=a,e=null},j.readAsDataURL(a)}else{var k=f.URL||f.webkitURL,l=k.createObjectURL(a);e?e.location=l:location.href=l,e=null,setTimeout(function(){k.revokeObjectURL(l)},4E4)}});f.saveAs=a.saveAs=a,"undefined"!=typeof module&&(module.exports=a)});
2 |
3 | //# sourceMappingURL=FileSaver.min.js.map
--------------------------------------------------------------------------------
/web/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 |
93 |
94 | body .c-checklist__body input {
95 | height: 30px;
96 | }
97 |
98 | .c-checklist__subitems {
99 | margin-left: 20px;
100 | padding-bottom: 20px;
101 |
102 | h4 {
103 | color: #606060;
104 | }
105 |
106 | ul {
107 | padding-inline-start: 20px;
108 | }
109 |
110 | ul li span {
111 | font-size: 14px !important;
112 | line-height: 14px;
113 | margin-left: 12px;
114 | }
115 |
116 | li.c-checklist__column {
117 | display: flex;
118 | position: relative;
119 | }
120 |
121 | span.label__title {
122 | order: 2;
123 | }
124 |
125 | span.description {
126 | font-size: 12px !important;
127 | font-weight: normal;
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 |
42 | if item.subitems
43 | .c-checklist__subitems
44 |
45 | section.c-checklist__body
46 | ul.subitems__list
47 | each subitem, j in item.subitems
48 | li.c-checklist__column.c-checklist__subitem.js-sub-section(data-subitem-check="false", data-section=item.title.toLowerCase(), data-subsection-id=`${i}`, data-sub-id=`item-${i}-sub-${j}`)
49 | input(type="checkbox" data-type='subitem' name=`c-checklist__item-${i}-subitem-${j}` id=`c-checklist__item-${i}-subitem-${j}`)
50 | +svg-icon.icon.icon-checkbox(data-icon-name='check')
51 | +svg-icon.icon.icon-checked(data-icon-name='check')
52 |
53 | span.label__title #{subitem.title}
54 | span.description #{subitem.description}
55 |
56 | .c-tags
57 | ul.c-tags__list
58 | each tag in item.tags
59 | if tag === 'all'
60 | else
61 | li.c-tags__item= tag.toUpperCase()
62 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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.77.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": "^2.0.0",
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 |
--------------------------------------------------------------------------------
/web/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 && button.classList && 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 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/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 | case 'sub':
64 | progressBar = section.querySelector('.js-sub-progress');
65 | break;
66 | default:
67 | progressBar = section.querySelector('.js-progress');
68 | break;
69 | }
70 |
71 | if (type === 'sub' || !progressBar) {
72 | return;
73 | }
74 |
75 | const getPercent = parseInt(checkedItems / totalItems * 100, 10);
76 |
77 | progressBar.setAttribute('value', getPercent);
78 |
79 | currentSection.querySelector('.c-progress__label',
80 | ).innerHTML = `${getPercent} %`;
81 |
82 | // section.getAttribute('data-section')
83 | document.querySelectorAll(
84 | '#js-nav-' + section.getAttribute('data-section'),
85 | )[0].setAttribute('data-notation', getPercent);
86 | }
87 |
88 | /**
89 | * Update all progress bar, the main and on each section
90 | *
91 | * @param {any} section
92 | * @param {number} items
93 | * @memberof ProgressBar
94 | */
95 | updateAllProgressBars(section, items) {
96 | new ProgressBar().updateProgressBar(section, items);
97 | // new ProgressBar().updateMainProgressBar();
98 | }
99 | }
100 |
101 | const Instance = new ProgressBar();
102 | Object.freeze(Instance);
103 |
104 | export default ProgressBar;
105 |
--------------------------------------------------------------------------------
/web/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 |
--------------------------------------------------------------------------------
/web/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at thedaviddias@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: http://contributor-covenant.org
46 | [version]: http://contributor-covenant.org/version/1/4/
47 |
--------------------------------------------------------------------------------
/web/src/styles/layout/_s-header.scss:
--------------------------------------------------------------------------------
1 | .sub-heading {
2 | margin: 5px 15px;
3 | font-family: Montserrat, sans-serif;
4 | color: hsla(0, 0%, 100%, .6);
5 | font-size: 1.3rem;
6 | line-height: 1.5;
7 |
8 | @include mq('handheld-and-up') {
9 | font-size: 1.5rem;
10 | margin: 15px;
11 | }
12 | }
13 |
14 | .s-header {
15 | grid-row: 1;
16 | grid-column-start: 2;
17 | padding: 15px 0;
18 | background-color: #415257;
19 | background-image: linear-gradient(45deg, #415257, #292e49);
20 | color: map-get($colors, white);
21 | font-size: 1rem;
22 | text-align: center;
23 | position: relative;
24 |
25 | @include mq('handheld-and-up') {
26 | padding-top: 25px;
27 | padding-bottom: 60px;
28 | }
29 |
30 | @include mq('print') {
31 | padding: 0;
32 | }
33 |
34 | &__banner {
35 | @include mq('handheld-and-up') {
36 | width: 795px;
37 | margin: 0 auto;
38 | }
39 | }
40 |
41 | &__media__list {
42 | display: flex;
43 | align-items: flex-start;
44 | justify-content: center;
45 | align-self: center;
46 | padding: 0;
47 | }
48 |
49 | &__media__item {
50 | margin: 0 5px;
51 | }
52 |
53 | &__checklist {
54 | display: grid;
55 | grid-template-columns: auto;
56 |
57 | @include mq('print') {
58 | margin: 0;
59 | }
60 |
61 | @include mq('handheld-and-up') {
62 | grid-template-rows: auto auto;
63 | grid-template-columns: repeat(5, 1fr);
64 | padding: 10px;
65 | border: 1px solid lightgray;
66 | }
67 |
68 | &__title {
69 | display: none;
70 | }
71 |
72 | &__el {
73 | display: grid;
74 |
75 | @include mq('handheld-and-up') {
76 | padding: 0 20px 0 0;
77 | }
78 | }
79 | // Form
80 | &__el:nth-child(2) {
81 | grid-column: 6;
82 | grid-row: 1 / 2;
83 |
84 | @include mq('print') {
85 | grid-column: 1 / 4;
86 | grid-row: 1;
87 | }
88 |
89 | @include mq('handheld') {
90 | grid-column: 1 / 4;
91 | grid-row: 1 / 2;
92 | }
93 |
94 | @include mq('lap-and-up') {
95 | grid-column: 1 / 2;
96 | grid-row: 1 / 1;
97 | }
98 | }
99 | // Nav
100 | &__el:nth-child(3) {
101 | grid-column: 6;
102 | grid-row: 3 / 4;
103 |
104 | @include mq('print') {
105 | display: none;
106 | }
107 |
108 | @include mq('handheld') {
109 | grid-column: 1 / 6;
110 | grid-row: 2 / 2;
111 | }
112 |
113 | @include mq('lap-and-up') {
114 | grid-column: 2 / 4;
115 | grid-row: 1 / 1;
116 | }
117 | }
118 | // Notation
119 | &__el:nth-child(4) {
120 | grid-column: 6;
121 | grid-row: 2 / 3;
122 |
123 | @include mq('print') {
124 | grid-column: 5 / 6;
125 | grid-row: 1;
126 | }
127 |
128 | @include mq('handheld') {
129 | grid-column: 4 / 6;
130 | grid-row: 1 / 2;
131 | }
132 |
133 | @include mq('lap-and-up') {
134 | grid-column: 4 / 6;
135 | grid-row: 1 / 1;
136 | padding-right: 0;
137 | }
138 | }
139 | }
140 |
141 | &__lang__list {
142 | display: flex;
143 | flex-direction: row;
144 | align-items: flex-start;
145 | align-self: center;
146 | justify-content: center;
147 | margin-top: 20px;
148 | }
149 |
150 | &__lang__item {
151 | margin: 0 5px;
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/web/src/scripts/components/Init.js:
--------------------------------------------------------------------------------
1 | import Filter from './Filter';
2 | import Dropdown from './Dropdown';
3 | import Storage from './Storage';
4 | import Checkboxes from './Checkboxes';
5 | import Notation from './Notation';
6 | import Tools from './Tools';
7 | import Report from './Report';
8 | import Ui from './Ui';
9 | import Analytics from './Analytics';
10 |
11 | let instance = null;
12 | /**
13 | *
14 | *
15 | * @class Init
16 | */
17 | class Init {
18 | constructor() {
19 | if (!instance) {
20 | instance = this;
21 | }
22 |
23 | this.sections = document.querySelectorAll('.js-section');
24 | this.main = document.getElementById('js-main');
25 |
26 | this.checkboxesInit();
27 | this.dropdownInit(this.sections);
28 | this.filterInit();
29 | this.itemsInit(this.sections);
30 | this.notationInit();
31 | this.toolsInit();
32 | this.reportInit();
33 | this.uiInit();
34 | this.AnalyticsInit();
35 |
36 | return instance;
37 | }
38 |
39 | /**
40 | * Initialize all elements in the header which are used in the report
41 | *
42 | * @memberof Init
43 | */
44 | reportInit() {
45 | new Report().enableReport();
46 | }
47 |
48 | /**
49 | * Initialize Storage and load the content
50 | *
51 | * @memberof Init
52 | */
53 | itemsInit(sections) {
54 | // Load all items by each section based on localStorage
55 | sections.forEach((section, i) => {
56 | new Storage().readItems(section, i, sections);
57 | });
58 | // Hide sections based on the localStorage
59 | new Storage().readHideSections();
60 | }
61 |
62 | /**
63 | * Initialize the notation
64 | *
65 | * @memberof Init
66 | */
67 | notationInit() {
68 | // Initilize the progress bar for all sections
69 | new Notation().updateNotation();
70 |
71 | new Notation().readPriority();
72 | }
73 |
74 | /**
75 | * Initialize buttons
76 | *
77 | * @memberof Init
78 | */
79 | toolsInit() {
80 | // Enable all buttons in the option section bar
81 | new Tools().enableTools();
82 | }
83 |
84 | /**
85 | * Initialize Dropdown and collapse on load
86 | *
87 | * @memberof Init
88 | */
89 | dropdownInit(sections) {
90 | // Enable each dropdown buttons
91 | new Dropdown().enableDropdown(document.querySelectorAll('.js-dropdown'));
92 |
93 | // Collapse on loading each item (except which present into localStorage)
94 | sections.forEach(section => {
95 | new Dropdown().collapseAllDropdown({section});
96 | });
97 | }
98 |
99 | /**
100 | * Initialize Checkboxes class
101 | *
102 | * @memberof Init
103 | */
104 | checkboxesInit() {
105 | // Enable each checkboxe for all items
106 | new Checkboxes().enableCheckbox();
107 | }
108 |
109 | /**
110 | * Initialize Filters
111 | *
112 | * @memberof Init
113 | */
114 | filterInit() {
115 | new Filter().readFilterStorage('tag');
116 |
117 | new Filter().enableFilter('tag', 'data-tag', '.js-filter-tag');
118 | }
119 |
120 | /**
121 | * Initialize UI components
122 | *
123 | * @memberof Init
124 | */
125 | uiInit() {
126 | new Ui().enableUi();
127 | }
128 |
129 | /**
130 | * Add analytics utils
131 | *
132 | * @memberof Init
133 | */
134 | AnalyticsInit() {
135 | new Analytics().enableAnalytics();
136 | }
137 | }
138 |
139 | const Instance = new Init();
140 | Object.freeze(Instance);
141 |
142 | export default Init;
143 |
--------------------------------------------------------------------------------
/rating/src/main.js:
--------------------------------------------------------------------------------
1 | var dimensions = {};
2 |
3 | function drawFromLocalStorage() {
4 | var savedItems = window.localStorage.getItem(window.storagePreifx);
5 | var lastResults = window.localStorage.getItem(window.storagePreifx + '.last.results');
6 | if (savedItems) {
7 | var parsedItems = JSON.parse(savedItems);
8 | drawChart(parsedItems);
9 | window.results = parsedItems;
10 | }
11 | if (lastResults) {
12 | window.lastResults = JSON.parse(lastResults);
13 | }
14 | }
15 |
16 | function renderForm() {
17 | var dimensions = {};
18 | var sections = document.getElementById('sections');
19 | var sectionsHtml = "";
20 | for (var i = 0; i < window.dimensionsArray.length; i++) {
21 | var dimension = window.dimensionsArray[i];
22 | var id = dimension.toLocaleLowerCase()
23 | .replace(/,/g, "")
24 | .replace(/ /g, "-");
25 | dimensions[id] = {
26 | id: id,
27 | axis: dimension
28 | };
29 | var value = 3;
30 | if (window.lastResults) {
31 | value = window.lastResults[id].value;
32 | window.location.hash = generateHash(window.results);
33 | }
34 | sectionsHtml = sectionsHtml + ' \n'
39 | }
40 |
41 | sections.innerHTML = sectionsHtml;
42 | window.dimensions = dimensions;
43 | }
44 |
45 | function initForm() {
46 | window.results = [];
47 | window.lastResult = [];
48 |
49 | if (hasHash()) {
50 | drawFromHash()
51 | } else {
52 | drawFromLocalStorage();
53 | }
54 |
55 | renderForm();
56 | }
57 |
58 | initForm();
59 |
60 | function bindSliderEvent() {
61 | var arr = Object.keys(window.dimensions);
62 | for (var i = 0; i < arr.length; i++) {
63 | document.getElementById(arr[i]).addEventListener('change', function (result) {
64 | document.getElementById(result.target.id + '_span').innerHTML = result.target.value;
65 | })
66 | }
67 | }
68 |
69 | bindSliderEvent();
70 |
71 | function handleClick() {
72 | event.preventDefault();
73 | var results = [];
74 | var arr = Object.keys(dimensions);
75 | for (var i = 0; i < arr.length; i++) {
76 | var currentDimension = dimensions[arr[i]];
77 | var value = document.getElementById(arr[i]).value;
78 | let parsedValue = parseInt(value);
79 | results.push({
80 | axis: currentDimension.axis,
81 | value: parsedValue
82 | });
83 |
84 | dimensions[arr[i]].value = parsedValue;
85 | }
86 |
87 | if (window.results.length <= 1) {
88 | window.results.push(results);
89 | } else {
90 | window.results.shift();
91 | window.results.push(results);
92 | }
93 |
94 | localStorage.setItem(window.storagePreifx, JSON.stringify(window.results));
95 | localStorage.setItem(window.storagePreifx + '.last.results', JSON.stringify(dimensions));
96 |
97 | window.location.hash = generateHash(window.results);
98 | drawChart(window.results);
99 | }
100 |
101 | function handleCustom() {
102 | event.preventDefault();
103 | var value = document.getElementById('custom-dimension').value;
104 | if (!value) {
105 | return;
106 | }
107 | window.storagePreifx = 'custom';
108 | window.dimensionsArray = value.split(',');
109 | renderForm();
110 | handleClick();
111 | }
112 |
--------------------------------------------------------------------------------
/web/data/en/items/technology.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "title": "技术远景",
4 | "priority": "High",
5 | "description": "在技术上,我们有什么追求",
6 | "tools": [
7 | "Lean Canvas"
8 | ],
9 | "documentation": [
10 | ],
11 | "tags": [
12 | "all",
13 | "vision"
14 | ]
15 | },
16 | {
17 | "title": "文档",
18 | "priority": "High",
19 | "description": "文档即代码——好的文档应该是版本管理的。",
20 | "subitems": [
21 | {
22 | "title": "Path to Production",
23 | "description": "旨在通过可视化的方式来展示项目的上线流程,并优化过程中的瓶颈问题。"
24 | },
25 | {
26 | "title": " 上线及发布日记",
27 | "description": ""
28 | },
29 | {
30 | "title": "项目相关的 wiki 和文档记录",
31 | "description": ""
32 | },
33 | {
34 | "title": "开发规范",
35 | "description": ""
36 | }
37 | ],
38 | "tags": [
39 | "all",
40 | "technology"
41 | ]
42 | },
43 | {
44 | "title": "架构",
45 | "priority": "High",
46 | "description": "系统相关的架构图,如 C4Model 方式描述\n 现有的技术栈及其关系",
47 | "subitems": [
48 | {
49 | "title": "系统相关的架构图",
50 | "description": "如 C4Model 方式描述"
51 | },
52 | {
53 | "title": "现有的技术栈及其未来方案",
54 | "description": ""
55 | }
56 | ],
57 | "tags": [
58 | "all",
59 | "technology"
60 | ]
61 | },
62 | {
63 | "title": "代码库",
64 | "priority": "High",
65 | "description": "在代码库中拥有诸如搭建指南、架构决策记录、编码器配置等相应的事项。",
66 | "subitems": [
67 | {
68 | "title": "搭建指南",
69 | "description": "这份指南应该随项目的代码一起分发。"
70 | },
71 | {
72 | "title": "架构决策记录",
73 | "description": "放置在代码库的 ``docs/adr`` 目录中"
74 | },
75 | {
76 | "title": "编辑器配置和代码风格规范",
77 | "description": "使用诸如 editorconfig 这样的工具,来统一规范化代码,并采用 Lint 工具来分析代码 。"
78 | },
79 | {
80 | "title": "模式和风格指南",
81 | "description": "在项目中融入系统架构,如 Clean Architecture 和风格,并有明显的指引。"
82 | },
83 | {
84 | "title": "分支管理模式",
85 | "description": "GitFlow 或者 master,或者 Feature Branch。"
86 | },
87 | {
88 | "title": "代码提交风格",
89 | "description": "业务风格或者是开源软件风格?"
90 | }
91 | ],
92 | "tags": [
93 | "all",
94 | "technology"
95 | ]
96 | },
97 | {
98 | "title": "测试",
99 | "priority": "High",
100 | "description": "如何针对项目进行有效的测试",
101 | "subitems": [
102 | {
103 | "title": "测试策略",
104 | "description": "测试层级, 测试金字塔"
105 | },
106 | {
107 | "title": "自动化测试"
108 | }
109 | ],
110 | "tags": [
111 | "all",
112 | "technology"
113 | ]
114 | },
115 | {
116 | "title": "项目演进",
117 | "priority": "High",
118 | "description": "未来的技术栈\n 系统的演进方案",
119 | "subitems": [
120 | {
121 | "title": "技术风险点",
122 | "description": "即需要提前 spike 调研的内容"
123 | },
124 | {
125 | "title": "未来的技术栈"
126 | },
127 | {
128 | "title": "系统的演进方案"
129 | }
130 | ],
131 | "tags": [
132 | "all",
133 | "technology"
134 | ]
135 | },
136 | {
137 | "title": "安全",
138 | "priority": "High",
139 | "description": "安全无小事",
140 | "subitems": [
141 | {
142 | "title": "安全标准",
143 | "description": "安全更重要,还是体验更重要?"
144 | },
145 | {
146 | "title": "代码中的数据加密"
147 | },
148 | {
149 | "title": "代码安全"
150 | }
151 | ],
152 | "tags": [
153 | "all",
154 | "technology"
155 | ]
156 | },
157 | {
158 | "title": "质量",
159 | "priority": "High",
160 | "description": "",
161 | "subitems": [
162 | {
163 | "title": "项目质量跟踪"
164 | },
165 | {
166 | "title": "代码质量可视化"
167 | },
168 | {
169 | "title": "应用质量策略"
170 | }
171 | ],
172 | "tags": [
173 | "all",
174 | "technology"
175 | ]
176 | }
177 | ]
178 |
--------------------------------------------------------------------------------
/web/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 | checkSubItems(el) {
13 | let section = instance.getClosest(el, '.js-section');
14 | let sectionId = section.getAttribute('data-section-id');
15 | let itemId = el.getAttribute('data-item-id');
16 | let elements = document.querySelectorAll(`[data-section-id="${sectionId}"] [data-item-id="${itemId}"] .js-sub-section`);
17 | for (let i = 0; i < elements.length; i++) {
18 | elements[i].setAttribute('data-subitem-check', 'true')
19 | }
20 | }
21 |
22 | uncheckSubItems(el) {
23 | let section = instance.getClosest(el, '.js-section');
24 | let sectionId = section.getAttribute('data-section-id');
25 | let itemId = el.getAttribute('data-item-id');
26 | let elements = document.querySelectorAll(`[data-section-id="${sectionId}"] [data-item-id="${itemId}"] .js-sub-section`);
27 | for (let i = 0; i < elements.length; i++) {
28 | elements[i].setAttribute('data-subitem-check', 'false')
29 | }
30 | }
31 |
32 | variableList(el) {
33 | let section;
34 | let isSubItem = el.getAttribute('data-type') === 'subitem';
35 | if (isSubItem) {
36 | section = instance.getClosest(el, '.js-sub-section');
37 | } else {
38 | section = instance.getClosest(el, '.js-section');
39 | }
40 |
41 | let sectionName = section.getAttribute('data-section');
42 | const sectionId = section.getAttribute('data-section-id');
43 | const subItemId = section.getAttribute('data-sub-id');
44 |
45 | const item = instance.getClosest(el, '.js-item ');
46 |
47 | let itemId;
48 | let itemCheck;
49 | let itemDropdown;
50 |
51 | if (item !== null) {
52 | itemId = item.getAttribute('data-item-id');
53 | itemCheck = item.getAttribute('data-item-check');
54 | itemDropdown = item.getAttribute('data-item-dropdown');
55 | }
56 |
57 |
58 | if (isSubItem) {
59 | sectionName = sectionName + '-sub';
60 | section = instance.getClosest(el, '.js-sub-section');
61 | itemId = subItemId;
62 | }
63 |
64 | return {
65 | sectionId,
66 | section,
67 | sectionName,
68 | item,
69 | itemId,
70 | itemCheck,
71 | itemDropdown,
72 | subItemId,
73 | };
74 | }
75 |
76 | visibityEl(container, el, status) {
77 | const tags = container.querySelectorAll(el)[0];
78 |
79 | if (tags !== undefined) {
80 | if (status === 'hide') {
81 | tags.style.display = 'none';
82 | } else {
83 | tags.style.display = 'flex';
84 | }
85 | }
86 | }
87 |
88 | detailsContainer(section) {
89 | const sectionClass = section.classList[1];
90 | const sectionObj = document.querySelectorAll('.' + sectionClass);
91 | const detailsContainer = sectionObj[0].querySelectorAll('.js-details');
92 |
93 | return detailsContainer;
94 | }
95 |
96 | /* eslint-disable */
97 | getClosest(elem, selector) {
98 | if (!Element.prototype.matches) {
99 | Element.prototype.matches =
100 | Element.prototype.matchesSelector ||
101 | Element.prototype.mozMatchesSelector ||
102 | Element.prototype.msMatchesSelector ||
103 | Element.prototype.oMatchesSelector ||
104 | Element.prototype.webkitMatchesSelector ||
105 | function parse(s) {
106 | let matches = (this.document || this.ownerDocument).querySelectorAll(
107 | s);
108 | let i = matches.length;
109 | while ((--i >= 0 && matches.item(i) !== this)) {
110 | }
111 | return i > -1;
112 | };
113 | }
114 |
115 | // Get closest match
116 | for (; elem && elem !== document; elem = elem.parentNode) {
117 | if (elem.matches(selector)) return elem;
118 | }
119 |
120 | return null;
121 | }
122 |
123 | /* eslint-enable */
124 | }
125 |
126 | const Instance = new Utils();
127 | Object.freeze(Instance);
128 |
129 | export default Utils;
130 |
--------------------------------------------------------------------------------
/web/data/en/_items.json:
--------------------------------------------------------------------------------
1 | {"domain":[{"title":"业务远景","priority":"High","description":"我们在做什么,我们要去哪里?","tags":["all","domain"]},{"title":"业务需求","priority":"Medium","description":"","subitems":[{"title":"需求列表","description":"有没有接近全的需求列表?在一定的时间(如迭代内),需求应该是稳定的。"},{"title":"需求管理","description":"需求是如何从口头到待办列表的?中间是不是存在不规范的问题"},{"title":" 业务是如何进行变更的?"}],"tags":["all","domain"]},{"title":"跨功能需求","priority":"High","description":"在系统运作时观察到的质量,例如保安性及易用性等","subitems":[{"title":"运行质量","description":"在系统运作时观察到的质量,例如保安性及易用性等"},{"title":"演进质量","description":"软件系统结构及开发过程有关的质量,例如软件可测试性、可维护性、可扩展性、可伸缩性(scalability)等"}],"tags":["all","domain"]}],"people":[{"title":"团队成员","priority":"High","description":"非技术问题找谁?","subitems":[{"title":"非技术问题找谁?"},{"title":"团队成员的技术栈及水平"},{"title":"每个人的技术水平","description":"包含应该怎么带:Coach(教练式), Pairing(结对式), Teach(教学式)"},{"title":"项目无关的技术,可以找谁一起“娱乐”?"},{"title":"1 to 1 Meetings"}],"tags":["all","people"]},{"title":"利益相关者","priority":"Medium","description":"","subitems":[{"title":"了解各个相关者(Level 1)","description":"如作为一个开发人员,大部分时间并不会和利益相关者有直接的沟通。"},{"title":"和相关者保持沟通(Level 2)","description":"适当沟通,可以帮助项目更好地进行"}],"tags":["all","people"]},{"title":"跨团队协作","priority":"Medium","description":"相关的合作方有哪些,各自的接口人是谁?","subitems":[{"title":"相关的合作方有哪些,各自的接口人是谁?"},{"title":"同组织、项目下的其它团队。"}],"tags":["all","people"]},{"title":"用户","priority":"Low","description":"用户是谁?我们是否与他们直接接触?","subitems":[{"title":"用户是谁?我们是否与他们直接接触?"},{"title":"反馈环。一个用户的反馈是如何变成需求的?"}],"tags":["all","people"]}],"process":[{"title":"Project Process","priority":"High","description":"完成业务需求的基本流程","subitems":[{"title":"项目的 Roadmap","description":"项目 Deadline,关键时间节点,项目规划等"},{"title":"项目功能的生命周期","description":"如敏捷中的故事卡工作流"},{"title":"沟通方式?","description":"如 IM,邮件,还有敏捷的每日站会,远程会议,Retro 等"}],"tags":["all","process"]},{"title":"Path to Development","priority":"High","description":"不同的的组织包含自身特别的情况,如 PC 端口、网络权限、代码库权限等的开通都需要一定的流程。","subitems":[{"title":"开发机申请及网络等权限准备"},{"title":"代码库权限管理"},{"title":"编辑器和相关的工具申请"}],"tags":["all","process"]},{"title":"Path to Production","priority":"High","description":"代码中的 Path to Production 只是一份说明——针对于开发人员的,而这里的则需要一个更详细的说明。","subitems":[{"title":"上线每一步的流程"},{"title":"相关的关键人"},{"title":"每一步所需要的工具"},{"title":"每一步所需要的流程","description":"如 QA 测试流程,上线流程"}],"tags":["all","process"]},{"title":"Path to Roll Off","priority":"Low","description":"换一个项目时,需要哪些东西?","tags":["all","process"]}],"technology":[{"title":"技术远景","priority":"High","description":"在技术上,我们有什么追求","tools":["Lean Canvas"],"documentation":[],"tags":["all","vision"]},{"title":"文档","priority":"High","description":"文档即代码——好的文档应该是版本管理的。","subitems":[{"title":"Path to Production","description":"旨在通过可视化的方式来展示项目的上线流程,并优化过程中的瓶颈问题。"},{"title":" 上线及发布日记","description":""},{"title":"项目相关的 wiki 和文档记录","description":""},{"title":"开发规范","description":""}],"tags":["all","technology"]},{"title":"架构","priority":"High","description":"系统相关的架构图,如 C4Model 方式描述\n 现有的技术栈及其关系","subitems":[{"title":"系统相关的架构图","description":"如 C4Model 方式描述"},{"title":"现有的技术栈及其未来方案","description":""}],"tags":["all","technology"]},{"title":"代码库","priority":"High","description":"在代码库中拥有诸如搭建指南、架构决策记录、编码器配置等相应的事项。","subitems":[{"title":"搭建指南","description":"这份指南应该随项目的代码一起分发。"},{"title":"架构决策记录","description":"放置在代码库的 ``docs/adr`` 目录中"},{"title":"编辑器配置和代码风格规范","description":"使用诸如 editorconfig 这样的工具,来统一规范化代码,并采用 Lint 工具来分析代码 。"},{"title":"模式和风格指南","description":"在项目中融入系统架构,如 Clean Architecture 和风格,并有明显的指引。"},{"title":"分支管理模式","description":"GitFlow 或者 master,或者 Feature Branch。"},{"title":"代码提交风格","description":"业务风格或者是开源软件风格?"}],"tags":["all","technology"]},{"title":"测试","priority":"High","description":"如何针对项目进行有效的测试","subitems":[{"title":"测试策略","description":"测试层级, 测试金字塔"},{"title":"自动化测试"}],"tags":["all","technology"]},{"title":"项目演进","priority":"High","description":"未来的技术栈\n 系统的演进方案","subitems":[{"title":"技术风险点","description":"即需要提前 spike 调研的内容"},{"title":"未来的技术栈"},{"title":"系统的演进方案"}],"tags":["all","technology"]},{"title":"安全","priority":"High","description":"安全无小事","subitems":[{"title":"安全标准","description":"安全更重要,还是体验更重要?"},{"title":"代码中的数据加密"},{"title":"代码安全"}],"tags":["all","technology"]},{"title":"质量","priority":"High","description":"","subitems":[{"title":"项目质量跟踪"},{"title":"代码质量可视化"},{"title":"应用质量策略"}],"tags":["all","technology"]}]}
--------------------------------------------------------------------------------
/web/src/styles/base/_print.scss:
--------------------------------------------------------------------------------
1 | @media print {
2 | @page {
3 | margin: 20px 15px;
4 | }
5 |
6 | body {
7 | margin: 0;
8 | overflow: hidden;
9 | position: relative;
10 | box-sizing: border-box;
11 | page-break-after: always;
12 | font: 10pt Arial, 'Times New Roman', Times, serif;
13 | line-height: 1.3;
14 | background: map-get($colors, white) !important;
15 | color: map-get($colors, black) !important;
16 | -webkit-print-color-adjust: exact;
17 | }
18 |
19 | /* Defining all page breaks */
20 | a {
21 | page-break-inside: avoid;
22 | }
23 |
24 | h1,
25 | h2,
26 | h3,
27 | h4,
28 | h5,
29 | h6 {
30 | page-break-after: avoid;
31 | page-break-inside: avoid;
32 | }
33 |
34 | img {
35 | page-break-inside: avoid;
36 | page-break-after: avoid;
37 | }
38 |
39 | table,
40 | pre {
41 | page-break-inside: avoid;
42 | }
43 |
44 | ul,
45 | ol,
46 | dl {
47 | page-break-before: avoid;
48 | }
49 |
50 | /* Displaying link color and link behaviour */
51 | a:link,
52 | a:visited,
53 | a {
54 | background: transparent;
55 | color: map-get($colors, primary);
56 | font-weight: bold;
57 | text-decoration: underline;
58 | text-align: left;
59 | }
60 |
61 | a[href^='http']::after {
62 | content: initial;
63 | }
64 | $a: after >
65 |
66 | article a[href^='#']::after {
67 | content: '';
68 | }
69 |
70 | /* stylelint-disable selector-pseudo-class-no-unknown */
71 | a:not(:local-link)::after {
72 | content: ' < ' attr(href) '> ';
73 | }
74 | /* stylelint-enable */
75 |
76 | .icon-checkbox,
77 | .icon-checked {
78 | display: none !important;
79 | }
80 |
81 | .c-checklist__body input {
82 | height: auto !important;
83 | top: 4px !important;
84 | opacity: 1 !important;
85 | }
86 |
87 | .c-checklist__body label {
88 | text-decoration: none !important;
89 | opacity: 1 !important;
90 | }
91 |
92 | .c-tags,
93 | .c-github-corner,
94 | .s-header__media,
95 | .s-header__lang,
96 | .img-logo,
97 | .s-content__filter,
98 | .s-content__search,
99 | .s-content__meta,
100 | .s-section__meta,
101 | .s-meta,
102 | .c-notation__generate,
103 | .s-nav {
104 | display: none !important;
105 | }
106 |
107 | .page-main {
108 | display: block !important;
109 | }
110 |
111 | h2 {
112 | font-size: 20pt !important;
113 | }
114 |
115 | label {
116 | font-size: 9pt !important;
117 | }
118 |
119 |
120 | .s-header {
121 | text-align: left !important;
122 | }
123 |
124 | .s-header__banner {
125 | padding: 15px;
126 | }
127 |
128 | .sub-heading {
129 | font-size: 9pt !important;
130 | margin: 0 !important;
131 | }
132 |
133 | .c-checklist__item::before {
134 | display: none;
135 | }
136 |
137 | .label__description {
138 | line-height: 1.5;
139 | }
140 |
141 | .c-checklist__dropdown {
142 | display: none;
143 | }
144 |
145 | .sub-heading::after {
146 | content: ' ★ Generated on http://frontendchecklist.io ★ ';
147 | white-space: pre;
148 | }
149 |
150 | .s-header__checklist__el {
151 | padding: 0 !important;
152 | }
153 |
154 | .c-notation__item {
155 | width: 80px !important;
156 | height: 80px !important;
157 | }
158 |
159 | .c-progress {
160 | padding: 0 20px;
161 | }
162 |
163 | .c-progress__counter,
164 | .c-progress__label {
165 | font-size: 8pt !important;
166 | }
167 |
168 | .c-progress__bar {
169 | display: none !important;
170 | }
171 |
172 | .c-progress__label {
173 | position: relative !important;
174 | padding: 20pt 0 !important;
175 | left: auto !important;
176 | }
177 |
178 | .c-nav {
179 | margin: 0 !important;
180 | position: relative !important;
181 | right: auto !important;
182 | z-index: 10 !important;
183 | }
184 |
185 | .c-nav__list {
186 | position: relative !important;
187 | top: 0 !important;
188 | flex-direction: row !important;
189 | }
190 |
191 | .c-nav__item .c-button {
192 | font-size: 9pt !important;
193 | border: 0 !important;
194 | }
195 |
196 | .form input {
197 | font-size: 9pt !important;
198 | padding: 3px !important;
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/web/src/styles/components/_c-button.scss:
--------------------------------------------------------------------------------
1 | // $control-radius: $radius !default;
2 | // $control-radius-small: $radius-small !default;
3 |
4 |
5 | $control-padding-vertical: calc(8px - 1px) !default;
6 | $control-padding-horizontal: calc(11px - 1px) !default;
7 | $control-padding-vertical-up: calc(6px - 1px) !default;
8 | $control-padding-horizontal-up: calc(10px - 1px) !default;
9 |
10 | @mixin control {
11 | -moz-appearance: none;
12 | -webkit-appearance: none;
13 | align-items: center;
14 | border: 1px solid transparent;
15 | border-radius: 3px;
16 | box-shadow: none;
17 | display: inline-flex;
18 | font-size: 1.3rem;
19 | padding: $control-padding-vertical $control-padding-horizontal;
20 | justify-content: flex-start;
21 | line-height: 1.4;
22 | position: relative;
23 | vertical-align: top;
24 |
25 | @include mq(lap-and-up) {
26 | font-size: $size-medium;
27 | height: 34px;
28 | padding: $control-padding-vertical-up $control-padding-horizontal-up;
29 | }
30 | // States
31 | &:focus,
32 | &.is-focused,
33 | &:active,
34 | &.is-active {
35 | outline: none;
36 | }
37 |
38 | &[disabled] {
39 | cursor: not-allowed;
40 | }
41 | }
42 |
43 | // The controls sizes use mixins so they can be used at different breakpoints
44 | @mixin control-small {
45 | // border-radius: $control-radius-small;
46 | font-size: $size-small;
47 | }
48 |
49 | @mixin control-medium {
50 | font-size: $size-medium;
51 | }
52 |
53 | @mixin control-large {
54 | font-size: $size-large;
55 | }
56 |
57 | $button-color: map-get($colors, grey-darker) !default;
58 | $button-background-color: map-get($colors, white) !default;
59 | $button-border-color: #999999 !default;
60 | $button-hover-color: $link-hover !default;
61 | $button-hover-border-color: $link-hover-border !default;
62 | $button-focus-color: $link-focus !default;
63 | $button-focus-border-color: $link-focus-border !default;
64 |
65 | // The button sizes use mixins so they can be used at different breakpoints
66 | @mixin button-small {
67 | // border-radius: $radius-small;
68 | font-size: $size-small;
69 | }
70 |
71 | @mixin button-medium {
72 | font-size: $size-medium;
73 | }
74 |
75 | @mixin button-large {
76 | font-size: $size-large;
77 | }
78 |
79 | // Declarations
80 | // =============================================================================
81 | #{$namespace-button},
82 | button {
83 | @include control;
84 | @include unselectable;
85 |
86 | background-color: $button-background-color;
87 | border-color: $button-border-color;
88 | color: $button-color;
89 | cursor: pointer;
90 | justify-content: center;
91 | text-align: center;
92 | white-space: nowrap;
93 |
94 | // States
95 | &:hover,
96 | &.--hovered {
97 | border-color: $button-hover-border-color;
98 | color: $button-hover-color;
99 | transition: all 200ms ease-in 0s;
100 | }
101 |
102 | &:focus,
103 | &.--focused {
104 | border-color: $button-focus-border-color;
105 | color: $button-focus-color;
106 | }
107 |
108 | &:active,
109 | &.--active {
110 | border-color: $button-focus-border-color;
111 | color: $button-focus-color;
112 | }
113 |
114 | // Sizes
115 | &.--small {
116 | @include button-small;
117 | }
118 |
119 | &.--medium {
120 | @include button-medium;
121 | }
122 |
123 | &.--large {
124 | @include button-large;
125 | }
126 |
127 | &.--fill {
128 | background-color: map-get($colors, green);
129 | color: map-get($colors, white);
130 | border-color: map-get($colors, green);
131 |
132 | & .icon {
133 | fill: map-get($colors, white);
134 | }
135 | }
136 |
137 | &-icon {
138 | border-color: map-get($colors, grey-light);
139 |
140 | .icon {
141 | margin: 0;
142 | }
143 |
144 | &:hover {
145 | border-color: $secondary;
146 |
147 | .icon {
148 | fill: $secondary;
149 | }
150 | }
151 | }
152 | }
153 |
154 | #{$namespace-button}__group {
155 | margin: 0 5px;
156 | }
157 |
158 | .s-section__meta .button-icon {
159 | .icon {
160 | margin: 0 !important;
161 | vertical-align: top;
162 | fill: map-get($colors, grey-light);
163 | }
164 |
165 | &:hover {
166 | .icon {
167 | fill: $button-hover-border-color;
168 | }
169 | }
170 |
171 | &.is-active {
172 | border-color: $secondary;
173 |
174 | svg {
175 | fill: $secondary;
176 | }
177 | }
178 | }
179 |
180 | button.filter-active {
181 | border: 2px $primary solid;
182 | color: $primary;
183 | }
184 |
185 |
186 |
187 |
--------------------------------------------------------------------------------
/web/src/styles/base/_icons.scss:
--------------------------------------------------------------------------------
1 | .icon {
2 | width: 18px;
3 | height: 18px;
4 | transition: all 200ms ease-in 0s;
5 | fill: map-get($colors, grey-light);
6 | display: inline-block;
7 | text-align: center;
8 | speak: none;
9 | backface-visibility: hidden;
10 | opacity: 1;
11 |
12 | @include mq('handheld-and-up') {
13 | width: 15px;
14 | height: 15px;
15 | }
16 | }
17 |
18 | button,
19 | .button {
20 | .icon {
21 | margin: 0 .7rem 0 -.2rem;
22 | }
23 | }
24 |
25 | .icon--small {
26 | width: 7px;
27 | height: 7px;
28 | }
29 |
30 | .icon-checkbox {
31 | .path-check {
32 | display: none;
33 | }
34 | }
35 |
36 | .icon-uncheck {
37 | .path-check {
38 | display: none;
39 | }
40 | }
41 |
42 | .icon-checkbox,
43 | .icon-checked {
44 | align-self: flex-start;
45 | width: 11px;
46 | height: 11px;
47 | fill: $primary;
48 | opacity: 1;
49 |
50 | @include mq('handheld-and-up') {
51 | width: 15px;
52 | height: 15px;
53 | }
54 |
55 | [data-item-check='false'] & {
56 | display: block;
57 | }
58 |
59 | [data-item-check='true'] & {
60 | display: none;
61 | }
62 |
63 | [data-subitem-check='false'].c-checklist__subitem & {
64 | display: block;
65 | }
66 |
67 | [data-subitem-check='true'].c-checklist__subitem & {
68 | display: none;
69 | }
70 | }
71 |
72 | .icon-checked {
73 | fill: map-get($colors, black);
74 | opacity: .1;
75 |
76 | [data-item-check='false'] & {
77 | display: none;
78 | }
79 |
80 | [data-item-check='true'] & {
81 | display: block;
82 | }
83 |
84 | [data-subitem-check='false'].c-checklist__subitem & {
85 | display: none;
86 | }
87 |
88 | [data-subitem-check='true'].c-checklist__subitem & {
89 | display: block;
90 | }
91 | }
92 |
93 | .icon-arrow {
94 | width: 15px;
95 | height: 15px;
96 | position: absolute;
97 | top: 10px;
98 | fill: map-get($colors, black);
99 | opacity: .2;
100 | }
101 |
102 | .icon-rotate {
103 | transform: rotate(180deg);
104 | transition: all 300ms ease-in 0s;
105 | }
106 |
107 | .icon-priority {
108 | &--high {
109 | fill: #f85f5f;
110 | align-self: flex-start;
111 | display: block;
112 | width: 7px;
113 | height: 7px;
114 |
115 | @include mq(lap-and-up) {
116 | margin-top: 0;
117 | width: 7px;
118 | height: 7px;
119 | }
120 | }
121 |
122 | &--medium {
123 | fill: #f2c741;
124 | align-self: flex-start;
125 | display: block;
126 | width: 7px;
127 | height: 7px;
128 |
129 | @include mq(lap-and-up) {
130 | margin-top: 0;
131 | width: 7px;
132 | height: 7px;
133 | }
134 | }
135 |
136 | &--low {
137 | fill: #62c547;
138 | align-self: flex-start;
139 | display: block;
140 | width: 7px;
141 | height: 7px;
142 |
143 | @include mq(lap-and-up) {
144 | margin-top: 0;
145 | width: 7px;
146 | height: 7px;
147 | }
148 | }
149 | }
150 |
151 | .btn--danger {
152 | border-color: #df5941;
153 | color: #df5941;
154 |
155 | .icon {
156 | fill: #df5941;
157 | }
158 | }
159 |
160 | @keyframes bounce {
161 | 0% {
162 | transform: scaleX(1);
163 | }
164 |
165 | 10% {
166 | transform: scaleX(1);
167 | }
168 |
169 | 20% {
170 | transform: scaleX(.8);
171 | }
172 |
173 | 35% {
174 | transform: scaleX(.8);
175 | }
176 |
177 | 45% {
178 | transform: scaleX(1);
179 | }
180 |
181 | 60% {
182 | transform: scaleX(1);
183 | }
184 |
185 | 75% {
186 | transform: scaleX(.8);
187 | }
188 |
189 | 85% {
190 | transform: scaleX(.8);
191 | }
192 |
193 | 100% {
194 | transform: scaleX(1);
195 | }
196 | }
197 |
198 | .code-icons {
199 |
200 | // height: 100%;
201 | margin: 0 auto;
202 | position: relative;
203 | width: 25px;
204 |
205 | &::after,
206 | &::before {
207 | box-sizing: content-box;
208 | content: '';
209 | height: 10px;
210 | position: absolute;
211 | top: 9px;
212 | transform: rotate(45deg);
213 | width: 10px;
214 | }
215 |
216 | &::before {
217 | border-bottom: 3px solid #cccccc;
218 | border-left: 3px solid #cccccc;
219 | left: 0;
220 | }
221 |
222 | &::after {
223 | border-right: 3px solid #cccccc;
224 | border-top: 3px solid #cccccc;
225 | right: 0;
226 | }
227 | }
228 |
229 | .icon-eye {
230 | path:nth-child(2),
231 | path:nth-child(3) {
232 | display: none;
233 | }
234 |
235 | &-hide {
236 | fill: #415257;
237 |
238 | path:nth-child(2),
239 | path:nth-child(3) {
240 | display: block;
241 | }
242 | }
243 | }
244 |
245 |
246 |
247 | .st0 {
248 | fill: map-get($colors, white);
249 | }
250 |
--------------------------------------------------------------------------------
/web/src/scripts/components/Ui.js:
--------------------------------------------------------------------------------
1 | let instance = null;
2 |
3 | class Ui {
4 | constructor() {
5 | if (!instance) {
6 | instance = this;
7 | }
8 |
9 | this.nav = document.querySelector('.c-nav');
10 | this.scrollToggle = document.querySelectorAll('.js-scroll');
11 |
12 | return instance;
13 | }
14 |
15 | lazyLoadImg(item) {
16 | [].forEach.call(item.querySelectorAll('img[data-src]'), (img) => {
17 | img.setAttribute('src', img.getAttribute('data-src'));
18 | img.onload = function() {
19 | img.removeAttribute('data-src');
20 | };
21 | });
22 | }
23 |
24 | isScrolledIntoView(el) {
25 | var elemTop = el.getBoundingClientRect().top;
26 | var elemBottom = el.getBoundingClientRect().bottom;
27 |
28 | // Only completely visible elements return true:
29 | var isVisible = elemTop >= 0 && elemBottom <= window.innerHeight;
30 | // Partially visible elements return true:
31 | // isVisible = elemTop < window.innerHeight && elemBottom >= 0;
32 | return isVisible;
33 | }
34 |
35 | smoothScroll(anchor, duration) {
36 | // Calculate how far and how fast to scroll
37 | const startLocation = window.pageYOffset;
38 | const endLocation = anchor.offsetTop + 300;
39 | const distance = endLocation - startLocation;
40 | const increments = distance / (duration / 16);
41 | let stopAnimation;
42 |
43 | // Scroll the page by an increment, and check if it's time to stop
44 | const animateScroll = () => {
45 | window.scrollBy(0, increments);
46 | stopAnimation();
47 | };
48 |
49 | // Loop the animation function
50 | const runAnimation = setInterval(animateScroll, 16);
51 |
52 | // If scrolling down
53 | if (increments >= 0) {
54 | // Stop animation when you reach the anchor OR the bottom of the page
55 | stopAnimation = () => {
56 | const travelled = window.pageYOffset;
57 | if ( (travelled >= (endLocation - increments)) || ((window.innerHeight + travelled) >= document.body.offsetHeight) ) {
58 | clearInterval(runAnimation);
59 | }
60 | };
61 | }
62 | // If scrolling up
63 | else {
64 | // Stop animation when you reach the anchor OR the top of the page
65 | stopAnimation = () => {
66 | const travelled = window.pageYOffset;
67 | if ( travelled <= (endLocation || 0) ) {
68 | clearInterval(runAnimation);
69 | }
70 | };
71 | }
72 | }
73 |
74 | scrollAnchor() {
75 |
76 | // For each smooth scroll link
77 | this.scrollToggle.forEach(toggle => {
78 | // When the smooth scroll link is clicked
79 | toggle.addEventListener('click', e => {
80 | // Prevent the default link behavior
81 | e.preventDefault();
82 | // Get anchor link and calculate distance from the top
83 | const dataID = toggle.getAttribute('href');
84 | const dataTarget = document.querySelector(dataID);
85 | const dataSpeed = toggle.getAttribute('data-speed');
86 | // If the anchor exists
87 | if (dataTarget) {
88 | // Scroll to the anchor
89 | instance.smoothScroll(dataTarget, dataSpeed || 3000);
90 |
91 | // Push new state history to dynamically change the URL
92 | if(history.pushState) {
93 | history.pushState(null, null, '/'+dataID);
94 | }
95 | else {
96 | location.hash = '/'+dataID;
97 | }
98 | }
99 | }, false);
100 | });
101 | }
102 |
103 | navScroll() {
104 |
105 | let lastScrollPosition = 0;
106 | let ticking = false;
107 |
108 | window.addEventListener(
109 | 'scroll',
110 | () => {
111 |
112 | lastScrollPosition = window.scrollY;
113 |
114 | if (!ticking) {
115 |
116 | window.requestAnimationFrame(() => {
117 |
118 | // Execute only on desktop and when the menu is already on the side
119 | if (window.innerWidth > 1265) {
120 | if (
121 | instance.isScrolledIntoView(this.nav) ===
122 | false
123 | ) {
124 | this.nav.classList.add('c-nav__sidebar');
125 | } else {
126 | this.nav.classList.remove('c-nav__sidebar');
127 | }
128 | }
129 |
130 | ticking = false;
131 | });
132 |
133 | ticking = true;
134 | }
135 |
136 | }, {passive: true});
137 | }
138 |
139 | enableUi() {
140 | // instance.scrollAnchor();
141 | instance.navScroll();
142 | }
143 | }
144 |
145 | const Instance = new Ui();
146 | Object.freeze(Instance);
147 |
148 | export default Ui;
149 |
--------------------------------------------------------------------------------
/web/src/scripts/components/Dropdown.js:
--------------------------------------------------------------------------------
1 | import Ui from './Ui';
2 | import Utils from '../Utils';
3 | import postscribe from 'postscribe';
4 |
5 | let instance = null;
6 | /**
7 | *
8 | *
9 | * @class Dropdown
10 | */
11 | class Dropdown {
12 | constructor() {
13 | if (!instance) {
14 | instance = this;
15 | }
16 |
17 | return instance;
18 | }
19 |
20 | // never called directly
21 | dropdownIcon(btn) {
22 | const item = new Utils().getClosest(btn, '.js-item');
23 | const ariaStatus = item.getAttribute('data-item-dropdown');
24 |
25 | if (ariaStatus === 'open') {
26 | item.querySelector('.icon-arrow').classList.add('icon-rotate');
27 | } else {
28 | item.querySelector('.icon-arrow').classList.remove('icon-rotate');
29 | }
30 | }
31 |
32 | allDropdown(options) {
33 |
34 | const el = options;
35 |
36 | const section = new Utils().getClosest(el.btn, '.js-section');
37 | const eachItem = section.querySelectorAll('.js-item[data-item-check="false"]');
38 |
39 | eachItem.forEach(item => {
40 | if (el.btn.classList.value.includes('js-collapse-all') === true) {
41 | item.setAttribute('data-item-dropdown', 'close');
42 | instance.removeCode(item);
43 | } else if (item.getAttributeNode('data-item-dropdown').value !== 'open') {
44 | item.setAttribute('data-item-dropdown', 'open');
45 | instance.loadCode(item);
46 |
47 | new Ui().lazyLoadImg(item);
48 | }
49 | });
50 | }
51 |
52 | removeCode(el) {
53 | const codeContainer = el.querySelector('.js-code');
54 | const loader = el.querySelector('.js-loader');
55 |
56 | if (codeContainer !== null) {
57 | while (codeContainer.hasChildNodes()) {
58 | codeContainer.removeChild(codeContainer.lastChild);
59 | }
60 | loader.style.display = 'inherit';
61 | }
62 | }
63 |
64 | loadCode(el) {
65 | const codeContainer = el.querySelector('.js-code');
66 |
67 | if (codeContainer !== null) {
68 | const scriptUrl = codeContainer.getAttribute('data-code-url');
69 |
70 | let script = document.createElement('script');
71 | script.src = scriptUrl;
72 |
73 | postscribe(codeContainer, script.outerHTML, {
74 | // eslint-disable-next-line func-names
75 | done: () => {
76 | const loader = el.querySelector('.js-loader');
77 | loader.style.display = 'none';
78 | },
79 | });
80 | }
81 |
82 | }
83 |
84 | moveDropdown(options) {
85 | const el = options;
86 |
87 | if (el.button !== null) {
88 | const eachItem = new Utils().getClosest(el.button, '.js-item');
89 | const ariaStatus = eachItem.getAttribute('data-item-dropdown');
90 |
91 | if (ariaStatus === 'open') {
92 | eachItem.setAttribute('data-item-dropdown', 'close');
93 | instance.removeCode(eachItem);
94 | instance.dropdownIcon(el.button);
95 | gtag('event', 'close-dropdown', {
96 | 'event_category': 'Click',
97 | 'event_label': 'Close dropdown'
98 | });
99 | } else if (ariaStatus === 'close') {
100 | eachItem.setAttribute('data-item-dropdown', 'open');
101 | instance.dropdownIcon(el.button);
102 | instance.loadCode(eachItem);
103 |
104 | new Ui().lazyLoadImg(eachItem);
105 |
106 | gtag('event', 'open-dropdown', {
107 | 'event_category': 'Click',
108 | 'event_label': 'Open dropdown'
109 | });
110 | }
111 | else {}
112 | }
113 | }
114 |
115 | collapseAllDropdown(options) {
116 | const el = options;
117 |
118 | const eachSection = new Utils().getClosest(el.button, '.js-section') ||
119 | el.section;
120 | const itemsBySection = eachSection.querySelectorAll('.js-item');
121 |
122 | itemsBySection.forEach(item => {
123 | item.setAttribute('data-item-dropdown', 'close');
124 | });
125 |
126 | // update local storage state dropdown hide
127 | }
128 |
129 | /**
130 | * Enable all dropdown buttons to be clickable
131 | *
132 | * @param {array} dropdownButtons
133 | * @memberof Dropdown
134 | */
135 | enableDropdown(dropdownButtons) {
136 | dropdownButtons.forEach(btn => {
137 | btn.addEventListener(
138 | 'click',
139 | e => {
140 | e.preventDefault();
141 |
142 | // If dropdown button clicked then close / open
143 | instance.moveDropdown({button: btn});
144 |
145 | e.stopImmediatePropagation();
146 | },
147 | false,
148 | );
149 | });
150 | }
151 | }
152 |
153 | const Instance = new Dropdown();
154 | Object.freeze(Instance);
155 |
156 | export default Dropdown;
157 |
--------------------------------------------------------------------------------
/rating/src/utils.js:
--------------------------------------------------------------------------------
1 | var width = 900, height = 800;
2 |
3 | // Set-up the export button
4 | d3.select('#saveButtonPng').on('click', function () {
5 | let svg = d3.select('#body').selectAll('svg');
6 | var svgString = getSVGString(svg.node());
7 | svgString2Image(svgString, 2 * width, 2 * height, 'png', save); // passes Blob and filesize String to the callback
8 |
9 | function save(dataBlob) {
10 | saveAs(dataBlob, 'tla.png');
11 | }
12 | });
13 |
14 | // Below are the functions that handle actual exporting:
15 | // getSVGString ( svgNode ) and svgString2Image( svgString, width, height, format, callback )
16 | function getSVGString(svgNode) {
17 | svgNode.setAttribute('xlink', 'http://www.w3.org/1999/xlink');
18 | var cssStyleText = getCSSStyles(svgNode);
19 | appendCSS(cssStyleText, svgNode);
20 |
21 | var serializer = new XMLSerializer();
22 | var svgString = serializer.serializeToString(svgNode);
23 | svgString = svgString.replace(/(\w+)?:?xlink=/g, 'xmlns:xlink='); // Fix root xlink without namespace
24 | svgString = svgString.replace(/NS\d+:href/g, 'xlink:href'); // Safari NS namespace fix
25 |
26 | return svgString;
27 |
28 | function getCSSStyles(parentElement) {
29 | var selectorTextArr = [];
30 |
31 | // Add Parent element Id and Classes to the list
32 | selectorTextArr.push('#' + parentElement.id);
33 | for (var c = 0; c < parentElement.classList.length; c++)
34 | if (!contains('.' + parentElement.classList[c], selectorTextArr))
35 | selectorTextArr.push('.' + parentElement.classList[c]);
36 |
37 | // Add Children element Ids and Classes to the list
38 | var nodes = parentElement.getElementsByTagName("*");
39 | for (var i = 0; i < nodes.length; i++) {
40 | var id = nodes[i].id;
41 | if (!contains('#' + id, selectorTextArr))
42 | selectorTextArr.push('#' + id);
43 |
44 | var classes = nodes[i].classList;
45 | for (var c = 0; c < classes.length; c++)
46 | if (!contains('.' + classes[c], selectorTextArr))
47 | selectorTextArr.push('.' + classes[c]);
48 | }
49 |
50 | // Extract CSS Rules
51 | var extractedCSSText = "";
52 | for (var i = 0; i < document.styleSheets.length; i++) {
53 | var s = document.styleSheets[i];
54 |
55 | try {
56 | if (!s.cssRules) continue;
57 | } catch (e) {
58 | if (e.name !== 'SecurityError') throw e; // for Firefox
59 | continue;
60 | }
61 |
62 | var cssRules = s.cssRules;
63 | for (var r = 0; r < cssRules.length; r++) {
64 | if (contains(cssRules[r].selectorText, selectorTextArr))
65 | extractedCSSText += cssRules[r].cssText;
66 | }
67 | }
68 |
69 |
70 | return extractedCSSText;
71 |
72 | function contains(str, arr) {
73 | return arr.indexOf(str) !== -1;
74 | }
75 |
76 | }
77 |
78 | function appendCSS(cssText, element) {
79 | var styleElement = document.createElement("style");
80 | styleElement.setAttribute("type", "text/css");
81 | styleElement.innerHTML = cssText;
82 | var refNode = element.hasChildNodes() ? element.children[0] : null;
83 | element.insertBefore(styleElement, refNode);
84 | }
85 | }
86 |
87 |
88 | function svgString2Image(svgString, width, height, format, callback) {
89 | var imgsrc = 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(svgString))); // Convert SVG string to data URL
90 |
91 | var canvas = document.createElement("canvas");
92 | var context = canvas.getContext("2d");
93 |
94 | canvas.width = width;
95 | canvas.height = height;
96 |
97 | var image = new Image();
98 | image.onload = function () {
99 | context.clearRect(0, 0, width, height);
100 | context.drawImage(image, 0, 0, width, height);
101 |
102 | canvas.toBlob(function (blob) {
103 | var fileSize = Math.round(blob.length / 1024) + ' KB';
104 | if (callback) callback(blob, fileSize);
105 | });
106 |
107 |
108 | };
109 |
110 | image.src = imgsrc;
111 | }
112 |
113 | function generateHash(resultsArray) {
114 | return '#' + window.storagePreifx + '_' + encodeURI(JSON.stringify(resultsArray));
115 | }
116 |
117 | function hasHash() {
118 | var hashScores = window.location.hash.split('_');
119 | if (hashScores[0] === '#' + window.storagePreifx || hashScores[0] === '#custom') {
120 | return true;
121 | }
122 | return false;
123 | }
124 |
125 | function drawFromHash() {
126 | var hashScores = window.location.hash.split('_');
127 | if (hashScores[0] === '#' + window.storagePreifx || hashScores[0] === '#custom') {
128 | window.results = JSON.parse(decodeURI(hashScores[1]));
129 | generateNewDimensions(window.results[0]);
130 | drawChart(results);
131 | }
132 | }
133 |
134 | function generateNewDimensions(dimensions) {
135 | var results = [];
136 | for (var i = 0; i < dimensions.length; i++) {
137 | results.push(dimensions[i].axis);
138 | }
139 |
140 | window.dimensionsArray = results;
141 | renderForm();
142 | }
143 |
--------------------------------------------------------------------------------
/web/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contribute
2 |
3 | ## Introduction
4 |
5 | First, thank you for considering contributing to front-end-checklist! It's people like you that make the open source community such a great community! 😊
6 |
7 | We welcome any type of contribution, not only code. You can help with
8 | - **QA**: file bug reports, the more details you can give the better (e.g. screenshots with the console open)
9 | - **Marketing**: writing blog posts, howto's, printing stickers, ...
10 | - **Community**: presenting the project at meetups, organizing a dedicated meetup for the local community, ...
11 | - **Code**: take a look at the [open issues](issues). Even if you can't write code, commenting on them, showing that you care about a given issue matters. It helps us triage them.
12 | - **Money**: we welcome financial contributions in full transparency on our [open collective](https://opencollective.com/front-end-checklist).
13 |
14 | ## Your First Contribution
15 |
16 | Working on your first Pull Request? You can learn how from this *free* series, [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github).
17 |
18 | ## Submitting code
19 |
20 | Any code change should be submitted as a pull request. The description should explain what the code does and give steps to execute it. The pull request should also contain tests.
21 |
22 | ## Code review process
23 |
24 | The bigger the pull request, the longer it will take to review and merge. Try to break down large pull requests in smaller chunks that are easier to review and merge.
25 | It is also always helpful to have some context for your pull request. What was the purpose? Why does it matter to you?
26 |
27 | ## Financial contributions
28 |
29 | We also welcome financial contributions in full transparency on our [open collective](https://opencollective.com/front-end-checklist).
30 | Anyone can file an expense. If the expense makes sense for the development of the community, it will be "merged" in the ledger of our open collective by the core contributors and the person who filed the expense will be reimbursed.
31 |
32 | ## Questions
33 |
34 | If you have any questions, create an [issue](issue) (protip: do a quick search first to see if someone else didn't ask the same question before!).
35 | You can also reach us at hello@front-end-checklist.opencollective.com.
36 |
37 | ## Credits
38 |
39 | ### Contributors
40 |
41 | Thank you to all the people who have already contributed to front-end-checklist!
42 |
43 |
44 |
45 | ### Backers
46 |
47 | Thank you to all our backers! [[Become a backer](https://opencollective.com/front-end-checklist#backer)]
48 |
49 |
50 |
51 |
52 | ### Sponsors
53 |
54 | Thank you to all our sponsors! (please ask your company to also support this open source project by [becoming a sponsor](https://opencollective.com/front-end-checklist#sponsor))
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/web/src/modernizr-custom.min.js:
--------------------------------------------------------------------------------
1 | /*! modernizr 3.6.0 (Custom Build) | MIT *
2 | * https://modernizr.com/download/?-flexbox-history-webworkers-domprefixes-mq-prefixedcssvalue-prefixes-setclasses-teststyles !*/
3 | !function(e,n,t){function r(e,n){return typeof e===n}function o(){var e,n,t,o,i,s,a;for(var l in C)if(C.hasOwnProperty(l)){if(e=[],n=C[l],n.name&&(e.push(n.name.toLowerCase()),n.options&&n.options.aliases&&n.options.aliases.length))for(t=0;td;d++)if(v=e[d],y=N.style[v],u(v,"-")&&(v=p(v)),N.style[v]!==t){if(i||r(o,"undefined"))return a(),"pfx"==n?v:!0;try{N.style[v]=o}catch(g){}if(N.style[v]!=y)return a(),"pfx"==n?v:!0}return a(),!1}function v(e,n){return function(){return e.apply(n,arguments)}}function y(e,n,t){var o;for(var i in e)if(e[i]in n)return t===!1?e[i]:(o=n[e[i]],r(o,"function")?v(o,t||n):o);return!1}function h(e,n,t,o,i){var s=e.charAt(0).toUpperCase()+e.slice(1),a=(e+" "+k.join(s+" ")+s).split(" ");return r(n,"string")||r(n,"undefined")?m(a,n,o,i):(a=(e+" "+P.join(s+" ")+s).split(" "),y(a,n,t))}function g(e,n,r){return h(e,t,t,n,r)}var C=[],S={_version:"3.6.0",_config:{classPrefix:"",enableClasses:!0,enableJSClass:!0,usePrefixes:!0},_q:[],on:function(e,n){var t=this;setTimeout(function(){n(t[e])},0)},addTest:function(e,n,t){C.push({name:e,fn:n,options:t})},addAsyncTest:function(e){C.push({name:null,fn:e})}},Modernizr=function(){};Modernizr.prototype=S,Modernizr=new Modernizr;var x=[],w=n.documentElement,_="svg"===w.nodeName.toLowerCase(),b="Moz O ms Webkit",P=S._config.usePrefixes?b.toLowerCase().split(" "):[];S._domPrefixes=P;var z=S._config.usePrefixes?" -webkit- -moz- -o- -ms- ".split(" "):["",""];S._prefixes=z;var E=function(){var n=e.matchMedia||e.msMatchMedia;return n?function(e){var t=n(e);return t&&t.matches||!1}:function(n){var t=!1;return l("@media "+n+" { #modernizr { position: absolute; } }",function(n){t="absolute"==(e.getComputedStyle?e.getComputedStyle(n,null):n.currentStyle).position}),t}}();S.mq=E;var T=function(e,n){var t=!1,r=s("div"),o=r.style;if(e in o){var i=P.length;for(o[e]=n,t=o[e];i--&&!t;)o[e]="-"+P[i]+"-"+n,t=o[e]}return""===t&&(t=!1),t};S.prefixedCSSValue=T;S.testStyles=l;Modernizr.addTest("history",function(){var n=navigator.userAgent;return-1===n.indexOf("Android 2.")&&-1===n.indexOf("Android 4.0")||-1===n.indexOf("Mobile Safari")||-1!==n.indexOf("Chrome")||-1!==n.indexOf("Windows Phone")||"file:"===location.protocol?e.history&&"pushState"in e.history:!1});var k=S._config.usePrefixes?b.split(" "):[];S._cssomPrefixes=k;var A={elem:s("modernizr")};Modernizr._q.push(function(){delete A.elem});var N={style:A.elem.style};Modernizr._q.unshift(function(){delete N.style}),S.testAllProps=h,S.testAllProps=g,Modernizr.addTest("flexbox",g("flexBasis","1px",!0)),Modernizr.addTest("webworkers","Worker"in e),o(),i(x),delete S.addTest,delete S.addAsyncTest;for(var O=0;O {
27 | const el = value;
28 |
29 | if (idNumber === el.id) {
30 | switch (type) {
31 | case 'state':
32 | el.state = 'checked';
33 | break;
34 |
35 | case 'dropdown':
36 | el.dropdown = 'open';
37 | break;
38 |
39 | case 'visible':
40 | el.visible = 'hide';
41 | break;
42 |
43 | default:
44 | break;
45 | }
46 | }
47 | });
48 |
49 | // Inject new array with new value
50 | storageData.forEach((el, i, arry) => {
51 | localStorage.setItem(sectionName, JSON.stringify(arry));
52 | });
53 |
54 | if (type !== 'visible') {
55 | // Count how many key in the localStorage array
56 | const nbrItemsChecked = JSON.parse(
57 | localStorage.getItem(sectionName),
58 | ).length;
59 |
60 | // Update progress bar
61 | if (subItemId) {
62 | new ProgressBar().updateProgressBar(section, nbrItemsChecked, 'sub');
63 | } else {
64 | new ProgressBar().updateProgressBar(section, nbrItemsChecked);
65 | }
66 |
67 | new Notation().updateNotation();
68 |
69 | if (!subItemId) {
70 | new Utils().visibityEl(item, '.c-tags', 'hide');
71 | new Utils().visibityEl(item, '.js-dropdown', 'hide');
72 | }
73 |
74 |
75 | if (subItemId) {
76 | section.setAttribute('data-subitem-check', 'true');
77 | return;
78 | } else {
79 | item.setAttribute('data-item-check', 'true');
80 | new Utils().checkSubItems(item);
81 | }
82 |
83 | new Notation().updatePriority();
84 |
85 | gtag('event', 'check', {
86 | 'event_category': 'Click',
87 | 'event_label': 'Item checked'
88 | });
89 |
90 | if (item !== null) {
91 | const button = item.querySelector('.js-dropdown');
92 | if (item.getAttribute('data-item-dropdown') === 'open') {
93 | new Dropdown().moveDropdown({button});
94 | }
95 | }
96 |
97 |
98 | }
99 | // TODO: à refaire // const itemExpanded = new Utils().variableList(list.item); // if (itemExpanded.checklistItem.querySelectorAll('.c-checklist__details')[0].getAttribute('aria-expanded') === true) { // new Dropdown().moveDropdown({itemExpanded, force:true}); // }
100 |
101 |
102 | }
103 | uncheckItem(list) {
104 | let currentObj;
105 | if (list.itemId !== undefined) {
106 | const currentStorage = localStorage.getItem(list.sectionName);
107 | currentObj = JSON.parse(currentStorage);
108 | }
109 | currentObj.forEach((el, i) => {
110 | if (el.id === list.itemId) {
111 | // Remove element from current localStorage object
112 | currentObj.splice(i, 1);
113 | // Count how many key in the localStorage array
114 | localStorage.setItem(list.sectionName, JSON.stringify(currentObj));
115 |
116 | // Update the progress bar
117 | const nbrItemsChecked = JSON.parse(
118 | localStorage.getItem(list.sectionName),
119 | ).length;
120 |
121 | // Update progress bar
122 | if (list.subItemId) {
123 | new ProgressBar().updateProgressBar(list.section, nbrItemsChecked, 'sub');
124 | } else {
125 | new ProgressBar().updateProgressBar(list.section, nbrItemsChecked);
126 | }
127 |
128 | new Notation().updateNotation();
129 | new Utils().visibityEl(list.item, '.c-tags');
130 |
131 | // Change data-check attribute to uncheck item
132 | new Utils().visibityEl(list.item, '.js-dropdown');
133 |
134 | if (list.subItemId) {
135 | list.section.setAttribute('data-subitem-check', 'false');
136 | return;
137 | } else {
138 | list.item.setAttribute('data-item-check', 'false');
139 | new Utils().uncheckSubItems(list.item);
140 | }
141 |
142 | new Notation().updatePriority();
143 |
144 | gtag('event', 'uncheck', {
145 | 'event_category': 'Click',
146 | 'event_label': 'Item unchecked'
147 | });
148 | }
149 | });
150 | }
151 | checkboxDetection(el) {
152 | // List of all variables needed for checking item
153 | const list = new Utils().variableList(el);
154 | // console.log(list)
155 | if (el.checked) {
156 | // Check item if unchecked
157 | new Storage().checkingItem(list);
158 | } else {
159 | // Uncheck item if checked
160 | instance.uncheckItem(list);
161 | }
162 | }
163 | enableCheckbox() {
164 | const allCheckboxes = document.querySelectorAll('input[type=checkbox]');
165 | allCheckboxes.forEach(el => {
166 | // Add a click event listener on all checkboxes
167 | console.log(el)
168 | el.addEventListener('click', () => instance.checkboxDetection(el));
169 | });
170 | }
171 | }
172 | const Instance = new Checkboxes();
173 | Object.freeze(Instance);
174 | export default Checkboxes;
175 |
--------------------------------------------------------------------------------
/web/data/en/_project.json:
--------------------------------------------------------------------------------
1 | {"_items":{"domain":[{"title":"业务远景","priority":"High","description":"我们在做什么,我们要去哪里?","tags":["all","domain"]},{"title":"业务需求","priority":"Medium","description":"","subitems":[{"title":"需求列表","description":"有没有接近全的需求列表?在一定的时间(如迭代内),需求应该是稳定的。"},{"title":"需求管理","description":"需求是如何从口头到待办列表的?中间是不是存在不规范的问题"},{"title":" 业务是如何进行变更的?"}],"tags":["all","domain"]},{"title":"跨功能需求","priority":"High","description":"在系统运作时观察到的质量,例如保安性及易用性等","subitems":[{"title":"运行质量","description":"在系统运作时观察到的质量,例如保安性及易用性等"},{"title":"演进质量","description":"软件系统结构及开发过程有关的质量,例如软件可测试性、可维护性、可扩展性、可伸缩性(scalability)等"}],"tags":["all","domain"]}],"people":[{"title":"团队成员","priority":"High","description":"非技术问题找谁?","subitems":[{"title":"非技术问题找谁?"},{"title":"团队成员的技术栈及水平"},{"title":"每个人的技术水平","description":"包含应该怎么带:Coach(教练式), Pairing(结对式), Teach(教学式)"},{"title":"项目无关的技术,可以找谁一起“娱乐”?"},{"title":"1 to 1 Meetings"}],"tags":["all","people"]},{"title":"利益相关者","priority":"Medium","description":"","subitems":[{"title":"了解各个相关者(Level 1)","description":"如作为一个开发人员,大部分时间并不会和利益相关者有直接的沟通。"},{"title":"和相关者保持沟通(Level 2)","description":"适当沟通,可以帮助项目更好地进行"}],"tags":["all","people"]},{"title":"跨团队协作","priority":"Medium","description":"相关的合作方有哪些,各自的接口人是谁?","subitems":[{"title":"相关的合作方有哪些,各自的接口人是谁?"},{"title":"同组织、项目下的其它团队。"}],"tags":["all","people"]},{"title":"用户","priority":"Low","description":"用户是谁?我们是否与他们直接接触?","subitems":[{"title":"用户是谁?我们是否与他们直接接触?"},{"title":"反馈环。一个用户的反馈是如何变成需求的?"}],"tags":["all","people"]}],"process":[{"title":"Project Process","priority":"High","description":"完成业务需求的基本流程","subitems":[{"title":"项目的 Roadmap","description":"项目 Deadline,关键时间节点,项目规划等"},{"title":"项目功能的生命周期","description":"如敏捷中的故事卡工作流"},{"title":"沟通方式?","description":"如 IM,邮件,还有敏捷的每日站会,远程会议,Retro 等"}],"tags":["all","process"]},{"title":"Path to Development","priority":"High","description":"不同的的组织包含自身特别的情况,如 PC 端口、网络权限、代码库权限等的开通都需要一定的流程。","subitems":[{"title":"开发机申请及网络等权限准备"},{"title":"代码库权限管理"},{"title":"编辑器和相关的工具申请"}],"tags":["all","process"]},{"title":"Path to Production","priority":"High","description":"代码中的 Path to Production 只是一份说明——针对于开发人员的,而这里的则需要一个更详细的说明。","subitems":[{"title":"上线每一步的流程"},{"title":"相关的关键人"},{"title":"每一步所需要的工具"},{"title":"每一步所需要的流程","description":"如 QA 测试流程,上线流程"}],"tags":["all","process"]},{"title":"Path to Roll Off","priority":"Low","description":"换一个项目时,需要哪些东西?","tags":["all","process"]}],"technology":[{"title":"技术远景","priority":"High","description":"在技术上,我们有什么追求","tools":["Lean Canvas"],"documentation":[],"tags":["all","vision"]},{"title":"文档","priority":"High","description":"文档即代码——好的文档应该是版本管理的。","subitems":[{"title":"Path to Production","description":"旨在通过可视化的方式来展示项目的上线流程,并优化过程中的瓶颈问题。"},{"title":" 上线及发布日记","description":""},{"title":"项目相关的 wiki 和文档记录","description":""},{"title":"开发规范","description":""}],"tags":["all","technology"]},{"title":"架构","priority":"High","description":"系统相关的架构图,如 C4Model 方式描述\n 现有的技术栈及其关系","subitems":[{"title":"系统相关的架构图","description":"如 C4Model 方式描述"},{"title":"现有的技术栈及其未来方案","description":""}],"tags":["all","technology"]},{"title":"代码库","priority":"High","description":"在代码库中拥有诸如搭建指南、架构决策记录、编码器配置等相应的事项。","subitems":[{"title":"搭建指南","description":"这份指南应该随项目的代码一起分发。"},{"title":"架构决策记录","description":"放置在代码库的 ``docs/adr`` 目录中"},{"title":"编辑器配置和代码风格规范","description":"使用诸如 editorconfig 这样的工具,来统一规范化代码,并采用 Lint 工具来分析代码 。"},{"title":"模式和风格指南","description":"在项目中融入系统架构,如 Clean Architecture 和风格,并有明显的指引。"},{"title":"分支管理模式","description":"GitFlow 或者 master,或者 Feature Branch。"},{"title":"代码提交风格","description":"业务风格或者是开源软件风格?"}],"tags":["all","technology"]},{"title":"测试","priority":"High","description":"如何针对项目进行有效的测试","subitems":[{"title":"测试策略","description":"测试层级, 测试金字塔"},{"title":"自动化测试"}],"tags":["all","technology"]},{"title":"项目演进","priority":"High","description":"未来的技术栈\n 系统的演进方案","subitems":[{"title":"技术风险点","description":"即需要提前 spike 调研的内容"},{"title":"未来的技术栈"},{"title":"系统的演进方案"}],"tags":["all","technology"]},{"title":"安全","priority":"High","description":"安全无小事","subitems":[{"title":"安全标准","description":"安全更重要,还是体验更重要?"},{"title":"代码中的数据加密"},{"title":"代码安全"}],"tags":["all","technology"]},{"title":"质量","priority":"High","description":"","subitems":[{"title":"项目质量跟踪"},{"title":"代码质量可视化"},{"title":"应用质量策略"}],"tags":["all","technology"]}]},"introductions":[{"head":{"introduction":""},"html":{"introduction":""}}],"translation":{"SITE_NAME":"New Project Checklist","INDEX_TITLE":"✨ Your best Project Tool ✨","URL_WEBSITE":"https://phodal.github.io/new-project-checklist/","SITE_TAGLINE":"🗂 The checklist for new project setup for developer","SITE_DESCRIPTION":"🗂 The checklist for new project setup for developer","SITE_LANGUAGE":"en","SITE_DIRECTION":"ltr","URL_GITHUB_ROOT":"https://github.com/phodal/new-project-checklist","URL_GITHUB_REPO":"https://github.com/phodal/new-project-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","SECTION_SUBITEMS":"Items","alert":{"JAVASCRIPT_DESACTIVATE":"Your JavaScript seems to be desactivated. 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 ✨ 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 📑!","TWITTER_VIA":"thedaviddias","TWITTER_HASHTAGS":"FrontEndChecklist #FrontEnd #Tool #Web","STAR":"Star","GITHUB_STAR_MSG":"Star thedaviddias/Front-End-Checklist on GitHub"}}}
--------------------------------------------------------------------------------
/web/src/scripts/components/Tools.js:
--------------------------------------------------------------------------------
1 | import Utils from '../Utils';
2 | import Dropdown from './Dropdown';
3 | import Checkboxes from './Checkboxes';
4 | import Storage from './Storage';
5 |
6 | let instance = null;
7 | /**
8 | *
9 | *
10 | * @class Tools
11 | */
12 | class Tools {
13 | constructor() {
14 | if (!instance) {
15 | instance = this;
16 | }
17 |
18 | this.checkAllButton = document.querySelectorAll('.js-check-all');
19 | this.uncheckAllButton = document.querySelectorAll('.js-uncheck-all');
20 |
21 | this.collapseAllButton = document.querySelectorAll('.js-collapse-all');
22 | this.expandAllButton = document.querySelectorAll('.js-expand-all');
23 |
24 | this.hideSectionButton = document.querySelectorAll('.js-hide-section');
25 |
26 | return instance;
27 | }
28 |
29 | /**
30 | * Chech or uncheck all items in a specific section
31 | *
32 | * @param {any} btn
33 | * @param {string} state
34 | * @memberof Tools
35 | */
36 | checkUncheckAll(btn, state) {
37 | const list = new Utils().variableList(btn);
38 | const checklistItem = list.section.querySelectorAll('.js-item');
39 |
40 | checklistItem.forEach(el => {
41 | if (state === 'true') {
42 | // if element is not already checked
43 | if (el.getAttribute('data-item-check') !== 'true') {
44 | // Change each item state
45 | el.setAttribute('data-item-check', state);
46 |
47 | const list2 = new Utils().variableList(el);
48 |
49 | new Storage().checkingItem(list2);
50 | }
51 | } else {
52 | // Change each item state
53 | el.setAttribute('data-item-check', state);
54 |
55 | const list2 = new Utils().variableList(el);
56 |
57 | new Checkboxes().uncheckItem(list2);
58 | }
59 | });
60 | }
61 |
62 | uncheckOption(list, keyName) {
63 | let currentObj;
64 |
65 | if (list.itemId === undefined) {
66 | const currentStorage = localStorage.getItem(keyName);
67 | currentObj = JSON.parse(currentStorage);
68 | }
69 |
70 | currentObj.forEach((el, i) => {
71 | if (el.id === list.sectionId) {
72 | // Remove element from current localStorage object
73 | currentObj.splice(i, 1);
74 |
75 | localStorage.setItem(keyName, JSON.stringify(currentObj));
76 | }
77 | });
78 | }
79 |
80 | /**
81 | * Hide the body
82 | *
83 | * @param {any} btn
84 | * @memberof Tools
85 | */
86 | hideShow(btn) {
87 | const list = new Utils().variableList(btn);
88 | const body = list.section.querySelectorAll('.js-checklist-body')[0];
89 |
90 | if (body !== undefined) {
91 | const status = body.getAttribute('data-body-visibility');
92 |
93 | if (status === 'visible') {
94 |
95 | btn.classList.add('is-active');
96 |
97 | btn.querySelector('.icon-eye').classList.add('icon-eye-hide');
98 |
99 | body.setAttribute('data-body-visibility', 'hide');
100 | body.setAttribute('aria-hidden', 'true');
101 |
102 | new Storage().checkingOption(list, 'hide-sections');
103 |
104 |
105 | } else {
106 |
107 | btn.classList.remove('is-active');
108 |
109 | btn.querySelector('.icon-eye').classList.remove('icon-eye-hide');
110 |
111 | body.setAttribute('data-body-visibility', 'visible');
112 | body.setAttribute('aria-hidden', 'false');
113 |
114 | instance.uncheckOption(list, 'hide-sections');
115 | }
116 | }
117 | }
118 |
119 | enableTools() {
120 | // Check all checkboxes
121 | this.checkAllButton.forEach(btn => {
122 | btn.addEventListener(
123 | 'click',
124 | () => {
125 | instance.checkUncheckAll(btn, 'true');
126 | }
127 | );
128 | });
129 |
130 | // Uncheck all checkboxes
131 | this.uncheckAllButton.forEach(btn => {
132 | btn.addEventListener(
133 | 'click',
134 | () => {
135 | instance.checkUncheckAll(btn, 'false');
136 | }
137 | );
138 | });
139 |
140 | // Collapse all dropdowns
141 | this.collapseAllButton.forEach(btn => {
142 | btn.addEventListener(
143 | 'click',
144 | () => {
145 | new Dropdown().allDropdown({btn});
146 | }
147 | );
148 | });
149 |
150 | // Expand all dropdowns
151 | this.expandAllButton.forEach(btn => {
152 | btn.addEventListener(
153 | 'click',
154 | () => {
155 | new Dropdown().allDropdown({btn});
156 | }
157 | );
158 | });
159 |
160 | // Hide section
161 | this.hideSectionButton.forEach(btn => {
162 | btn.addEventListener(
163 | 'click',
164 | () => {
165 | instance.hideShow(btn);
166 | }
167 | );
168 | });
169 | }
170 | }
171 |
172 | const Instance = new Tools();
173 | Object.freeze(Instance);
174 |
175 | export default Tools;
176 | // enableReset() {
177 | // const uncheckAll = document.querySelectorAll(".js-uncheck-section");
178 | // const checkAll = document.querySelectorAll(".js-check-section");
179 | // uncheckAll.forEach((el, i, array) => {
180 | // el.addEventListener('click', e => {
181 | // e.preventDefault();
182 | // const section = new Utils().getClosest(el, '.js-section');
183 | // const sectionName = section.getAttribute('data-section');
184 | // const checklistItem = new Utils().getClosest(el, '.js-item ');
185 | // localStorage.removeItem(sectionName);
186 | // instance.resetItems(section, sectionName);
187 | // });
188 | // });
189 | // checkAll.forEach((el, i, array) => {
190 | // el.addEventListener('click', e => {
191 | // e.preventDefault();
192 | // const section = new Utils().getClosest(el, '.js-section');
193 | // const sectionName = section.getAttribute('data-section');
194 | // const checklistItem = new Utils().getClosest(el, '.js-item ');
195 | // localStorage.addItem(sectionName);
196 | // });
197 | // });
198 | // }
199 |
--------------------------------------------------------------------------------