From d4ec80de29401bc37e61ae7ef24839596f015777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Uzna=C5=84ski?= Date: Sat, 31 Oct 2020 15:04:44 +0100 Subject: [PATCH] [FEATURE] Add frontend linting (#120) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Łukasz Uznański Co-authored-by: Oliver Klee --- .gitattributes | 5 + .github/workflows/ci.yml | 20 ++++ .gitignore | 4 + Configuration/TCA/Overrides/sys_template.php | 1 + .../TypoScript/Frontend/setup.typoscript | 8 ++ Resources/Private/.eslintignore | 1 + Resources/Private/.eslintrc.json | 10 ++ Resources/Private/.prettierrc.js | 7 ++ Resources/Private/Language/de.locallang.xlf | 8 ++ Resources/Private/Language/locallang.xlf | 6 + Resources/Private/Templates/Tea/Index.html | 6 + Resources/Private/package.json | 27 +++++ Resources/Private/stylelint.config.js | 110 ++++++++++++++++++ Resources/Public/CSS/.gitkeep | 0 Resources/Public/Css/Main.css | 15 +++ Resources/Public/JavaScript/.gitkeep | 0 Resources/Public/JavaScript/Main.js | 41 +++++++ 17 files changed, 269 insertions(+) create mode 100644 Configuration/TypoScript/Frontend/setup.typoscript create mode 100644 Resources/Private/.eslintignore create mode 100644 Resources/Private/.eslintrc.json create mode 100644 Resources/Private/.prettierrc.js create mode 100644 Resources/Private/package.json create mode 100644 Resources/Private/stylelint.config.js delete mode 100644 Resources/Public/CSS/.gitkeep create mode 100644 Resources/Public/Css/Main.css delete mode 100644 Resources/Public/JavaScript/.gitkeep create mode 100644 Resources/Public/JavaScript/Main.js diff --git a/.gitattributes b/.gitattributes index 67d8112..787d112 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8,3 +8,8 @@ /Tests/ export-ignore /codeception.yml export-ignore /phpcs.xml export-ignore +/Resources/Private/.eslintignore export-ignore +/Resources/Private/.eslintrc.json export-ignore +/Resources/Private/.prettierrc.js export-ignore +/Resources/Private/package.json export-ignore +/Resources/Private/stylelint.config.js export-ignore diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 095d6cb..0275717 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -62,6 +62,26 @@ jobs: - "php:codestyle" php-version: - 7.4 + code-quality-frontend: + name: "Code quality frontend checks" + runs-on: ubuntu-latest + strategy: + matrix: + command: + - "style" + - "js" + steps: + - + name: Checkout + uses: actions/checkout@v2 + - + name: "Install modules" + working-directory: ./Resources/Private + run: yarn + - + name: "Run command" + working-directory: ./Resources/Private + run: "yarn lint:${{ matrix.command }}" xliff-lint: name: "Xliff linter" runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index 3366010..faf4896 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,7 @@ /composer.lock /nbproject /var +/Resources/Private/node_modules/ +/Resources/Private/yarn.lock +/Resources/Private/yarn-error.log +/Resources/Private/package-lock.json diff --git a/Configuration/TCA/Overrides/sys_template.php b/Configuration/TCA/Overrides/sys_template.php index d45a3e1..1bb8d7b 100644 --- a/Configuration/TCA/Overrides/sys_template.php +++ b/Configuration/TCA/Overrides/sys_template.php @@ -3,3 +3,4 @@ defined('TYPO3_MODE') || die('Access denied.'); \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile('tea', 'Configuration/TypoScript', 'Tea'); +\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile('tea', 'Configuration/TypoScript/Frontend/', 'Tea frontend (optional)'); diff --git a/Configuration/TypoScript/Frontend/setup.typoscript b/Configuration/TypoScript/Frontend/setup.typoscript new file mode 100644 index 0000000..3ffbbef --- /dev/null +++ b/Configuration/TypoScript/Frontend/setup.typoscript @@ -0,0 +1,8 @@ +page { + includeCSS { + tea = EXT:tea/Resources/Public/Css/Main.css + } + includeJSFooter { + tea = EXT:tea/Resources/Public/JavaScript/Main.js + } +} diff --git a/Resources/Private/.eslintignore b/Resources/Private/.eslintignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/Resources/Private/.eslintignore @@ -0,0 +1 @@ +node_modules diff --git a/Resources/Private/.eslintrc.json b/Resources/Private/.eslintrc.json new file mode 100644 index 0000000..c81af52 --- /dev/null +++ b/Resources/Private/.eslintrc.json @@ -0,0 +1,10 @@ +{ + "root": true, + "extends": [ + "eslint:recommended", + "plugin:prettier/recommended" + ], + "env": { + "browser": true + } +} diff --git a/Resources/Private/.prettierrc.js b/Resources/Private/.prettierrc.js new file mode 100644 index 0000000..20bf3f3 --- /dev/null +++ b/Resources/Private/.prettierrc.js @@ -0,0 +1,7 @@ +module.exports = { + semi: true, + trailingComma: "all", + singleQuote: true, + printWidth: 120, + tabWidth: 4 +}; diff --git a/Resources/Private/Language/de.locallang.xlf b/Resources/Private/Language/de.locallang.xlf index 0931930..370de29 100644 --- a/Resources/Private/Language/de.locallang.xlf +++ b/Resources/Private/Language/de.locallang.xlf @@ -23,6 +23,14 @@ Our selection of assorted teas Unsere Auswahl an erlesenen Tees + + UID + UID + + + Title + Titel + diff --git a/Resources/Private/Language/locallang.xlf b/Resources/Private/Language/locallang.xlf index 73a1f52..534246b 100644 --- a/Resources/Private/Language/locallang.xlf +++ b/Resources/Private/Language/locallang.xlf @@ -18,6 +18,12 @@ Our selection of assorted teas + + UID + + + Title + diff --git a/Resources/Private/Templates/Tea/Index.html b/Resources/Private/Templates/Tea/Index.html index 362b4ef..f23f4b2 100644 --- a/Resources/Private/Templates/Tea/Index.html +++ b/Resources/Private/Templates/Tea/Index.html @@ -8,6 +8,12 @@ + + + + + + diff --git a/Resources/Private/package.json b/Resources/Private/package.json new file mode 100644 index 0000000..2d30199 --- /dev/null +++ b/Resources/Private/package.json @@ -0,0 +1,27 @@ +{ + "name": "tea", + "description": "", + "repository": { + "url": "https://github.com/TYPO3-Documentation/tea.git" + }, + "keywords": [], + "author": "", + "version": "1.0.0", + "license": "ISC", + "scripts": { + "lint:js": "eslint --config .eslintrc.json '../Public/**/*.js'", + "lint:js:fix": "eslint --config .eslintrc.json '../Public/**/*.js' --quiet --fix", + "lint:style": "stylelint --config stylelint.config.js ../Public/**/*.css", + "lint:style:fix": "stylelint --config stylelint.config.js ../Public/**/*.css --fix" + }, + "devDependencies": { + "eslint": "^6.8.0", + "eslint-config-prettier": "^6.11.0", + "eslint-plugin-import": "^2.20.1", + "eslint-plugin-prettier": "^3.1.4", + "prettier": "^2.0.5", + "stylelint": "^13", + "stylelint-config-recommended": "^3.0.0", + "stylelint-no-browser-hacks": "^1.2.1" + } +} diff --git a/Resources/Private/stylelint.config.js b/Resources/Private/stylelint.config.js new file mode 100644 index 0000000..cf1b3b3 --- /dev/null +++ b/Resources/Private/stylelint.config.js @@ -0,0 +1,110 @@ +"use strict"; + +module.exports = { + extends: "stylelint-config-recommended", + rules: { + "at-rule-empty-line-before": [ + "always", + { + except: ["blockless-after-same-name-blockless", "first-nested"], + ignore: ["after-comment"], + }, + ], + "at-rule-name-case": "lower", + "at-rule-name-space-after": "always-single-line", + "at-rule-semicolon-newline-after": "always", + "block-closing-brace-empty-line-before": "never", + "block-closing-brace-newline-after": "always", + "block-closing-brace-newline-before": "always-multi-line", + "block-closing-brace-space-before": "always-single-line", + "block-opening-brace-newline-after": "always-multi-line", + "block-opening-brace-space-after": "always-single-line", + "block-opening-brace-space-before": "always", + "color-hex-case": "lower", + "color-hex-length": "short", + "comment-empty-line-before": [ + "always", + { + except: ["first-nested"], + ignore: ["stylelint-commands"], + }, + ], + "comment-whitespace-inside": "always", + "custom-property-empty-line-before": [ + "always", + { + except: ["after-custom-property", "first-nested"], + ignore: ["after-comment", "inside-single-line-block"], + }, + ], + "declaration-bang-space-after": "never", + "declaration-bang-space-before": "always", + "declaration-block-semicolon-newline-after": "always-multi-line", + "declaration-block-semicolon-space-after": "always-single-line", + "declaration-block-semicolon-space-before": "never", + "declaration-block-single-line-max-declarations": 1, + "declaration-block-trailing-semicolon": "always", + "declaration-colon-newline-after": "always-multi-line", + "declaration-colon-space-after": "always-single-line", + "declaration-colon-space-before": "never", + "declaration-empty-line-before": [ + "always", + { + except: ["after-declaration", "first-nested"], + ignore: ["after-comment", "inside-single-line-block"], + }, + ], + "function-comma-newline-after": "always-multi-line", + "function-comma-space-after": "always-single-line", + "function-comma-space-before": "never", + "function-max-empty-lines": 0, + "function-name-case": "lower", + "function-parentheses-newline-inside": "always-multi-line", + "function-parentheses-space-inside": "never-single-line", + "function-whitespace-after": "always", + indentation: 2, + "length-zero-no-unit": true, + "max-empty-lines": 1, + "media-feature-colon-space-after": "always", + "media-feature-colon-space-before": "never", + "media-feature-name-case": "lower", + "media-feature-parentheses-space-inside": "never", + "media-feature-range-operator-space-after": "always", + "media-feature-range-operator-space-before": "always", + "media-query-list-comma-newline-after": "always-multi-line", + "media-query-list-comma-space-after": "always-single-line", + "media-query-list-comma-space-before": "never", + "no-eol-whitespace": true, + "no-missing-end-of-source-newline": true, + "number-leading-zero": "always", + "number-no-trailing-zeros": true, + "property-case": "lower", + "rule-empty-line-before": [ + "always-multi-line", + { + except: ["first-nested"], + ignore: ["after-comment"], + }, + ], + "selector-attribute-brackets-space-inside": "never", + "selector-attribute-operator-space-after": "never", + "selector-attribute-operator-space-before": "never", + "selector-combinator-space-after": "always", + "selector-combinator-space-before": "always", + "selector-descendant-combinator-no-non-space": true, + "selector-list-comma-newline-after": "always", + "selector-list-comma-space-before": "never", + "selector-max-empty-lines": 0, + "selector-pseudo-class-case": "lower", + "selector-pseudo-class-parentheses-space-inside": "never", + "selector-pseudo-element-case": "lower", + "selector-pseudo-element-colon-notation": "double", + "selector-type-case": "lower", + "unit-case": "lower", + "value-keyword-case": "lower", + "value-list-comma-newline-after": "always-multi-line", + "value-list-comma-space-after": "always-single-line", + "value-list-comma-space-before": "never", + "value-list-max-empty-lines": 0, + }, +}; diff --git a/Resources/Public/CSS/.gitkeep b/Resources/Public/CSS/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/Resources/Public/Css/Main.css b/Resources/Public/Css/Main.css new file mode 100644 index 0000000..3803255 --- /dev/null +++ b/Resources/Public/Css/Main.css @@ -0,0 +1,15 @@ +.tx-tea table { + border-collapse: collapse; + width: 100%; +} + +.tx-tea table, +.tx-tea th, +.tx-tea td { + border: 1px solid black; +} + +.tx-tea thead th { + height: 50px; + cursor: pointer; +} diff --git a/Resources/Public/JavaScript/.gitkeep b/Resources/Public/JavaScript/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/Resources/Public/JavaScript/Main.js b/Resources/Public/JavaScript/Main.js new file mode 100644 index 0000000..fc96c45 --- /dev/null +++ b/Resources/Public/JavaScript/Main.js @@ -0,0 +1,41 @@ +var TYPO3 = TYPO3 || {}; +TYPO3.tea = {}; + +TYPO3.tea.makeSortable = function (table) { + var th = table.tHead, + i; + th && (th = th.rows[0]) && (th = th.cells); + if (th) i = th.length; + else return; + while (--i >= 0) + (function (i) { + var dir = 1; + th[i].addEventListener("click", function () { + TYPO3.tea.sortTable(table, i, (dir = 1 - dir)); + }); + })(i); +}; + +TYPO3.tea.sortTable = function (table, col, reverse) { + var tb = table.tBodies[0], + tr = Array.prototype.slice.call(tb.rows, 0), + i; + reverse = -(+reverse || -1); + tr = tr.sort(function (a, b) { + return ( + reverse * + a.cells[col].textContent + .trim() + .localeCompare(b.cells[col].textContent.trim()) + ); + }); + for (i = 0; i < tr.length; ++i) tb.appendChild(tr[i]); +}; + +document.addEventListener("DOMContentLoaded", function () { + var t = document.querySelectorAll(".tx-tea table"), + i = t.length; + while (--i >= 0) { + TYPO3.tea.makeSortable(t[i]); + } +});