├── .editorconfig ├── .ember-cli ├── .eslintignore ├── .eslintrc.js ├── .github └── workflows │ ├── ci.yml │ ├── gh-pages.yml │ ├── plan-release.yml │ └── publish.yml ├── .gitignore ├── .netlifyredirects ├── .npmignore ├── .percy.yml ├── .prettierignore ├── .prettierrc.js ├── .release-plan.json ├── .stylelintignore ├── .stylelintrc.js ├── .template-lintrc.js ├── .watchmanconfig ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── LICENSE.md ├── README.md ├── RELEASE.md ├── addon ├── .gitkeep ├── components │ ├── es-banner.hbs │ ├── es-button.hbs │ ├── es-button.js │ ├── es-card-content.hbs │ ├── es-card-content.js │ ├── es-card.hbs │ ├── es-card.js │ ├── es-footer-contributions.hbs │ ├── es-footer-contributions.js │ ├── es-footer-help.hbs │ ├── es-footer-help.js │ ├── es-footer-info.hbs │ ├── es-footer-info.js │ ├── es-footer-statement.hbs │ ├── es-footer-statement.js │ ├── es-footer.hbs │ ├── es-footer.js │ ├── es-header-navbar-link.hbs │ ├── es-header-navbar-link.js │ ├── es-header.hbs │ ├── es-header.js │ ├── es-icon.hbs │ ├── es-icon.js │ ├── es-link-card.hbs │ ├── es-link-card.js │ ├── es-note.hbs │ ├── es-note.js │ ├── es-pagination.hbs │ ├── es-progress-bar.hbs │ ├── es-progress-bar.js │ ├── es-sidebar.hbs │ └── es-sidebar.js ├── constants │ ├── es-footer.js │ ├── icons.js │ └── links.js ├── services │ ├── navbar.js │ └── progress.js └── styles │ ├── addon.css │ ├── background-shapes.css │ ├── backgrounds.css │ ├── central-content.css │ ├── components │ ├── es-banner.css │ ├── es-button.css │ ├── es-card.css │ ├── es-footer.css │ ├── es-header.css │ ├── es-note.css │ ├── es-pagination.css │ ├── es-progress-bar.css │ └── es-sidebar.css │ ├── container.css │ ├── flex.css │ ├── global.css │ ├── grid.css │ ├── header-anchor.css │ ├── helpers │ ├── embed.css │ ├── flex.css │ ├── index.css │ ├── margin.css │ ├── padding.css │ ├── rounded.css │ └── unstyled.css │ ├── icon.css │ ├── layout.css │ ├── on-this-page.css │ ├── sidebar-container.css │ ├── table-of-contents.css │ ├── typography.css │ └── well.css ├── app ├── .gitkeep ├── components │ ├── es-banner.js │ ├── es-button.js │ ├── es-card-content.js │ ├── es-card.js │ ├── es-footer-contributions.js │ ├── es-footer-help.js │ ├── es-footer-info.js │ ├── es-footer-statement.js │ ├── es-footer.js │ ├── es-header-navbar-link.js │ ├── es-header.js │ ├── es-icon.js │ ├── es-link-card.js │ ├── es-note.js │ ├── es-pagination.js │ ├── es-progress-bar.js │ └── es-sidebar.js └── services │ ├── navbar.js │ └── progress.js ├── config ├── fastboot.js └── index.js ├── docs-styles └── app.css ├── docs ├── components │ ├── banner.md │ ├── button.js │ ├── button.md │ ├── card.md │ ├── footer.md │ ├── header.js │ ├── header.md │ ├── link-card.md │ ├── note.md │ ├── pagination.md │ ├── progress-bar.md │ └── sidebar.md ├── concepts │ ├── accessibility.md │ ├── background-shapes.md │ ├── central-content.md │ ├── colors.md │ ├── header-anchor.md │ ├── layout.md │ ├── markdown.md │ ├── on-this-page.md │ ├── table-of-contents.md │ ├── typography.md │ └── wells.md ├── css │ ├── global.md │ ├── helpers.md │ └── overview.md └── index.md ├── ember-cli-build.js ├── index.js ├── package.json ├── percy-test └── visual-regression-test-test.js ├── pnpm-lock.yaml ├── public ├── ember-logo.png ├── emberconf.jpg ├── fonts │ ├── Inter-ExtraLight.woff │ ├── Inter-ExtraLight.woff2 │ ├── Inter-Italic.woff │ ├── Inter-Italic.woff2 │ ├── Inter-Regular.woff │ ├── Inter-Regular.woff2 │ ├── Inter-SemiBold.woff │ ├── Inter-SemiBold.woff2 │ ├── Inter-SemiBoldItalic.woff │ ├── Inter-SemiBoldItalic.woff2 │ └── Inter-roman.var.woff2 └── images │ ├── arrow-icon.svg │ ├── boxes-bottom-continued.svg │ ├── boxes-bottom-light.svg │ ├── boxes-bottom.svg │ ├── boxes-top.svg │ ├── ember-logo-white.svg │ ├── ember-logo.svg │ ├── mascots │ ├── tomster.png │ └── zoey.png │ ├── quotes.svg │ ├── swipe-bottom.svg │ └── swipe-top.svg ├── testem.js └── tests ├── acceptance └── progress-bar-test.js ├── dummy ├── .DS_Store ├── app │ ├── app.js │ ├── helpers │ │ └── increment.js │ ├── index.html │ ├── router.js │ ├── routes │ │ ├── basicy.js │ │ ├── fancy.js │ │ └── slow.js │ ├── styles │ │ └── app.css │ └── templates │ │ ├── .gitignore │ │ ├── application.hbs │ │ ├── basicy.hbs │ │ ├── fancy.hbs │ │ ├── index.hbs │ │ └── slow.hbs ├── config │ ├── ember-cli-update.json │ ├── ember-try.js │ ├── environment.js │ ├── optional-features.json │ └── targets.js └── public │ └── robots.txt ├── helpers └── index.js ├── index.html ├── integration ├── .gitkeep └── components │ ├── es-banner-test.js │ ├── es-button-test.js │ ├── es-card-test.js │ ├── es-footer-test.js │ ├── es-header-test.js │ ├── es-note-test.js │ ├── es-pagination-test.js │ ├── es-progress-bar-test.js │ └── es-sidebar-test.js ├── test-helper.js └── unit └── .gitkeep /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | indent_style = space 13 | indent_size = 2 14 | 15 | [*.hbs] 16 | insert_final_newline = false 17 | 18 | [*.{diff,md}] 19 | trim_trailing_whitespace = false 20 | -------------------------------------------------------------------------------- /.ember-cli: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | Setting `isTypeScriptProject` to true will force the blueprint generators to generate TypeScript 4 | rather than JavaScript by default, when a TypeScript version of a given blueprint is available. 5 | */ 6 | "isTypeScriptProject": false 7 | } 8 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # unconventional js 2 | /blueprints/*/files/ 3 | /vendor/ 4 | 5 | # compiled output 6 | /declarations/ 7 | /dist/ 8 | /tmp/ 9 | /dist-* 10 | 11 | # dependencies 12 | /bower_components/ 13 | /node_modules/ 14 | 15 | # misc 16 | /coverage/ 17 | !.* 18 | .*/ 19 | .eslintcache 20 | 21 | # ember-try 22 | /.node_modules.ember-try/ 23 | /bower.json.ember-try 24 | /npm-shrinkwrap.json.ember-try 25 | /package.json.ember-try 26 | /package-lock.json.ember-try 27 | /yarn.lock.ember-try 28 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | root: true, 5 | parser: '@babel/eslint-parser', 6 | parserOptions: { 7 | ecmaVersion: 'latest', 8 | sourceType: 'module', 9 | requireConfigFile: false, 10 | babelOptions: { 11 | plugins: [ 12 | ['@babel/plugin-proposal-decorators', { decoratorsBeforeExport: true }], 13 | ], 14 | }, 15 | }, 16 | plugins: ['ember'], 17 | extends: [ 18 | 'eslint:recommended', 19 | 'plugin:ember/recommended', 20 | 'plugin:prettier/recommended', 21 | ], 22 | env: { 23 | browser: true, 24 | }, 25 | rules: {}, 26 | overrides: [ 27 | // node files 28 | { 29 | files: [ 30 | './.eslintrc.js', 31 | './.prettierrc.js', 32 | './.stylelintrc.js', 33 | './.template-lintrc.js', 34 | './ember-cli-build.js', 35 | './index.js', 36 | './testem.js', 37 | './blueprints/*/index.js', 38 | './config/**/*.js', 39 | './tests/dummy/config/**/*.js', 40 | ], 41 | parserOptions: { 42 | sourceType: 'script', 43 | }, 44 | env: { 45 | browser: false, 46 | node: true, 47 | }, 48 | extends: ['plugin:n/recommended'], 49 | }, 50 | { 51 | // test files 52 | files: ['tests/**/*-test.{js,ts}'], 53 | extends: ['plugin:qunit/recommended'], 54 | }, 55 | ], 56 | }; 57 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - master 8 | pull_request: {} 9 | 10 | concurrency: 11 | group: ci-${{ github.head_ref || github.ref }} 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | lint: 16 | name: "Lint" 17 | runs-on: ubuntu-latest 18 | timeout-minutes: 5 19 | 20 | steps: 21 | - uses: actions/checkout@v4 22 | - uses: pnpm/action-setup@v4 23 | - uses: actions/setup-node@v4 24 | with: 25 | node-version: 18.x 26 | cache: pnpm 27 | - run: pnpm install 28 | - run: pnpm run lint 29 | 30 | percy: 31 | name: "Percy Tests" 32 | runs-on: ubuntu-latest 33 | timeout-minutes: 10 34 | env: 35 | PERCY_TOKEN: ee0a9d5c1122d6a21852edf19b5b309aaec18077fb3900c98995c90bc48ed240 36 | steps: 37 | - uses: actions/checkout@v4 38 | - uses: pnpm/action-setup@v4 39 | - uses: actions/setup-node@v4 40 | with: 41 | node-version: 18.x 42 | cache: pnpm 43 | - run: pnpm install 44 | - run: pnpm percy exec -- npm run test:docs 45 | 46 | test: 47 | name: "Tests" 48 | runs-on: ubuntu-latest 49 | timeout-minutes: 10 50 | 51 | steps: 52 | - uses: actions/checkout@v4 53 | - uses: pnpm/action-setup@v4 54 | - uses: actions/setup-node@v4 55 | with: 56 | node-version: 18.x 57 | cache: pnpm 58 | - run: pnpm install 59 | - run: pnpm run test:ember 60 | 61 | floating: 62 | name: "Floating Dependencies" 63 | runs-on: ubuntu-latest 64 | timeout-minutes: 10 65 | 66 | steps: 67 | - uses: actions/checkout@v4 68 | - uses: pnpm/action-setup@v4 69 | - uses: actions/setup-node@v4 70 | with: 71 | node-version: 18.x 72 | cache: pnpm 73 | - run: pnpm install --no-lockfile 74 | - run: pnpm run test:ember 75 | 76 | try-scenarios: 77 | name: ${{ matrix.try-scenario }} 78 | runs-on: ubuntu-latest 79 | needs: "test" 80 | timeout-minutes: 10 81 | 82 | strategy: 83 | fail-fast: false 84 | matrix: 85 | try-scenario: 86 | - ember-lts-3.28 87 | - ember-lts-4.4 88 | - ember-lts-4.8 89 | - ember-lts-4.12 90 | - ember-lts-5.4 91 | - ember-lts-5.8 92 | - ember-release 93 | - ember-beta 94 | - embroider-safe 95 | - embroider-optimized 96 | - no-deprecations 97 | 98 | steps: 99 | - uses: actions/checkout@v4 100 | - uses: pnpm/action-setup@v4 101 | - uses: actions/setup-node@v4 102 | with: 103 | node-version: 18.x 104 | cache: pnpm 105 | - run: pnpm install 106 | - name: Run Tests 107 | run: ./node_modules/.bin/ember try:one ${{ matrix.try-scenario }} 108 | 109 | allow-fail-try-scenarios: 110 | name: ${{ matrix.try-scenario }} - Allowed to fail 111 | runs-on: ubuntu-latest 112 | needs: 'test' 113 | timeout-minutes: 10 114 | permissions: 115 | pull-requests: write 116 | 117 | strategy: 118 | fail-fast: false 119 | matrix: 120 | try-scenario: 121 | - ember-canary 122 | - ember-release-no-deprecations 123 | 124 | steps: 125 | - uses: actions/checkout@v4 126 | - uses: pnpm/action-setup@v4 127 | - uses: actions/setup-node@v4 128 | with: 129 | node-version: 18.x 130 | cache: pnpm 131 | - run: pnpm install 132 | - name: Run Tests 133 | id: tests 134 | run: ./node_modules/.bin/ember try:one ${{ matrix.try-scenario }} 135 | continue-on-error: true 136 | - uses: mainmatter/continue-on-error-comment@v1 137 | with: 138 | repo-token: ${{ secrets.GITHUB_TOKEN }} 139 | outcome: ${{ steps.tests.outcome }} 140 | test-id: ${{ matrix.try-scenario }} 141 | -------------------------------------------------------------------------------- /.github/workflows/gh-pages.yml: -------------------------------------------------------------------------------- 1 | name: Lint to the Future Dashboard 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - main 8 | 9 | jobs: 10 | deploy: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | - uses: pnpm/action-setup@v4 15 | - uses: mansona/lttf-dashboard@v1 16 | with: 17 | token: ${{secrets.GITHUB_TOKEN}} 18 | -------------------------------------------------------------------------------- /.github/workflows/plan-release.yml: -------------------------------------------------------------------------------- 1 | name: Plan Release 2 | on: 3 | workflow_dispatch: 4 | push: 5 | branches: 6 | - main 7 | - master 8 | pull_request_target: # This workflow has permissions on the repo, do NOT run code from PRs in this workflow. See https://securitylab.github.com/research/github-actions-preventing-pwn-requests/ 9 | types: 10 | - labeled 11 | - unlabeled 12 | 13 | concurrency: 14 | group: plan-release # only the latest one of these should ever be running 15 | cancel-in-progress: true 16 | 17 | jobs: 18 | is-this-a-release: 19 | name: "Is this a release?" 20 | runs-on: ubuntu-latest 21 | outputs: 22 | command: ${{ steps.check-release.outputs.command }} 23 | 24 | steps: 25 | - uses: actions/checkout@v4 26 | with: 27 | fetch-depth: 2 28 | ref: 'master' 29 | # This will only cause the `is-this-a-release` job to have a "command" of `release` 30 | # when the .release-plan.json file was changed on the last commit. 31 | - id: check-release 32 | run: if git diff --name-only HEAD HEAD~1 | grep -w -q ".release-plan.json"; then echo "command=release"; fi >> $GITHUB_OUTPUT 33 | 34 | create-prepare-release-pr: 35 | name: Create Prepare Release PR 36 | runs-on: ubuntu-latest 37 | timeout-minutes: 5 38 | needs: is-this-a-release 39 | permissions: 40 | contents: write 41 | issues: read 42 | pull-requests: write 43 | # only run on push event or workflow dispatch if plan wasn't updated (don't create a release plan when we're releasing) 44 | # only run on labeled event if the PR has already been merged 45 | if: ((github.event_name == 'push' || github.event_name == 'workflow_dispatch') && needs.is-this-a-release.outputs.command != 'release') || (github.event_name == 'pull_request_target' && github.event.pull_request.merged == true) 46 | 47 | steps: 48 | - uses: actions/checkout@v4 49 | # We need to download lots of history so that 50 | # github-changelog can discover what's changed since the last release 51 | with: 52 | fetch-depth: 0 53 | ref: 'master' 54 | - uses: pnpm/action-setup@v4 55 | - uses: actions/setup-node@v4 56 | with: 57 | node-version: 18 58 | cache: pnpm 59 | - run: pnpm install --frozen-lockfile 60 | - name: "Generate Explanation and Prep Changelogs" 61 | id: explanation 62 | run: | 63 | set +e 64 | pnpm release-plan prepare 2> >(tee -a release-plan-stderr.txt >&2) 65 | 66 | if [ $? -ne 0 ]; then 67 | release_plan_output=$(cat release-plan-stderr.txt) 68 | else 69 | release_plan_output=$(jq .description .release-plan.json -r) 70 | rm release-plan-stderr.txt 71 | 72 | if [ $(jq '.solution | length' .release-plan.json) -eq 1 ]; then 73 | new_version=$(jq -r '.solution[].newVersion' .release-plan.json) 74 | echo "new_version=v$new_version" >> $GITHUB_OUTPUT 75 | fi 76 | fi 77 | echo 'text<> $GITHUB_OUTPUT 78 | echo "$release_plan_output" >> $GITHUB_OUTPUT 79 | echo 'EOF' >> $GITHUB_OUTPUT 80 | env: 81 | GITHUB_AUTH: ${{ secrets.GITHUB_TOKEN }} 82 | 83 | - uses: peter-evans/create-pull-request@v7 84 | with: 85 | commit-message: "Prepare Release ${{ steps.explanation.outputs.new_version}} using 'release-plan'" 86 | labels: "internal" 87 | branch: release-preview 88 | title: Prepare Release ${{ steps.explanation.outputs.new_version }} 89 | body: | 90 | This PR is a preview of the release that [release-plan](https://github.com/embroider-build/release-plan) has prepared. To release you should just merge this PR 👍 91 | 92 | ----------------------------------------- 93 | 94 | ${{ steps.explanation.outputs.text }} 95 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | # For every push to the primary branch with .release-plan.json modified, 2 | # runs release-plan. 3 | 4 | name: Publish Stable 5 | 6 | on: 7 | workflow_dispatch: 8 | push: 9 | branches: 10 | - main 11 | - master 12 | paths: 13 | - '.release-plan.json' 14 | 15 | concurrency: 16 | group: publish-${{ github.head_ref || github.ref }} 17 | cancel-in-progress: true 18 | 19 | jobs: 20 | publish: 21 | name: "NPM Publish" 22 | runs-on: ubuntu-latest 23 | permissions: 24 | contents: write 25 | pull-requests: write 26 | id-token: write 27 | attestations: write 28 | 29 | steps: 30 | - uses: actions/checkout@v4 31 | - uses: pnpm/action-setup@v4 32 | - uses: actions/setup-node@v4 33 | with: 34 | node-version: 18 35 | # This creates an .npmrc that reads the NODE_AUTH_TOKEN environment variable 36 | registry-url: 'https://registry.npmjs.org' 37 | cache: pnpm 38 | - run: pnpm install --frozen-lockfile 39 | - name: Publish to NPM 40 | run: NPM_CONFIG_PROVENANCE=true pnpm release-plan publish 41 | env: 42 | GITHUB_AUTH: ${{ secrets.GITHUB_TOKEN }} 43 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist/ 3 | /dist-* 4 | /tmp/ 5 | /declarations/ 6 | 7 | # dependencies 8 | /node_modules/ 9 | 10 | # misc 11 | /.env* 12 | /.pnp* 13 | /.eslintcache 14 | /coverage/ 15 | /npm-debug.log* 16 | /testem.log 17 | /yarn-error.log 18 | 19 | # ember-try 20 | /.node_modules.ember-try/ 21 | /npm-shrinkwrap.json.ember-try 22 | /package.json.ember-try 23 | /package-lock.json.ember-try 24 | /yarn.lock.ember-try 25 | 26 | # broccoli-debug 27 | /DEBUG/ 28 | -------------------------------------------------------------------------------- /.netlifyredirects: -------------------------------------------------------------------------------- 1 | /* /index.html 200 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist/ 3 | /tmp/ 4 | 5 | # misc 6 | /.editorconfig 7 | /.ember-cli 8 | /.env* 9 | /.eslintcache 10 | /.eslintignore 11 | /.eslintrc.js 12 | /.git/ 13 | /.github/ 14 | /.gitignore 15 | /.prettierignore 16 | /.prettierrc.js 17 | /.stylelintignore 18 | /.stylelintrc.js 19 | /.template-lintrc.js 20 | /.travis.yml 21 | /.watchmanconfig 22 | /CONTRIBUTING.md 23 | /ember-cli-build.js 24 | /testem.js 25 | /tests/ 26 | /tsconfig.declarations.json 27 | /tsconfig.json 28 | /yarn-error.log 29 | /yarn.lock 30 | .gitkeep 31 | 32 | # ember-try 33 | /.node_modules.ember-try/ 34 | /npm-shrinkwrap.json.ember-try 35 | /package.json.ember-try 36 | /package-lock.json.ember-try 37 | /yarn.lock.ember-try 38 | -------------------------------------------------------------------------------- /.percy.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | snapshot: 3 | widths: 4 | - 375 5 | - 1500 6 | minHeight: 1024 7 | percyCSS: "" 8 | enableJavaScript: false 9 | cliEnableJavaScript: true 10 | disableShadowDOM: false 11 | discovery: 12 | allowedHostnames: [] 13 | disallowedHostnames: [] 14 | networkIdleTimeout: 100 15 | captureMockedServiceWorker: false 16 | upload: 17 | files: "**/*.{png,jpg,jpeg}" 18 | ignore: "" 19 | stripExtensions: false 20 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # unconventional js 2 | /blueprints/*/files/ 3 | 4 | # compiled output 5 | /dist/ 6 | 7 | # misc 8 | /coverage/ 9 | !.* 10 | .*/ 11 | 12 | # ember-try 13 | /.node_modules.ember-try/ 14 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | overrides: [ 5 | { 6 | files: '*.{js,ts}', 7 | options: { 8 | singleQuote: true, 9 | }, 10 | }, 11 | ], 12 | }; 13 | -------------------------------------------------------------------------------- /.release-plan.json: -------------------------------------------------------------------------------- 1 | { 2 | "solution": { 3 | "ember-styleguide": { 4 | "impact": "minor", 5 | "oldVersion": "11.0.3", 6 | "newVersion": "11.1.0", 7 | "tagName": "latest", 8 | "constraints": [ 9 | { 10 | "impact": "minor", 11 | "reason": "Appears in changelog section :rocket: Enhancement" 12 | }, 13 | { 14 | "impact": "patch", 15 | "reason": "Appears in changelog section :house: Internal" 16 | } 17 | ], 18 | "pkgJSONPath": "./package.json" 19 | } 20 | }, 21 | "description": "## Release (2025-05-28)\n\n* ember-styleguide 11.1.0 (minor)\n\n#### :rocket: Enhancement\n* `ember-styleguide`\n * [#527](https://github.com/ember-learn/ember-styleguide/pull/527) move ember-auto-import to a dependency ([@mansona](https://github.com/mansona))\n\n#### :house: Internal\n* `ember-styleguide`\n * [#531](https://github.com/ember-learn/ember-styleguide/pull/531) update to v5.12 with ember-cli-update ([@mansona](https://github.com/mansona))\n * [#530](https://github.com/ember-learn/ember-styleguide/pull/530) Update to ember 4.12 with ember-cli-update ([@mansona](https://github.com/mansona))\n * [#529](https://github.com/ember-learn/ember-styleguide/pull/529) start using pnpm ([@mansona](https://github.com/mansona))\n\n#### Committers: 1\n- Chris Manson ([@mansona](https://github.com/mansona))\n" 22 | } 23 | -------------------------------------------------------------------------------- /.stylelintignore: -------------------------------------------------------------------------------- 1 | # unconventional files 2 | /blueprints/*/files/ 3 | 4 | # compiled output 5 | /dist/ 6 | /dist-* 7 | 8 | # addons 9 | /.node_modules.ember-try/ 10 | 11 | /node_modules/ 12 | -------------------------------------------------------------------------------- /.stylelintrc.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | 'use strict'; 3 | 4 | module.exports = { 5 | extends: ['stylelint-config-standard', 'stylelint-prettier/recommended'], 6 | plugins: [ 7 | 'stylelint-declaration-strict-value', 8 | 'stylelint-order' 9 | ], 10 | rules: { 11 | // Disables this rule to allow case agnostic color hex values 12 | 'color-hex-case': null, 13 | // Require the long version of hex colors 14 | 'color-hex-length': 'long', 15 | // Disallow ids 16 | 'selector-max-id': 0, 17 | // Require that color, background-color, etc use variables for colors, instead of direct values 18 | 'scale-unlimited/declaration-strict-value': [ 19 | ['/color/'] // We can enforce variables for font-size, margin, etc as well by adding here 20 | ], 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /.template-lintrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | extends: 'recommended', 5 | }; 6 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | { 2 | "ignore_dirs": ["dist"] 3 | } 4 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | The Ember team and community are committed to everyone having a safe and inclusive experience. 2 | 3 | Our Community Guidelines / Code of Conduct can be found here: 4 | 5 | https://emberjs.com/guidelines/ 6 | 7 | For a history of updates, see the page history here: 8 | 9 | https://github.com/emberjs/website/commits/master/source/guidelines.html.erb 10 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How To Contribute 2 | 3 | ## Installation 4 | 5 | - `git clone ` 6 | - `cd ember-styleguide` 7 | - `pnpm install` 8 | 9 | ## Linting 10 | 11 | - `pnpm lint` 12 | - `pnpm lint:fix` 13 | 14 | ## Running tests 15 | 16 | - `pnpm test` – Runs the test suite on the current Ember version 17 | - `pnpm test:ember --server` – Runs the test suite in "watch mode" 18 | - `pnpm test:ember-compatibility` – Runs the test suite against multiple Ember versions 19 | 20 | ## Running the dummy application 21 | 22 | - `pnpm start` 23 | - Visit the dummy application at [http://localhost:4200](http://localhost:4200). 24 | 25 | For more information on using ember-cli, visit [https://cli.emberjs.com/release/](https://cli.emberjs.com/release/). 26 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Expected Behavior 2 | // what did you expect to happen? 3 | 4 | ## Actual Behavior 5 | // what actually happened? 6 | 7 | ## Steps to Reproduce 8 | // how can we reproduce this issue? 9 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ember-styleguide 2 | 3 | [![This project uses GitHub Actions for continuous integration.](https://github.com/ember-learn/ember-styleguide/workflows/CI/badge.svg)](https://github.com/ember-learn/ember-styleguide/actions?query=workflow%3ACI) 4 | [![This project uses Percy.io for visual regression testing.](https://percy.io/static/images/percy-badge.svg)](https://percy.io/Ember/ember-styleguide) 5 | [![Latest NPM release](https://img.shields.io/npm/v/ember-styleguide.svg)](https://www.npmjs.com/package/ember-styleguide.svg) 6 | 7 | 8 | This addon is intended to provide basic components for easier style coordination among the Ember family of websites, although the original intent is to support the emberjs.com website. We are committed to the goal of meeting WCAG 2.0 AA conformance standards. 9 | 10 | ## Compatibility 11 | 12 | * Ember.js v3.24 or above 13 | * Ember CLI v3.24 or above 14 | * Node.js v14 or above 15 | 16 | ## Contributing 17 | 18 | See the [Contributing](CONTRIBUTING.md) guide for details. 19 | 20 | ## License 21 | 22 | This project is licensed under the [MIT License](LICENSE.md). 23 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # Release Process 2 | 3 | Releases in this repo are mostly automated using [release-plan](https://github.com/embroider-build/release-plan/). Once you label all your PRs correctly (see below) you will have an automatically generated PR that updates your CHANGELOG.md file and a `.release-plan.json` that is used to prepare the release once the PR is merged. 4 | 5 | ## Preparation 6 | 7 | Since the majority of the actual release process is automated, the remaining tasks before releasing are: 8 | 9 | - correctly labeling **all** pull requests that have been merged since the last release 10 | - updating pull request titles so they make sense to our users 11 | 12 | Some great information on why this is important can be found at [keepachangelog.com](https://keepachangelog.com/en/1.1.0/), but the overall 13 | guiding principle here is that changelogs are for humans, not machines. 14 | 15 | When reviewing merged PR's the labels to be used are: 16 | 17 | - breaking - Used when the PR is considered a breaking change. 18 | - enhancement - Used when the PR adds a new feature or enhancement. 19 | - bug - Used when the PR fixes a bug included in a previous release. 20 | - documentation - Used when the PR adds or updates documentation. 21 | - internal - Internal changes or things that don't fit in any other category. 22 | 23 | **Note:** `release-plan` requires that **all** PRs are labeled. If a PR doesn't fit in a category it's fine to label it as `internal` 24 | 25 | ## Release 26 | 27 | Once the prep work is completed, the actual release is straight forward: you just need to merge the open [Plan Release](https://github.com/ember-learn/ember-styleguide/pulls?q=is%3Apr+is%3Aopen+%22Prepare+Release%22+in%3Atitle) PR 28 | -------------------------------------------------------------------------------- /addon/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ember-learn/ember-styleguide/6d709151fcfb90896b41667cff9442db41edc541/addon/.gitkeep -------------------------------------------------------------------------------- /addon/components/es-banner.hbs: -------------------------------------------------------------------------------- 1 |
5 | {{yield}} 6 |
7 | -------------------------------------------------------------------------------- /addon/components/es-button.hbs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addon/components/es-button.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | import Component from '@glimmer/component'; 3 | import { action } from '@ember/object'; 4 | 5 | export default class EsButtonComponent extends Component { 6 | // default value 7 | _onClicked = () => {}; 8 | _type = "button"; 9 | 10 | constructor() { 11 | super(...arguments); 12 | 13 | 14 | if(!this.args.onClicked) { 15 | // eslint-disable-next-line no-console 16 | console.warn(new Error('Button created with no onClicked')); 17 | } else { 18 | this._onClicked = this.args.onClicked; 19 | } 20 | 21 | if(!this.args.type) { 22 | // eslint-disable-next-line no-console 23 | console.warn(new Error('Button created with no @type defined - defaulting to `type="button"`')); 24 | } else { 25 | this._type = this.args.type; 26 | } 27 | } 28 | 29 | @action 30 | buttonClicked() { 31 | this._onClicked(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /addon/components/es-card-content.hbs: -------------------------------------------------------------------------------- 1 | {{!-- template-lint-disable require-valid-alt-text --}} 2 | {{!-- Bug link: https://github.com/ember-template-lint/ember-template-lint/issues/1286 --}} 3 | 4 | {{#if @icon}} 5 | 6 | {{/if}} 7 | 8 | {{#if @image}} 9 | {{if 17 | {{/if}} 18 | 19 |
20 | {{yield}} 21 |
22 | -------------------------------------------------------------------------------- /addon/components/es-card-content.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable ember/no-empty-glimmer-component-classes, prettier/prettier */ 2 | import Component from '@glimmer/component'; 3 | 4 | export default class EsCardContentComponent extends Component { 5 | } 6 | -------------------------------------------------------------------------------- /addon/components/es-card.hbs: -------------------------------------------------------------------------------- 1 |
  • 2 | 3 | {{yield}} 4 | 5 |
  • -------------------------------------------------------------------------------- /addon/components/es-card.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable ember/no-empty-glimmer-component-classes, prettier/prettier */ 2 | import Component from '@glimmer/component'; 3 | 4 | export default class EsCardComponent extends Component { 5 | } 6 | -------------------------------------------------------------------------------- /addon/components/es-footer-contributions.hbs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addon/components/es-footer-contributions.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable ember/no-empty-glimmer-component-classes, prettier/prettier */ 2 | import Component from '@glimmer/component'; 3 | 4 | export default class EsFooterContributionsComponent extends Component { 5 | } 6 | -------------------------------------------------------------------------------- /addon/components/es-footer-help.hbs: -------------------------------------------------------------------------------- 1 | {{! template-lint-disable no-whitespace-for-layout }} 2 | -------------------------------------------------------------------------------- /addon/components/es-footer-help.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | import Component from '@glimmer/component'; 3 | 4 | export default class EsFooterHelpComponent extends Component { 5 | 6 | get linkUrl() { 7 | return this.args.contributeLink || 'https://github.com/ember-learn/ember-website'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /addon/components/es-footer-info.hbs: -------------------------------------------------------------------------------- 1 | {{! template-lint-disable no-redundant-role }} 2 | -------------------------------------------------------------------------------- /addon/components/es-footer-info.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable ember/no-empty-glimmer-component-classes, prettier/prettier */ 2 | import Component from '@glimmer/component'; 3 | 4 | export default class EsFooterInfoComponent extends Component { 5 | } 6 | -------------------------------------------------------------------------------- /addon/components/es-footer-statement.hbs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addon/components/es-footer-statement.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | import Component from '@glimmer/component'; 3 | 4 | export default class EsFooterStatementComponent extends Component { 5 | constructor() { 6 | super(...arguments) 7 | 8 | this.currentYear = new Date().getUTCFullYear(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /addon/components/es-footer.hbs: -------------------------------------------------------------------------------- 1 |
    2 | {{!-- 3 | Pass footer properties to support 4 | 5 | --}} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    -------------------------------------------------------------------------------- /addon/components/es-footer.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | import Component from '@glimmer/component'; 3 | 4 | import { 5 | socialLinks, 6 | infoLinks, 7 | contributorLinks, 8 | tagline 9 | } from '../constants/es-footer'; 10 | 11 | export default class EsFooterComponent extends Component { 12 | get socialLinks() { 13 | if (this.args.socialLinks) { 14 | return this.args.socialLinks; 15 | } 16 | 17 | return socialLinks; 18 | } 19 | 20 | get contributorLinks() { 21 | if (this.args.contributorLinks) { 22 | return this.args.contributorLinks; 23 | } 24 | 25 | return contributorLinks; 26 | } 27 | 28 | get tagline() { 29 | if (this.args.tagline) { 30 | return this.args.tagline; 31 | } 32 | 33 | return tagline; 34 | } 35 | 36 | get currentYear() { 37 | return new Date().getUTCFullYear() 38 | } 39 | 40 | get infoLinks() { 41 | if (this.args && this.args.infoLinks) { 42 | return this.args.infoLinks; 43 | } 44 | 45 | return infoLinks; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /addon/components/es-header-navbar-link.hbs: -------------------------------------------------------------------------------- 1 | {{! template-lint-disable no-at-ember-render-modifiers }} 2 | -------------------------------------------------------------------------------- /addon/components/es-header-navbar-link.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable ember/no-classic-classes, ember/no-classic-components, ember/no-component-lifecycle-hooks, ember/no-get, ember/no-runloop, ember/no-tracked-properties-from-args, ember/require-super-in-lifecycle-hooks, ember/require-tagless-components, prettier/prettier */ 2 | import Component from '@glimmer/component'; 3 | import { inject as service } from '@ember/service'; 4 | import { schedule, next } from '@ember/runloop'; 5 | import { action } from '@ember/object'; 6 | import { tracked } from '@glimmer/tracking'; 7 | 8 | export default class EsHeaderNavbarLink extends Component { 9 | @service navbar; 10 | 11 | @tracked element = null; 12 | @tracked linkType = this.args.link.type; 13 | @tracked isDropdownOpen = false; 14 | 15 | get isDropdown() { 16 | return this.linkType === 'dropdown'; 17 | } 18 | 19 | // because aria-expanded requires a string value instead of a boolean 20 | get isExpanded() { 21 | return this.isDropdownOpen ? 'true' : 'false'; 22 | } 23 | 24 | constructor() { 25 | super(...arguments); 26 | this.navbar.register(this); 27 | } 28 | 29 | setupLinkBlurs() { 30 | if (this.linkBlursActive) { 31 | return; 32 | } 33 | 34 | this.linkBlursActive = true; 35 | let links = Array.from(this.element.querySelectorAll('.navbar-dropdown-list-item-link')); 36 | 37 | links.forEach(anchor => { 38 | anchor.addEventListener('blur', () => this.processBlur()); 39 | }); 40 | } 41 | 42 | @action 43 | setElement(element) { 44 | this.element = element; 45 | } 46 | 47 | @action 48 | toggleDropdown(event) { 49 | this.navbar.closePopupMenu(this); 50 | this.isDropdownOpen = !this.isDropdownOpen; 51 | 52 | if (this.isDropdownOpen) { 53 | // if it's open, let's make sure it can do some things 54 | schedule('afterRender', this, function() { 55 | this.setupLinkBlurs(); 56 | 57 | // move focus to the first item in the dropdown only when opened with keyboard 58 | // ref https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail 59 | if (event.detail === 0) { 60 | this.processFirstElementFocus(); 61 | } 62 | 63 | this.processKeyPress(); 64 | }); 65 | } 66 | } 67 | 68 | @action 69 | processBlur() { 70 | next(this, function() { 71 | let subItems = Array.from(this.element.querySelectorAll('.navbar-dropdown-list li')); 72 | let focused = subItems.find(item => document.activeElement === item.querySelector('a')); 73 | 74 | //if the dropdown isn't focused, close it 75 | if (!focused) { 76 | this.closeDropdown(); 77 | } 78 | }); 79 | } 80 | 81 | @action 82 | unregisterListener(element) { 83 | element.removeEventListener('keydown', this.triggerDropdown); 84 | element.removeEventListener('click', this.triggerDropdown); 85 | } 86 | 87 | closeDropdown() { 88 | // set the isDropdownOpen to false, which will make the dropdown go away 89 | this.isDropdownOpen = false; 90 | } 91 | 92 | openDropdown() { 93 | //might not need this 94 | // open the dropdown and set the focus to the first item inside 95 | this.isDropdownOpen = true; 96 | this.processFirstElementFocus(); 97 | } 98 | 99 | processClick() { 100 | // TODO handle mouseclick outside the current dropdown 101 | } 102 | 103 | processFirstElementFocus() { 104 | // Identify the first item in the dropdown list & set focus on it 105 | let firstFocusable = this.element.querySelector('.navbar-dropdown-list li:first-of-type a'); 106 | firstFocusable.focus(); 107 | } 108 | 109 | processKeyPress() { 110 | // add event listeners 111 | let dropdownList = this.element.querySelector('.navbar-dropdown-list'); 112 | 113 | //...for certain keypress events 114 | dropdownList.addEventListener('keydown', event => { 115 | // ESC key should close the dropdown and return focus to the toggle 116 | if (event.keyCode === 27 && this.isDropdownOpen) { 117 | this.closeDropdown(); 118 | this.returnFocus(); 119 | 120 | // if focus leaves the open dropdown via keypress, close it (without trying to otherwise control focus) 121 | } else if (this.isDropdownOpen) { 122 | this.processBlur(); 123 | } else { 124 | return; 125 | } 126 | }); 127 | } 128 | 129 | returnFocus() { 130 | // after that rendering bit happens, we need to return the focus to the trigger 131 | schedule('afterRender', this, function() { 132 | let dropdownTrigger = this.element.querySelector('.navbar-list-item-dropdown-toggle'); 133 | dropdownTrigger.focus(); 134 | }); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /addon/components/es-header.hbs: -------------------------------------------------------------------------------- 1 | {{! template-lint-disable no-redundant-role }} 2 | -------------------------------------------------------------------------------- /addon/components/es-header.js: -------------------------------------------------------------------------------- 1 | import Component from '@glimmer/component'; 2 | import { action, set } from '@ember/object'; 3 | 4 | import defaultLinks from '../constants/links'; 5 | 6 | const defautHomePage = 'https://www.emberjs.com'; 7 | 8 | export default class EsHeaderComponent extends Component { 9 | expanded = false; 10 | 11 | get navHome() { 12 | return this.args.home ?? defautHomePage; 13 | } 14 | 15 | get navLinks() { 16 | return this.args.links ?? defaultLinks; 17 | } 18 | 19 | @action 20 | onTogglerClick() { 21 | set(this, 'expanded', !this.expanded); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /addon/components/es-icon.hbs: -------------------------------------------------------------------------------- 1 | {{!-- template-lint-disable no-triple-curlies --}} 2 | {{{this.icon}}} -------------------------------------------------------------------------------- /addon/components/es-icon.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | import Component from '@glimmer/component'; 3 | import { assert } from '@ember/debug'; 4 | 5 | import icons from '../constants/icons'; 6 | 7 | export default class EsIconComponent extends Component { 8 | get icon() { 9 | if (!(this.args.icon in icons)) { 10 | assert( 11 | `${ 12 | this.args.icon 13 | } isn't a supported icon. We no longer support dynamid svg lookup and can only support the following icons: ${Object.keys( 14 | icons 15 | ).join(', ')}` 16 | ); 17 | } 18 | 19 | return icons[this.args.icon].replace( 20 | ' 2 | 3 |

    {{@title}}

    4 | 5 | {{yield}} 6 | 7 | -------------------------------------------------------------------------------- /addon/components/es-link-card.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable ember/no-empty-glimmer-component-classes, prettier/prettier */ 2 | import Component from '@glimmer/component'; 3 | 4 | export default class EsLinkCardComponent extends Component { 5 | } 6 | -------------------------------------------------------------------------------- /addon/components/es-note.hbs: -------------------------------------------------------------------------------- 1 | {{! template-lint-disable no-redundant-role }} 2 |
    3 |
    4 |
    5 |
    {{this.mascot.name}} says...
    6 |
    {{yield}}
    7 |
    8 | 9 |
    10 |
    -------------------------------------------------------------------------------- /addon/components/es-note.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | import Component from '@glimmer/component'; 3 | 4 | const Mascots = { 5 | tomster: { image: '/images/mascots/tomster.png', name: 'Tomster' }, 6 | zoey: { image: '/images/mascots/zoey.png', name: 'Zoey' }, 7 | } 8 | 9 | function randomMascot() { 10 | let mascotKeys = Object.keys(Mascots); 11 | 12 | let randomIndex = Math.floor(Math.random() * Math.floor(mascotKeys.length)); 13 | 14 | return Mascots[mascotKeys[randomIndex]]; 15 | } 16 | 17 | export default class EsNoteComponent extends Component { 18 | constructor() { 19 | super(...arguments); 20 | 21 | if (this.args.mascot) { 22 | this.mascot = Mascots[this.args.mascot]; 23 | } else { 24 | this.mascot = randomMascot(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /addon/components/es-pagination.hbs: -------------------------------------------------------------------------------- 1 |
    2 | {{#if (and (has-block "previous") @showPrevious)}} 3 |
    4 | left arrow 5 |
    {{yield to='previous'}}
    6 |
    7 | {{/if}} 8 | 9 | {{#if (and (has-block "next") @showNext)}} 10 |
    11 |
    {{yield to='next'}}
    12 | right arrow 13 |
    14 | {{/if}} 15 |
    16 | -------------------------------------------------------------------------------- /addon/components/es-progress-bar.hbs: -------------------------------------------------------------------------------- 1 | {{! template-lint-disable no-invalid-aria-attributes }} 2 |
    -------------------------------------------------------------------------------- /addon/components/es-progress-bar.js: -------------------------------------------------------------------------------- 1 | import Component from '@glimmer/component'; 2 | import { inject as service } from '@ember/service'; 3 | 4 | export default class EsProgressBarComponent extends Component { 5 | @service progress; 6 | } 7 | -------------------------------------------------------------------------------- /addon/components/es-sidebar.hbs: -------------------------------------------------------------------------------- 1 | {{! template-lint-disable no-unsupported-role-attributes }} 2 | 16 | 17 | 23 | 24 | -------------------------------------------------------------------------------- /addon/components/es-sidebar.js: -------------------------------------------------------------------------------- 1 | import Component from '@glimmer/component'; 2 | import { tracked } from '@glimmer/tracking'; 3 | import { action } from '@ember/object'; 4 | import { inject as service } from '@ember/service'; 5 | 6 | export default class EsSidebarComponent extends Component { 7 | @service router; 8 | 9 | @tracked isOpen = false; 10 | 11 | constructor() { 12 | super(...arguments); 13 | 14 | this.router.on('routeDidChange', this.close); 15 | } 16 | 17 | willDestroy() { 18 | this.router.off('routeDidChange', this.close); 19 | 20 | super.willDestroy(...arguments); 21 | } 22 | 23 | @action 24 | toggle() { 25 | this.isOpen = !this.isOpen; 26 | } 27 | 28 | @action 29 | close() { 30 | if (this.isOpen) { 31 | this.isOpen = false; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /addon/constants/es-footer.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | 3 | const socialLinks = [{ 4 | title: 'Twitter', 5 | href: 'http://twitter.com/emberjs', 6 | class: 'twitter-logo', 7 | label: 'Official Ember Twitter Account' 8 | }, { 9 | title: 'GitHub', 10 | href: 'https://github.com/emberjs/ember.js', 11 | class: 'github-logo', 12 | label: 'Ember.js github repository' 13 | }, { 14 | title: 'Discord', 15 | href: 'https://discordapp.com/invite/zT3asNS', 16 | class: 'discord-logo', 17 | label: 'Join the Ember Community Discord' 18 | }, { 19 | title: 'Mastodon', 20 | href: 'https://hachyderm.io/@emberjs', 21 | class: 'mastodon-logo', 22 | label: 'Official Ember Mastodon Account' 23 | }]; 24 | 25 | 26 | const contributorLinks = [{ 27 | name: 'Hosted by:', 28 | title: "Netlify", 29 | href: 'https://www.netlify.com/', 30 | class: 'netlify-logo', 31 | }, { 32 | name: 'Hosted by:', 33 | title: "Heroku", 34 | href: 'https://www.heroku.com/', 35 | class: 'heroku-logo', 36 | }, { 37 | name: 'CDN provided by:', 38 | title: "Fastly", 39 | href: 'https://www.fastly.com', 40 | class: 'fastly-logo' 41 | }, { 42 | name: 'Tested with:', 43 | title: "Percy", 44 | href: 'https://percy.io', 45 | class: 'percy-logo' 46 | }, { 47 | name: 'Resolved with:', 48 | title: "Dnsimple", 49 | href: 'https://dnsimple.link/resolving-emberjs', 50 | class: 'dnsimple-logo-dark' 51 | }]; 52 | 53 | const infoLinks = [{ 54 | name: 'Team', 55 | href: 'https://emberjs.com/team' 56 | }, { 57 | name: 'Sponsors', 58 | href: 'https://emberjs.com/sponsors', 59 | lineBreak: true 60 | }, { 61 | name: 'Security', 62 | href: 'https://emberjs.com/security' 63 | }, { 64 | name: 'Legal', 65 | href: 'https://emberjs.com/about/legal' 66 | }, { 67 | name: 'Branding', 68 | href: 'https://emberjs.com/logos', 69 | lineBreak: true 70 | }, { 71 | name: 'Community Guidelines', 72 | href: 'https://emberjs.com/guidelines' 73 | }]; 74 | 75 | 76 | const tagline = 'Ember.js is free, open source and always will be.'; 77 | 78 | export { socialLinks, infoLinks, contributorLinks, tagline }; 79 | -------------------------------------------------------------------------------- /addon/constants/links.js: -------------------------------------------------------------------------------- 1 | export default [ 2 | { 3 | name: 'Docs', 4 | type: 'dropdown', 5 | items: [ 6 | { 7 | href: 'https://guides.emberjs.com/release/', 8 | name: 'Ember.js Guides', 9 | type: 'link', 10 | }, 11 | { 12 | href: 'https://api.emberjs.com', 13 | name: 'API Reference', 14 | type: 'link', 15 | }, 16 | { 17 | href: 'https://cli.emberjs.com', 18 | name: 'CLI Guides', 19 | type: 'link', 20 | }, 21 | { 22 | type: 'divider', 23 | }, 24 | { 25 | href: 'https://emberjs.com/learn', 26 | name: 'Learn Ember', 27 | type: 'link', 28 | }, 29 | ], 30 | }, 31 | { 32 | name: 'Releases', 33 | type: 'dropdown', 34 | items: [ 35 | { 36 | href: 'https://emberjs.com/releases', 37 | name: 'Overview', 38 | type: 'link', 39 | }, 40 | { 41 | href: 'https://emberjs.com/releases/lts', 42 | name: '→ LTS', 43 | type: 'link', 44 | }, 45 | { 46 | href: 'https://emberjs.com/releases/release', 47 | name: '→ Stable', 48 | type: 'link', 49 | }, 50 | { 51 | href: 'https://emberjs.com/releases/beta', 52 | name: '→ Beta', 53 | type: 'link', 54 | }, 55 | { 56 | href: 'https://emberjs.com/releases/canary', 57 | name: '→ Canary', 58 | type: 'link', 59 | }, 60 | { 61 | type: 'divider', 62 | }, 63 | { 64 | href: 'https://emberjs.com/editions', 65 | name: 'Editions', 66 | type: 'link', 67 | }, 68 | { 69 | href: 'https://emberjs.com/browser-support', 70 | name: 'Browser Support', 71 | type: 'link', 72 | }, 73 | { 74 | href: 'https://deprecations.emberjs.com', 75 | name: 'Deprecations', 76 | type: 'link', 77 | }, 78 | { 79 | href: 'https://rfcs.emberjs.com', 80 | name: 'RFCs Website', 81 | type: 'link', 82 | }, 83 | ], 84 | }, 85 | { 86 | href: 'https://blog.emberjs.com', 87 | name: 'Blog', 88 | type: 'link', 89 | }, 90 | { 91 | name: 'Community', 92 | type: 'dropdown', 93 | items: [ 94 | { 95 | href: 'https://emberjs.com/community', 96 | name: 'The Ember Community', 97 | type: 'link', 98 | }, 99 | { 100 | href: 'https://emberjs.com/guidelines', 101 | name: 'Guidelines', 102 | type: 'link', 103 | }, 104 | { 105 | href: 'https://emberjs.com/community/black-lives-matter/', 106 | name: 'Black Lives Matter', 107 | type: 'link', 108 | }, 109 | { 110 | type: 'divider', 111 | }, 112 | { 113 | href: 'https://help-wanted.emberjs.com/', 114 | name: 'Help Wanted', 115 | type: 'link', 116 | }, 117 | { 118 | href: 'https://emberjs.com/survey', 119 | name: 'Ember Community Survey', 120 | type: 'link', 121 | }, 122 | { 123 | type: 'divider', 124 | }, 125 | { 126 | href: 'https://emberconf.com/', 127 | name: 'EmberConf', 128 | type: 'link', 129 | }, 130 | { 131 | href: 'https://emberjs.com/community/meetups', 132 | name: 'Meetups', 133 | type: 'link', 134 | }, 135 | ], 136 | }, 137 | { 138 | name: 'About', 139 | type: 'dropdown', 140 | items: [ 141 | { 142 | href: 'https://emberjs.com/teams', 143 | name: 'The Team', 144 | type: 'link', 145 | }, 146 | { 147 | type: 'divider', 148 | }, 149 | { 150 | href: 'https://emberjs.com/logos', 151 | name: 'Branding', 152 | type: 'link', 153 | }, 154 | { 155 | href: 'https://emberjs.com/mascots', 156 | name: 'Mascots', 157 | type: 'link', 158 | }, 159 | { 160 | type: 'divider', 161 | }, 162 | { 163 | href: 'https://emberjs.com/ember-users', 164 | name: 'Who Uses Ember', 165 | type: 'link', 166 | }, 167 | { 168 | href: 'https://emberjs.com/sponsors', 169 | name: 'Sponsors', 170 | type: 'link', 171 | }, 172 | { 173 | type: 'divider', 174 | }, 175 | { 176 | href: 'https://emberjs.com/about/legal', 177 | name: 'Legal', 178 | type: 'link', 179 | }, 180 | { 181 | href: 'https://emberjs.com/security', 182 | name: 'Security', 183 | type: 'link', 184 | }, 185 | ], 186 | }, 187 | ]; 188 | -------------------------------------------------------------------------------- /addon/services/navbar.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable ember/no-classic-classes, prettier/prettier */ 2 | import Service from '@ember/service'; 3 | 4 | export default Service.extend({ 5 | init() { 6 | this._super(...arguments); 7 | 8 | this.items = []; 9 | }, 10 | 11 | register(item) { 12 | this.items.push(item); 13 | }, 14 | 15 | closePopupMenu(menu) { 16 | this.items.forEach(item => { 17 | if(item !== menu) { 18 | item.closeDropdown() 19 | } 20 | }); 21 | }, 22 | }); 23 | -------------------------------------------------------------------------------- /addon/services/progress.js: -------------------------------------------------------------------------------- 1 | import Service, { inject as service } from '@ember/service'; 2 | import { htmlSafe } from '@ember/template'; 3 | import { tracked } from '@glimmer/tracking'; 4 | import { action } from '@ember/object'; 5 | 6 | import { rawTimeout, task } from 'ember-concurrency'; 7 | import { buildWaiter } from '@ember/test-waiters'; 8 | 9 | const SPEED = 200; 10 | 11 | let waiter = buildWaiter('progress-bar'); 12 | 13 | export default class ProgressService extends Service { 14 | @service router; 15 | 16 | count = 0; 17 | progress = 0; 18 | 19 | @tracked _style = ''; 20 | 21 | constructor() { 22 | super(...arguments); 23 | 24 | this.router.on('routeWillChange', this.onRouteWillChange); 25 | this.router.on('routeDidChange', this.onRouteDidChange); 26 | } 27 | 28 | willDestroy() { 29 | this.router.off('routeWillChange', this.onRouteWillChange); 30 | this.router.off('routeDidChange', this.onRouteDidChange); 31 | 32 | super.willDestroy(...arguments); 33 | } 34 | 35 | get style() { 36 | return htmlSafe(this._style); 37 | } 38 | 39 | @action 40 | async onRouteWillChange() { 41 | this.updateTask.perform(); 42 | } 43 | 44 | @action 45 | onRouteDidChange() { 46 | this.updateTask.cancelAll(); 47 | } 48 | 49 | @(task(function* () { 50 | let token = waiter.beginAsync(); 51 | 52 | this.progress = 0; 53 | this._style = `width: 0%`; 54 | 55 | try { 56 | while (true) { 57 | yield rawTimeout(SPEED); 58 | 59 | let currentAmount; 60 | if (this.progress >= 0 && this.progress < 0.2) { 61 | currentAmount = 0.1; 62 | } else if (this.progress >= 0.2 && this.progress < 0.5) { 63 | currentAmount = 0.04; 64 | } else if (this.progress >= 0.5 && this.progress < 0.8) { 65 | currentAmount = 0.02; 66 | } else if (this.progress >= 0.8 && this.progress < 0.99) { 67 | currentAmount = 0.005; 68 | } else { 69 | currentAmount = 0; 70 | } 71 | 72 | this.progress += currentAmount; 73 | if (this.progress > 0.998) { 74 | this.progress = 0.998; 75 | } 76 | 77 | this._style = `transition: width ${SPEED}ms linear; width: ${ 78 | this.progress * 100 79 | }%`; 80 | } 81 | } finally { 82 | this._style = `transition: width ${SPEED}ms linear; width: 100%`; 83 | yield rawTimeout(SPEED); 84 | this._style = `transition: opacity ${ 85 | SPEED * 2 86 | }ms linear; width: 100%; opacity: 0`; 87 | 88 | waiter.endAsync(token); 89 | } 90 | }).drop()) 91 | updateTask; 92 | } 93 | -------------------------------------------------------------------------------- /addon/styles/addon.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable import-notation, prettier/prettier */ 2 | 3 | /* Reset */ 4 | @import 'normalize.css'; 5 | 6 | /* Globals */ 7 | @import 'global.css'; 8 | @import 'typography.css'; 9 | 10 | /* Modules */ 11 | @import 'backgrounds.css'; 12 | @import 'background-shapes.css'; 13 | @import 'container.css'; 14 | @import 'layout.css'; 15 | @import 'grid.css'; 16 | @import 'icon.css'; 17 | @import 'sidebar-container.css'; 18 | @import 'well.css'; 19 | @import 'table-of-contents.css'; 20 | @import 'header-anchor'; 21 | @import 'central-content.css'; 22 | @import 'on-this-page.css'; 23 | 24 | /* Helpers */ 25 | @import 'helpers/index.css'; 26 | 27 | /* Components */ 28 | @import 'components/es-banner.css'; 29 | @import 'components/es-button.css'; 30 | @import 'components/es-card.css'; 31 | @import 'components/es-footer.css'; 32 | @import 'components/es-header.css'; 33 | @import 'components/es-note.css'; 34 | @import 'components/es-sidebar.css'; 35 | @import 'components/es-progress-bar.css'; 36 | @import 'components/es-pagination.css'; 37 | -------------------------------------------------------------------------------- /addon/styles/background-shapes.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable comment-empty-line-before, media-feature-range-notation, prettier/prettier */ 2 | .bg-shape-boxes { 3 | background-image: url('/images/boxes-top.svg'); 4 | background-repeat: no-repeat; 5 | background-position: top right; 6 | } 7 | 8 | .bg-shape-boxes-bottom { 9 | background-image: url('/images/boxes-bottom-light.svg'); 10 | background-repeat: no-repeat; 11 | background-position: bottom right; 12 | } 13 | 14 | .dark .bg-shape-boxes-bottom { 15 | background-image: url('/images/boxes-bottom.svg'); 16 | } 17 | 18 | .bg-shape-boxes-bottom + * { 19 | background-image: url('/images/boxes-bottom-continued.svg'); 20 | background-repeat: no-repeat; 21 | background-position: top right; 22 | } 23 | 24 | .bg-shape-swipe-top { 25 | background: var(--color-brand) url('/images/swipe-top.svg') no-repeat bottom left; 26 | background-size: cover; 27 | /* this fixes a slight rendering issue in chrome */ 28 | margin-bottom: -1px; 29 | } 30 | 31 | .bg-shape-swipe-bottom { 32 | background-image: url('/images/swipe-bottom.svg'); 33 | background-repeat: no-repeat; 34 | background-position: bottom left; 35 | } 36 | 37 | @media (max-width: 1007px) { 38 | .bg-shape-boxes-bottom { 39 | background-size: 300px; 40 | } 41 | 42 | .bg-shape-boxes-bottom + * { 43 | background-size: 100px; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /addon/styles/backgrounds.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable custom-property-empty-line-before, custom-property-pattern */ 2 | .bg-brand { 3 | background-color: var(--color-brand); 4 | color: var(--color-brand-text); 5 | 6 | & h1, 7 | & h2, 8 | & h3, 9 | & h4, 10 | & h5, 11 | & h6, 12 | & .medium, 13 | & .large, 14 | & .xlarge { 15 | color: var(--color-white); 16 | } 17 | } 18 | 19 | .bg-light { 20 | background-color: var(--color-gray-100); 21 | color: var(--color-gray-700); 22 | } 23 | 24 | .bg-light-muted { 25 | background-color: var(--color-gray-200); 26 | color: var(--color-gray-700); 27 | } 28 | 29 | .bg-dark { 30 | background-color: var(--color-gray-900); 31 | color: var(--color-gray-300); 32 | 33 | --color-link: var(--color-brand); 34 | --color-link-hover: var(--color-brand-hc-light); 35 | 36 | --color-card-bg: var(--color-gray-900); 37 | --color-card-border: var(--color-gray-700); 38 | --color-card-bg-hover: var(--color-gray-800); 39 | --color-card-icon: var(--color-gray-400); 40 | --color-card-icon-hover: var(--color-white); 41 | --color-card-text: var(--color-gray-400); 42 | --color-card-text-hover: var(---color-white); 43 | 44 | & h1, 45 | & h2, 46 | & h3, 47 | & h4, 48 | & h5, 49 | & h6, 50 | & .medium, 51 | & .large, 52 | & .xlarge, 53 | & a { 54 | color: var(--color-white); 55 | } 56 | 57 | & a { 58 | background-image: linear-gradient( 59 | var(--color-white-40), 60 | var(--color-white-40) 61 | ); 62 | } 63 | } 64 | 65 | .bg-info { 66 | background: var(--color-info); 67 | } 68 | 69 | .bg-none, 70 | .bg-none a, 71 | .bg-none a:link, 72 | .bg-none a:visited { 73 | background: none; 74 | } 75 | 76 | .text-light { 77 | color: var(--color-white); 78 | 79 | & h1, 80 | & h2, 81 | & h3, 82 | & h4, 83 | & h5, 84 | & h6, 85 | & .medium, 86 | & .large, 87 | & .xlarge { 88 | color: var(--color-white); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /addon/styles/central-content.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable media-feature-range-notation */ 2 | .content-wrapper { 3 | display: grid; 4 | gap: 3em; 5 | grid-template-columns: minmax(20ch, 80ch) 16em; 6 | padding-top: var(--spacing-4); 7 | padding-bottom: var(--spacing-4); 8 | justify-content: center; 9 | } 10 | 11 | @media (max-width: 80em) { 12 | .content-wrapper { 13 | display: grid; 14 | grid-template-columns: minmax(20ch, 80ch); 15 | justify-content: center; 16 | padding-bottom: var(--spacing-2); 17 | } 18 | 19 | .on-this-page-wrapper { 20 | display: none; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /addon/styles/components/es-banner.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable no-descending-specificity, prettier/prettier */ 2 | .es-banner { 3 | position: relative; 4 | display: flex; 5 | justify-content: center; 6 | align-items: center; 7 | background-color: var(--color-brand-hc-dark); 8 | padding: 8px 8px 10px; 9 | color: var(--color-white); 10 | } 11 | 12 | .es-banner a, .es-banner a:link, .es-banner a:visited { 13 | color: var(--color-white); 14 | text-decoration: none; 15 | border-bottom: 1px solid var(--color-white-40); 16 | background: none; 17 | font-size: 16px; 18 | line-height: 15px; 19 | } 20 | 21 | .es-banner a:hover, .es-banner a:focus { 22 | border-bottom: 1px solid var(--color-white); 23 | } 24 | 25 | .es-banner a + a { 26 | margin-left: 20px; 27 | position: relative; 28 | } 29 | 30 | .es-banner a + a::before { 31 | content: ''; 32 | width: 3px; 33 | height: 3px; 34 | background: var(--color-white); 35 | border-radius: 50%; 36 | top: 50%; 37 | transform: translateY(-50%) translateX(-50%); 38 | display: block; 39 | left: -10px; 40 | pointer-events: none; 41 | position: absolute; 42 | } 43 | -------------------------------------------------------------------------------- /addon/styles/components/es-button.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable declaration-block-no-redundant-longhand-properties, no-descending-specificity, prettier/prettier */ 2 | .es-button, 3 | a.es-button, 4 | a.es-button:link, 5 | a.es-button:visited, 6 | .es-button-secondary, 7 | a.es-button-secondary, 8 | a.es-button-secondary:link, 9 | a.es-button-secondary:visited { 10 | background-color: var(--color-button-bg); 11 | color: var(--color-button-text); 12 | padding-left: var(--spacing-3); 13 | padding-right: var(--spacing-3); 14 | padding-top: var(--spacing-1); 15 | padding-bottom: var(--spacing-1); 16 | border: 0; 17 | border-radius: var(--radius); 18 | font-size: var(--font-size-md); 19 | line-height: var(--line-height-md); 20 | transition: background-color 0.2s, color 0.1s; 21 | box-shadow: 0 0 2px -1px var(--color-gray-800), 0 2px 9px -5px var(--color-gray-800); 22 | } 23 | 24 | .es-button:focus, 25 | a.es-button:focus, 26 | .es-button-secondary:focus, 27 | a.es-button-secondary:focus { 28 | box-shadow: var(--focus), 0 0 2px -1px var(--color-gray-800), 0 2px 8px -4px var(--color-gray-800); 29 | } 30 | 31 | .es-button:hover, 32 | .es-button:active, 33 | a.es-button:hover, 34 | a.es-button:active { 35 | background: var(--color-button-bg-hover); 36 | } 37 | 38 | a.es-button, 39 | a.es-button-secondary { 40 | display: inline-block; 41 | text-decoration: none; 42 | } 43 | 44 | .es-button-secondary, 45 | a.es-button-secondary, 46 | a.es-button-secondary:link, 47 | a.es-button-secondary:visited { 48 | background: var(--color-button-secondary-bg); 49 | color: var(--color-button-secondary-text); 50 | } 51 | 52 | .es-button-secondary:hover, 53 | .es-button-secondary:active, 54 | a.es-button-secondary:hover, 55 | a.es-button-secondary:active { 56 | background: var(--color-button-secondary-bg-hover); 57 | color: var(--color-button-secondary-text-hover); 58 | } 59 | -------------------------------------------------------------------------------- /addon/styles/components/es-card.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable declaration-block-no-redundant-longhand-properties, prettier/prettier, selector-class-pattern */ 2 | .card { 3 | align-items: flex-start; 4 | border: 2px solid var(--color-card-border); 5 | border-radius: var(--radius-lg); 6 | height: 100%; 7 | overflow: hidden; 8 | position: relative; 9 | background: var(--color-card-bg); 10 | color: var(--color-card-text); 11 | } 12 | 13 | .card__image { 14 | display: block; 15 | max-width: 100%; 16 | max-height: auto; 17 | border-bottom: 2px solid var(--color-card-border); 18 | } 19 | 20 | .card__icon { 21 | display: block; 22 | margin: var(--spacing-3) auto 0; 23 | width: 64px; 24 | height: auto; 25 | flex: 0 0 auto; 26 | color: var(--color-card-icon); 27 | } 28 | 29 | .card__content { 30 | flex: 1 1 100%; 31 | padding: var(--spacing-3); 32 | } 33 | 34 | .card[full-image] .card__image { 35 | max-width: 100%; 36 | max-height: inherit; 37 | margin: 0; 38 | } 39 | 40 | .card--link { 41 | display: flex; 42 | flex-flow: row nowrap; 43 | } 44 | 45 | .card--link:focus-within, 46 | .card--link:hover { 47 | background-color: var(--color-card-bg-hover); 48 | border-color: var(--color-card-bg-hover); 49 | color: var(--color-card-text-hover); 50 | } 51 | 52 | .card--link a::after { 53 | position: absolute; 54 | top: 0; 55 | left: 0; 56 | right: 0; 57 | bottom: 0; 58 | content: ''; 59 | } 60 | 61 | .card--link .card__icon { 62 | margin: var(--spacing-3) 0 var(--spacing-3) var(--spacing-3); 63 | } 64 | 65 | .card--link:focus-within .card__icon, 66 | .card--link:hover .card__icon { 67 | color: var(--color-card-icon-hover); 68 | } 69 | -------------------------------------------------------------------------------- /addon/styles/components/es-footer.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable media-feature-range-notation, no-descending-specificity */ 2 | 3 | /* .es-footer.container { 4 | padding: 0; 5 | } */ 6 | 7 | .es-footer { 8 | background-color: var(--color-white); 9 | 10 | & a, 11 | &:link, 12 | &:visited { 13 | text-decoration: none; 14 | color: var(--color-gray-600); 15 | background-image: none; 16 | } 17 | 18 | & a:focus, 19 | & a:hover { 20 | text-decoration: underline; 21 | color: var(--color-brand); 22 | } 23 | 24 | & .footer-info { 25 | padding-bottom: var(--spacing-5); 26 | padding-top: var(--spacing-5); 27 | display: flex; 28 | justify-content: space-between; 29 | 30 | & .spacer { 31 | grid-row: 2 / 4; 32 | } 33 | 34 | & .info-link { 35 | margin-top: auto; 36 | margin-bottom: auto; 37 | line-height: 40px; 38 | } 39 | } 40 | 41 | & .footer-info-links { 42 | display: grid; 43 | grid-gap: 0.5rem; 44 | grid-template-columns: repeat(3, 1fr); 45 | } 46 | 47 | & .footer-social { 48 | display: grid; 49 | grid-gap: 0.5rem; 50 | 51 | & a { 52 | align-items: center; 53 | display: flex; 54 | } 55 | 56 | & svg { 57 | fill: var(--color-gray-600); 58 | margin-right: var(--spacing-1); 59 | width: 1rem; 60 | } 61 | } 62 | 63 | & .footer-statement { 64 | justify-content: space-between; 65 | } 66 | 67 | & .footer-copyright { 68 | color: var(--color-gray-600); 69 | 70 | & svg { 71 | fill: var(--color-gray-600); 72 | width: 1rem; 73 | } 74 | } 75 | 76 | & .footer-spacer { 77 | border: 0; 78 | display: block; 79 | height: 2px; 80 | } 81 | 82 | & .footer-contributions { 83 | align-items: center; 84 | color: var(--color-gray-600); 85 | display: flex; 86 | justify-content: space-between; 87 | 88 | & .sponsor-icons { 89 | margin-top: var(--spacing-1); 90 | } 91 | } 92 | 93 | & .footer-contributor-logo, 94 | & .footer-contributor-logo-link { 95 | height: 1.6875rem; 96 | line-height: 1.6875rem; 97 | max-width: 4rem; 98 | } 99 | 100 | @media (max-width: 1007px) { 101 | & .footer-info { 102 | padding-bottom: var(--spacing-3); 103 | padding-top: var(--spacing-3); 104 | flex-direction: column; 105 | 106 | & .footer-logo { 107 | width: 5rem; 108 | } 109 | } 110 | 111 | & .footer-info-links { 112 | display: block; 113 | flex-wrap: wrap; 114 | 115 | & > a { 116 | margin-right: var(--spacing-2); 117 | } 118 | } 119 | 120 | & .footer-contributions { 121 | align-items: start; 122 | flex-direction: column; 123 | 124 | & .sponsor-icons { 125 | margin-top: var(--spacing-2); 126 | } 127 | } 128 | } 129 | } 130 | 131 | footer.es-footer { 132 | & a, 133 | &:link, 134 | &:visited { 135 | color: var(--color-gray-600); 136 | background-image: none; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /addon/styles/components/es-note.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable length-zero-no-unit, prettier/prettier, selector-pseudo-element-colon-notation */ 2 | .cta { 3 | background-color: var(--color-yellow-light); 4 | border-radius: var(--radius-lg); 5 | margin: var(--spacing-1) auto; 6 | max-width: 90%; 7 | position: relative; 8 | overflow: hidden; 9 | } 10 | 11 | .cta .cta-note { 12 | display: flex; 13 | justify-content: space-between; 14 | } 15 | 16 | .cta-note .cta-note-body { 17 | padding: var(--spacing-2); 18 | padding-left: var(--spacing-4); 19 | padding-top: var(--spacing-4); 20 | } 21 | 22 | .cta-note .cta-note-heading { 23 | font-size: var(--font-size-lg); 24 | font-weight: var(--font-weight-3); 25 | line-height: var(--line-height-lg); 26 | margin-bottom: var(--spacing-1); 27 | } 28 | 29 | .cta-note img { 30 | margin: var(--spacing-2); 31 | transform: rotate(15deg); 32 | object-fit: contain; 33 | } 34 | 35 | .cta:before { 36 | content: ""; 37 | position: absolute; 38 | top: 0; 39 | left: 0; 40 | width: 0px; 41 | height: 0px; 42 | border-radius: 0 0 var(--radius-lg) 0; 43 | border-width: 16px; 44 | border-color: var(--color-gray-100) var(--color-yellow) var(--color-yellow) var(--color-gray-100); 45 | border-style: solid; 46 | } 47 | 48 | @media only percy { 49 | .cta-note .cta-note-heading, 50 | .cta-note img { 51 | visibility: hidden; 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /addon/styles/components/es-pagination.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable declaration-block-no-redundant-longhand-properties, length-zero-no-unit, no-descending-specificity, prettier/prettier, rule-empty-line-before */ 2 | .pagination-wrapper { 3 | width: 100%; 4 | display: grid; 5 | grid-template-columns: 1fr 1fr; 6 | grid-template-rows: 1fr; 7 | gap: 0px 40px; 8 | grid-template-areas: 9 | "previous next"; 10 | margin: var(--spacing-1) 0; 11 | & > .previous-wrapper{ 12 | grid-area: previous; 13 | & > img { 14 | transform: rotate(90deg); 15 | } 16 | &:hover > img { 17 | transform: rotate(90deg) translateY(0.5em); 18 | } 19 | } 20 | 21 | & > .next-wrapper { 22 | grid-area: next; 23 | justify-content: end; 24 | text-align: right; 25 | & > img { 26 | transform: rotate(270deg); 27 | } 28 | 29 | &:hover > img { 30 | transform: rotate(270deg) translateY(0.5em); 31 | } 32 | } 33 | 34 | & > .previous-wrapper, & > .next-wrapper { 35 | display: flex; 36 | align-items: center; 37 | & > img { 38 | margin: 0 0.5em; 39 | transition: transform 0.3s; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /addon/styles/components/es-progress-bar.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable alpha-value-notation, color-function-notation */ 2 | .progress-bar { 3 | position: fixed; 4 | left: 0; 5 | top: 0; 6 | height: 3px; 7 | box-shadow: 0 0 10px rgba(0, 13, 41, 0.6); 8 | background: var(--color-brand) !important; 9 | } 10 | -------------------------------------------------------------------------------- /addon/styles/components/es-sidebar.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable alpha-value-notation, color-function-notation, color-hex-length, declaration-empty-line-before, prettier/prettier, rule-empty-line-before, selector-attribute-quotes, selector-class-pattern, value-keyword-case */ 2 | :root { 3 | --es-sidebar-padding: 1rem; 4 | --es-sidebar-shadow: 0 0 1px 0 rgba(73, 79, 95, 0.6), 0 2px 10px -5px rgba(73, 79, 95, 0.55), 0 3px 30px -15px rgba(73, 79, 95, 0.8), 0 0 50px -5px rgba(73, 79, 95, 0.5); 5 | --es-sidebar-transition-duration: .3s; 6 | } 7 | 8 | .es-sidebar-toggle, 9 | .es-sidebar-close { 10 | display: none; 11 | } 12 | 13 | .es-sidebar--border-right { 14 | border-right: 2px solid var(--color-gray-300); 15 | } 16 | 17 | .es-sidebar { 18 | background-color: var(--color-gray-200); 19 | } 20 | 21 | @media (width <= 844px) { 22 | .es-sidebar-toggle { 23 | position: fixed; 24 | z-index: 1; 25 | bottom: 30px; 26 | right: 30px; 27 | 28 | display: flex; 29 | justify-content: center; 30 | align-items: center; 31 | height: 60px; 32 | width: 60px; 33 | padding: 0; 34 | 35 | border-radius: 30px; 36 | box-shadow: var(--es-sidebar-shadow); 37 | } 38 | 39 | @keyframes es-sidebar-in { 40 | 0% { 41 | display: block; 42 | opacity: 0; 43 | transform: scale(0.01); 44 | } 45 | 100% { 46 | display: block; 47 | opacity: 1; 48 | transform: scale(1); 49 | } 50 | } 51 | 52 | .es-sidebar { 53 | box-sizing: border-box; 54 | display: none; 55 | position: fixed; 56 | z-index: 1; 57 | top: var(--es-sidebar-padding); 58 | left: var(--es-sidebar-padding); 59 | height: calc(100% - var(--es-sidebar-padding) * 2); 60 | width: calc(100vw - var(--es-sidebar-padding) * 2); 61 | overflow-y: auto; 62 | 63 | padding: 1rem; 64 | background: #FFF; 65 | border-radius: var(--radius); 66 | box-shadow: none; 67 | 68 | transform-origin: bottom right; 69 | transition: box-shadow var(--es-sidebar-transition-duration); 70 | } 71 | 72 | .es-sidebar[aria-expanded=true] { 73 | display: block; 74 | animation: var(--es-sidebar-transition-duration) es-sidebar-in ease-out forwards; 75 | box-shadow: var(--es-sidebar-shadow); 76 | } 77 | 78 | .es-sidebar-content { 79 | margin-top: var(--spacing-5); 80 | } 81 | 82 | .es-sidebar-close { 83 | display: inline-flex; 84 | float: right; 85 | position: sticky; 86 | top: 0; 87 | z-index: 1; 88 | padding: var(--spacing-1); 89 | background: #FFF; 90 | } 91 | 92 | .es-sidebar-close svg path { 93 | fill: currentColor; 94 | } 95 | 96 | .es-sidebar--border-right { 97 | border-right: none; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /addon/styles/container.css: -------------------------------------------------------------------------------- 1 | .container { 2 | max-width: var(--container-width); 3 | margin-left: auto; 4 | margin-right: auto; 5 | padding: var(--spacing-6) var(--grid-margin); 6 | box-sizing: content-box; 7 | } 8 | -------------------------------------------------------------------------------- /addon/styles/flex.css: -------------------------------------------------------------------------------- 1 | .flex-row { 2 | display: flex; 3 | align-items: center; 4 | flex-direction: row; 5 | } 6 | 7 | .justify-content-between { 8 | justify-content: space-between; 9 | } 10 | -------------------------------------------------------------------------------- /addon/styles/grid.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable media-feature-range-notation, selector-class-pattern */ 2 | 3 | /** 4 | * A grid is an equally spaced matrix of items of a common type. 5 | * e.q. a bunch of logos, mascots, cards, etc. 6 | */ 7 | .grid { 8 | --column-count: 1; 9 | 10 | display: grid; 11 | grid-template-columns: repeat(var(--column-count), 1fr); 12 | grid-gap: var(--grid-gap-md); 13 | } 14 | 15 | .grid > * { 16 | grid-column: span 1; 17 | align-items: stretch; 18 | } 19 | 20 | @media (max-width: 1007px) { 21 | .sm\:grid-2 { 22 | --column-count: 2; 23 | } 24 | 25 | .sm\:grid-3 { 26 | --column-count: 3; 27 | } 28 | 29 | .sm\:grid-4 { 30 | --column-count: 4; 31 | } 32 | } 33 | 34 | @media (min-width: 1008px) { 35 | .lg\:grid-2 { 36 | --column-count: 2; 37 | } 38 | 39 | .lg\:grid-3 { 40 | --column-count: 3; 41 | } 42 | 43 | .lg\:grid-4 { 44 | --column-count: 4; 45 | } 46 | 47 | .lg\:grid-5 { 48 | --column-count: 5; 49 | 50 | grid-gap: var(--grid-gap-sm); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /addon/styles/header-anchor.css: -------------------------------------------------------------------------------- 1 | h1 > a, 2 | h2 > a, 3 | h3 > a, 4 | h4 > a, 5 | h5 > a, 6 | h6 > a { 7 | margin-left: 12px; 8 | vertical-align: middle; 9 | } 10 | 11 | main h1 > a:link, 12 | main h2 > a:link, 13 | main h3 > a:link, 14 | main h4 > a:link, 15 | main h5 > a:link, 16 | main h6 > a:link { 17 | background: none; 18 | } 19 | 20 | h1 > a > svg, 21 | h2 > a > svg, 22 | h3 > a > svg, 23 | h4 > a > svg, 24 | h5 > a > svg, 25 | h6 > a > svg { 26 | height: 18px; 27 | fill: var(--color-gray-600); 28 | transform: rotate(45deg); 29 | } 30 | 31 | h1 > a:hover > svg, 32 | h2 > a:hover > svg, 33 | h3 > a:hover > svg, 34 | h4 > a:hover > svg, 35 | h5 > a:hover > svg, 36 | h6 > a:hover > svg { 37 | fill: var(--color-brand); 38 | } 39 | -------------------------------------------------------------------------------- /addon/styles/helpers/embed.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Wrap YouTube and other iFrame based video embeds into this class. 3 | * 4 | * ```html 5 | *
    6 | * 7 | * 15 | * 16 | *
    17 | * ``` 18 | */ 19 | .embed-video { 20 | position: relative; 21 | height: 0; 22 | padding: 0 0 56.25%; /* 16:9 */ 23 | } 24 | 25 | .embed-video > iframe { 26 | position: absolute; 27 | top: 0; 28 | left: 0; 29 | width: 100%; 30 | height: 100%; 31 | } 32 | -------------------------------------------------------------------------------- /addon/styles/helpers/flex.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable prettier/prettier */ 2 | 3 | /* Flex boxes */ 4 | 5 | .flex-horizontal-between { 6 | display: flex; 7 | justify-content: space-between; 8 | } 9 | 10 | .flex-responsive{ 11 | display: flex; 12 | flex-wrap: wrap; 13 | gap: var(--spacing-1); 14 | } 15 | 16 | .flex-centered { 17 | display: flex; 18 | justify-content: center; 19 | align-items: center; 20 | } 21 | -------------------------------------------------------------------------------- /addon/styles/helpers/index.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable import-notation, media-feature-range-notation, prettier/prettier */ 2 | @import './unstyled.css'; 3 | @import './embed.css'; 4 | @import './flex.css'; 5 | @import './margin.css'; 6 | @import './padding.css'; 7 | @import './rounded.css'; 8 | 9 | .img-fluid { 10 | width: 100%; 11 | } 12 | 13 | .max-width { 14 | max-width: 100%; 15 | } 16 | 17 | @media (max-width: 1007px) { 18 | .hide-on-mobile { 19 | display: none !important; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /addon/styles/helpers/margin.css: -------------------------------------------------------------------------------- 1 | /* Margin helpers. Class names are intentionally short to discern them from "proper" class names */ 2 | 3 | .m-0 { 4 | margin: 0; 5 | } 6 | 7 | .m-1 { 8 | margin: var(--spacing-1); 9 | } 10 | 11 | .m-2 { 12 | margin: var(--spacing-2); 13 | } 14 | 15 | .m-3 { 16 | margin: var(--spacing-3); 17 | } 18 | 19 | .m-4 { 20 | margin: var(--spacing-4); 21 | } 22 | 23 | .m-5 { 24 | margin: var(--spacing-5); 25 | } 26 | 27 | .m-6 { 28 | margin: var(--spacing-6); 29 | } 30 | 31 | .mx-0 { 32 | margin-right: 0; 33 | margin-left: 0; 34 | } 35 | 36 | .mx-1 { 37 | margin-right: var(--spacing-1); 38 | margin-left: var(--spacing-1); 39 | } 40 | 41 | .mx-2 { 42 | margin-right: var(--spacing-2); 43 | margin-left: var(--spacing-2); 44 | } 45 | 46 | .mx-3 { 47 | margin-right: var(--spacing-3); 48 | margin-left: var(--spacing-3); 49 | } 50 | 51 | .mx-4 { 52 | margin-right: var(--spacing-4); 53 | margin-left: var(--spacing-4); 54 | } 55 | 56 | .mx-5 { 57 | margin-right: var(--spacing-5); 58 | margin-left: var(--spacing-5); 59 | } 60 | 61 | .mx-6 { 62 | margin-right: var(--spacing-6); 63 | margin-left: var(--spacing-6); 64 | } 65 | 66 | .my-0 { 67 | margin-top: 0; 68 | margin-bottom: 0; 69 | } 70 | 71 | .my-1 { 72 | margin-top: var(--spacing-1); 73 | margin-bottom: var(--spacing-1); 74 | } 75 | 76 | .my-2 { 77 | margin-top: var(--spacing-2); 78 | margin-bottom: var(--spacing-2); 79 | } 80 | 81 | .my-3 { 82 | margin-top: var(--spacing-3); 83 | margin-bottom: var(--spacing-3); 84 | } 85 | 86 | .my-4 { 87 | margin-top: var(--spacing-4); 88 | margin-bottom: var(--spacing-4); 89 | } 90 | 91 | .my-5 { 92 | margin-top: var(--spacing-5); 93 | margin-bottom: var(--spacing-5); 94 | } 95 | 96 | .my-6 { 97 | margin-top: var(--spacing-6); 98 | margin-bottom: var(--spacing-6); 99 | } 100 | 101 | .mt-0 { 102 | margin-top: 0; 103 | } 104 | 105 | .mt-1 { 106 | margin-top: var(--spacing-1); 107 | } 108 | 109 | .mt-2 { 110 | margin-top: var(--spacing-2); 111 | } 112 | 113 | .mt-3 { 114 | margin-top: var(--spacing-3); 115 | } 116 | 117 | .mt-4 { 118 | margin-top: var(--spacing-4); 119 | } 120 | 121 | .mt-5 { 122 | margin-top: var(--spacing-5); 123 | } 124 | 125 | .mt-6 { 126 | margin-top: var(--spacing-6); 127 | } 128 | 129 | .mr-0 { 130 | margin-right: 0; 131 | } 132 | 133 | .mr-1 { 134 | margin-right: var(--spacing-1); 135 | } 136 | 137 | .mr-2 { 138 | margin-right: var(--spacing-2); 139 | } 140 | 141 | .mr-3 { 142 | margin-right: var(--spacing-3); 143 | } 144 | 145 | .mr-4 { 146 | margin-right: var(--spacing-4); 147 | } 148 | 149 | .mr-5 { 150 | margin-right: var(--spacing-5); 151 | } 152 | 153 | .mr-6 { 154 | margin-right: var(--spacing-6); 155 | } 156 | 157 | .mb-0 { 158 | margin-bottom: 0; 159 | } 160 | 161 | .mb-1 { 162 | margin-bottom: var(--spacing-1); 163 | } 164 | 165 | .mb-2 { 166 | margin-bottom: var(--spacing-2); 167 | } 168 | 169 | .mb-3 { 170 | margin-bottom: var(--spacing-3); 171 | } 172 | 173 | .mb-4 { 174 | margin-bottom: var(--spacing-4); 175 | } 176 | 177 | .mb-5 { 178 | margin-bottom: var(--spacing-5); 179 | } 180 | 181 | .mb-6 { 182 | margin-bottom: var(--spacing-6); 183 | } 184 | 185 | .ml-0 { 186 | margin-left: 0; 187 | } 188 | 189 | .ml-1 { 190 | margin-left: var(--spacing-1); 191 | } 192 | 193 | .ml-2 { 194 | margin-left: var(--spacing-2); 195 | } 196 | 197 | .ml-3 { 198 | margin-left: var(--spacing-3); 199 | } 200 | 201 | .ml-4 { 202 | margin-left: var(--spacing-4); 203 | } 204 | 205 | .ml-5 { 206 | margin-left: var(--spacing-5); 207 | } 208 | 209 | .ml-6 { 210 | margin-left: var(--spacing-6); 211 | } 212 | -------------------------------------------------------------------------------- /addon/styles/helpers/padding.css: -------------------------------------------------------------------------------- 1 | .p-0 { 2 | padding: 0; 3 | } 4 | 5 | .p-1 { 6 | padding: var(--spacing-1); 7 | } 8 | 9 | .p-2 { 10 | padding: var(--spacing-2); 11 | } 12 | 13 | .p-3 { 14 | padding: var(--spacing-3); 15 | } 16 | 17 | .p-4 { 18 | padding: var(--spacing-4); 19 | } 20 | 21 | .p-5 { 22 | padding: var(--spacing-5); 23 | } 24 | 25 | .p-6 { 26 | padding: var(--spacing-6); 27 | } 28 | 29 | .px-0 { 30 | padding-right: 0; 31 | padding-left: 0; 32 | } 33 | 34 | .px-1 { 35 | padding-right: var(--spacing-1); 36 | padding-left: var(--spacing-1); 37 | } 38 | 39 | .px-2 { 40 | padding-right: var(--spacing-2); 41 | padding-left: var(--spacing-2); 42 | } 43 | 44 | .px-3 { 45 | padding-right: var(--spacing-3); 46 | padding-left: var(--spacing-3); 47 | } 48 | 49 | .px-4 { 50 | padding-right: var(--spacing-4); 51 | padding-left: var(--spacing-4); 52 | } 53 | 54 | .px-5 { 55 | padding-right: var(--spacing-5); 56 | padding-left: var(--spacing-5); 57 | } 58 | 59 | .px-6 { 60 | padding-right: var(--spacing-6); 61 | padding-left: var(--spacing-6); 62 | } 63 | 64 | .py-0 { 65 | padding-top: 0; 66 | padding-bottom: 0; 67 | } 68 | 69 | .py-1 { 70 | padding-top: var(--spacing-1); 71 | padding-bottom: var(--spacing-1); 72 | } 73 | 74 | .py-2 { 75 | padding-top: var(--spacing-2); 76 | padding-bottom: var(--spacing-2); 77 | } 78 | 79 | .py-3 { 80 | padding-top: var(--spacing-3); 81 | padding-bottom: var(--spacing-3); 82 | } 83 | 84 | .py-4 { 85 | padding-top: var(--spacing-4); 86 | padding-bottom: var(--spacing-4); 87 | } 88 | 89 | .py-5 { 90 | padding-top: var(--spacing-5); 91 | padding-bottom: var(--spacing-5); 92 | } 93 | 94 | .py-6 { 95 | padding-top: var(--spacing-6); 96 | padding-bottom: var(--spacing-6); 97 | } 98 | 99 | .pt-0 { 100 | padding-top: 0; 101 | } 102 | 103 | .pt-1 { 104 | padding-top: var(--spacing-1); 105 | } 106 | 107 | .pt-2 { 108 | padding-top: var(--spacing-2); 109 | } 110 | 111 | .pt-3 { 112 | padding-top: var(--spacing-3); 113 | } 114 | 115 | .pt-4 { 116 | padding-top: var(--spacing-4); 117 | } 118 | 119 | .pt-5 { 120 | padding-top: var(--spacing-5); 121 | } 122 | 123 | .pt-6 { 124 | padding-top: var(--spacing-6); 125 | } 126 | 127 | .pr-0 { 128 | padding-right: 0; 129 | } 130 | 131 | .pr-1 { 132 | padding-right: var(--spacing-1); 133 | } 134 | 135 | .pr-2 { 136 | padding-right: var(--spacing-2); 137 | } 138 | 139 | .pr-3 { 140 | padding-right: var(--spacing-3); 141 | } 142 | 143 | .pr-4 { 144 | padding-right: var(--spacing-4); 145 | } 146 | 147 | .pr-5 { 148 | padding-right: var(--spacing-5); 149 | } 150 | 151 | .pr-6 { 152 | padding-right: var(--spacing-6); 153 | } 154 | 155 | .pb-0 { 156 | padding-bottom: 0; 157 | } 158 | 159 | .pb-1 { 160 | padding-bottom: var(--spacing-1); 161 | } 162 | 163 | .pb-2 { 164 | padding-bottom: var(--spacing-2); 165 | } 166 | 167 | .pb-3 { 168 | padding-bottom: var(--spacing-3); 169 | } 170 | 171 | .pb-4 { 172 | padding-bottom: var(--spacing-4); 173 | } 174 | 175 | .pb-5 { 176 | padding-bottom: var(--spacing-5); 177 | } 178 | 179 | .pb-6 { 180 | padding-bottom: var(--spacing-6); 181 | } 182 | 183 | .pl-0 { 184 | padding-left: 0; 185 | } 186 | 187 | .pl-1 { 188 | padding-left: var(--spacing-1); 189 | } 190 | 191 | .pl-2 { 192 | padding-left: var(--spacing-2); 193 | } 194 | 195 | .pl-3 { 196 | padding-left: var(--spacing-3); 197 | } 198 | 199 | .pl-4 { 200 | padding-left: var(--spacing-4); 201 | } 202 | 203 | .pl-5 { 204 | padding-left: var(--spacing-5); 205 | } 206 | 207 | .pl-6 { 208 | padding-left: var(--spacing-6); 209 | } 210 | -------------------------------------------------------------------------------- /addon/styles/helpers/rounded.css: -------------------------------------------------------------------------------- 1 | .rounded, 2 | .rounded-sm { 3 | border-radius: var(--radius); 4 | } 5 | 6 | .rounded-lg { 7 | border-radius: var(--radius-lg); 8 | } 9 | -------------------------------------------------------------------------------- /addon/styles/helpers/unstyled.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable prettier/prettier */ 2 | [class*='unstyled'], 3 | .list-unstyled { 4 | list-style: none; 5 | padding: 0; 6 | margin: 0; 7 | border: 0; 8 | } 9 | -------------------------------------------------------------------------------- /addon/styles/icon.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable prettier/prettier */ 2 | .icon-wrapper { 3 | display: inline-block; 4 | } 5 | 6 | .circle { 7 | border-radius: 50%; 8 | padding: 1em; 9 | } 10 | 11 | .icon { 12 | width: 1.5em; 13 | vertical-align: middle; 14 | } 15 | 16 | .icon-left { 17 | margin-right: 0.5em; 18 | } 19 | 20 | .icon-right { 21 | margin-left: 0.5em; 22 | } -------------------------------------------------------------------------------- /addon/styles/layout.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable media-feature-range-notation, selector-class-pattern */ 2 | 3 | /** 4 | * Layout provides a way to arrange children of different types 5 | * in a designed and meaningful way. 6 | * Each child that should not cover the full width needs 7 | * at least a class that specifies how many columns it will span and may 8 | * have an additional class that specifies the start column. 9 | * Columns can be reordered by specifying a start column for two elements, 10 | * making them start in switched places. 11 | * 12 | * The layout uses 6 columns on large and 4 columns on smaller screens. 13 | */ 14 | 15 | .layout { 16 | display: grid; 17 | grid-template-columns: repeat(4, 1fr); 18 | grid-gap: var(--grid-gap-md) var(--grid-gap-lg); 19 | grid-auto-flow: row dense; 20 | } 21 | 22 | @media (max-width: 1007px) { 23 | .layout > * { 24 | grid-column-end: span 4; 25 | } 26 | 27 | .layout .sm\:col-1 { 28 | grid-column-end: span 1; 29 | } 30 | 31 | .layout .sm\:col-2 { 32 | grid-column-end: span 2; 33 | } 34 | 35 | .layout .sm\:col-3 { 36 | grid-column-end: span 3; 37 | } 38 | 39 | .layout .sm\:col-4 { 40 | grid-column-end: span 4; 41 | } 42 | 43 | .layout .sm\:start-1 { 44 | grid-column-start: 1; 45 | } 46 | 47 | .layout .sm\:start-2 { 48 | grid-column-start: 2; 49 | } 50 | 51 | .layout .sm\:start-3 { 52 | grid-column-start: 3; 53 | } 54 | 55 | .layout .sm\:start-4 { 56 | grid-column-start: 4; 57 | } 58 | } 59 | 60 | @media (min-width: 1008px) { 61 | .layout { 62 | grid-template-columns: repeat(6, 1fr); 63 | } 64 | 65 | .layout > * { 66 | grid-column-end: span 6; 67 | } 68 | 69 | .layout .lg\:col-1 { 70 | grid-column-end: span 1; 71 | } 72 | 73 | .layout .lg\:col-2 { 74 | grid-column-end: span 2; 75 | } 76 | 77 | .layout .lg\:col-3 { 78 | grid-column-end: span 3; 79 | } 80 | 81 | .layout .lg\:col-4 { 82 | grid-column-end: span 4; 83 | } 84 | 85 | .layout .lg\:col-5 { 86 | grid-column-end: span 5; 87 | } 88 | 89 | .layout .lg\:col-6 { 90 | grid-column-end: span 5; 91 | } 92 | 93 | .layout .lg\:start-1 { 94 | grid-column-start: 1; 95 | } 96 | 97 | .layout .lg\:start-2 { 98 | grid-column-start: 2; 99 | } 100 | 101 | .layout .lg\:start-3 { 102 | grid-column-start: 3; 103 | } 104 | 105 | .layout .lg\:start-4 { 106 | grid-column-start: 4; 107 | } 108 | 109 | .layout .lg\:start-5 { 110 | grid-column-start: 5; 111 | } 112 | 113 | .layout .lg\:start-6 { 114 | grid-column-start: 6; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /addon/styles/on-this-page.css: -------------------------------------------------------------------------------- 1 | .on-this-page-wrapper ul { 2 | list-style: none; 3 | padding: 0; 4 | } 5 | 6 | .on-this-page-wrapper ul li { 7 | margin-bottom: var(--spacing-1); 8 | } 9 | 10 | .on-this-page-wrapper-header { 11 | color: var(--color-gray-600); 12 | margin-top: 0.6em; 13 | } 14 | 15 | .on-this-page-wrapper hr { 16 | margin-top: 0; 17 | display: none; 18 | } 19 | 20 | main .on-this-page-wrapper a { 21 | text-decoration: none; 22 | color: var(--color-text); 23 | background: none; 24 | } 25 | -------------------------------------------------------------------------------- /addon/styles/sidebar-container.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable media-feature-range-notation, prettier/prettier, selector-class-pattern, selector-not-notation */ 2 | :root { 3 | --sidebar-width: 21rem; 4 | } 5 | 6 | .sidebar-container { 7 | display: grid; 8 | grid-gap: 2rem; 9 | grid-template-columns: var(--sidebar-width) minmax(0, 1fr) var(--sidebar-width); 10 | margin: auto; 11 | max-width: var(--container-width); 12 | padding: var(--spacing-6) var(--grid-margin); 13 | } 14 | 15 | .sidebar-container > *:not(.es-sidebar-toggle) { 16 | padding: var(--spacing-4) var(--spacing-2); 17 | } 18 | 19 | .sidebar-container > *:not(.es-sidebar):not(.es-sidebar-toggle) { 20 | grid-column: 1 / span 2; 21 | } 22 | 23 | .sidebar-container > .es-sidebar + .es-sidebar-toggle + * { 24 | grid-column: 2 / span 2; 25 | } 26 | 27 | .sidebar-container--full-width { 28 | max-width: 100%; 29 | padding: 0; 30 | } 31 | 32 | @media (max-width: 844px) { 33 | .sidebar-container { 34 | display: block; 35 | padding: var(--spacing-4) var(--grid-margin); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /addon/styles/table-of-contents.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable media-feature-range-notation */ 2 | .table-of-contents { 3 | list-style-type: none; 4 | padding-left: 0; 5 | font-size: var(--font-size-base); 6 | font-weight: var(--font-weight-3); 7 | } 8 | 9 | .sub-table-of-contents { 10 | padding-left: var(--spacing-1); 11 | font-size: var(--font-size-base); 12 | font-weight: var(--font-weight-2); 13 | } 14 | 15 | .sub-table-of-contents .sub-table-of-contents { 16 | padding-left: var(--spacing-3); 17 | margin-bottom: 0; 18 | } 19 | 20 | .table-of-contents li.toc-heading { 21 | margin-top: var(--spacing-4); 22 | color: var(--color-gray-600); 23 | } 24 | 25 | .table-of-contents li.toc-heading:first-child { 26 | margin-top: 0; 27 | } 28 | 29 | .table-of-contents li { 30 | margin: 3px 0; 31 | list-style-type: none; 32 | } 33 | 34 | .table-of-contents a:link { 35 | background: none; 36 | } 37 | 38 | .sub-table-of-contents .toc-item a { 39 | display: block; 40 | padding: var(--spacing-1); 41 | border-radius: var(--radius); 42 | line-height: var(--line-height-xs); 43 | color: var(--color-gray-700); 44 | border-left: 0 solid transparent; 45 | transition: border-width 0.3s; 46 | } 47 | 48 | .sub-table-of-contents .toc-item a:hover { 49 | border-left: 4px solid var(--color-gray-400); 50 | border-radius: 0; 51 | } 52 | 53 | .sub-table-of-contents .toc-item.selected > a, 54 | .sub-table-of-contents .toc-item > a.active { 55 | border-left: 4px solid var(--color-brand-hc-dark); 56 | border-radius: 0; 57 | } 58 | 59 | @media (max-width: 844px) { 60 | .table-of-contents { 61 | font-size: var(--font-size-lg); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /addon/styles/typography.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable prettier/prettier */ 2 | @font-face { 3 | font-family: "Inter web"; 4 | font-style: normal; 5 | font-weight: 400; 6 | font-display: swap; 7 | src: url("/fonts/Inter-Regular.woff2?v=3.15") format("woff2"), 8 | url("/fonts/Inter-Regular.woff?v=3.15") format("woff"); 9 | } 10 | 11 | @font-face { 12 | font-family: "Inter web"; 13 | font-style: normal; 14 | font-weight: 600; 15 | font-display: swap; 16 | src: url("/fonts/Inter-SemiBold.woff2?v=3.15") format("woff2"), 17 | url("/fonts/Inter-SemiBold.woff?v=3.15") format("woff"); 18 | } 19 | 20 | @font-face { 21 | font-family: "Inter web"; 22 | font-style: normal; 23 | font-weight: 200; 24 | font-display: swap; 25 | src: url("/fonts/Inter-ExtraLight.woff2?v=3.15") format("woff2"), 26 | url("/fonts/Inter-ExtraLight.woff?v=3.15") format("woff"); 27 | } 28 | 29 | @font-face { 30 | font-family: "Inter web italic"; 31 | font-style: italic; 32 | font-weight: 400; 33 | font-display: swap; 34 | src: url("/fonts/Inter-Italic.woff2?v=3.15") format("woff2"), 35 | url("/fonts/Inter-Italic.woff?v=3.15") format("woff"); 36 | } 37 | 38 | @font-face { 39 | font-family: "Inter web italic"; 40 | font-style: italic; 41 | font-weight: 600; 42 | font-display: swap; 43 | src: url("/fonts/Inter-SemiBoldItalic.woff2?v=3.15") format("woff2"), 44 | url("/fonts/Inter-SemiBoldItalic.woff?v=3.15") format("woff"); 45 | } 46 | 47 | @font-face { 48 | font-family: "Inter var"; 49 | font-weight: 100 900; 50 | font-display: swap; 51 | font-style: normal; 52 | src: url("/fonts/Inter-roman.var.woff2?v=3.15") format("woff2"); 53 | } 54 | 55 | .sans { 56 | font-family: var(--font-family-sans); 57 | } 58 | 59 | .bold { 60 | font-weight: var(--font-weight-3); 61 | } 62 | 63 | .italic { 64 | font-style: italic; 65 | } 66 | 67 | p { 68 | margin: 0; 69 | } 70 | 71 | p + * { 72 | margin-top: var(--spacing-2); 73 | } 74 | 75 | .text-sm, 76 | small { 77 | font-size: var(--font-size-sm); 78 | line-height: var(--line-height-sm); 79 | } 80 | 81 | .text-base, 82 | p { 83 | font-size: var(--font-size-base); 84 | line-height: var(--line-height-base); 85 | } 86 | 87 | .text-md, 88 | h3 { 89 | font-size: var(--font-size-md); 90 | line-height: var(--line-height-md); 91 | font-weight: var(--font-weight-3); 92 | } 93 | 94 | .text-lg, 95 | h2 { 96 | font-size: var(--font-size-lg); 97 | line-height: var(--line-height-lg); 98 | font-weight: var(--font-weight-3); 99 | } 100 | 101 | .text-xl, 102 | h1 { 103 | font-size: var(--font-size-xl); 104 | line-height: var(--line-height-xl); 105 | font-weight: var(--font-weight-2); 106 | } 107 | 108 | .text-hero-xl { 109 | font-size: var(--font-size-hero-1); 110 | line-height: var(--line-height-hero-1); 111 | font-weight: var(--font-weight-1); 112 | } 113 | 114 | .text-hero-base { 115 | font-size: var(--font-size-hero-2); 116 | line-height: var(--line-height-hero-2); 117 | } 118 | 119 | h1 { 120 | margin-bottom: var(--spacing-2); 121 | } 122 | 123 | h2, 124 | h3, 125 | h4, 126 | h5 { 127 | margin-bottom: var(--spacing-1); 128 | } 129 | 130 | * + h1, 131 | * + h2, 132 | * + h3, 133 | * + h4, 134 | * + h5 { 135 | margin-top: var(--spacing-3); 136 | } 137 | 138 | .regular { 139 | font-weight: var(--font-weight-2); 140 | } 141 | 142 | .bold, 143 | strong { 144 | font-weight: var(--font-weight-3); 145 | } 146 | 147 | .text-center { 148 | text-align: center; 149 | } 150 | 151 | .text-left { 152 | text-align: left; 153 | } 154 | 155 | .text-right { 156 | text-align: right; 157 | } 158 | 159 | .text-light { 160 | color: var(--color-gray-100); 161 | } 162 | 163 | .text-muted { 164 | color: var(--color-gray-600); 165 | } 166 | 167 | /* Legacy, to be removed */ 168 | 169 | .xsmall { 170 | font-size: var(--font-size-sm); 171 | line-height: var(--line-height-sm); 172 | } 173 | 174 | .small { 175 | font-size: var(--font-size-base); 176 | line-height: var(--line-height-base); 177 | } 178 | 179 | .medium { 180 | font-size: var(--font-size-md); 181 | line-height: var(--line-height-md); 182 | font-weight: var(--font-weight-3); 183 | } 184 | 185 | .large { 186 | font-size: var(--font-size-lg); 187 | line-height: var(--line-height-lg); 188 | font-weight: var(--font-weight-3); 189 | } 190 | 191 | .xlarge { 192 | font-size: var(--font-size-xl); 193 | line-height: var(--line-height-xl); 194 | font-weight: var(--font-weight-2); 195 | } 196 | -------------------------------------------------------------------------------- /addon/styles/well.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable selector-class-pattern */ 2 | .well { 3 | display: flex; 4 | height: 100%; 5 | box-sizing: border-box; 6 | border-radius: var(--radius-lg); 7 | border: 2px solid var(--color-gray-200); 8 | overflow: hidden; 9 | } 10 | 11 | a.well:link, 12 | a.well:visited, 13 | .well { 14 | background: var(--color-white); 15 | } 16 | 17 | a.well:focus { 18 | border-color: var(--color-white); 19 | } 20 | 21 | a.well:hover { 22 | border-color: var(--color-gray-300); 23 | } 24 | 25 | .well img { 26 | display: block; 27 | margin: auto; 28 | } 29 | 30 | [class*="well-"] { 31 | position: relative; 32 | height: 0; 33 | } 34 | 35 | .well-1\/1 { 36 | height: 0; 37 | padding: 0 0 100%; 38 | } 39 | 40 | .well-4\/3 { 41 | height: 0; 42 | padding: 0 0 75%; 43 | } 44 | 45 | .well-16\/9 { 46 | height: 0; 47 | padding: 0 0 56.25%; 48 | } 49 | 50 | [class*="well-"] img { 51 | position: absolute; 52 | top: 50%; 53 | left: 50%; 54 | max-width: calc(100% - 2 * var(--spacing-3)); 55 | max-height: calc(100% - 2 * var(--spacing-3)); 56 | transform: translate(-50%, -50%); 57 | } 58 | -------------------------------------------------------------------------------- /app/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ember-learn/ember-styleguide/6d709151fcfb90896b41667cff9442db41edc541/app/.gitkeep -------------------------------------------------------------------------------- /app/components/es-banner.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-styleguide/components/es-banner'; 2 | -------------------------------------------------------------------------------- /app/components/es-button.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | export { default } from 'ember-styleguide/components/es-button'; -------------------------------------------------------------------------------- /app/components/es-card-content.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | export { default } from 'ember-styleguide/components/es-card-content'; -------------------------------------------------------------------------------- /app/components/es-card.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | export { default } from 'ember-styleguide/components/es-card'; -------------------------------------------------------------------------------- /app/components/es-footer-contributions.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-styleguide/components/es-footer-contributions'; 2 | -------------------------------------------------------------------------------- /app/components/es-footer-help.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-styleguide/components/es-footer-help'; 2 | -------------------------------------------------------------------------------- /app/components/es-footer-info.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-styleguide/components/es-footer-info'; 2 | -------------------------------------------------------------------------------- /app/components/es-footer-statement.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-styleguide/components/es-footer-statement'; 2 | -------------------------------------------------------------------------------- /app/components/es-footer.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | export { default } from 'ember-styleguide/components/es-footer'; -------------------------------------------------------------------------------- /app/components/es-header-navbar-link.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-styleguide/components/es-header-navbar-link'; 2 | -------------------------------------------------------------------------------- /app/components/es-header.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | export { default } from 'ember-styleguide/components/es-header'; -------------------------------------------------------------------------------- /app/components/es-icon.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-styleguide/components/es-icon'; 2 | -------------------------------------------------------------------------------- /app/components/es-link-card.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | export { default } from 'ember-styleguide/components/es-link-card'; -------------------------------------------------------------------------------- /app/components/es-note.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | export { default } from 'ember-styleguide/components/es-note'; -------------------------------------------------------------------------------- /app/components/es-pagination.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-styleguide/components/es-pagination'; 2 | -------------------------------------------------------------------------------- /app/components/es-progress-bar.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-styleguide/components/es-progress-bar'; 2 | -------------------------------------------------------------------------------- /app/components/es-sidebar.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-styleguide/components/es-sidebar'; 2 | -------------------------------------------------------------------------------- /app/services/navbar.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-styleguide/services/navbar'; 2 | -------------------------------------------------------------------------------- /app/services/progress.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-styleguide/services/progress'; 2 | -------------------------------------------------------------------------------- /config/fastboot.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | module.exports = function () { 3 | return { 4 | buildSandboxGlobals(defaultGlobals) { 5 | return Object.assign({}, defaultGlobals, { 6 | atob: atob, 7 | fetch, 8 | AbortController, 9 | ReadableStream: 10 | typeof ReadableStream !== 'undefined' 11 | ? ReadableStream 12 | : require('node:stream/web').ReadableStream, 13 | WritableStream: 14 | typeof WritableStream !== 'undefined' 15 | ? WritableStream 16 | : require('node:stream/web').WritableStream, 17 | TransformStream: 18 | typeof TransformStream !== 'undefined' 19 | ? TransformStream 20 | : require('node:stream/web').TransformStream, 21 | Headers: typeof Headers !== 'undefined' ? Headers : undefined, 22 | }); 23 | }, 24 | }; 25 | }; 26 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function (/* environment */) { 2 | return { 3 | 'field-guide': { 4 | name: 'Ember', 5 | tagLine: 'Ember Styleguide', 6 | logo: '/ember-logo.png', 7 | copyright: 8 | 'Ember Field Guide is designed to document the [ember-styleguide](https://github.com/ember-learn/ember-styleguide) project. For more information view the [README](https://github.com/ember-learn/ember-styleguide),', 9 | github: 'https://github.com/ember-learn/ember-styleguide', 10 | }, 11 | }; 12 | }; 13 | 14 | module.exports['ember-cli-build'] = { 15 | fingerprint: { 16 | extensions: ['js', 'css', 'map'], 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /docs-styles/app.css: -------------------------------------------------------------------------------- 1 | .self-executing-code-block { 2 | margin-bottom: 2rem; 3 | } 4 | 5 | @media only percy { 6 | .hide-in-percy { 7 | visibility: hidden; 8 | } 9 | } 10 | 11 | .border-dashed { 12 | border: 1px dashed var(--color-gray-500); 13 | } 14 | 15 | .spacer-xsmall { 16 | height: var(--spacing-1); 17 | } 18 | 19 | .spacer-small { 20 | height: var(--spacing-2); 21 | } 22 | 23 | .spacer-medium { 24 | height: var(--spacing-3); 25 | } 26 | 27 | .spacer-large { 28 | height: var(--spacing-4); 29 | } 30 | 31 | .spacer-xlarge { 32 | height: var(--spacing-5); 33 | } 34 | -------------------------------------------------------------------------------- /docs/components/banner.md: -------------------------------------------------------------------------------- 1 | # Banner 2 | 3 | ## Usage 4 | 5 | A banner will be shown at the top of the page. That can be filled with text. 6 | ```handlebars 7 | Some content goes here 8 | ``` 9 | The banner can also contain a link. 10 | ```handlebars 11 | Visit Website 12 | ``` 13 | 14 | When you pass multiple links into the component they will be separated by a tiny dot. 15 | ```handlebars 16 | Visit WebsiteVisit Something else 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/components/button.js: -------------------------------------------------------------------------------- 1 | import Component from '@glimmer/component'; 2 | import { tracked } from '@glimmer/tracking'; 3 | import { action } from '@ember/object'; 4 | 5 | export default class ButtonComponent extends Component { 6 | @tracked 7 | value = 0; 8 | 9 | @action 10 | incrementValue() { 11 | this.value++; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /docs/components/button.md: -------------------------------------------------------------------------------- 1 | # Button 2 | 3 | ## Usage 4 | 5 | Simplest use case: a button with text in it, telling the user what to do. 6 | 7 | ```handlebars 8 | 9 | ``` 10 | 11 | Also supported- block use: 12 | 13 | ```handlebars 14 | 15 | click me 🐹 16 | 17 | ``` 18 | 19 | To add interactivity you can pass an action to `onClicked` 20 | 21 | ```handlebars 22 | 23 | Increment Value 24 | 25 | 26 | {{this.value}} 27 | ``` 28 | 29 | ## Secondary Buttons 30 | 31 | ```handlebars 32 | 33 | ``` 34 | 35 | ## Styling Links 36 | It is also possible to style a link to look like a button using the `es-button` or `es-button-secondary` class. 37 | 38 | ```html 39 | Go to Ember homepage 40 | Go to the Guides 41 | ``` 42 | 43 | ## Accessibility 44 | 45 | Since we're using the native HTML button element and requiring a label value to be provided, the component itself is accesible as it is. 46 | 47 | If you are going to put an icon in the button, then you will need to set an aria-label property on the button: 48 | 49 | ```handlebars 50 | 51 | 🐹 52 | 53 | ``` 54 | -------------------------------------------------------------------------------- /docs/components/card.md: -------------------------------------------------------------------------------- 1 | # Card 2 | 3 | A card component that serves as a content container for images, text and links. When used within grid layouts cards are expected to share the same content structure and matching height. For accessibility reasons cards should always be implemented as lists, and for this reason the `` component's root element is a `
  • ` so it should always be wrapped in a `
      `. 4 | 5 | Here is an example of a card 6 | 7 | ```html 8 |
        9 | 10 | This is a card 11 | 12 |
      13 | ``` 14 | 15 | You can also add an image to the card using the `@image` parameter: 16 | 17 | ```html 18 |
        19 | 20 | This is a card 21 | 22 |
      23 | ``` 24 | 25 | By default images will be considered decorative and ignored by screen readers, but if you want to provide an alt text for the image you can provide it with the `alt` key in the `@image` hash: 26 | 27 | ```html 28 |
        29 | 30 | This is a card 31 | 32 |
      33 | ``` 34 | 35 | Here is a fuller example of a card that has more structure in the card body 36 | 37 | ```html 38 |
        39 | 40 |

        Ember.js

        41 |

        A framework for ambitious web developers. Try it out!

        42 |
        43 | 44 |
        COPYRIGHT 2019 TILDE INC.
        45 |
        46 |
        47 |
      48 | ``` 49 | 50 | And here is a full card based page layout (which also makes use of the [ESLinkCard](/components/link-card) component) that might be useful when building sites using this component: 51 | 52 | ```html 53 |
        54 | 60 |

        Post and search longer-form questions in our public forum.

        61 |
        62 | 68 |

        Join our real-time chat server to connect with other developers and get answers.

        69 |
        70 |
      71 | 72 |

      73 | Beyond our core online channels, you can dig deeper with these learning resources from the 74 | community members 75 |

      76 | 77 | 98 | ``` 99 | -------------------------------------------------------------------------------- /docs/components/footer.md: -------------------------------------------------------------------------------- 1 | # Footer 2 | 3 | ```handlebars 4 | 5 | ``` 6 | 7 | You can also add a "contribute to this page" link in the footer by passing `@contributeLink`: 8 | 9 | ```handlebars 10 | 11 | ``` 12 | -------------------------------------------------------------------------------- /docs/components/header.js: -------------------------------------------------------------------------------- 1 | import Component from '@glimmer/component'; 2 | 3 | export default class HeaderComponent extends Component { 4 | links = [ 5 | { 6 | name: 'Example Links', 7 | type: 'dropdown', 8 | items: [ 9 | { 10 | href: 'https://guides.emberjs.com/release/', 11 | name: 'Ember.js Guides', 12 | type: 'link', 13 | }, 14 | { 15 | href: 'https://api.emberjs.com', 16 | name: 'API Reference', 17 | type: 'link', 18 | }, 19 | { 20 | href: 'https://cli.emberjs.com', 21 | name: 'CLI Guides', 22 | type: 'link', 23 | }, 24 | { 25 | type: 'divider', 26 | }, 27 | { 28 | href: 'https://emberjs.com/learn', 29 | name: 'Learn Ember', 30 | type: 'link', 31 | }, 32 | ], 33 | }, 34 | ]; 35 | } 36 | -------------------------------------------------------------------------------- /docs/components/header.md: -------------------------------------------------------------------------------- 1 | # Global Header 2 | 3 | Shows the side wide header with the global navigation. 4 | 5 | ```handlebars 6 | 7 | ``` 8 | 9 | If you would like to override the default links you can pass a json object to update the links in the navbar. 10 | 11 | ```handlebars 12 | 13 | ``` 14 | 15 | You can also use the block form of the component to add extra HTML to the navigation bar 16 | 17 | ```handlebars 18 | 19 |
      Hello World
      20 |
      21 | ``` 22 | -------------------------------------------------------------------------------- /docs/components/link-card.md: -------------------------------------------------------------------------------- 1 | # Link Card 2 | 3 | An `` is a card that allows a link to an external resource. 4 | 5 | ```html 6 |
        7 | 8 |

        Post and search longer-form questions in our public forum.

        9 |
        10 |
      11 | ``` 12 | 13 | You can add an icon to the card with `@icon` 14 | 15 | ```html 16 |
        17 | 23 |

        Post and search longer-form questions in our public forum.

        24 |
        25 |
      26 | ``` 27 | 28 | Here is what that looks like on a dark background 29 | 30 | ```html 31 |
      32 |
        33 | 38 |

        Post and search longer-form questions in our public forum.

        39 |
        40 |
      41 |
      42 | ``` 43 | -------------------------------------------------------------------------------- /docs/components/note.md: -------------------------------------------------------------------------------- 1 | # Note 2 | 3 | Sometimes in our documentation we might want to bring someone's attention to something, either as a warning or a quick suggestion. We have a qwirky component that can be used for exactly this 4 | 5 | ## Usage 6 | 7 | ```handlebars 8 | You should try out this cool note component 9 | ``` 10 | 11 | If you don't pass in a specific mascot (either `tomster` or `zoey`) then it will randomly pick between them. Try refreshing the page now and see them change! 12 | 13 | You might notice on this page that they flicker a little bit and seem to swap between a Tomster and a Zoey sometimes just after rendering. This is related to how we are pre-rendering this page and then when the page is loaded Ember will re-run the code that picks the mascot that is displayed. 14 | 15 | In **all** cases where we are pre-rendering a page using fastboot or prember, we **must** pass in the `@mascot` argument to the component. 16 | 17 | ```handlebars 18 | I am a Tomster, and I approve this message 19 | ``` 20 | 21 | ```handlebars 22 | I am a Zoey, and I approve this message 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/components/pagination.md: -------------------------------------------------------------------------------- 1 | # Pagination 2 | 3 | Adds back and forth pagination, using `named blocks`. You insert your previous link into a `<:previous>` block and the next link into a `<:next>` block. This will add the underline styling to the link and an animated arrow to your link. You will use the `showPrevious` and `showNext` prop to make sure the correct links are visible. 4 | 5 | ## Usage 6 | 7 | Add the following code to the template 8 | 9 | ```handlebars 10 | 11 | <:previous> 12 | 13 | Newer articles 14 | 15 | 16 | <:next> 17 | 18 | Older articles 19 | 20 | 21 | 22 | ``` 23 | 24 | To only show the previous you've to pass `false` to the `showNext` prop. 25 | 26 | ```handlebars 27 | 28 | <:previous> 29 | 30 | Newer articles 31 | 32 | 33 | <:next> 34 | 35 | Older articles 36 | 37 | 38 | 39 | ``` 40 | 41 | To only show the previous you've to pass `false` to the `showPrevious` prop. 42 | 43 | ```handlebars 44 | 45 | <:previous> 46 | 47 | Newer articles 48 | 49 | 50 | <:next> 51 | 52 | Older articles 53 | 54 | 55 | 56 | ``` 57 | -------------------------------------------------------------------------------- /docs/components/progress-bar.md: -------------------------------------------------------------------------------- 1 | # Progress bar 2 | 3 | The progress bar component is designed to give some visual feedback to the user when they are navigating between routes. Internally it uses a service to keep track of route changes so you don't need to do anything special to make it work 4 | 5 | ## Usage 6 | 7 | Just make sure that you add the following code to the Application template and the component will take care of the rest! 8 | 9 | ```handlebars 10 | 11 | ``` 12 | 13 | The above demo doesn't look like much, but if you want to see it in action you need to navigate to a different route and keep an eye on the top of the screen. Try it now by clicking something in the table of contents and then navigate back to this page 14 | -------------------------------------------------------------------------------- /docs/components/sidebar.md: -------------------------------------------------------------------------------- 1 | # Sidebar 2 | 3 | ## Usage 4 | 5 | The sidebar component can be used together with the sidebar-container class to add a responsive sidebar to the page. If the sidebar is the first element in the sidebar-container it will display as a left sidebar. Otherwise it will display as a right sidebar. 6 | 7 | The sidebar component will automatically switch to the mobile mode once your browser window is smaller than or equal to 844px. 8 | 9 | 29 | 30 | ### Left Sidebar Example 31 | ```handlebars 32 | 40 | ``` 41 | 42 | ### Right Sidebar Example 43 | ```handlebars 44 | 52 | ``` 53 | 54 | 55 | ### Full Width Left Sidebar Example 56 | ```handlebars 57 | 65 | ``` 66 | 67 | ### Full Width Right Sidebar Example 68 | ```handlebars 69 | 77 | ``` 78 | 79 | ### Sidebar Right Border 80 | There is a class, `es-sidebar--border-right`, that you can add to your sidebar to give it a right border. This will not show up in mobile. 81 | ```handlebars 82 | 90 | ``` 91 | 92 | -------------------------------------------------------------------------------- /docs/concepts/accessibility.md: -------------------------------------------------------------------------------- 1 | # Accessibility 2 | 3 | ## Code Guide 4 | 5 | Our goal is to meet [WCAG](https://www.w3.org/WAI/standards-guidelines/aria/) [AA level conformance](https://www.w3.org/WAI/WCAG21/quickref/?currentsidebar=%23col_customize&levels=aaa&technologies=flash%2Csl) for all Ember.js websites. 6 | 7 | ### Iterative Improvements 8 | - It is 100% okay to ship code that can iterate to being a more inclusive experience- as long as it can still be used by people with assistive technology. 9 | - It is not okay to ship code that actively breaks the experience for users with assistive technology. 10 | -------------------------------------------------------------------------------- /docs/concepts/background-shapes.md: -------------------------------------------------------------------------------- 1 | # Background Shapes 2 | 3 | In the new design we have a number of background shapes that can be used to spruce up the design of sections of the website if necessary. 4 | 5 | ## Background boxes 6 | 7 | To use the "background boxes" shape then you need to use the `bg-shape-boxes` css helper as follows 8 | 9 | ```html 10 |
      11 |
      12 |

      Build with the teams that never stop shipping.

      13 |

      14 | Some of the best development teams in the world have been iterating on their products for 15 | years with Ember. With scalable UI architecture baked-in from the start, you’ll be working 16 | with the same patterns these organizations use every step of the way. 17 |

      18 |
      19 |
      20 |

      More stuff to show location of boxes

      21 |
      22 |
      23 |

      Even more stuff to show location of boxes

      24 |
      25 |
      26 | ``` 27 | 28 | There is an alternative "background boxes" shape that you can use with `bg-shape-boxes-bottom` that will automatically continue into the following dom node (e.g. the next div) 29 | 30 | ```html 31 |
      32 |
      33 |

      Build with the teams that never stop shipping.

      34 |

      35 | Some of the best development teams in the world have been iterating on their products for 36 | years with Ember. With scalable UI architecture baked-in from the start, you’ll be working 37 | with the same patterns these organizations use every step of the way. 38 |

      39 |
      40 |
      41 |
      42 |
      43 |

      More content to show off the shapes

      44 |

      45 | Some of the best development teams in the world have been iterating on their products for 46 | years with Ember. With scalable UI architecture baked-in from the start, you’ll be working 47 | with the same patterns these organizations use every step of the way. 48 |

      49 |
      50 |
      51 | ``` 52 | 53 | ## Swipes 54 | 55 | The other type of background shape is a "swipe" that can either be a swipe across the top of the section using `bg-shape-swipe-top` or a rectangle from the bottom of the section using `bg-shape-swipe-bottom`. 56 | 57 | ```html 58 |
      59 |
      60 |

      Build with the teams that never stop shipping.

      61 |

      62 | Some of the best development teams in the world have been iterating on their products for 63 | years with Ember. With scalable UI architecture baked-in from the start, you’ll be working 64 | with the same patterns these organizations use every step of the way. 65 |

      66 |
      67 |
      68 |

      More stuff to show location of swipe

      69 |
      70 | 71 |
      72 |

      Even more stuff to show location of swipe

      73 |
      74 |
      75 | ``` 76 | 77 | and then using the `bg-shape-swipe-bottom` we can get a shape for the bottom of a section: 78 | 79 | ```html 80 |
      81 |
      82 |

      Build with the teams that never stop shipping.

      83 |

      84 | Some of the best development teams in the world have been iterating on their products for 85 | years with Ember. With scalable UI architecture baked-in from the start, you’ll be working 86 | with the same patterns these organizations use every step of the way. 87 |

      88 |
      89 |
      90 |

      More stuff to show location of swipe

      91 |
      92 |
      93 |

      Even more stuff to show location of swipe

      94 |
      95 |
      96 |

      yes this needs quite a large section

      97 |
      98 |
      99 | ``` 100 | -------------------------------------------------------------------------------- /docs/concepts/central-content.md: -------------------------------------------------------------------------------- 1 | # Central content 2 | 3 | In our ecosystem we have a sidebar and the central content. This content includes the actual content and an [on this page menu](on-this-page) if there is one. The content should be centered in the container that it's place in. We use the `content-wrapper` class to indicate this structure. The [on this page menu](on-this-page) will dissappear at `80em`. 4 | 5 | ```html 6 |
      7 |
      8 |
      9 |

      10 | Introduction 11 |

      12 |
      13 |
      14 |

      This section of the Guides describes the essential features of EmberData, a powerful set of tools for formatting requests, normalizing responses, and efficiently managing a local cache of data.

      15 |

      Ember.js itself works with any type of back end: REST, JSON:API, GraphQL, or anything else.

      16 |
      17 |
      18 |
      On this page
      19 |
      20 | 49 |
      50 |
      51 | ``` 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /docs/concepts/colors.md: -------------------------------------------------------------------------------- 1 | # Colors 2 | 3 | ### Usage 4 | 5 | #### Legibility 6 | 7 | Website elements like text and icons should meet accesibility standards when used against colored backgrounds. The following swatches contain a sample of each of the primary palette colors, along with recommendations for its usage and the acceptable contrast guidelines when coupled with text. 8 | 9 | ## Primary Colors 10 | 11 | The primary palette is applied across every page of the website and contains the brand, accent and neutral colors. The purpose of the primary palette is to keep uniformity across all pages while encouraging accessibility best practices. 12 | 13 | 14 | 19 | 20 |
      21 | {{#each (array 22 | (hash color="#E04E39" name="Brand" variable="--color-brand" className="bg-brand") 23 | (hash color="#FFFFFF" name="White" variable="--color-white") 24 | (hash color="#F4F6F8" name="Gray 100" variable="--color-gray-100") 25 | (hash color="#EBEEF2" name="Gray 200" variable="--color-gray-200") 26 | (hash color="#DCE0E6" name="Gray 300" variable="--color-gray-300") 27 | (hash color="#BEC4CC" name="Gray 400" variable="--color-gray-400") 28 | (hash color="#8F949F" name="Gray 500" variable="--color-gray-500") 29 | (hash color="#6A707A" name="Gray 600" variable="--color-gray-600") 30 | (hash color="#42474F" name="Gray 700" variable="--color-gray-700") 31 | (hash color="#2B2D34" name="Gray 800" variable="--color-gray-800") 32 | (hash color="#1C1E24" name="Gray 900" variable="--color-gray-900") 33 | (hash color="#000000" name="Black" variable="--color-black") 34 | ) as |item|}} 35 | 44 | {{/each}} 45 |
      46 | 47 | ## Illustration Colors 48 | 49 | These colors are for charts and diagrams only. The secondary palette is applied to UI elements and is not part of the base colors. The purpose of the secondary palette is to ensure the readability, usability, and accessibility of charts and diagrams and enhance the communication of actions, changes in state, or errors. 50 | 51 |
      52 | 60 | 68 | 76 |
      77 | 78 |
      79 | 87 | 95 |
      96 | 97 |
      98 | 106 | 114 |
      115 | 116 |
      117 | 125 | 133 |
      134 | -------------------------------------------------------------------------------- /docs/concepts/header-anchor.md: -------------------------------------------------------------------------------- 1 | # Header anchor 2 | 3 | In our documentation we want to be able to link to specific headers, that's why we introduce this pattern. The `` includes the `` that includes the link ``. This removes the link underline default styling from all ``s wrapped in ``-elements and rotates all `svg`s by 45 degrees if they are wrapped in both. 4 | 5 | ```html 6 |

      7 | Multiple Dynamic Segments 8 | 9 | 10 | 12 | 13 | 14 |

      15 | ``` 16 | -------------------------------------------------------------------------------- /docs/concepts/markdown.md: -------------------------------------------------------------------------------- 1 | # Markdown 2 | 3 | A lot of the ember websites use markdown to render all or part of the page which means that we can use standard styles to render. This page is intended to be a reference implementation of all the styles that would apply to standard markdown and are supported by the Ember styleguide. 4 | 5 | ``` handlebars 6 | {{markdown-to-html " 7 | # Header 1 8 | 9 | This is my initial paragraph, but an introduction 10 | 11 | ## Header 2 12 | 13 | Here I will go into more detail... and may repeat myself a few times but please don't hold that against me. Here I will go into more detail... and may repeat myself a few times but please don't hold that against me. Here I will go into more detail... and may repeat myself a few times but please don't hold that against me. Here I will go into more detail... and may repeat myself a few times but please don't hold that against me. Here I will go into more detail... and may repeat myself a few times but please don't hold that against me. 14 | 15 | ### Header 3 16 | 17 | This section won't have much text, but it will have some other examples! 18 | 19 | - list item 1 20 | - list item 2 21 | - list item 3 22 | 23 | > You can also add some block quotes if you like. 24 | 25 | #### Header 4 26 | 27 | You thought you got away with 3 headers, well you haven't seen nothin yet! 28 | 29 | 1. order 1 30 | 1. order 2 31 | 1. order 3 32 | 33 | ##### Header 5 34 | 35 | Will the headers never stop!? 36 | 37 | Sometimes you just want to be **bold with your words**! But other times _you might feel a bit off center_. And if you're really bad you might feel **both at the _same_ time** 38 | 39 | [Ember is the best framework](https://emberjs.com) 40 | 41 | ##### Inline code 42 | 43 | Let's refer to some libraries like `ember-cli` and make sure the inline code styles are applied. 44 | 45 | --- 46 | 47 | ![Zoey Mascot](/images/mascots/zoey.png) 48 | 49 | ![Big Emberconf Photo](/emberconf.jpg) 50 | 51 | "}} 52 | ``` 53 | -------------------------------------------------------------------------------- /docs/concepts/on-this-page.md: -------------------------------------------------------------------------------- 1 | # On This Page 2 | 3 | To allow the users easy and quick access to all the content on the page we provide styling for an `on this page` list, using the `on-this-page-wrapper` class will make sure that the styling of the links is good, and also that it disappears at `80em` to keep the page responsive. This concept should be used within the [central-content](central-content) concept. 4 | 5 | ```html 6 |
      7 |
      On this page
      8 |
      9 | 38 |
      39 | ``` 40 | -------------------------------------------------------------------------------- /docs/concepts/table-of-contents.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | Instead of providing a component we provide this concept for our table of contents. You can see the concept below. 4 | Every item in the list is either a `toc-heading`, giving it heading styling, or an `toc-item`. The `anchor`-tags wrapped in a `toc-item` will get specific styling. On the main level, not wrapped in a `sub-table-of-contents`, they will be the brand-color. When they are wrapped in a `sub-table-of-contents`, they will have an "active" indicator and a hover state, this will also indent them from the main level. 5 | 6 | ```html 7 | 43 | ``` 44 | -------------------------------------------------------------------------------- /docs/concepts/typography.md: -------------------------------------------------------------------------------- 1 | # Typography 2 | 3 | ### Usage 4 | 5 | #### Legibility 6 | 7 | Text legibility is primarily affected by color. All text on the website should comply with the Web Content Accessibility Guidelines (WCAG 2.0) Level AA requirements. 8 | 9 | Please refer to the Colors section for more information on color contrast and accessibility. 10 | 11 | ### Sizes 12 | 13 | Disclaimer: Use these helpers when you need to modify the look of an element in cases where using a different element would lead to the wrong semantic meaning. A good example is the Ember.js home page, where a hero element exists which contains the `

      ` for that page and therefore requires all subsequent headlines to shift down one level. The design does not know about this semantic shift, so all `

      ` on that page need `.text-xl` to look like `

      ` and so on. 14 | 15 | Use `.text-sm` for small headings or notice paragraphs. 16 | 17 | ```html 18 |
      19 | Build with the teams that never stop shipping. 20 |
      21 | ``` 22 | 23 | Use `.text-base` for body text, navigation items or links. 24 | 25 | ```html 26 |
      27 | Build with the teams that never stop shipping. 28 |
      29 | ``` 30 | 31 | `.text-base` is also the default paragraph size. 32 | 33 | ```html 34 |
      35 | Build with the teams that never stop shipping. 36 |
      37 | ``` 38 | 39 | Use `.text-md` for section headings. This is also the default size for the `h3` element. 40 | 41 | ```html 42 |
      43 | Build with the teams that never stop shipping. 44 |
      45 | ``` 46 | 47 | Use `.text-lg` for content page headings. This is also the default size for the `h2` element. 48 | 49 | ```html 50 |
      51 | Build with the teams that never stop shipping. 52 |
      53 | ``` 54 | 55 | Use `.text-xl` for landing page headlines. This is also the default size for the `h1` element. 56 | 57 | ```html 58 |
      59 | Build with the teams that never stop shipping. 60 |
      61 | ``` 62 | 63 | Use `.text-hero-xl` for headlines in page headers (heros). 64 | 65 | ```html 66 |

      67 | Build with the teams that never stop shipping. 68 |

      69 | ``` 70 | 71 | Use `.text-hero-base` for plain text in page headers (heros). 72 | 73 | ```html 74 |

      75 | Ember.js is a productive, battle-tested JavaScript framework for building 76 | modern web applications. It includes everything you need to build rich UIs 77 | that work on any device. 78 |

      79 | ``` 80 | 81 | ## Weights 82 | 83 | Use `.regular` 84 | 85 | ```html 86 |
      87 | Build with the teams that never stop shipping. 88 |
      89 | ``` 90 | 91 | Use `.bold` if you must style something as bold and no semantic information needs to be carried. Prefer using ``. 92 | 93 | ```html 94 |
      95 | Build with the teams that never stop shipping. 96 |
      97 | ``` 98 | -------------------------------------------------------------------------------- /docs/concepts/wells.md: -------------------------------------------------------------------------------- 1 | # Wells 2 | 3 | Wells provide a box to wrap images that should be presented on a background, most likely because they have transparency. 4 | 5 | ```html 6 | 7 |
      8 | Hello World 9 |
      10 | ``` 11 | 12 | They also come in multiple ratios and ensure that a contained image is resized to fill the space appropriatly. 13 | 14 | ```html 15 |
      16 |
      17 |

      Ratio 1:1

      18 |
      19 | Ember.js 20 |
      21 |
      22 |
      23 |

      Ratio 4:3

      24 |
      25 | Ember.js 26 |
      27 |
      28 |
      29 |

      Ratio 16:9

      30 |
      31 | Ember.js 32 |
      33 |
      34 |
      35 | ``` 36 | 37 | Wells can be applied to anchors and work well with HTML `
      ` elements. 38 | 39 | ```html 40 |
      41 |
      42 |
      43 |
      44 | Ember.js 45 |
      46 |
      47 | A well thought out caption to add more information to the image above 48 |
      49 |
      50 |
      51 |
      52 |
      53 | 54 | Ember.js 55 | 56 |
      57 | Using an anchor for the well works, too. You may want to add an additional link to the text 58 | and or make sure this becomes clear from the context. 59 |
      60 |
      61 |
      62 |
      63 | ``` 64 | -------------------------------------------------------------------------------- /docs/css/global.md: -------------------------------------------------------------------------------- 1 | # CSS Global Styles 2 | 3 | ## Element styles 4 | 5 | All of the below are default element styles. 6 | 7 | ### Horizontal Rule `
      ` 8 | 9 | If you would like to add a break between content then you can use the pre-styled Horizontal Rule `
      ` element. 10 | 11 | ```html 12 |
      13 | ``` 14 | -------------------------------------------------------------------------------- /docs/css/helpers.md: -------------------------------------------------------------------------------- 1 | # CSS Helper Classes 2 | 3 | ## Theming Helpers 4 | 5 | All of the below will set the desired background color and ensure corresponding foreground colors as well. 6 | 7 | ### Light Background 8 | 9 | If you would like a section or a div to use the dark style then you need to add `class="bg-light"` to the element that you would like to be light. 10 | 11 | ```html 12 |
      13 | hello there 14 |
      15 | ``` 16 | 17 | ### Light Muted Background 18 | 19 | If you would like a section or a div to use the dark style then you need to add `class="bg-light-muted"` to the element that you would like to be light, but slightly darker. 20 | 21 | ```html 22 |
      23 | hello there 24 |
      25 | ``` 26 | 27 | ### Dark Background 28 | 29 | If you would like a section or a div to use the dark style then you need to add `class="bg-dark"` to the element that you would like to be dark. 30 | 31 | ```html 32 |
      33 | hello there 34 |
      35 | ``` 36 | 37 | Please note that there currently is no `bg-dark-muted`, as it's unused. 38 | 39 | ## Border Helpers 40 | 41 | If you want to adjust border properties. 42 | 43 | ### Rounded Corners 44 | 45 | ```html 46 |
      Hello!
      47 | ``` 48 | 49 | ```html 50 |
      Hello!
      51 | ``` 52 | 53 | ## List Styles 54 | 55 | If you want to remove default list styling you can use the `list-unstyled` css helper 56 | 57 | ```html 58 |
        59 |
      • One
      • 60 |
      • Two
      • 61 |
      • Three
      • 62 |
      63 | ``` 64 | 65 | ## Spacing Helpers 66 | 67 | In order to apply the spacing scale on pages, a set of predefined helper classes exist for both margins and paddings. 68 | 69 | ### Margin Helpers 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | {{#each 82 | (array 83 | (hash value='' name='all') 84 | (hash value='x' name="horizontal") 85 | (hash value='y' name="vertical") 86 | (hash value='t' name="top") 87 | (hash value='r' name="right") 88 | (hash value='b' name="bottom") 89 | (hash value='l' name="left") 90 | ) as |direction| 91 | }} 92 | {{#each (array '0' '1' '2' '3' '4' '5') as |size|}} 93 | 94 | 95 | 96 | 97 | 102 | 103 | {{/each}} 104 | {{/each}} 105 | 106 |
      ScaleLocationHelper ClassExample
      {{size}}{{direction.name}}.m{{direction.value}}-{{size}} 98 |
      99 |
      Content
      100 |
      101 |
      107 | 108 | ### Padding Helpers 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | {{#each 121 | (array 122 | (hash value='' name='all') 123 | (hash value='x' name="horizontal") 124 | (hash value='y' name="vertical") 125 | (hash value='t' name="top") 126 | (hash value='r' name="right") 127 | (hash value='b' name="bottom") 128 | (hash value='l' name="left") 129 | ) as |direction| 130 | }} 131 | {{#each (array '0' '1' '2' '3' '4' '5') as |size|}} 132 | 133 | 134 | 135 | 136 | 141 | 142 | {{/each}} 143 | {{/each}} 144 | 145 |
      ScaleLocationHelper ClassExample
      {{size}}{{direction.name}}.p{{direction.value}}-{{size}} 137 |
      138 |
      Content
      139 |
      140 |
      146 | 147 | ### Flex helpers 148 | 149 | We provide a few `flex` helpers to make it easier to position elements on your page. All classes provide the `display: flex` property. 150 | 151 | `.flex-horizontal-between` does `justify-content: space-between`. 152 | ```html 153 |
      154 | 155 |
      156 | ``` 157 | 158 | `.flex-center` does `justify-content: center` and `align-items: center`, making sure your content is centered. 159 | ```html 160 |
      161 | 162 |
      163 | ``` 164 | 165 | `.flex-responsive` adds `flex-wrap: wrap` to your element, making sure the content wraps with the parent. It adds a `gap` too. You can resize the window to see the effect of the class. 166 | ```html 167 |
      168 | 169 |
      170 | ``` 171 | 172 | You can also combine these helper-classes, allowing the content to wrap and stay centered. 173 | ```html 174 |
      175 | 176 |
      177 | ``` 178 | 179 | ### Responsive Videos 180 | 181 | ```html 182 |
      183 | 184 | 192 | 193 |
      194 | ``` 195 | 196 | ### Hide elements on mobile 197 | 198 | If you would like to hide any element only on mobile screens you can use the `.hide-on-mobile` class helper. 199 | 200 | ```html 201 |

      A secret message for desktop users: ♥️

      202 | 203 |

      If you can see the secret message above try resizing the window!

      204 | ``` 205 | 206 | ## Turn off link-underline styles 207 | 208 | You will probably have noticed that all links automatically have custom underline functionality: 209 | 210 | ```html 211 |
      212 | Ember Homepage 213 |
      214 | ``` 215 | 216 | To get the style that we wanted we needed to implement a custom background image for all links instead of making use of the `text-decoration: underline` styles. If you have a link (or a set of links) that you would like to turn off this behaviour then you can use the `bg-none` helper to turn off this styling: 217 | 218 | ```html 219 |
      220 | Ember Homepage 221 |
      222 | ``` 223 | -------------------------------------------------------------------------------- /docs/css/overview.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | maybe we talk about the fact that we're using CSS features stage 3 or higher? 4 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | ```bash{data-execute=false} 4 | ember install ember-styleguide 5 | ``` 6 | 7 | ## Understanding ember-styleguide 8 | 9 | As we were working on the Ember.js website, we found ourselves wanting a more scalable approach to all of the Ember family of websites. 10 | 11 | Currently, these websites are considered "core" websites and are maintained by contributors: 12 | 13 | - emberjs.com 14 | - cli.emberjs.com 15 | - guides.emberjs.com 16 | - deprecations.emberjs.com 17 | - help-wanted.emberjs.com 18 | - api.emberjs.com 19 | 20 | There are also other websites that are still maintained by contributors but would need an upgrade to be able to avail of ember-styleguide 21 | 22 | - ember-fastboot.com 23 | - ember-engines.com 24 | 25 | Ember components are ideal for this, because all of these websites need similar types of components. By standardizing our component approach, we could more easily contribute to any of the websites in the Ember ecosystem. 26 | 27 | ## Goals 28 | 29 | This project is currently in active development status. 30 | 31 | We intend to provide an easy way to create a fully accessible Ember site from the components offered in this addon. 32 | 33 | ## Contributing to the project 34 | 35 | As with any Ember project, contributions are welcome! Visit [https://github.com/ember-learn/ember-styleguide](https://github.com/ember-learn/ember-styleguide) to file an issue or even better, submit a PR! 36 | 37 | If you have questions about the design/architecture, please contact [Melanie Sumner](mailto:melaniersumner@gmail.com) directly. 38 | -------------------------------------------------------------------------------- /ember-cli-build.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | 'use strict'; 3 | const EmberAddon = require('ember-cli/lib/broccoli/ember-addon'); 4 | 5 | module.exports = function (defaults) { 6 | const app = new EmberAddon(defaults, { 7 | fingerprint: { 8 | extensions: ['js', 'css', 'map'] 9 | }, 10 | svgJar: { 11 | sourceDirs: [ 12 | 'public', 13 | 'addon/public', 14 | 'node_modules/ember-styleguide/public', 15 | 'node_modules/ember-cli-addon-docs/public', 16 | 'tests/dummy/public' 17 | ] 18 | }, 19 | // required until https://github.com/ember-cli/ember-cli/issues/8448 is fixed 20 | 'ember-prism': { 21 | components: [ 22 | 'apacheconf', 23 | 'bash', 24 | 'css', 25 | 'handlebars', 26 | 'http', 27 | 'javascript', 28 | 'json', 29 | 'markup-templating', 30 | 'ruby', 31 | 'scss' 32 | ], 33 | 34 | plugins: ['line-numbers', 'normalize-whitespace'] 35 | } 36 | }); 37 | 38 | /* 39 | This build file specifies the options for the dummy test app of this 40 | addon, located in `/tests/dummy` 41 | This build file does *not* influence how the addon or the app using it 42 | behave. You most likely want to be modifying `./index.js` or app's build file 43 | */ 44 | 45 | const { maybeEmbroider } = require('@embroider/test-setup'); 46 | return maybeEmbroider(app, { 47 | skipBabel: [ 48 | { 49 | package: 'qunit', 50 | }, 51 | ], 52 | }); 53 | }; 54 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | 'use strict'; 3 | const Funnel = require('broccoli-funnel'); 4 | const path = require('path'); 5 | const CssImport = require('postcss-import') 6 | const PresetEnv = require('postcss-preset-env'); 7 | 8 | const plugins = [ 9 | { module: CssImport }, 10 | { 11 | module: PresetEnv, 12 | options: { 13 | stage: 3, 14 | features: { 'nesting-rules': true }, 15 | } 16 | } 17 | ]; 18 | 19 | module.exports = { 20 | name: require('./package').name, 21 | 22 | options: { 23 | postcssOptions: { 24 | compile: { 25 | enabled: true, 26 | plugins, 27 | } 28 | } 29 | }, 30 | 31 | included: function(app) { 32 | this._super.included.apply(this, arguments); 33 | app.options = app.options || {}; 34 | app.options.postcssOptions = { 35 | compile: { 36 | enabled: true, 37 | plugins, 38 | } 39 | } 40 | }, 41 | 42 | treeForPublic: function() { 43 | return new Funnel(path.join(this.root, 'public')); 44 | }, 45 | 46 | contentFor: function(type) { 47 | if (type === 'head') { 48 | // preload the most common fonts for modern browsers 49 | return ``; 50 | } 51 | 52 | return ''; 53 | }, 54 | }; 55 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ember-styleguide", 3 | "version": "11.1.0", 4 | "description": "Addon to help standardize the ember family of websites", 5 | "keywords": [ 6 | "ember-addon" 7 | ], 8 | "homepage": "https://ember-styleguide.netlify.app/", 9 | "repository": "https://github.com/ember-learn/ember-styleguide.git", 10 | "license": "MIT", 11 | "contributors": [ 12 | "Sivakumar Kailasam ", 13 | "Ember.JS Learning team" 14 | ], 15 | "directories": { 16 | "doc": "doc", 17 | "test": "tests" 18 | }, 19 | "scripts": { 20 | "build": "bottled-ember build --ember-version 5.12 --deps field-guide,field-guide-default-template,ember-cli-fastboot,prember --links docs,public,docs-styles:app/styles,config/fastboot.js --no-overlay --environment=production", 21 | "lint": "concurrently \"pnpm:lint:*(!fix)\" --names \"lint:\"", 22 | "lint:css": "stylelint \"**/*.css\"", 23 | "lint:css:fix": "concurrently \"pnpm:lint:css -- --fix\"", 24 | "lint:fix": "concurrently \"pnpm:lint:*:fix\" --names \"fix:\"", 25 | "lint:hbs": "ember-template-lint .", 26 | "lint:hbs:fix": "ember-template-lint . --fix", 27 | "lint:js": "eslint . --cache", 28 | "lint:js:fix": "eslint . --fix", 29 | "start": "concurrently \"npm:start:*\" --restart-after 5000 --prefix-colors cyan,white,yellow", 30 | "start:tests": "ember serve -p 0", 31 | "start:docs": "bottled-ember serve --ember-version 5.12 --output-path dist-bottled-docs --deps field-guide,field-guide-default-template,ember-cli-fastboot,prember,@percy/cli,@percy/ember --links docs,public,percy-test:tests/acceptance,docs-styles:app/styles,config/fastboot.js --cache-name docs --no-overlay", 32 | "test": "concurrently \"pnpm:lint\" \"pnpm:test:*\" --names \"lint,test:\"", 33 | "test:docs": "bottled-ember test --ember-version 5.12 --output-path dist-bottled-docs --deps field-guide,field-guide-default-template,ember-cli-fastboot,prember,@percy/cli,@percy/ember --links docs,public,percy-test:tests/acceptance,docs-styles:app/styles,config/fastboot.js --cache-name docs --no-overlay", 34 | "test:ember": "ember test", 35 | "ember-compatibility-tests": "ember try:all" 36 | }, 37 | "dependencies": { 38 | "@babel/core": "^7.25.2", 39 | "@ember/render-modifiers": "^2.0.2", 40 | "@glimmer/component": "^1.1.2", 41 | "broccoli-funnel": "^3.0.2", 42 | "broccoli-merge-trees": "^4.2.0", 43 | "ember-auto-import": "^2.10.0", 44 | "ember-cli-babel": "^8.2.0", 45 | "ember-cli-htmlbars": "^6.3.0", 46 | "ember-cli-postcss": "^8.2.0", 47 | "ember-concurrency": "^2.2.0", 48 | "ember-named-blocks-polyfill": "^0.2.5", 49 | "ember-test-waiters": "^2.1.3", 50 | "ember-truth-helpers": "^3.0.0", 51 | "lodash.get": "^4.4.2", 52 | "normalize.css": "^8.0.1", 53 | "postcss-import": "^12.0.1", 54 | "postcss-preset-env": "^6.7.0", 55 | "static-postcss-addon-tree": "^2.0.0" 56 | }, 57 | "devDependencies": { 58 | "@babel/eslint-parser": "^7.25.1", 59 | "@babel/plugin-proposal-decorators": "^7.24.7", 60 | "@ember/optional-features": "^2.1.0", 61 | "@ember/test-helpers": "^3.3.1", 62 | "@embroider/test-setup": "^4.0.0", 63 | "@glimmer/tracking": "^1.1.2", 64 | "@percy/cli": "^1.27.7", 65 | "@percy/ember": "^4.2.0", 66 | "bottled-ember": "^1.1.0", 67 | "broccoli-asset-rev": "^3.0.0", 68 | "concurrently": "^8.2.2", 69 | "ember-array-helper": "^5.1.0", 70 | "ember-cli": "~5.12.0", 71 | "ember-cli-clean-css": "^3.0.0", 72 | "ember-cli-dependency-checker": "^3.3.2", 73 | "ember-cli-fastboot": "^4.1.2", 74 | "ember-cli-inject-live-reload": "^2.1.0", 75 | "ember-cli-netlify": "^0.4.1", 76 | "ember-cli-sri": "^2.1.1", 77 | "ember-cli-terser": "^4.0.2", 78 | "ember-decorators-polyfill": "^1.1.5", 79 | "ember-fetch": "^8.1.1", 80 | "ember-load-initializers": "^2.1.2", 81 | "ember-native-dom-helpers": "^0.6.2", 82 | "ember-page-title": "^8.2.3", 83 | "ember-qunit": "^8.1.0", 84 | "ember-resolver": "^12.0.1", 85 | "ember-scroll": "^1.0.3", 86 | "ember-sinon": "^2.2.0", 87 | "ember-source": "~5.12.0", 88 | "ember-source-channel-url": "^3.0.0", 89 | "ember-template-lint": "^7.7.0", 90 | "ember-try": "^3.0.0", 91 | "eslint": "^8.57.1", 92 | "eslint-config-prettier": "^9.1.0", 93 | "eslint-plugin-ember": "^12.2.1", 94 | "eslint-plugin-n": "^16.6.2", 95 | "eslint-plugin-prettier": "^5.2.1", 96 | "eslint-plugin-qunit": "^8.1.2", 97 | "lint-to-the-future": "^2.6.3", 98 | "lint-to-the-future-ember-template": "^3.1.0", 99 | "lint-to-the-future-eslint": "^3.1.0", 100 | "lint-to-the-future-stylelint": "^2.1.0", 101 | "loader.js": "^4.7.0", 102 | "pnpm": "^7.0.0", 103 | "prember": "^2.0.0", 104 | "prettier": "^3.3.3", 105 | "qunit": "^2.22.0", 106 | "qunit-dom": "^3.2.1", 107 | "release-plan": "^0.16.0", 108 | "stylelint": "^15.11.0", 109 | "stylelint-config-standard": "^34.0.0", 110 | "stylelint-declaration-strict-value": "^1.8.0", 111 | "stylelint-order": "^4.0.0", 112 | "stylelint-prettier": "^4.1.0", 113 | "webpack": "^5.95.0" 114 | }, 115 | "packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977", 116 | "engines": { 117 | "node": "18.* || >= 20" 118 | }, 119 | "volta": { 120 | "node": "18.18.2" 121 | }, 122 | "publishConfig": { 123 | "registry": "https://registry.npmjs.org" 124 | }, 125 | "ember": { 126 | "before": [ 127 | "ember-cli-postcss" 128 | ], 129 | "edition": "octane" 130 | }, 131 | "ember-addon": { 132 | "configPath": "tests/dummy/config" 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /percy-test/visual-regression-test-test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | import { module, test } from 'qunit'; 3 | import { visit } from '@ember/test-helpers'; 4 | import { setupApplicationTest } from 'ember-qunit'; 5 | import percySnapshot from '@percy/ember'; 6 | 7 | async function renderFromToc(tableOfContents, path = "") { 8 | for (const item of tableOfContents) { 9 | if (!item.pages || item.pages.length === 0) { 10 | await visit(path + item.title); 11 | await percySnapshot(path + item.title); 12 | } else { 13 | await renderFromToc(item.pages, `${path + item.title}/`); 14 | } 15 | } 16 | } 17 | 18 | module('Acceptance | visual regression test', function(hooks) { 19 | setupApplicationTest(hooks); 20 | 21 | test(`visiting visual regressions with Percy`, async function(assert) { 22 | assert.expect(0); 23 | await visit('/'); 24 | 25 | let tableOfContents = this.owner.lookup('controller:application').model; 26 | 27 | await renderFromToc(tableOfContents); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /public/ember-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ember-learn/ember-styleguide/6d709151fcfb90896b41667cff9442db41edc541/public/ember-logo.png -------------------------------------------------------------------------------- /public/emberconf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ember-learn/ember-styleguide/6d709151fcfb90896b41667cff9442db41edc541/public/emberconf.jpg -------------------------------------------------------------------------------- /public/fonts/Inter-ExtraLight.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ember-learn/ember-styleguide/6d709151fcfb90896b41667cff9442db41edc541/public/fonts/Inter-ExtraLight.woff -------------------------------------------------------------------------------- /public/fonts/Inter-ExtraLight.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ember-learn/ember-styleguide/6d709151fcfb90896b41667cff9442db41edc541/public/fonts/Inter-ExtraLight.woff2 -------------------------------------------------------------------------------- /public/fonts/Inter-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ember-learn/ember-styleguide/6d709151fcfb90896b41667cff9442db41edc541/public/fonts/Inter-Italic.woff -------------------------------------------------------------------------------- /public/fonts/Inter-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ember-learn/ember-styleguide/6d709151fcfb90896b41667cff9442db41edc541/public/fonts/Inter-Italic.woff2 -------------------------------------------------------------------------------- /public/fonts/Inter-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ember-learn/ember-styleguide/6d709151fcfb90896b41667cff9442db41edc541/public/fonts/Inter-Regular.woff -------------------------------------------------------------------------------- /public/fonts/Inter-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ember-learn/ember-styleguide/6d709151fcfb90896b41667cff9442db41edc541/public/fonts/Inter-Regular.woff2 -------------------------------------------------------------------------------- /public/fonts/Inter-SemiBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ember-learn/ember-styleguide/6d709151fcfb90896b41667cff9442db41edc541/public/fonts/Inter-SemiBold.woff -------------------------------------------------------------------------------- /public/fonts/Inter-SemiBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ember-learn/ember-styleguide/6d709151fcfb90896b41667cff9442db41edc541/public/fonts/Inter-SemiBold.woff2 -------------------------------------------------------------------------------- /public/fonts/Inter-SemiBoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ember-learn/ember-styleguide/6d709151fcfb90896b41667cff9442db41edc541/public/fonts/Inter-SemiBoldItalic.woff -------------------------------------------------------------------------------- /public/fonts/Inter-SemiBoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ember-learn/ember-styleguide/6d709151fcfb90896b41667cff9442db41edc541/public/fonts/Inter-SemiBoldItalic.woff2 -------------------------------------------------------------------------------- /public/fonts/Inter-roman.var.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ember-learn/ember-styleguide/6d709151fcfb90896b41667cff9442db41edc541/public/fonts/Inter-roman.var.woff2 -------------------------------------------------------------------------------- /public/images/arrow-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /public/images/boxes-bottom-continued.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /public/images/boxes-bottom-light.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/images/boxes-bottom.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/images/boxes-top.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/images/ember-logo-white.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /public/images/ember-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /public/images/mascots/tomster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ember-learn/ember-styleguide/6d709151fcfb90896b41667cff9442db41edc541/public/images/mascots/tomster.png -------------------------------------------------------------------------------- /public/images/mascots/zoey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ember-learn/ember-styleguide/6d709151fcfb90896b41667cff9442db41edc541/public/images/mascots/zoey.png -------------------------------------------------------------------------------- /public/images/quotes.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | F54016F1-E960-4060-978C-4E8A2A944716@1.00x 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /public/images/swipe-bottom.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/images/swipe-top.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /testem.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | test_page: 'tests/index.html?hidepassed&nolint', 5 | disable_watching: true, 6 | launch_in_ci: ['Chrome'], 7 | launch_in_dev: ['Chrome'], 8 | browser_start_timeout: 120, 9 | browser_args: { 10 | Chrome: { 11 | ci: [ 12 | // --no-sandbox is needed when running Chrome inside a container 13 | process.env.CI ? '--no-sandbox' : null, 14 | '--headless', 15 | '--disable-dev-shm-usage', 16 | '--disable-software-rasterizer', 17 | '--mute-audio', 18 | '--remote-debugging-port=0', 19 | '--window-size=1440,900', 20 | ].filter(Boolean), 21 | }, 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /tests/acceptance/progress-bar-test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable qunit/no-assert-equal */ 2 | import { module, test } from 'qunit'; 3 | import { visit, currentURL, click } from '@ember/test-helpers'; 4 | import { setupApplicationTest } from 'ember-qunit'; 5 | 6 | module('Acceptance | progress bar', function (hooks) { 7 | setupApplicationTest(hooks); 8 | 9 | test('progress bar should not causea a transition abort error', async function (assert) { 10 | await visit('/'); 11 | 12 | await click('[data-test-basic-route]'); 13 | 14 | assert.equal(currentURL(), '/fancy'); 15 | 16 | await visit('/'); 17 | 18 | await click('[data-test-slow-route]'); 19 | 20 | assert.equal(currentURL(), '/fancy'); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /tests/dummy/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ember-learn/ember-styleguide/6d709151fcfb90896b41667cff9442db41edc541/tests/dummy/.DS_Store -------------------------------------------------------------------------------- /tests/dummy/app/app.js: -------------------------------------------------------------------------------- 1 | import Application from '@ember/application'; 2 | import Resolver from 'ember-resolver'; 3 | import loadInitializers from 'ember-load-initializers'; 4 | import config from 'dummy/config/environment'; 5 | 6 | export default class App extends Application { 7 | modulePrefix = config.modulePrefix; 8 | podModulePrefix = config.podModulePrefix; 9 | Resolver = Resolver; 10 | } 11 | 12 | loadInitializers(App, config.modulePrefix); 13 | -------------------------------------------------------------------------------- /tests/dummy/app/helpers/increment.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | import { helper } from '@ember/component/helper'; 3 | 4 | export function inc(params/*, hash*/) { 5 | return parseInt(params[0] || '0', 10) + 1; 6 | } 7 | 8 | export default helper(inc); 9 | -------------------------------------------------------------------------------- /tests/dummy/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {{content-for "head"}} 8 | 9 | 10 | 11 | 12 | {{content-for "head-footer"}} 13 | 14 | 15 | {{content-for "body"}} 16 | 17 | 18 | 19 | 20 | {{content-for "body-footer"}} 21 | 22 | 23 | -------------------------------------------------------------------------------- /tests/dummy/app/router.js: -------------------------------------------------------------------------------- 1 | import EmberRouter from '@ember/routing/router'; 2 | import config from 'dummy/config/environment'; 3 | 4 | export default class Router extends EmberRouter { 5 | location = config.locationType; 6 | rootURL = config.rootURL; 7 | } 8 | 9 | Router.map(function () { 10 | this.route('basicy'); 11 | this.route('slow'); 12 | this.route('fancy'); 13 | }); 14 | -------------------------------------------------------------------------------- /tests/dummy/app/routes/basicy.js: -------------------------------------------------------------------------------- 1 | import Route from '@ember/routing/route'; 2 | import { inject as service } from '@ember/service'; 3 | 4 | export default class BasicRoute extends Route { 5 | @service router; 6 | model() { 7 | return this.router.transitionTo('fancy'); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/dummy/app/routes/fancy.js: -------------------------------------------------------------------------------- 1 | import Route from '@ember/routing/route'; 2 | 3 | export default class FancyRoute extends Route {} 4 | -------------------------------------------------------------------------------- /tests/dummy/app/routes/slow.js: -------------------------------------------------------------------------------- 1 | import Route from '@ember/routing/route'; 2 | import { inject as service } from '@ember/service'; 3 | import { timeout } from 'ember-concurrency'; 4 | 5 | export default class BasicRoute extends Route { 6 | @service router; 7 | async model() { 8 | await timeout(2000); 9 | return this.router.transitionTo('fancy'); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/dummy/app/styles/app.css: -------------------------------------------------------------------------------- 1 | .self-executing-code-block { 2 | margin-bottom: 2rem; 3 | } 4 | 5 | @media only percy { 6 | .hide-in-percy { 7 | visibility: hidden; 8 | } 9 | } 10 | 11 | .border-dashed { 12 | border: 1px dashed var(--color-gray-500); 13 | } 14 | 15 | .spacer-xsmall { 16 | height: var(--spacing-1); 17 | } 18 | 19 | .spacer-small { 20 | height: var(--spacing-2); 21 | } 22 | 23 | .spacer-medium { 24 | height: var(--spacing-3); 25 | } 26 | 27 | .spacer-large { 28 | height: var(--spacing-4); 29 | } 30 | 31 | .spacer-xlarge { 32 | height: var(--spacing-5); 33 | } 34 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ember-learn/ember-styleguide/6d709151fcfb90896b41667cff9442db41edc541/tests/dummy/app/templates/.gitignore -------------------------------------------------------------------------------- /tests/dummy/app/templates/application.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{outlet}} -------------------------------------------------------------------------------- /tests/dummy/app/templates/basicy.hbs: -------------------------------------------------------------------------------- 1 | {{page-title "Basic"}} 2 | 3 |

      Basicy

      4 | {{outlet}} -------------------------------------------------------------------------------- /tests/dummy/app/templates/fancy.hbs: -------------------------------------------------------------------------------- 1 | {{page-title "Fancy"}} 2 |

      Fancy

      3 | {{outlet}} -------------------------------------------------------------------------------- /tests/dummy/app/templates/index.hbs: -------------------------------------------------------------------------------- 1 | Go to my basic route 2 | Go to my slow route -------------------------------------------------------------------------------- /tests/dummy/app/templates/slow.hbs: -------------------------------------------------------------------------------- 1 | {{page-title "Basic"}} 2 | 3 |

      Slow

      4 | {{outlet}} -------------------------------------------------------------------------------- /tests/dummy/config/ember-cli-update.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": "1.0.0", 3 | "packages": [ 4 | { 5 | "name": "ember-cli", 6 | "version": "5.12.0", 7 | "blueprints": [ 8 | { 9 | "name": "addon", 10 | "outputRepo": "https://github.com/ember-cli/ember-addon-output", 11 | "codemodsSource": "ember-addon-codemods-manifest@1", 12 | "isBaseBlueprint": true, 13 | "options": [ 14 | "--no-welcome", 15 | "--pnpm" 16 | ] 17 | } 18 | ] 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /tests/dummy/config/ember-try.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const getChannelURL = require('ember-source-channel-url'); 4 | const { embroiderSafe, embroiderOptimized } = require('@embroider/test-setup'); 5 | 6 | module.exports = async function () { 7 | return { 8 | usePnpm: true, 9 | scenarios: [ 10 | { 11 | name: 'ember-lts-3.28', 12 | npm: { 13 | devDependencies: { 14 | 'ember-source': '~3.28.0', 15 | 'ember-cli': '~4.12.0', 16 | 'ember-resolver': '^11.0.0', 17 | }, 18 | }, 19 | }, 20 | { 21 | name: 'ember-lts-4.4', 22 | npm: { 23 | devDependencies: { 24 | 'ember-source': '~4.4.0', 25 | 'ember-resolver': '^11.0.0', 26 | }, 27 | }, 28 | }, 29 | { 30 | name: 'ember-lts-4.8', 31 | npm: { 32 | devDependencies: { 33 | 'ember-source': '~4.8.0', 34 | 'ember-resolver': '^11.0.0', 35 | }, 36 | }, 37 | }, 38 | { 39 | name: 'ember-lts-4.12', 40 | npm: { 41 | devDependencies: { 42 | 'ember-source': '~4.12.0', 43 | }, 44 | }, 45 | }, 46 | { 47 | name: 'ember-lts-5.4', 48 | npm: { 49 | devDependencies: { 50 | 'ember-source': '~5.4.0', 51 | }, 52 | }, 53 | }, 54 | { 55 | name: 'ember-lts-5.8', 56 | npm: { 57 | devDependencies: { 58 | 'ember-source': '~5.8.0', 59 | }, 60 | }, 61 | }, 62 | { 63 | name: 'ember-release', 64 | npm: { 65 | devDependencies: { 66 | 'ember-source': await getChannelURL('release'), 67 | '@ember/string': '*', 68 | }, 69 | overrides: { 70 | 'ember-source': '$ember-source', 71 | }, 72 | }, 73 | }, 74 | { 75 | name: 'ember-beta', 76 | npm: { 77 | devDependencies: { 78 | 'ember-source': await getChannelURL('beta'), 79 | '@ember/string': '*', 80 | }, 81 | overrides: { 82 | 'ember-source': '$ember-source', 83 | }, 84 | }, 85 | }, 86 | { 87 | name: 'ember-canary', 88 | npm: { 89 | devDependencies: { 90 | 'ember-source': await getChannelURL('canary'), 91 | '@ember/string': '*', 92 | }, 93 | overrides: { 94 | 'ember-source': '$ember-source', 95 | }, 96 | }, 97 | }, 98 | embroiderSafe(), 99 | embroiderOptimized(), 100 | { 101 | name: 'no-deprecations', 102 | npm: { 103 | devDependencies: { 104 | 'ember-deprecation-error': '*', 105 | }, 106 | }, 107 | }, 108 | { 109 | name: 'ember-release-no-deprecations', 110 | npm: { 111 | devDependencies: { 112 | 'ember-source': await getChannelURL('release'), 113 | 'ember-deprecation-error': '*', 114 | '@ember/string': '*', 115 | }, 116 | overrides: { 117 | 'ember-source': '$ember-source', 118 | }, 119 | }, 120 | }, 121 | ], 122 | }; 123 | }; 124 | -------------------------------------------------------------------------------- /tests/dummy/config/environment.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | 'use strict'; 3 | 4 | module.exports = function (environment) { 5 | const ENV = { 6 | modulePrefix: 'dummy', 7 | environment, 8 | rootURL: '/', 9 | locationType: 'history', 10 | EmberENV: { 11 | EXTEND_PROTOTYPES: false, 12 | FEATURES: { 13 | // Here you can enable experimental features on an ember canary build 14 | // e.g. EMBER_NATIVE_DECORATOR_SUPPORT: true 15 | }, 16 | }, 17 | 18 | APP: { 19 | // Here you can pass flags/options to your application instance 20 | // when it is created 21 | }, 22 | 23 | fastboot: { 24 | hostWhitelist: [/^localhost:\d+$/] 25 | }, 26 | 27 | 'field-guide': { 28 | name: 'Ember', 29 | tagLine: 'Ember Styleguide', 30 | logo: '/ember-logo.png', 31 | copyright: 'Ember Field Guide is designed to document the [ember-styleguide](https://github.com/ember-learn/ember-styleguide) project. For more information view the [README](https://github.com/ember-learn/ember-styleguide),', 32 | github: 'https://github.com/ember-learn/ember-styleguide' 33 | }, 34 | 35 | historySupportMiddleware: true, 36 | }; 37 | 38 | if (environment === 'development') { 39 | // ENV.APP.LOG_RESOLVER = true; 40 | // ENV.APP.LOG_ACTIVE_GENERATION = true; 41 | // ENV.APP.LOG_TRANSITIONS = true; 42 | // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; 43 | // ENV.APP.LOG_VIEW_LOOKUPS = true; 44 | } 45 | 46 | if (environment === 'test') { 47 | // Testem prefers this... 48 | ENV.locationType = 'none'; 49 | 50 | // keep test console output quieter 51 | ENV.APP.LOG_ACTIVE_GENERATION = false; 52 | ENV.APP.LOG_VIEW_LOOKUPS = false; 53 | 54 | ENV.APP.rootElement = '#ember-testing'; 55 | ENV.APP.autoboot = false; 56 | } 57 | 58 | if (environment === 'production') { 59 | // here you can enable a production-specific feature 60 | } 61 | 62 | return ENV; 63 | }; 64 | -------------------------------------------------------------------------------- /tests/dummy/config/optional-features.json: -------------------------------------------------------------------------------- 1 | { 2 | "application-template-wrapper": false, 3 | "default-async-observers": true, 4 | "jquery-integration": false, 5 | "template-only-glimmer-components": true 6 | } 7 | -------------------------------------------------------------------------------- /tests/dummy/config/targets.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const browsers = [ 4 | 'last 1 Chrome versions', 5 | 'last 1 Firefox versions', 6 | 'last 1 Safari versions', 7 | ]; 8 | 9 | module.exports = { 10 | browsers, 11 | node: 'current', 12 | }; 13 | -------------------------------------------------------------------------------- /tests/dummy/public/robots.txt: -------------------------------------------------------------------------------- 1 | # http://www.robotstxt.org 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /tests/helpers/index.js: -------------------------------------------------------------------------------- 1 | import { 2 | setupApplicationTest as upstreamSetupApplicationTest, 3 | setupRenderingTest as upstreamSetupRenderingTest, 4 | setupTest as upstreamSetupTest, 5 | } from 'ember-qunit'; 6 | 7 | // This file exists to provide wrappers around ember-qunit's 8 | // test setup functions. This way, you can easily extend the setup that is 9 | // needed per test type. 10 | 11 | function setupApplicationTest(hooks, options) { 12 | upstreamSetupApplicationTest(hooks, options); 13 | 14 | // Additional setup for application tests can be done here. 15 | // 16 | // For example, if you need an authenticated session for each 17 | // application test, you could do: 18 | // 19 | // hooks.beforeEach(async function () { 20 | // await authenticateSession(); // ember-simple-auth 21 | // }); 22 | // 23 | // This is also a good place to call test setup functions coming 24 | // from other addons: 25 | // 26 | // setupIntl(hooks, 'en-us'); // ember-intl 27 | // setupMirage(hooks); // ember-cli-mirage 28 | } 29 | 30 | function setupRenderingTest(hooks, options) { 31 | upstreamSetupRenderingTest(hooks, options); 32 | 33 | // Additional setup for rendering tests can be done here. 34 | } 35 | 36 | function setupTest(hooks, options) { 37 | upstreamSetupTest(hooks, options); 38 | 39 | // Additional setup for unit tests can be done here. 40 | } 41 | 42 | export { setupApplicationTest, setupRenderingTest, setupTest }; 43 | -------------------------------------------------------------------------------- /tests/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Dummy Tests 6 | 7 | 8 | 9 | {{content-for "head"}} 10 | {{content-for "test-head"}} 11 | 12 | 13 | 14 | 15 | 16 | {{content-for "head-footer"}} 17 | {{content-for "test-head-footer"}} 18 | 19 | 20 | {{content-for "body"}} 21 | {{content-for "test-body"}} 22 | 23 |
      24 |
      25 |
      26 |
      27 |
      28 |
      29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | {{content-for "body-footer"}} 37 | {{content-for "test-body-footer"}} 38 | 39 | 40 | -------------------------------------------------------------------------------- /tests/integration/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ember-learn/ember-styleguide/6d709151fcfb90896b41667cff9442db41edc541/tests/integration/.gitkeep -------------------------------------------------------------------------------- /tests/integration/components/es-banner-test.js: -------------------------------------------------------------------------------- 1 | import { module, test } from 'qunit'; 2 | import { setupRenderingTest } from 'ember-qunit'; 3 | import { render } from '@ember/test-helpers'; 4 | import { hbs } from 'ember-cli-htmlbars'; 5 | 6 | module('Integration | Component | es-banner', function (hooks) { 7 | setupRenderingTest(hooks); 8 | 9 | test('it renders', async function (assert) { 10 | await render(hbs` 11 | 12 | I have an announcement to make 13 | 14 | `); 15 | 16 | assert 17 | .dom('[data-test-es-banner]') 18 | .hasText('I have an announcement to make', 'We see the correct message'); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /tests/integration/components/es-button-test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | import { click, render } from '@ember/test-helpers'; 3 | import { module, test, skip } from 'qunit'; 4 | import { setupRenderingTest } from 'ember-qunit'; 5 | import { setProperties, set } from '@ember/object'; 6 | import hbs from 'htmlbars-inline-precompile'; 7 | import sinon from 'sinon'; 8 | 9 | module('Integration | Component | es button', function(hooks){ 10 | setupRenderingTest(hooks); 11 | 12 | test('it renders', async function(assert) { 13 | await render(hbs`{{es-button}}`); 14 | 15 | assert.dom(this.element).hasText(''); 16 | 17 | await render(hbs` 18 | {{#es-button}} 19 | template block text 20 | {{/es-button}} 21 | `); 22 | 23 | assert.dom(this.element).hasText('template block text'); 24 | }); 25 | 26 | test('has html button tag and base class', async function(assert) { 27 | await render(hbs`{{es-button}}`); 28 | assert.dom('button').exists('has button tag'); 29 | assert.ok(document.querySelector('.es-button'), 'has base es-button class'); 30 | }); 31 | 32 | test('can display set label', async function(assert) { 33 | const label = 'Button Label'; 34 | 35 | setProperties(this, { label }); 36 | 37 | await render(hbs` 38 | {{es-button 39 | label=this.label 40 | }} 41 | `); 42 | 43 | assert.dom(this.element).hasText(label, 'displays button label'); 44 | }); 45 | 46 | test('calls closure function when clicked', async function(assert) { 47 | const onClicked = sinon.spy(); 48 | 49 | setProperties(this, { onClicked }); 50 | 51 | await render(hbs`{{es-button onClicked=this.onClicked}}`); 52 | await click('button'); 53 | 54 | assert.ok(onClicked.calledOnce, 'onClicked called'); 55 | }); 56 | 57 | skip('can disable button', async function(assert) { 58 | const disabled = false; 59 | 60 | setProperties(this, { disabled}); 61 | 62 | await render(hbs`{{es-button isDisabled=true}}`); 63 | 64 | assert.dom('.es-button').hasAttribute('disabled'); 65 | }); 66 | 67 | skip('displays set data-role', async function(assert) { 68 | const dataRole = 'some-data-role'; 69 | 70 | setProperties(this, { dataRole }); 71 | 72 | await render(hbs`{{es-button}}`); 73 | 74 | assert.dom('.es-button').hasAttribute('data-role'); 75 | }); 76 | 77 | test('does not render aria-pressed unless set', async function(assert) { 78 | const ariaPressed = 'false'; 79 | 80 | setProperties(this, { ariaPressed }); 81 | 82 | await render(hbs``); 83 | 84 | assert.dom('.es-button').doesNotHaveAttribute('aria-pressed') 85 | 86 | set(this, 'ariaPressed', null); 87 | 88 | await render(hbs``); 89 | 90 | assert.dom('.es-button').hasAttribute('aria-pressed', 'true') 91 | }); 92 | }); 93 | -------------------------------------------------------------------------------- /tests/integration/components/es-card-test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | import { render } from '@ember/test-helpers'; 3 | import { module, test } from 'qunit'; 4 | import { setupRenderingTest } from 'ember-qunit'; 5 | import hbs from 'htmlbars-inline-precompile'; 6 | 7 | module('Integration | Component | es card', function(hooks){ 8 | setupRenderingTest(hooks); 9 | 10 | test('it renders', async function(assert) { 11 | 12 | // Set any properties with this.set('myProperty', 'value'); 13 | // Handle any actions with this.on('myAction', function(val) { ... }); 14 | 15 | await render(hbs`{{es-card}}`); 16 | assert.dom('*').hasText(''); 17 | 18 | 19 | // Template block usage: 20 | await render(hbs` 21 | {{#es-card}} 22 | template block text 23 | {{/es-card}} 24 | `); 25 | 26 | assert.dom(this.element).hasText('template block text'); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /tests/integration/components/es-footer-test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier, qunit/no-assert-equal */ 2 | import { module, test } from 'qunit'; 3 | import { setupRenderingTest } from 'ember-qunit'; 4 | import { render } from '@ember/test-helpers'; 5 | import hbs from 'htmlbars-inline-precompile'; 6 | 7 | module('Integration | Component | es footer', function(hooks) { 8 | setupRenderingTest(hooks); 9 | 10 | test('it renders', async function(assert) { 11 | await render(hbs``); 12 | 13 | const footerSocialLinks = this.element.querySelectorAll('.footer-social a'); 14 | const footerContribtuionsLinks = this.element.querySelectorAll('.footer-contributions a'); 15 | 16 | assert.equal(footerSocialLinks.length, 4, 'social links are loading'); 17 | assert.equal(footerContribtuionsLinks.length, 5, 'contributors links are loading'); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /tests/integration/components/es-header-test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | import { click, render } from '@ember/test-helpers'; 3 | import { setProperties } from '@ember/object'; 4 | import { module, test } from 'qunit'; 5 | import { setupRenderingTest } from 'ember-qunit'; 6 | import hbs from 'htmlbars-inline-precompile'; 7 | 8 | const customHomeUrl = 'https://github.com/emberjs'; 9 | 10 | module('Integration | Component | es header', function(hooks) { 11 | setupRenderingTest(hooks); 12 | 13 | test('it uses the header HTML element with correct attributes', async function(assert) { 14 | await render(hbs``); 15 | 16 | assert.dom('header').exists({ count: 1 }); 17 | assert.dom('header').hasClass('es-header'); 18 | assert.dom('header').hasAttribute('role', 'banner'); 19 | }); 20 | 21 | test('it renders the logo', async function(assert) { 22 | await render(hbs``); 23 | 24 | assert.dom('.navbar-brand').hasAttribute('src', '/images/ember-logo.svg'); 25 | }); 26 | 27 | test('it renders the link to the Ember homepage by default', async function(assert) { 28 | await render(hbs``); 29 | 30 | assert.dom('.navbar-brand-wrapper').hasAttribute('href', 'https://www.emberjs.com'); 31 | }); 32 | 33 | test('it renders a link to a custom homepage', async function(assert) { 34 | setProperties(this, { customHomeUrl }); 35 | await render(hbs``); 36 | 37 | assert.dom('.navbar-brand-wrapper').hasAttribute('href', customHomeUrl); 38 | }); 39 | 40 | test('it renders custom content at the end', async function(assert) { 41 | await render(hbs` 42 | 43 | Custom content 44 | 45 | `); 46 | 47 | assert.dom('.navbar-end').containsText('Custom content'); 48 | }); 49 | 50 | test('it renders the navbar collapsed by default', async function(assert) { 51 | await render(hbs``); 52 | 53 | assert.dom('.es-navbar').doesNotHaveClass('navbar-expanded'); 54 | assert.dom('.navbar-toggler').containsText('Show Site Navigation'); 55 | }); 56 | 57 | test('it toggles the navbar when click the toggler', async function(assert) { 58 | await render(hbs``); 59 | 60 | await click('.navbar-toggler'); 61 | 62 | assert.dom('.es-navbar').hasClass('navbar-expanded'); 63 | assert.dom('.navbar-toggler').containsText('Hide Site Navigation'); 64 | 65 | await click('.navbar-toggler'); 66 | 67 | assert.dom('.es-navbar').doesNotHaveClass('navbar-expanded'); 68 | assert.dom('.navbar-toggler').containsText('Show Site Navigation'); 69 | }); 70 | }); 71 | -------------------------------------------------------------------------------- /tests/integration/components/es-note-test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | import { find, render } from '@ember/test-helpers'; 3 | import { module, test } from 'qunit'; 4 | import { setupRenderingTest } from 'ember-qunit'; 5 | import hbs from 'htmlbars-inline-precompile'; 6 | 7 | module('Integration | Component | es note', function(hooks){ 8 | setupRenderingTest(hooks); 9 | 10 | test('it renders', async function(assert) { 11 | await render(hbs``); 12 | 13 | assert.dom('[data-test-es-note-heading]').hasText('Tomster says...'); 14 | 15 | await render(hbs` 16 | 17 | template block text 18 | 19 | `); 20 | 21 | assert.dom('.cta-note-message').hasText('template block text'); 22 | }); 23 | 24 | test('out of 2 mascots randomly selects each at least 1 in 15 renders', async function(assert) { 25 | const renderedNames = []; 26 | 27 | for (let i = 0; i < 15; i++) { 28 | let name; 29 | 30 | await render(hbs``); 31 | name = find('[data-test-es-note-heading]').textContent.trim().split(' ')[0]; 32 | 33 | renderedNames.push(name); 34 | } 35 | 36 | assert.ok( 37 | renderedNames.includes('Tomster'), 38 | 'Tomster rendered' 39 | ); 40 | 41 | assert.ok( 42 | renderedNames.includes('Zoey'), 43 | 'Zoey rendered' 44 | ); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /tests/integration/components/es-pagination-test.js: -------------------------------------------------------------------------------- 1 | import { module, test } from 'qunit'; 2 | import { setupRenderingTest } from 'ember-qunit'; 3 | import { render } from '@ember/test-helpers'; 4 | import { hbs } from 'ember-cli-htmlbars'; 5 | 6 | module('Integration | Component | es-pagination', function (hooks) { 7 | setupRenderingTest(hooks); 8 | 9 | test('it renders', async function (assert) { 10 | await render(hbs` 11 | 12 | <:previous> 13 | Newer articles 14 | 15 | <:next> 16 | Older articles 17 | 18 | 19 | `); 20 | 21 | assert.dom(this.element).hasText('Newer articles Older articles'); 22 | }); 23 | test('it renders only previous', async function (assert) { 24 | await render(hbs` 25 | 26 | <:previous> 27 | Newer articles 28 | 29 | <:next> 30 | Older articles 31 | 32 | 33 | `); 34 | 35 | assert.dom(this.element).hasText('Newer articles'); 36 | assert.dom(this.element).doesNotIncludeText('Older articles'); 37 | }); 38 | test('it renders only next', async function (assert) { 39 | await render(hbs` 40 | 41 | <:previous> 42 | Newer articles 43 | 44 | <:next> 45 | Older articles 46 | 47 | 48 | `); 49 | 50 | assert.dom(this.element).hasText('Older articles'); 51 | assert.dom(this.element).doesNotIncludeText('Newer articles'); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /tests/integration/components/es-progress-bar-test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prettier/prettier */ 2 | import { render } from '@ember/test-helpers'; 3 | import { module, test } from 'qunit'; 4 | import { setupRenderingTest } from 'ember-qunit'; 5 | import hbs from 'htmlbars-inline-precompile'; 6 | 7 | module('Integration | Component | es progress bar', function (hooks) { 8 | setupRenderingTest(hooks); 9 | 10 | test('it renders', async function (assert) { 11 | await render(hbs``); 12 | 13 | assert.dom('.progress-bar').exists('progress bar exists'); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /tests/integration/components/es-sidebar-test.js: -------------------------------------------------------------------------------- 1 | import { module, test } from 'qunit'; 2 | import { setupRenderingTest } from 'ember-qunit'; 3 | import { render, click } from '@ember/test-helpers'; 4 | import { hbs } from 'ember-cli-htmlbars'; 5 | 6 | module('Integration | Component | es-sidebar', function (hooks) { 7 | setupRenderingTest(hooks); 8 | 9 | test('it renders correctly in desktop mode', async function (assert) { 10 | await render(hbs`Test`); 11 | 12 | assert.dom('.es-sidebar .es-sidebar-content').hasText('Test'); 13 | assert.dom('.es-sidebar-toggle').exists(); 14 | assert.dom('.es-sidebar-toggle').isNotVisible(); 15 | assert.dom('.es-sidebar-close').exists(); 16 | assert.dom('.es-sidebar-close').isNotVisible(); 17 | }); 18 | 19 | test('it opens/closes', async function (assert) { 20 | await render(hbs`Test`); 21 | 22 | assert.dom('.es-sidebar').hasAttribute('aria-expanded', 'false'); 23 | 24 | await click('.es-sidebar-toggle'); 25 | assert.dom('.es-sidebar').hasAttribute('aria-expanded', 'true'); 26 | 27 | await click('.es-sidebar-close'); 28 | assert.dom('.es-sidebar').hasAttribute('aria-expanded', 'false'); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /tests/test-helper.js: -------------------------------------------------------------------------------- 1 | import Application from 'dummy/app'; 2 | import config from 'dummy/config/environment'; 3 | import * as QUnit from 'qunit'; 4 | import { setApplication } from '@ember/test-helpers'; 5 | import { setup } from 'qunit-dom'; 6 | import { start } from 'ember-qunit'; 7 | 8 | setApplication(Application.create(config.APP)); 9 | 10 | setup(QUnit.assert); 11 | 12 | start(); 13 | -------------------------------------------------------------------------------- /tests/unit/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ember-learn/ember-styleguide/6d709151fcfb90896b41667cff9442db41edc541/tests/unit/.gitkeep --------------------------------------------------------------------------------