├── .editorconfig
├── .ember-cli
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .netlifyheaders
├── .netlifyredirects
├── .travis.yml
├── .watchmanconfig
├── README.md
├── app.json
├── app
├── adapters
│ ├── application.js
│ └── version.js
├── app.js
├── components
│ ├── .gitkeep
│ ├── chapter-links.js
│ ├── dropdown-header.js
│ ├── guides-article.js
│ ├── link-to.js
│ ├── search-input.js
│ ├── search-result.js
│ └── table-of-contents.js
├── controllers
│ ├── .gitkeep
│ ├── application.js
│ └── version.js
├── helpers
│ ├── .gitkeep
│ └── shorten-version.js
├── index.html
├── initializers
│ └── regiser-showdown-extenions.js
├── locations
│ └── trailing-history.js
├── models
│ ├── .gitkeep
│ ├── content.js
│ ├── page.js
│ └── version.js
├── resolver.js
├── router.js
├── routes
│ ├── .gitkeep
│ ├── application.js
│ ├── error.js
│ ├── index.js
│ ├── version.js
│ └── version
│ │ ├── index.js
│ │ └── show.js
├── services
│ ├── head-data.js
│ ├── page.js
│ └── search.js
├── styles
│ ├── _code-block-file-name.scss
│ ├── _prism-overrides.scss
│ ├── _search-input.scss
│ ├── _table-of-contents.scss
│ └── app.scss
└── templates
│ ├── application.hbs
│ ├── components
│ ├── .gitkeep
│ ├── chapter-links.hbs
│ ├── dropdown-header.hbs
│ ├── guides-article.hbs
│ ├── search-input.hbs
│ ├── search-result.hbs
│ └── table-of-contents.hbs
│ ├── error.hbs
│ ├── version.hbs
│ └── version
│ ├── index.hbs
│ └── show.hbs
├── appveyor.yml
├── config
├── deploy.js
├── environment.js
└── targets.js
├── ember-cli-build.js
├── lib
└── content-guides-generator
│ ├── index.js
│ └── package.json
├── package-lock.json
├── package.json
├── public
├── fonts
│ ├── config.json
│ ├── fontello.eot
│ ├── fontello.svg
│ ├── fontello.ttf
│ ├── fontello.woff
│ └── fontello.woff2
├── images
│ └── logos
│ │ ├── ember.png
│ │ └── search-by-algolia.svg
└── robots.txt
├── static.json
├── testem.js
├── tests
├── acceptance
│ ├── cookbook-test.js
│ ├── current-url-test.js
│ ├── error-page-test.js
│ ├── meta-data-test.js
│ ├── previous-next-links-test.js
│ ├── table-of-contents-test.js
│ ├── version-menu-test.js
│ └── visual-regression-test.js
├── helpers
│ ├── .gitkeep
│ └── start-app.js
├── index.html
├── integration
│ ├── components
│ │ ├── dropdown-header-test.js
│ │ └── search-input-test.js
│ └── helpers
│ │ └── shorten-version-test.js
├── test-helper.js
└── unit
│ └── services
│ ├── head-data-test.js
│ └── search-test.js
└── vendor
├── .gitkeep
└── ember-cli-spinkit
├── styles
└── spinkit-cube-grid.css
└── templates
└── components
└── spinkit-cube-grid.hbs
/.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 | [*]
9 | end_of_line = lf
10 | charset = utf-8
11 | trim_trailing_whitespace = true
12 | insert_final_newline = true
13 | indent_style = space
14 | indent_size = 2
15 |
16 | [*.hbs]
17 | insert_final_newline = false
18 |
19 | [*.{diff,md}]
20 | trim_trailing_whitespace = false
21 |
--------------------------------------------------------------------------------
/.ember-cli:
--------------------------------------------------------------------------------
1 | {
2 | /**
3 | Ember CLI sends analytics information by default. The data is completely
4 | anonymous, but there are times when you might want to disable this behavior.
5 |
6 | Setting `disableAnalytics` to true will prevent any data from being sent.
7 | */
8 | "disableAnalytics": false
9 | }
10 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | /blueprints/*/files/**/*.js
2 | # unconventional js
3 | /blueprints/*/files/
4 | /vendor/
5 |
6 | # compiled output
7 | /dist/
8 | /tmp/
9 |
10 | # dependencies
11 | /bower_components/
12 |
13 | # misc
14 | /coverage/
15 | !.*
16 |
17 | # ember-try
18 | /.node_modules.ember-try/
19 | /bower.json.ember-try
20 | /package.json.ember-try
21 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parserOptions: {
4 | ecmaVersion: 2017,
5 | sourceType: 'module'
6 | },
7 | plugins: [
8 | 'ember'
9 | ],
10 | extends: [
11 | 'eslint:recommended',
12 | 'plugin:ember/recommended'
13 | ],
14 | env: {
15 | browser: true
16 | },
17 | rules: {
18 | },
19 | globals: {
20 | Prism: true,
21 | compareVersions: true
22 | },
23 | overrides: [
24 | // node files
25 | {
26 | files: [
27 | 'ember-cli-build.js',
28 | 'testem.js',
29 | 'blueprints/*/index.js',
30 | 'config/**/*.js',
31 | 'lib/*/index.js'
32 | ],
33 | parserOptions: {
34 | sourceType: 'script',
35 | ecmaVersion: 2015
36 | },
37 | env: {
38 | browser: false,
39 | node: true
40 | }
41 | },
42 |
43 | // test files
44 | {
45 | files: ['tests/**/*.js'],
46 | excludedFiles: ['tests/dummy/**/*.js'],
47 | env: {
48 | embertest: true
49 | }
50 | }
51 | ]
52 | };
53 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # compiled output
4 | /dist
5 | /tmp
6 |
7 | # dependencies
8 | /node_modules
9 | /bower_components
10 |
11 | # misc
12 | /.sass-cache
13 | /connect.lock
14 | /coverage/*
15 | /libpeerconnection.log
16 | npm-debug.log*
17 | yarn-error.log
18 | testem.log
19 | .DS_Store
20 |
21 | # ember-try
22 | .node_modules.ember-try/
23 | bower.json.ember-try
24 | package.json.ember-try
25 |
26 | # Deployment credentials
27 | config/credentials.json
28 |
29 | .vscode
30 |
--------------------------------------------------------------------------------
/.netlifyheaders:
--------------------------------------------------------------------------------
1 | /*/
2 | Cache-Control: public, max-age=3600
3 |
4 | /content/*
5 | Cache-Control: public, max-age=3600
6 |
7 | /assets/*
8 | Cache-Control: public, max-age=31536000
9 |
--------------------------------------------------------------------------------
/.netlifyredirects:
--------------------------------------------------------------------------------
1 | / /release/
2 | /current/* /release/:splat
3 | /* /_empty.html 200
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | ---
2 | language: node_js
3 | node_js:
4 | - "8"
5 |
6 | sudo: required
7 | dist: trusty
8 |
9 | branches:
10 | only:
11 | - master
12 |
13 | addons:
14 | chrome: stable
15 |
16 | cache:
17 | directories:
18 | - $HOME/.npm
19 |
20 | env:
21 | global:
22 | # See https://git.io/vdao3 for details.
23 | - JOBS=1
24 | - PERCY_TOKEN=877df6aad8486060f69a34864b6cd33f870633743b23411343737c46a875a762
25 |
26 | before_install:
27 | - npm config set spin false
28 |
29 | script:
30 | - npm run lint:js
31 | - ember build --prod
32 | - npm test
33 |
34 | after_failure:
35 | - wget https://gist.github.com/sivakumar-kailasam/730c6d2e5d0847cf9e0bc17df386c852/raw/discord_notifier.sh
36 | - chmod +x discord_notifier.sh
37 | - ./discord_notifier.sh
38 |
--------------------------------------------------------------------------------
/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {
2 | "ignore_dirs": ["tmp", "dist"]
3 | }
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # [deprecated] Ember Guides App
2 |
3 | This repository was the source for the Ember App that used to power the [Ember.js Guides](https://guides.emberjs.com/release/). This work has since been extracted into [Guidemaker](https://github.com/empress/guidemaker) and the [Guidemaker Ember Template](https://github.com/ember-learn/guidemaker-ember-template).
4 |
5 | The source for the guides is still avaliable in the same place in the [Guides Source](https://github.com/ember-learn/guides-source) repository.
6 |
7 | ## Contributing
8 |
9 | All further work will be done on [Guidemaker](https://github.com/empress/guidemaker), the [Guidemaker Ember Template](https://github.com/ember-learn/guidemaker-ember-template) and [Guides Source](https://github.com/ember-learn/guides-source).
10 |
11 | If you are interested in contributing then you can check out the [contributing instructions for the Guides Source](https://github.com/ember-learn/guides-source/blob/master/CONTRIBUTING.md).
12 |
13 | If you have questions you can join the #dev-ember-learning channel in the [Ember Community Discord](https://discordapp.com/invite/zT3asNS).
14 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "guides-app",
3 | "description": "The ember.js guides app",
4 | "scripts": {
5 | },
6 | "env": {
7 | },
8 | "formation": {
9 | "web": {
10 | "quantity": 1
11 | }
12 | },
13 | "addons": [
14 |
15 | ],
16 | "buildpacks": [
17 | {
18 | "url": "https://github.com/stonecircle/heroku-buildpack-ember-static"
19 | }
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/app/adapters/application.js:
--------------------------------------------------------------------------------
1 | import DS from 'ember-data';
2 |
3 | export default DS.JSONAPIAdapter.extend({
4 | buildURL(modelName, id, snapshot, requestType, query) {
5 | let url;
6 |
7 | if (requestType === 'queryRecord') {
8 | url = [modelName, query.version, `${query.path}.json`];
9 | } else if(requestType === 'query' && modelName === 'page') {
10 | url = ['content', query.version, 'pages.json'];
11 | } else {
12 | return this._super(...arguments);
13 | }
14 |
15 | let host = this.host;
16 | let prefix = this.urlPrefix();
17 |
18 | if (prefix) { url.unshift(prefix); }
19 |
20 | url = url.join('/');
21 | if (!host && url && url.charAt(0) !== '/') {
22 | url = '/' + url;
23 | }
24 |
25 | return url;
26 | },
27 | });
28 |
--------------------------------------------------------------------------------
/app/adapters/version.js:
--------------------------------------------------------------------------------
1 | import DS from 'ember-data';
2 |
3 | export default DS.JSONAPIAdapter.extend({
4 | buildURL() {
5 | let url = ['content', 'versions.json'];
6 | let host = this.host;
7 | let prefix = this.urlPrefix();
8 |
9 | if (prefix) { url.unshift(prefix); }
10 |
11 | url = url.join('/');
12 | if (!host && url && url.charAt(0) !== '/') {
13 | url = '/' + url;
14 | }
15 |
16 | return url;
17 | },
18 | });
19 |
--------------------------------------------------------------------------------
/app/app.js:
--------------------------------------------------------------------------------
1 | import Application from '@ember/application';
2 | import Resolver from './resolver';
3 | import loadInitializers from 'ember-load-initializers';
4 | import config from './config/environment';
5 |
6 | const App = Application.extend({
7 | modulePrefix: config.modulePrefix,
8 | podModulePrefix: config.podModulePrefix,
9 | Resolver
10 | });
11 |
12 | loadInitializers(App, config.modulePrefix);
13 |
14 | export default App;
15 |
--------------------------------------------------------------------------------
/app/components/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ember-learn/guides-app/2e3a25fd3b924d6ced52d15d65f19232cc3145b3/app/components/.gitkeep
--------------------------------------------------------------------------------
/app/components/chapter-links.js:
--------------------------------------------------------------------------------
1 | import Component from '@ember/component';
2 | import { get, computed } from '@ember/object';
3 | import { inject as service } from '@ember/service';
4 |
5 | export default Component.extend({
6 | tagName: 'footer',
7 |
8 | page: service(),
9 |
10 | nextSectionPage: computed('page.nextSection.pages.[]', function() {
11 | let pages = get(this, 'page.nextSection.pages');
12 |
13 | if(pages && pages.length) {
14 | return pages[0];
15 | }
16 | }),
17 | previousSectionPage: computed('page.previousSection.pages.[]', function() {
18 | let pages = get(this, 'page.previousSection.pages');
19 |
20 | if(pages && pages.length) {
21 | return pages[pages.length - 1];
22 | }
23 | })
24 | });
25 |
--------------------------------------------------------------------------------
/app/components/dropdown-header.js:
--------------------------------------------------------------------------------
1 | import Component from '@ember/component';
2 |
3 | export default Component.extend({
4 | classNames: ['ds-suggestion']
5 | });
6 |
--------------------------------------------------------------------------------
/app/components/guides-article.js:
--------------------------------------------------------------------------------
1 | import Component from '@ember/component';
2 | import { inject as service } from '@ember/service';
3 |
4 | export default Component.extend({
5 | tagName: 'article',
6 | classNames: 'chapter',
7 | page: service(),
8 | didRender() {
9 |
10 | let nodeList = this.$('pre:not(.no-line-numbers) > code');
11 |
12 | if (nodeList) {
13 | nodeList.each((index, code) => {
14 | code.parentNode.classList.add('line-numbers');
15 | });
16 | }
17 |
18 | let filenameNodeList = this.$('pre > code[data-filename]');
19 |
20 | if (filenameNodeList) {
21 | filenameNodeList.each((index, code) => {
22 | if (code.parentNode.parentNode.classList.contains('filename')) {
23 | //do nothing
24 | return;
25 | }
26 |
27 | let filename = code.attributes['data-filename'].value;
28 | let match = filename.match(/\.(\w+)$/);
29 |
30 | let ext = '';
31 |
32 | if (match && match[1]) {
33 | ext = match[1];
34 | }
35 |
36 | this.$(code.parentNode).wrap(`
`);
37 |
38 | this.$(code.parentNode.parentNode).prepend(this.$(`${code.attributes['data-filename'].value} `));
39 | this.$(code.parentNode.parentNode).prepend('
');
40 | });
41 | }
42 |
43 | let allHeaders = document.querySelectorAll("h1, h2, h3, h4, h5, h6")
44 |
45 | for (var element of allHeaders) {
46 | if (element.id) {
47 | element.className = 'anchorable-toc'
48 | let link = document.createElement('a');
49 | link.className = 'toc-anchor';
50 | link.href = `#${element.id}`;
51 | element.insertBefore(link, element.firstElementChild);
52 | }
53 | }
54 |
55 | Prism.highlightAll();
56 |
57 | /**
58 | * Prism doesn't support diff & a secondary language highlighting.
59 | *
60 | * So first, we let prism convert the content of `
` blocks
61 | * from a string into a different dom structure
62 | * by calling `Prism.highlightAll()`
63 | *
64 | * In the following block, we add + & - symbols to the lines inside the
65 | * code block based on the data-diff attribute on the code tag.
66 | * e.g., data-diff="-4,+5,+6,+7"
67 | *
68 | **/
69 | filenameNodeList.each((_, codeBlock) => {
70 |
71 | let diffInfo = codeBlock.attributes['data-diff'] ? codeBlock.attributes["data-diff"].value.split(',') : [];
72 |
73 | if (diffInfo.length === 0) {
74 | return;
75 | }
76 |
77 | let lines = codeBlock.innerHTML.split('\n');
78 |
79 | diffInfo.forEach(pD => {
80 | let operator = pD[0];
81 | let lineNo = +(pD.replace(operator, ''));
82 | let text = lines[lineNo - 1];
83 | if (operator === '+') {
84 | lines[lineNo - 1] = `+ ${text} `;
85 | } else {
86 | lines[lineNo - 1] = `- ${text} `;
87 | }
88 | });
89 | codeBlock.innerHTML = lines.join('\n');
90 | })
91 |
92 | }
93 | });
94 |
--------------------------------------------------------------------------------
/app/components/link-to.js:
--------------------------------------------------------------------------------
1 | import LinkComponent from '@ember/routing/link-component';
2 |
3 | export default LinkComponent.extend({
4 | click() {
5 | if(window.scrollTo) {
6 | window.scrollTo(0,0);
7 | }
8 |
9 | if(document) {
10 | document.getElementById('toc-toggle').checked = false;
11 | }
12 | }
13 | });
14 |
--------------------------------------------------------------------------------
/app/components/search-input.js:
--------------------------------------------------------------------------------
1 | import { getOwner } from '@ember/application';
2 | import Component from '@ember/component';
3 | import { get, set } from '@ember/object';
4 | import { and } from '@ember/object/computed';
5 | import { inject as service } from '@ember/service';
6 | import { task, timeout } from 'ember-concurrency';
7 |
8 | const SEARCH_DEBOUNCE_PERIOD = 300;
9 | const SEARCH_CLOSE_PERIOD = 200;
10 |
11 | export default Component.extend({
12 | classNames: ['search-input'],
13 |
14 | // page: service(),
15 | searchService: service('search'),
16 |
17 | _resultTetherConstraints: Object.freeze([
18 | {
19 | to: 'window',
20 | pin: ['left','right']
21 | }
22 | ]),
23 |
24 | _focused: false,
25 |
26 | init() {
27 | this._super(...arguments);
28 | const config = getOwner(this).resolveRegistration('config:environment');
29 | this.deprecationsGuideURL = config['deprecationsGuideURL'];
30 | },
31 |
32 | showDropdown: and('query', '_focused'),
33 |
34 | search: task(function * (query) {
35 |
36 | yield timeout(SEARCH_DEBOUNCE_PERIOD);
37 |
38 | set(this, 'query', query);
39 |
40 | // Hide and don't run query if there's no search query
41 | if (!query) {
42 | return set(this, '_focused', false);
43 | }
44 |
45 | // ensure search results are visible if the menu was previously closed above
46 | set(this, '_focused', true);
47 |
48 | yield get(this, 'searchService.search').perform(query, this.projectVersion);
49 |
50 | }).restartable(),
51 |
52 | closeMenu: task(function * () {
53 | yield timeout(SEARCH_CLOSE_PERIOD);
54 |
55 | set(this, '_focused', false);
56 | }),
57 |
58 | actions: {
59 | onfocus() {
60 | set(this, '_focused', true);
61 | },
62 |
63 | onblur() {
64 | this.get('closeMenu').perform();
65 | }
66 |
67 | }
68 | });
69 |
--------------------------------------------------------------------------------
/app/components/search-result.js:
--------------------------------------------------------------------------------
1 | import Component from '@ember/component';
2 | import { computed } from '@ember/object';
3 | import { inject as service } from '@ember/service';
4 |
5 | export default Component.extend({
6 | classNames: ['ds-suggestion'],
7 |
8 | page: service(),
9 | sectionTitle: computed('result.path', function() {
10 | let sectionId = this.result.path.split('/')[0];
11 |
12 | let section = this.page.pages.find((page) => page.id === sectionId);
13 | return section.title;
14 | }),
15 |
16 | pageHeading: computed('result._highlightResult.headings.[]', function() {
17 | return this.result._highlightResult.headings[0];
18 | }),
19 |
20 | remainingHeadings: computed('result._highlightResult.headings.[]', function() {
21 | return this.result._highlightResult.headings;
22 | })
23 | });
24 |
--------------------------------------------------------------------------------
/app/components/table-of-contents.js:
--------------------------------------------------------------------------------
1 | import Component from '@ember/component';
2 | import { computed } from '@ember/object';
3 | import { inject as service } from '@ember/service';
4 |
5 | export default Component.extend({
6 | fastboot: service(),
7 |
8 | level: '0',
9 | tagName: 'ol',
10 | tocLevel: computed('level', function() {
11 | return `toc-level-${this.level}`;
12 | }),
13 | classNameBindings: ['tocLevel'],
14 | });
15 |
--------------------------------------------------------------------------------
/app/controllers/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ember-learn/guides-app/2e3a25fd3b924d6ced52d15d65f19232cc3145b3/app/controllers/.gitkeep
--------------------------------------------------------------------------------
/app/controllers/application.js:
--------------------------------------------------------------------------------
1 | import Controller from '@ember/controller';
2 | import { inject as service } from '@ember/service';
3 |
4 | export default Controller.extend({
5 | page: service(),
6 | });
7 |
--------------------------------------------------------------------------------
/app/controllers/version.js:
--------------------------------------------------------------------------------
1 | import Controller, {
2 | inject as controller,
3 | } from '@ember/controller';
4 | import { get, computed } from '@ember/object';
5 | import { alias } from '@ember/object/computed';
6 | import { inject as service } from '@ember/service';
7 |
8 | export default Controller.extend({
9 | page: service(),
10 | application: controller(),
11 |
12 | pages: alias('model.pages'),
13 |
14 | versions: computed('application.model.allVersions.[]', function () {
15 | let allVersions = get(this, 'application.model.allVersions');
16 |
17 | return allVersions.sort(compareVersions).reverse();
18 | }),
19 |
20 | actions: {
21 | selectVersion(version) {
22 | // Navigate to same section/page if it exists
23 | const path = get(this, 'page.currentPage.url');
24 | this.store.queryRecord('content', {version, path}).then(() => {
25 | this.transitionToRoute(`/${version}/${path}`);
26 | }).catch(() => {
27 | this.transitionToRoute('version', version);
28 | })
29 | }
30 | }
31 | });
32 |
--------------------------------------------------------------------------------
/app/helpers/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ember-learn/guides-app/2e3a25fd3b924d6ced52d15d65f19232cc3145b3/app/helpers/.gitkeep
--------------------------------------------------------------------------------
/app/helpers/shorten-version.js:
--------------------------------------------------------------------------------
1 | import { helper } from '@ember/component/helper';
2 |
3 | export function shortenVersion([version='']) {
4 | return version.slice(version.indexOf('v') + 1 || 0, version.lastIndexOf('.') === version.indexOf('.') ? version.length : version.lastIndexOf('.'));
5 | }
6 |
7 | export default helper(shortenVersion);
8 |
--------------------------------------------------------------------------------
/app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | {{content-for "head"}}
9 |
10 |
11 |
12 |
13 |
14 | {{content-for "head-footer"}}
15 |
16 |
17 | {{content-for "body"}}
18 |
19 |
20 |
21 |
22 | {{content-for "body-footer"}}
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/initializers/regiser-showdown-extenions.js:
--------------------------------------------------------------------------------
1 | import showdown from 'showdown';
2 | import showdownSectionGroups from 'showdown-section-groups';
3 |
4 | export function initialize() {
5 | showdown.subParser('ellipsis', function (text, options, globals) {
6 | text = globals.converter._dispatch('ellipsis.before', text, options, globals);
7 | text = globals.converter._dispatch('ellipsis.after', text, options, globals);
8 | return text;
9 | });
10 |
11 | showdown.extension('showdown-section-groups', showdownSectionGroups);
12 |
13 | showdown.subParser('githubCodeBlocks', function (text, options, globals) {
14 | 'use strict';
15 |
16 | // early exit if option is not enabled
17 | if (!options.ghCodeBlocks) {
18 | return text;
19 | }
20 |
21 | text = globals.converter._dispatch('githubCodeBlocks.before', text, options, globals);
22 |
23 | text += '¨0';
24 |
25 | text = text.replace(/(?:^|\n)```(.*)\n([\s\S]*?)\n```/g, function (wholeMatch, languageBlock, codeblock) {
26 | var end = (options.omitExtraWLInCodeBlocks) ? '' : '\n';
27 |
28 | // First parse the github code block
29 | codeblock = showdown.subParser('encodeCode')(codeblock, options, globals);
30 | codeblock = showdown.subParser('detab')(codeblock, options, globals);
31 | codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines
32 | codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing whitespace
33 |
34 | var match = languageBlock.match(/(\w+)(\s+{(.*)})?/);
35 | var languageString = '';
36 | var attributeString = '';
37 |
38 | if(match && match[1]) {
39 | languageString = ' class="' + match[1] + ' language-' + match[1] + '"';
40 | }
41 |
42 | if (match && match[3]) {
43 | attributeString = match[3];
44 | }
45 |
46 | codeblock = '' + codeblock + end + '
';
47 |
48 | codeblock = showdown.subParser('hashBlock')(codeblock, options, globals);
49 |
50 | // Since GHCodeblocks can be false positives, we need to
51 | // store the primitive text and the parsed text in a global var,
52 | // and then return a token
53 | return '\n\n¨G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n';
54 | });
55 |
56 | // attacklab: strip sentinel
57 | text = text.replace(/¨0/, '');
58 |
59 | return globals.converter._dispatch('githubCodeBlocks.after', text, options, globals);
60 | });
61 | }
62 |
63 | export default {
64 | name: 'register-showdown-extensions',
65 | initialize
66 | };
67 |
--------------------------------------------------------------------------------
/app/locations/trailing-history.js:
--------------------------------------------------------------------------------
1 | import HistoryLocation from '@ember/routing/history-location';
2 |
3 | export default HistoryLocation.extend({
4 | formatURL() {
5 | let url = this._super(...arguments);
6 |
7 | if (url.includes('#')) {
8 | return url.replace(/([^/])#(.*)/, '$1/#$2');
9 | } else {
10 | return url.replace(/\/?$/, '/');
11 | }
12 | }
13 | });
14 |
--------------------------------------------------------------------------------
/app/models/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ember-learn/guides-app/2e3a25fd3b924d6ced52d15d65f19232cc3145b3/app/models/.gitkeep
--------------------------------------------------------------------------------
/app/models/content.js:
--------------------------------------------------------------------------------
1 | import DS from 'ember-data';
2 |
3 | export default DS.Model.extend({
4 | title: DS.attr(),
5 | content: DS.attr(),
6 | description: DS.attr(),
7 | canonical: DS.attr(),
8 | redirect: DS.attr(),
9 | });
10 |
--------------------------------------------------------------------------------
/app/models/page.js:
--------------------------------------------------------------------------------
1 | import DS from 'ember-data';
2 |
3 | export default DS.Model.extend({
4 | title: DS.attr('string'),
5 | pages: DS.attr(),
6 | skipToc: DS.attr('boolean'),
7 | });
8 |
--------------------------------------------------------------------------------
/app/models/version.js:
--------------------------------------------------------------------------------
1 | import DS from 'ember-data';
2 |
3 | export default DS.Model.extend({
4 | allVersions: DS.attr(),
5 | currentVersion: DS.attr('string'),
6 | });
7 |
--------------------------------------------------------------------------------
/app/resolver.js:
--------------------------------------------------------------------------------
1 | import Resolver from 'ember-resolver';
2 |
3 | export default Resolver;
4 |
--------------------------------------------------------------------------------
/app/router.js:
--------------------------------------------------------------------------------
1 | import EmberRouter from '@ember/routing/router';
2 |
3 | import { get } from '@ember/object';
4 | import { inject as service } from '@ember/service';
5 | import { scheduleOnce } from '@ember/runloop';
6 |
7 | import config from './config/environment';
8 |
9 | const Router = EmberRouter.extend({
10 | location: config.locationType,
11 | rootURL: config.rootURL,
12 |
13 | metrics: service(),
14 | fastboot: service(),
15 |
16 | didTransition() {
17 | this._super(...arguments);
18 | this._trackPage();
19 | },
20 |
21 | _trackPage() {
22 | if(get(this, 'fastboot.isFastBoot')) {
23 | return;
24 | }
25 |
26 | scheduleOnce('afterRender', this, () => {
27 | const page = this.url;
28 | const title = this.getWithDefault('currentRouteName', 'unknown');
29 |
30 | // this is constant for this app and is only used to identify page views in the GA dashboard
31 | const hostname = 'guides.emberjs.com';
32 |
33 | this.metrics.trackPage({ page, title, hostname });
34 | });
35 | },
36 | });
37 |
38 | Router.map(function() {
39 | this.route('version', { path: ':version' }, function() {
40 | this.route('show', { path: '*path' });
41 | });
42 | });
43 |
44 | export default Router;
45 |
--------------------------------------------------------------------------------
/app/routes/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ember-learn/guides-app/2e3a25fd3b924d6ced52d15d65f19232cc3145b3/app/routes/.gitkeep
--------------------------------------------------------------------------------
/app/routes/application.js:
--------------------------------------------------------------------------------
1 | import Route from '@ember/routing/route';
2 |
3 | export default Route.extend({
4 | model() {
5 | return this.store.findRecord('version', 'versions');
6 | }
7 | });
8 |
--------------------------------------------------------------------------------
/app/routes/error.js:
--------------------------------------------------------------------------------
1 | import Route from '@ember/routing/route';
2 |
3 | export default Route.extend({
4 | classNames: ['x404'],
5 | });
6 |
--------------------------------------------------------------------------------
/app/routes/index.js:
--------------------------------------------------------------------------------
1 | import Route from '@ember/routing/route';
2 |
3 | export default Route.extend({
4 | redirect() {
5 | this.transitionTo('version', 'release');
6 | }
7 | });
8 |
--------------------------------------------------------------------------------
/app/routes/version.js:
--------------------------------------------------------------------------------
1 | import { get, set } from '@ember/object';
2 | import Route from '@ember/routing/route';
3 | import { inject as service } from '@ember/service';
4 | import { hash } from 'rsvp';
5 |
6 | export default Route.extend({
7 | page: service(),
8 | model(params) {
9 | let applicationModel = this.modelFor('application');
10 | let currentVersion = get(applicationModel, 'currentVersion');
11 | let version = params.version;
12 |
13 | if (params.version === 'release') {
14 | version = currentVersion;
15 | }
16 |
17 | return hash({
18 | pages: this.store.query('page', { version }),
19 | allVersions: get(applicationModel, 'allVersions'),
20 | currentVersion,
21 | version: version,
22 | });
23 | },
24 |
25 | afterModel(model) {
26 | set(this.page, 'pages', get(model, 'pages'));
27 | }
28 | });
29 |
--------------------------------------------------------------------------------
/app/routes/version/index.js:
--------------------------------------------------------------------------------
1 | import Route from '@ember/routing/route';
2 | import { inject as service } from '@ember/service';
3 | import { get, set } from '@ember/object';
4 | import { hash } from 'rsvp';
5 |
6 | export default Route.extend({
7 | page: service(),
8 | model() {
9 | let { version, currentVersion } = this.modelFor('version');
10 |
11 | return hash({
12 | content: this.store.queryRecord('content', {
13 | path: 'index',
14 | version,
15 | }),
16 | pages: this.store.query('page', { version }),
17 | version,
18 | currentVersion,
19 | });
20 | },
21 |
22 | afterModel(model) {
23 | let content = get(model, 'content');
24 | set(this.page, 'content', content);
25 | let version = get(model, 'version');
26 | set(this.page, 'currentVersion', version);
27 | }
28 | });
29 |
--------------------------------------------------------------------------------
/app/routes/version/show.js:
--------------------------------------------------------------------------------
1 | import Route from '@ember/routing/route';
2 | import { inject as service } from '@ember/service';
3 | import { get, set } from '@ember/object';
4 | import { hash } from 'rsvp';
5 |
6 | export default Route.extend({
7 | page: service(),
8 | model(params) {
9 | const path = params.path.replace(/\/$/, '');
10 |
11 | if (path === 'index') {
12 | return this.transitionTo('version');
13 | }
14 |
15 | if (path.endsWith('/index')) {
16 | return this.transitionTo('version.show', path.replace(/\/index$/, ''))
17 | }
18 |
19 | const {
20 | version,
21 | currentVersion,
22 | pages,
23 | } = this.modelFor('version');
24 |
25 | let contentPromise = this.store.queryRecord('content', {
26 | path,
27 | version
28 | })
29 | .catch((e) => {
30 | if (['404', '403'].includes(get(e, 'errors.0.status'))) {
31 | return this.store.queryRecord('content', {
32 | path: `${path}/index`,
33 | version
34 | });
35 | }
36 | throw e;
37 | });
38 |
39 | return hash({
40 | content: contentPromise,
41 | pages,
42 | path,
43 | version,
44 | currentVersion,
45 | })
46 | },
47 | afterModel(model) {
48 | if(model.content.redirect) {
49 | this.transitionTo('version.show', model.content.redirect)
50 | }
51 |
52 | let content = get(model, 'content');
53 | set(this.page, 'content', content);
54 | let version = get(model, 'version');
55 | set(this.page, 'currentVersion', version);
56 | }
57 | });
58 |
--------------------------------------------------------------------------------
/app/services/head-data.js:
--------------------------------------------------------------------------------
1 | import HeadData from 'ember-meta/services/head-data';
2 | import { computed } from '@ember/object';
3 | import { getOwner } from '@ember/application';
4 | import { inject as service } from '@ember/service';
5 | import { isPresent } from '@ember/utils';
6 |
7 | import config from '../config/environment';
8 |
9 | export default HeadData.extend({
10 | page: service(),
11 | currentRouteModel: computed('routeName', function() {
12 | return getOwner(this).lookup(`route:${this.routeName}`).get('currentModel.content');
13 | }),
14 |
15 | title: computed('routeName', 'page.{currentPage,currentSection}', function() {
16 | if(!this.page.currentPage || !this.page.currentSection) {
17 | return 'Ember Guides';
18 | }
19 |
20 | return `${this.page.currentPage.title} - ${this.page.currentSection.title} - Ember Guides`
21 | }),
22 |
23 | description: computed('routeName', function() {
24 | return this.getWithDefault('currentRouteModel.description', config['ember-meta'].description);
25 | }),
26 |
27 | slug: computed('routeName', function() {
28 | // if there is no current model
29 | if (!this.currentRouteModel) {
30 | return null;
31 | }
32 |
33 | if(this.currentRouteModel.id === 'index') {
34 | return this.page.currentVersion;
35 | }
36 |
37 | return `${this.page.currentVersion}/${this.currentRouteModel.id.replace(/\/index$/, '')}`;
38 | }),
39 |
40 | canonical: computed('routeName', function() {
41 | // if there is no current model
42 | if (!this.currentRouteModel) {
43 | return null;
44 | }
45 |
46 | if (isPresent(this.currentRouteModel.canonical)) {
47 | return this.currentRouteModel.canonical;
48 | }
49 |
50 | let slug;
51 |
52 | if (this.currentRouteModel.id === 'index') {
53 | slug = 'release';
54 | } else {
55 | slug = `release/${this.currentRouteModel.id.replace(/\/index$/, '')}`
56 | }
57 |
58 | return `${config['ember-meta'].url}${slug}/`;
59 | }),
60 | });
61 |
--------------------------------------------------------------------------------
/app/services/page.js:
--------------------------------------------------------------------------------
1 | import Service from '@ember/service';
2 | import { inject as service } from '@ember/service';
3 | import { get, set, computed } from '@ember/object';
4 |
5 | export default Service.extend({
6 | router: service(),
7 | fastboot: service(),
8 | headData: service(),
9 |
10 | currentSection: computed('router.currentURL', 'pages.[]', 'content.id', function() {
11 | let tocSections = this.pages;
12 |
13 | let contentId = get(this, 'content.id');
14 |
15 | if(!tocSections || !contentId) { return; }
16 |
17 | let section = contentId.split('/')[0]
18 | let currentSection = tocSections.find((tocSection) => tocSection.id === section);
19 |
20 | if(!currentSection) {
21 | return;
22 | }
23 |
24 | // eslint-disable-next-line ember/no-side-effects
25 | set(this, 'metaSection', get(currentSection, 'title'));
26 |
27 | return currentSection;
28 | }),
29 |
30 | /**
31 | * Find the TOC item that matches the current visible content. This is needed because the title comes
32 | * from the TOC and not the content. Also we use this to compute nextPage and previousPage
33 | * @return {Promise} the current page as a POJO
34 | */
35 | currentPage: computed('router.currentURL', 'currentSection.pages', 'content.id', function() {
36 | let currentSection = this.currentSection;
37 |
38 | if(!currentSection) { return; }
39 |
40 | // special case for the index section - there should always be only exactly 1 page in the "index" section
41 | if (currentSection.id === 'index') {
42 | return get(currentSection, 'pages')[0];
43 | }
44 |
45 | let pages = get(currentSection, 'pages');
46 |
47 | let currentPage = pages.find((page) => page.url === get(this, 'content.id'));
48 |
49 | if(!currentPage) {
50 | return;
51 | }
52 |
53 | // eslint-disable-next-line ember/no-side-effects
54 | set(this, 'metaPage', get(currentPage, 'title'));
55 |
56 | return currentPage;
57 | }),
58 |
59 | isFirstPage: computed('currentSection', 'currentPage', function() {
60 | let currentSection = this.currentSection;
61 |
62 | if(!currentSection) { return; }
63 |
64 | let pages = get(currentSection, 'pages');
65 | if(pages) {
66 | return pages.indexOf(this.currentPage) === 0;
67 | }
68 | }),
69 |
70 | isLastPage: computed('currentSection', 'currentPage', function() {
71 | let currentSection = this.currentSection;
72 |
73 | if(!currentSection) { return; }
74 |
75 | let pages = get(currentSection, 'pages');
76 | if(pages) {
77 | return pages.indexOf(this.currentPage) === (pages.length-1);
78 | }
79 | }),
80 |
81 | previousPage: computed('currentSection.pages', 'currentPage.url', function() {
82 | let currentSection = this.currentSection;
83 | let currentPage = this.currentPage;
84 |
85 | if(!currentSection || !currentPage) { return; }
86 |
87 | let pages = get(currentSection, 'pages');
88 |
89 | if(pages) {
90 | let currentLocalPage = pages.find((page) => page.url === currentPage.url);
91 | let index = pages.indexOf(currentLocalPage);
92 |
93 | if (index > 0) {
94 | return pages[index - 1];
95 | }
96 | }
97 | }),
98 |
99 | nextPage: computed('currentSection.pages', 'currentPage.url', function() {
100 | let currentSection = this.currentSection;
101 | let currentPage = this.currentPage;
102 |
103 | if(!currentSection || !currentPage) { return; }
104 |
105 | let pages = get(currentSection, 'pages');
106 |
107 | if(pages) {
108 | let currentLocalPage = pages.find((page) => page.url === currentPage.url);
109 | let index = pages.indexOf(currentLocalPage);
110 |
111 | if (index < pages.length-1) {
112 | return pages[index + 1];
113 | }
114 | }
115 | }),
116 |
117 | previousSection: computed('currentSection', 'pages.[]', function() {
118 | let currentSection = this.currentSection;
119 |
120 | if(!currentSection) { return; }
121 |
122 | let pages = this.pages;
123 |
124 | if (pages) {
125 | let page = pages.content.find((content) => content.id === currentSection.id);
126 |
127 | let index = pages.content.indexOf(page);
128 |
129 | if (index > 0) {
130 | return pages.objectAt(index-1);
131 | }
132 | }
133 | }),
134 |
135 | nextSection: computed('currentSection', 'pages.[]', function() {
136 | let currentSection = this.currentSection;
137 |
138 | if(!currentSection) { return; }
139 |
140 | let pages = this.pages;
141 |
142 | if (pages) {
143 | let page = pages.content.find((content) => content.id === currentSection.id);
144 |
145 | let index = pages.content.indexOf(page);
146 |
147 | if (index < get(pages, 'length') - 1) {
148 | return pages.objectAt(index + 1);
149 | }
150 | }
151 | }),
152 | });
153 |
--------------------------------------------------------------------------------
/app/services/search.js:
--------------------------------------------------------------------------------
1 | import Service from '@ember/service';
2 | import { task } from 'ember-concurrency';
3 | import { get, set } from '@ember/object';
4 | import { A as emberArray } from '@ember/array';
5 | import { denodeify } from 'rsvp';
6 | import algoliasearch from 'algoliasearch';
7 | import { getOwner } from '@ember/application';
8 |
9 | export default Service.extend({
10 |
11 | results: emberArray(),
12 |
13 | search: task(function * (query, projectVersion) {
14 | const searchObj = {
15 | hitsPerPage: 15,
16 | restrictSearchableAttributes: ['content'],
17 | facetFilters: [[`version:${projectVersion}`]],
18 | query
19 | };
20 |
21 | return set(this, 'results', yield this.doSearch(searchObj));
22 |
23 | }).restartable(),
24 |
25 | doSearch(searchObj) {
26 | const config = getOwner(this).resolveRegistration('config:environment');
27 | const { algoliaId, algoliaKey } = config['ember-algolia'];
28 |
29 | const client = algoliasearch(algoliaId, algoliaKey);
30 | const index = client.initIndex('ember-guides');
31 | const searchFunction = denodeify(index.search.bind(index));
32 |
33 | return searchFunction(searchObj).then((results) => {
34 | return get(results, 'hits');
35 | });
36 | }
37 | });
38 |
--------------------------------------------------------------------------------
/app/styles/_code-block-file-name.scss:
--------------------------------------------------------------------------------
1 | div.filename {
2 | background-color: #292929;
3 | }
4 |
5 | pre[class*="language-"] {
6 | background-color: #151515;
7 | }
8 |
9 | .filename {
10 | border-radius: 0.3em;
11 | }
12 |
13 | .ribbon {
14 | margin-top: 0.33em;
15 | float: right;
16 | height: 20px;
17 | width: 52px;
18 | background: 0 0 no-repeat;
19 | background-size: 52px 20px;
20 | }
21 |
22 | .filename > span {
23 | font-family: Menlo, "DejaVu Sans Mono", "Bitstream Vera Sans Mono", Courier, monospace;
24 | font-size: 0.8em;
25 | color: lightgrey;
26 | display: block;
27 | padding: 5px 0 0 10px;
28 | }
29 |
30 | .filename.javascript .ribbon,
31 | .filename.js .ribbon {
32 | background-image: url("../images/ribbon-js.svg");
33 | }
34 |
35 | .filename.html .ribbon {
36 | background-image: url("../images/ribbon-html.svg");
37 | }
38 |
39 | .filename.handlebars .ribbon,
40 | .filename.hbs .ribbon {
41 | background-image: url("../images/ribbon-hbs.svg");
42 | }
43 |
44 | code {
45 | -webkit-font-feature-settings: "kern", "tnum";
46 | -moz-font-feature-settings: "kern", "tnum";
47 | -ms-font-feature-settings: "kern", "tnum";
48 | font-feature-settings: "kern", "tnum";
49 | }
50 |
51 | code:not([class*="language-"]) {
52 | background-color: #F8E7CF;
53 | border-radius: 3px;
54 | font-family: Menlo, "DejaVu Sans Mono", "Bitstream Vera Sans Mono", Courier, monospace;
55 | font-size: 0.9em;
56 | padding: 0.2em 0.5em;
57 | margin: 0 0.1em;
58 | }
59 |
--------------------------------------------------------------------------------
/app/styles/_prism-overrides.scss:
--------------------------------------------------------------------------------
1 | .token.regex,
2 | .token.important,
3 | .token.variable {
4 | color: #C3F590;
5 | }
6 |
7 | code > .diff-insertion {
8 | background-color: rgba(93, 125, 93, 0.5);
9 |
10 | .token.property,
11 | .token.tag,
12 | .token.constant,
13 | .token.symbol,
14 | .token.deleted {
15 | color: #ff95bb;
16 | }
17 | }
18 |
19 | code > .diff-deletion {
20 | background-color: rgba(144, 84, 84, .7);
21 |
22 | .token.property,
23 | .token.tag,
24 | .token.constant,
25 | .token.symbol,
26 | .token.deleted {
27 | color: #ffaac8;
28 | }
29 | }
30 |
31 | code .diff-operator {
32 | user-select: none;
33 | }
34 |
35 | code .token.comment {
36 | color: #E6E6E6;
37 | }
38 |
39 | code {
40 | .token.property,
41 | .token.tag,
42 | .token.constant,
43 | .token.symbol,
44 | .token.deleted {
45 | color: #ff6fa3;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/app/styles/_search-input.scss:
--------------------------------------------------------------------------------
1 |
2 | // Typography
3 | $base-font-family: 'Source Sans Pro', sans-serif;
4 | $heading-font-family: $base-font-family;
5 | $monospace-font-family: Menlo, "DejaVu Sans Mono", "Bitstream Vera Sans Mono", Courier, monospace;
6 | $footer-font-family: proxima-nova, sans-serif;
7 |
8 | // Font Sizes
9 | $base-font-size: 1rem;
10 | $small-font-size: 0.75rem;
11 | $large-font-size: 1.5rem;
12 |
13 | // Line height
14 | $base-line-height: 1.5;
15 | $heading-line-height: 1.2;
16 |
17 | // Spacing
18 | $base-spacing: $base-line-height * 1em;
19 | $small-spacing: $base-spacing / 2;
20 | $large-spacing: $base-spacing * 2;
21 | $top-spacing: $base-spacing * 3.333; // 80px
22 |
23 |
24 | // Colors
25 | $ember-orange: #dd6a58;
26 | $light-brown: #b67d47;
27 | $brown: #865931;
28 | $medium-gray: #999;
29 | $dark-gray: #444545;
30 | $tan: #fffdf9;
31 | $white: #fff;
32 | $black: #000;
33 | $creme: #FFFBF5;
34 | $linen: #f9e7e4;
35 | $near-black: #444;
36 |
37 | $base-background-color: #FDFDFD;
38 | $sidebar-background-color: #FFFDF9;
39 |
40 | // Code Highlighting
41 | $highlight-yellow: #F5E090;
42 | $highlight-green: #C3F590;
43 | $highlight-red: #EC605E;
44 | $highlight-blue: #90D7F5;
45 | $highlight-cyan: #78CEC8;
46 | $highlight-added: #5D7D5D;
47 | $highlight-removed: #905454;
48 | $code-background: $dark-gray;
49 | $code-header-background: shade($code-background, 40%);
50 | // $code-line-number-background: mix($code-background, $code-header-background);
51 |
52 | $highlight-colors: (
53 | attribute-name: $highlight-red,
54 | comment: $medium-gray,
55 | content: $highlight-cyan,
56 | function: $highlight-red,
57 | key: $highlight-red,
58 | keyword: $highlight-yellow,
59 | local-variable: $highlight-red,
60 | string: $highlight-cyan,
61 | tag: $highlight-red,
62 | );
63 |
64 | // Font Colors
65 | $base-font-color: $near-black;
66 | $dark-font-color: $dark-gray;
67 | $light-font-color: $light-brown;
68 | $action-color: $ember-orange;
69 |
70 | // Border
71 | $base-border-radius: 3px;
72 | $base-border-color: #F8E7CF;
73 | $base-border: 1px solid $base-border-color;
74 |
75 | // Forms
76 | $form-box-shadow: inset 0 1px 3px rgba(#000, 0.06);
77 | $form-box-shadow-focus: $form-box-shadow, 0 0 5px adjust-color($action-color, $lightness: -5%, $alpha: -0.3);
78 |
79 | // Animations
80 | $duration: 200ms;
81 |
82 | // Z-indices
83 | $base-z-index: 0;
84 |
85 |
86 | $mobile-portrait-screen: 30em; // 480px
87 | $medium-screen: 40em; // 640px
88 | $large-screen: 54em; // 864px
89 |
90 |
91 | // https://github.com/algolia/docsearch/blob/master/src/styles/main.scss
92 | $color-border: darken($base-border-color, 10%);
93 | $color-border-light: $base-border-color;
94 | $color-category-header-background: $ember-orange;
95 | $color-highlight-header-background: lighten($color-category-header-background, 15%);
96 | $color-highlight-text: $highlight-red;
97 | $color-selected-background: white;
98 | $color-selected-text: darken($action-color, 15%);
99 | $color-left-column-bg: $sidebar-background-color;
100 | $color-left-column: $base-font-color;
101 |
102 | $breakpoint-medium: $medium-screen;
103 | $breakpoint-large: $large-screen;
104 |
105 | $dropdown-min-width-medium: 100%;
106 | $dropdown-min-width-large: 600px;
107 |
108 | // The dropdown adapts to screen size, to provide three different displays.
109 | // - A simple list of matching results
110 | // - Same list, but with text snippetting added if size is large enough
111 | // - Adding a second colum to let the content breath if enough room available
112 |
113 | .search-input {
114 | input {
115 | width: 100%;
116 | height: 35px;
117 | margin-bottom: 0;
118 | padding-left: 2.5em;
119 | border: none;
120 | border-radius: 35px;
121 | outline: none;
122 | appearance: none;
123 | background: url("/images/search-icon.svg") rgba(255,255,255,0.1) 10px 10px no-repeat;
124 | box-shadow: none;
125 | line-height: 35px;
126 | font-size: 0.9rem;
127 | color: #fff;
128 | }
129 | input,
130 | input::placeholder {
131 | font-size: 0.9rem;
132 | color: #fff;
133 | }
134 | input::-webkit-search-cancel-button {
135 | margin-right: 10px;
136 | }
137 | }
138 |
139 | .ds-dropdown-results {
140 | z-index: 10;
141 |
142 | a {
143 | color: #000000;
144 | }
145 | }
146 | // Main autocomplete wrapper
147 | .ds-dropdown-menu {
148 | background-color: #ffffff;
149 | border-radius: 4px;
150 | box-shadow: 0 1px 2px rgba(0,0,0,0.5);
151 | color: black;
152 | display: block;
153 | font-size: 12.8px;
154 | margin: 6px 0 0;
155 | text-align: left;
156 | }
157 |
158 | // No Results
159 | .algolia-docsearch-suggestion--noresults {
160 | padding: 0 5px 10px 10px;
161 | a {
162 | color: $ember-orange;
163 | text-decoration: none;
164 | }
165 | }
166 |
167 | // Each suggestion
168 | .algolia-docsearch-suggestion {
169 | color: #333;
170 | cursor: pointer;
171 | overflow: hidden;
172 | border-bottom: 1px solid $color-border;
173 | }
174 |
175 | // Main category headers
176 | .algolia-docsearch-suggestion--category-header {
177 | display: none;
178 | border: 2px solid white;
179 | background: $color-category-header-background;
180 | color: white;
181 | font-weight: 600;
182 | padding: 5px 10px;
183 | text-align: left;
184 | // Only show it when flagged as "__main"
185 | .algolia-docsearch-suggestion__main & {
186 | display: block;
187 | }
188 | }
189 |
190 | // Highlight
191 | .algolia-docsearch-suggestion--subcategory-column-text em, .algolia-docsearch-suggestion--title em {
192 | padding: 0;
193 | font-style: normal;
194 | color: $color-highlight-text;
195 | background: none;
196 | font-weight: 600;
197 | // Highlight the background in header
198 | .algolia-docsearch-suggestion--category-header & {
199 | color: inherit;
200 | background: $color-highlight-header-background;
201 | }
202 | }
203 |
204 | // Selected suggestion
205 | .aa-cursor .algolia-docsearch-suggestion--content {
206 | color: $color-selected-text;
207 | }
208 | .aa-cursor .algolia-docsearch-suggestion {
209 | background: $color-selected-background;
210 | }
211 |
212 | // The secondary column is hidden on small screens
213 | .algolia-docsearch-suggestion--subcategory-column {
214 | display: none;
215 | }
216 | // The text snippet is hidden on small screens
217 | .algolia-docsearch-suggestion--text {
218 | display: none;
219 |
220 | // If text parent node has --no-results
221 | // we should display the content
222 | .algolia-docsearch-suggestion--no-results & {
223 | display: block;
224 | }
225 | }
226 |
227 | .algolia-docsearch-suggestion--content {
228 | padding: 3px 5px;
229 | }
230 |
231 | .algolia-docsearch-suggestion--subcategory-inline {
232 | display: inline-block;
233 | font-weight: bold;
234 | &:after {
235 | content: " › ";
236 | }
237 | }
238 | .algolia-docsearch-suggestion--title {
239 | display: inline;
240 | }
241 |
242 | // Footer
243 | .powered-by-algolia {
244 | display: flex;
245 | flex-direction: row-reverse;
246 | padding: .5em;
247 | }
248 |
249 | // BREAKPOINT 1:
250 | // Screen is big enough to display the text snippets
251 | @media (min-width: $breakpoint-medium) {
252 | .ds-dropdown-menu {
253 | min-width: $dropdown-min-width-medium;
254 | }
255 | .algolia-docsearch-suggestion--text {
256 | display: block;
257 | font-size: .9em;
258 | padding: 2px 0;
259 | }
260 | }
261 |
262 | // BREAKPOINT 2:
263 | // Screen is big enough to display results in two columns
264 | @media (min-width: $breakpoint-large) {
265 | .ds-dropdown-menu {
266 | width: $dropdown-min-width-large;
267 | }
268 | .algolia-docsearch-suggestion {
269 | display: table;
270 | width: 100%;
271 | border-bottom: 1px solid $color-border-light;
272 | }
273 | .algolia-docsearch-suggestion--subcategory-column {
274 | border-right: 1px solid $color-border-light;
275 | background: $color-left-column-bg;
276 | color: $color-left-column;
277 | display: table-cell;
278 | overflow: hidden;
279 | padding: 3px 7px 3px 5px;
280 | text-align: right;
281 | text-overflow: ellipsis;
282 | vertical-align: top;
283 |
284 | width: 135px; // Hardcoded
285 | max-width: 135px; // Hardcoded
286 | min-width: 135px; // Hardcoded
287 | }
288 |
289 | .algolia-docsearch-suggestion--subcategory-column-text {
290 | display: none;
291 |
292 | .algolia-docsearch-suggestion__secondary & {
293 | display: block;
294 | }
295 | }
296 | .algolia-docsearch-suggestion--content {
297 | display: table-cell;
298 | padding: 3px 10px;
299 | }
300 | .algolia-docsearch-suggestion--subcategory-inline {
301 | display: none;
302 | }
303 | .algolia-docsearch-suggestion--title {
304 | font-weight: 600;
305 | }
306 | .algolia-docsearch-suggestion--text {
307 | display: block;
308 | font-weight: normal;
309 | padding: 2px;
310 | }
311 | }
312 |
--------------------------------------------------------------------------------
/app/styles/_table-of-contents.scss:
--------------------------------------------------------------------------------
1 | @media only percy {
2 | .version-select {
3 | display: none;
4 | }
5 |
6 | .sidebar .ember-power-select-trigger {
7 | display: none;
8 | }
9 | }
10 |
11 | .anchorable-toc {
12 | position: relative;
13 | margin-left: -22px;
14 | padding-left: 22px;
15 | }
16 |
17 | .anchorable-toc:hover a.toc-anchor {
18 | display: block;
19 | }
20 |
21 | a.toc-anchor {
22 | display: none;
23 | position: absolute;
24 | text-decoration: none;
25 | border: none;
26 | width: 30px;
27 | height: 13px;
28 | background: url("../images/link.png") no-repeat;
29 | background-size: 18px 9px;
30 | left: 0;
31 | opacity: 0.5;
32 | top: 50%;
33 | margin-top: -5px;
34 | }
35 |
36 | label[for="toc-toggle"] {
37 | cursor: pointer;
38 | font-size: 1.25em;
39 | position: relative;
40 | }
41 |
42 | label[for="toc-toggle"]:hover {
43 | color: #dd6a58;
44 | }
45 |
46 | label[for="toc-toggle"]:hover:after {
47 | border-color: #dd6a58 transparent transparent transparent;
48 | }
49 |
50 | .toc-toggle:checked ~ label[for="toc-toggle"]:hover:after {
51 | border-color: transparent transparent #dd6a58 transparent;
52 | }
53 |
54 | label[for="toc-toggle"]:after {
55 | content: '';
56 | border-color: #b67d47 transparent transparent transparent;
57 | border-style: solid;
58 | border-width: 5px 4px 0 4px;
59 | height: 0;
60 | margin-left: -4px;
61 | margin-top: -2px;
62 | position: absolute;
63 | right: 6px;
64 | top: 50%;
65 | width: 0;
66 | }
67 |
68 | .toc-toggle:checked ~ label[for="toc-toggle"]:after {
69 | border-color: transparent transparent #b67d47 transparent;
70 | border-width: 0 4px 5px 4px;
71 | }
72 | @media screen and (min-width: 53.75em) {
73 | label[for="toc-toggle"] {
74 | display: none;
75 | }
76 | }
77 |
78 | .toc-container {
79 | border-top: 1px solid #F8E7CF;
80 | overflow: hidden;
81 | display: none;
82 | }
83 |
84 | .toc-toggle:checked ~ .toc-container {
85 | display: block;
86 | }
87 | @media screen and (min-width: 53.75em) {
88 | .toc-container {
89 | display: block;
90 | }
91 |
92 | .toc-container[style] {
93 | display: block !important;
94 | }
95 | }
96 |
97 | .toc-container a {
98 | text-decoration: none;
99 | }
100 |
101 | li.toc-level-0 {
102 | margin-bottom: 0.5em;
103 | }
104 |
105 | .toc-container {
106 | .cp-Panel-toggle {
107 | color: #9b2918;
108 | display: block;
109 | line-height: 1.25;
110 | padding: 0.33em 0;
111 | }
112 |
113 | .cp-Panel-toggle:hover {
114 | color: darken(#9b2918, 5);
115 | }
116 | }
117 |
118 | li.toc-level-0 > div > a {
119 | font-weight: bold;
120 | margin: 0.33em 0;
121 | }
122 |
123 | ol.toc-level-1 {
124 | border-left: 1px solid #74B0CE;
125 | font-size: 0.9rem;
126 | }
127 |
128 | // ol.toc-level-1:not(.selected) {
129 | // display: none;
130 | // }
131 |
132 | ol.toc-level-1 li {
133 | border-left: 3px solid transparent;
134 | transition: border-width 200ms, margin-right 200ms;
135 | }
136 |
137 | ol.toc-level-1 li.selected,
138 | ol.toc-level-1 li:hover {
139 | border-left-color: #74B0CE;
140 | }
141 |
142 | ol.toc-level-1 li:hover {
143 | border-left-width: 6px;
144 | margin-right: -3px;
145 | }
146 |
147 | ol.toc-level-1 a {
148 | color: #444;
149 | padding: 0.33em 0 0.33em 1.618em;
150 | display: block;
151 | line-height: 1.25;
152 | }
153 |
154 | ol.toc-level-1 .selected a {
155 | font-weight: 500;
156 | }
157 |
--------------------------------------------------------------------------------
/app/styles/app.scss:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'fontello';
3 | src: url("../fonts/fontello.eot?60624967");
4 | src: url("../fonts/fontello.eot?60624967#iefix") format("embedded-opentype"),url("../fonts/fontello.woff?60624967") format("woff"),url("../fonts/fontello.ttf?60624967") format("truetype"),url("../fonts/fontello.svg?60624967#fontello") format("svg");
5 | font-weight: normal;
6 | font-style: normal;
7 | }
8 |
9 | [class^="icon-"]:before,
10 | [class*=" icon-"]:before {
11 | font-family: "fontello";
12 | font-style: normal;
13 | font-weight: normal;
14 | speak: none;
15 | display: inline-block;
16 | text-decoration: inherit;
17 | width: 1em;
18 | margin-right: 0.2em;
19 | text-align: center;
20 | font-variant: normal;
21 | text-transform: none;
22 | line-height: 1em;
23 | margin-left: 0.2em;
24 | }
25 |
26 | .icon-search:before {
27 | content: '\e804';
28 | }
29 |
30 | .icon-cancel:before {
31 | content: '\e802';
32 | }
33 |
34 | .icon-link:before {
35 | content: '\e803';
36 | }
37 |
38 | .icon-pencil:before {
39 | content: '\e801';
40 | }
41 |
42 | .icon-fork:before {
43 | content: '\e800';
44 | }
45 |
46 | .icon-github:before {
47 | content: '\e806';
48 | }
49 |
50 | .icon-gplus:before {
51 | content: '\e807';
52 | }
53 |
54 | .icon-twitter:before {
55 | content: '\e805';
56 | }
57 |
58 | .select2-container {
59 | box-sizing: border-box;
60 | display: inline-block;
61 | margin: 0;
62 | position: relative;
63 | vertical-align: middle;
64 | }
65 |
66 | .select2-container .select2-selection--single {
67 | box-sizing: border-box;
68 | cursor: pointer;
69 | display: block;
70 | height: 28px;
71 | user-select: none;
72 | -webkit-user-select: none;
73 | }
74 |
75 | .select2-container .select2-selection--single .select2-selection__rendered {
76 | display: block;
77 | padding-left: 8px;
78 | padding-right: 20px;
79 | overflow: hidden;
80 | text-overflow: ellipsis;
81 | white-space: nowrap;
82 | }
83 |
84 | .select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered {
85 | padding-right: 8px;
86 | padding-left: 20px;
87 | }
88 |
89 | .select2-container .select2-selection--multiple {
90 | box-sizing: border-box;
91 | cursor: pointer;
92 | display: block;
93 | min-height: 32px;
94 | user-select: none;
95 | -webkit-user-select: none;
96 | }
97 |
98 | .select2-container .select2-selection--multiple .select2-selection__rendered {
99 | display: inline-block;
100 | overflow: hidden;
101 | padding-left: 8px;
102 | text-overflow: ellipsis;
103 | white-space: nowrap;
104 | }
105 |
106 | .select2-container .select2-search--inline {
107 | float: left;
108 | }
109 |
110 | .select2-container .select2-search--inline .select2-search__field {
111 | box-sizing: border-box;
112 | border: none;
113 | font-size: 100%;
114 | margin-top: 5px;
115 | }
116 |
117 | .select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button {
118 | -webkit-appearance: none;
119 | }
120 |
121 | .select2-dropdown {
122 | background-color: white;
123 | border: 1px solid #aaa;
124 | border-radius: 4px;
125 | box-sizing: border-box;
126 | display: block;
127 | position: absolute;
128 | left: -100000px;
129 | width: 100%;
130 | z-index: 1051;
131 | }
132 |
133 | .select2-results {
134 | display: block;
135 | }
136 |
137 | .select2-results__options {
138 | list-style: none;
139 | margin: 0;
140 | padding: 0;
141 | }
142 |
143 | .select2-results__option {
144 | padding: 6px;
145 | user-select: none;
146 | -webkit-user-select: none;
147 | }
148 |
149 | .select2-results__option[aria-selected] {
150 | cursor: pointer;
151 | }
152 |
153 | .select2-container--open .select2-dropdown {
154 | left: 0;
155 | }
156 |
157 | .select2-container--open .select2-dropdown--above {
158 | border-bottom: none;
159 | border-bottom-left-radius: 0;
160 | border-bottom-right-radius: 0;
161 | }
162 |
163 | .select2-container--open .select2-dropdown--below {
164 | border-top: none;
165 | border-top-left-radius: 0;
166 | border-top-right-radius: 0;
167 | }
168 |
169 | .select2-search--dropdown {
170 | display: block;
171 | padding: 4px;
172 | }
173 |
174 | .select2-search--dropdown .select2-search__field {
175 | padding: 4px;
176 | width: 100%;
177 | box-sizing: border-box;
178 | }
179 |
180 | .select2-search--dropdown .select2-search__field::-webkit-search-cancel-button {
181 | -webkit-appearance: none;
182 | }
183 |
184 | .select2-search--dropdown.select2-search--hide {
185 | display: none;
186 | }
187 |
188 | .select2-close-mask {
189 | border: 0;
190 | margin: 0;
191 | padding: 0;
192 | display: block;
193 | position: fixed;
194 | left: 0;
195 | top: 0;
196 | min-height: 100%;
197 | min-width: 100%;
198 | height: auto;
199 | width: auto;
200 | opacity: 0;
201 | z-index: 99;
202 | background-color: #fff;
203 | filter:alpha(opacity=0);
204 | }
205 |
206 | .select2-container--default .select2-selection--single {
207 | background-color: #fff;
208 | border: 1px solid #aaa;
209 | border-radius: 4px;
210 | }
211 |
212 | .select2-container--default .select2-selection--single .select2-selection__rendered {
213 | color: #444;
214 | line-height: 28px;
215 | }
216 |
217 | .select2-container--default .select2-selection--single .select2-selection__clear {
218 | cursor: pointer;
219 | float: right;
220 | font-weight: bold;
221 | }
222 |
223 | .select2-container--default .select2-selection--single .select2-selection__placeholder {
224 | color: #999;
225 | }
226 |
227 | .select2-container--default .select2-selection--single .select2-selection__arrow {
228 | height: 26px;
229 | position: absolute;
230 | top: 1px;
231 | right: 1px;
232 | width: 20px;
233 | }
234 |
235 | .select2-container--default .select2-selection--single .select2-selection__arrow b {
236 | border-color: #888 transparent transparent transparent;
237 | border-style: solid;
238 | border-width: 5px 4px 0 4px;
239 | height: 0;
240 | left: 50%;
241 | margin-left: -4px;
242 | margin-top: -2px;
243 | position: absolute;
244 | top: 50%;
245 | width: 0;
246 | }
247 |
248 | .select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear {
249 | float: left;
250 | }
251 |
252 | .select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow {
253 | left: 1px;
254 | right: auto;
255 | }
256 |
257 | .select2-container--default.select2-container--disabled .select2-selection--single {
258 | background-color: #eee;
259 | cursor: default;
260 | }
261 |
262 | .select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear {
263 | display: none;
264 | }
265 |
266 | .select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b {
267 | border-color: transparent transparent #888 transparent;
268 | border-width: 0 4px 5px 4px;
269 | }
270 |
271 | .select2-container--default .select2-selection--multiple {
272 | background-color: white;
273 | border: 1px solid #aaa;
274 | border-radius: 4px;
275 | cursor: text;
276 | }
277 |
278 | .select2-container--default .select2-selection--multiple .select2-selection__rendered {
279 | box-sizing: border-box;
280 | list-style: none;
281 | margin: 0;
282 | padding: 0 5px;
283 | width: 100%;
284 | }
285 |
286 | .select2-container--default .select2-selection--multiple .select2-selection__placeholder {
287 | color: #999;
288 | margin-top: 5px;
289 | float: left;
290 | }
291 |
292 | .select2-container--default .select2-selection--multiple .select2-selection__clear {
293 | cursor: pointer;
294 | float: right;
295 | font-weight: bold;
296 | margin-top: 5px;
297 | margin-right: 10px;
298 | }
299 |
300 | .select2-container--default .select2-selection--multiple .select2-selection__choice {
301 | background-color: #e4e4e4;
302 | border: 1px solid #aaa;
303 | border-radius: 4px;
304 | cursor: default;
305 | float: left;
306 | margin-right: 5px;
307 | margin-top: 5px;
308 | padding: 0 5px;
309 | }
310 |
311 | .select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
312 | color: #999;
313 | cursor: pointer;
314 | display: inline-block;
315 | font-weight: bold;
316 | margin-right: 2px;
317 | }
318 |
319 | .select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover {
320 | color: #333;
321 | }
322 |
323 | .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice,
324 | .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder {
325 | float: right;
326 | }
327 |
328 | .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
329 | margin-left: 5px;
330 | margin-right: auto;
331 | }
332 |
333 | .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
334 | margin-left: 2px;
335 | margin-right: auto;
336 | }
337 |
338 | .select2-container--default.select2-container--focus .select2-selection--multiple {
339 | border: solid black 1px;
340 | outline: 0;
341 | }
342 |
343 | .select2-container--default.select2-container--disabled .select2-selection--multiple {
344 | background-color: #eee;
345 | cursor: default;
346 | }
347 |
348 | .select2-container--default.select2-container--disabled .select2-selection__choice__remove {
349 | display: none;
350 | }
351 |
352 | .select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple,
353 | .select2-container--default.select2-container--open.select2-container--above .select2-selection--single {
354 | border-top-left-radius: 0;
355 | border-top-right-radius: 0;
356 | }
357 |
358 | .select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple,
359 | .select2-container--default.select2-container--open.select2-container--below .select2-selection--single {
360 | border-bottom-left-radius: 0;
361 | border-bottom-right-radius: 0;
362 | }
363 |
364 | .select2-container--default .select2-search--dropdown .select2-search__field {
365 | border: 1px solid #aaa;
366 | }
367 |
368 | .select2-container--default .select2-search--inline .select2-search__field {
369 | background: transparent;
370 | border: none;
371 | outline: 0;
372 | }
373 |
374 | .select2-container--default .select2-results > .select2-results__options {
375 | max-height: 200px;
376 | overflow-y: auto;
377 | }
378 |
379 | .select2-container--default .select2-results__option[role=group] {
380 | padding: 0;
381 | }
382 |
383 | .select2-container--default .select2-results__option[aria-disabled=true] {
384 | color: #999;
385 | }
386 |
387 | .select2-container--default .select2-results__option[aria-selected=true] {
388 | background-color: #ddd;
389 | }
390 |
391 | .select2-container--default .select2-results__option .select2-results__option {
392 | padding-left: 1em;
393 | }
394 |
395 | .select2-container--default .select2-results__option .select2-results__option .select2-results__group {
396 | padding-left: 0;
397 | }
398 |
399 | .select2-container--default .select2-results__option .select2-results__option .select2-results__option {
400 | margin-left: -1em;
401 | padding-left: 2em;
402 | }
403 |
404 | .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
405 | margin-left: -2em;
406 | padding-left: 3em;
407 | }
408 |
409 | .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
410 | margin-left: -3em;
411 | padding-left: 4em;
412 | }
413 |
414 | .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
415 | margin-left: -4em;
416 | padding-left: 5em;
417 | }
418 |
419 | .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
420 | margin-left: -5em;
421 | padding-left: 6em;
422 | }
423 |
424 | .select2-container--default .select2-results__option--highlighted[aria-selected] {
425 | background-color: #5897fb;
426 | color: white;
427 | }
428 |
429 | .select2-container--default .select2-results__group {
430 | cursor: default;
431 | display: block;
432 | padding: 6px;
433 | }
434 |
435 | .select2-container--classic .select2-selection--single {
436 | background-color: #f6f6f6;
437 | border: 1px solid #aaa;
438 | border-radius: 4px;
439 | outline: 0;
440 | background-image: -webkit-linear-gradient(top, #fff 50%, #eee 100%);
441 | background-image: -o-linear-gradient(top, #fff 50%, #eee 100%);
442 | background-image: linear-gradient(to bottom, #fff 50%, #eee 100%);
443 | background-repeat: repeat-x;
444 | filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
445 | }
446 |
447 | .select2-container--classic .select2-selection--single:focus {
448 | border: 1px solid #5897fb;
449 | }
450 |
451 | .select2-container--classic .select2-selection--single .select2-selection__rendered {
452 | color: #444;
453 | line-height: 28px;
454 | }
455 |
456 | .select2-container--classic .select2-selection--single .select2-selection__clear {
457 | cursor: pointer;
458 | float: right;
459 | font-weight: bold;
460 | margin-right: 10px;
461 | }
462 |
463 | .select2-container--classic .select2-selection--single .select2-selection__placeholder {
464 | color: #999;
465 | }
466 |
467 | .select2-container--classic .select2-selection--single .select2-selection__arrow {
468 | background-color: #ddd;
469 | border: none;
470 | border-left: 1px solid #aaa;
471 | border-top-right-radius: 4px;
472 | border-bottom-right-radius: 4px;
473 | height: 26px;
474 | position: absolute;
475 | top: 1px;
476 | right: 1px;
477 | width: 20px;
478 | background-image: -webkit-linear-gradient(top, #eee 50%, #ccc 100%);
479 | background-image: -o-linear-gradient(top, #eee 50%, #ccc 100%);
480 | background-image: linear-gradient(to bottom, #eee 50%, #ccc 100%);
481 | background-repeat: repeat-x;
482 | filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#cccccc', GradientType=0);
483 | }
484 |
485 | .select2-container--classic .select2-selection--single .select2-selection__arrow b {
486 | border-color: #888 transparent transparent transparent;
487 | border-style: solid;
488 | border-width: 5px 4px 0 4px;
489 | height: 0;
490 | left: 50%;
491 | margin-left: -4px;
492 | margin-top: -2px;
493 | position: absolute;
494 | top: 50%;
495 | width: 0;
496 | }
497 |
498 | .select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear {
499 | float: left;
500 | }
501 |
502 | .select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow {
503 | border: none;
504 | border-right: 1px solid #aaa;
505 | border-radius: 0;
506 | border-top-left-radius: 4px;
507 | border-bottom-left-radius: 4px;
508 | left: 1px;
509 | right: auto;
510 | }
511 |
512 | .select2-container--classic.select2-container--open .select2-selection--single {
513 | border: 1px solid #5897fb;
514 | }
515 |
516 | .select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow {
517 | background: transparent;
518 | border: none;
519 | }
520 |
521 | .select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b {
522 | border-color: transparent transparent #888 transparent;
523 | border-width: 0 4px 5px 4px;
524 | }
525 |
526 | .select2-container--classic.select2-container--open.select2-container--above .select2-selection--single {
527 | border-top: none;
528 | border-top-left-radius: 0;
529 | border-top-right-radius: 0;
530 | background-image: -webkit-linear-gradient(top, #fff 0%, #eee 50%);
531 | background-image: -o-linear-gradient(top, #fff 0%, #eee 50%);
532 | background-image: linear-gradient(to bottom, #fff 0%, #eee 50%);
533 | background-repeat: repeat-x;
534 | filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
535 | }
536 |
537 | .select2-container--classic.select2-container--open.select2-container--below .select2-selection--single {
538 | border-bottom: none;
539 | border-bottom-left-radius: 0;
540 | border-bottom-right-radius: 0;
541 | background-image: -webkit-linear-gradient(top, #eee 50%, #fff 100%);
542 | background-image: -o-linear-gradient(top, #eee 50%, #fff 100%);
543 | background-image: linear-gradient(to bottom, #eee 50%, #fff 100%);
544 | background-repeat: repeat-x;
545 | filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0);
546 | }
547 |
548 | .select2-container--classic .select2-selection--multiple {
549 | background-color: white;
550 | border: 1px solid #aaa;
551 | border-radius: 4px;
552 | cursor: text;
553 | outline: 0;
554 | }
555 |
556 | .select2-container--classic .select2-selection--multiple:focus {
557 | border: 1px solid #5897fb;
558 | }
559 |
560 | .select2-container--classic .select2-selection--multiple .select2-selection__rendered {
561 | list-style: none;
562 | margin: 0;
563 | padding: 0 5px;
564 | }
565 |
566 | .select2-container--classic .select2-selection--multiple .select2-selection__clear {
567 | display: none;
568 | }
569 |
570 | .select2-container--classic .select2-selection--multiple .select2-selection__choice {
571 | background-color: #e4e4e4;
572 | border: 1px solid #aaa;
573 | border-radius: 4px;
574 | cursor: default;
575 | float: left;
576 | margin-right: 5px;
577 | margin-top: 5px;
578 | padding: 0 5px;
579 | }
580 |
581 | .select2-container--classic .select2-selection--multiple .select2-selection__choice__remove {
582 | color: #888;
583 | cursor: pointer;
584 | display: inline-block;
585 | font-weight: bold;
586 | margin-right: 2px;
587 | }
588 |
589 | .select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover {
590 | color: #555;
591 | }
592 |
593 | .select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
594 | float: right;
595 | }
596 |
597 | .select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
598 | margin-left: 5px;
599 | margin-right: auto;
600 | }
601 |
602 | .select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
603 | margin-left: 2px;
604 | margin-right: auto;
605 | }
606 |
607 | .select2-container--classic.select2-container--open .select2-selection--multiple {
608 | border: 1px solid #5897fb;
609 | }
610 |
611 | .select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple {
612 | border-top: none;
613 | border-top-left-radius: 0;
614 | border-top-right-radius: 0;
615 | }
616 |
617 | .select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple {
618 | border-bottom: none;
619 | border-bottom-left-radius: 0;
620 | border-bottom-right-radius: 0;
621 | }
622 |
623 | .select2-container--classic .select2-search--dropdown .select2-search__field {
624 | border: 1px solid #aaa;
625 | outline: 0;
626 | }
627 |
628 | .select2-container--classic .select2-search--inline .select2-search__field {
629 | outline: 0;
630 | }
631 |
632 | .select2-container--classic .select2-dropdown {
633 | background-color: white;
634 | border: 1px solid transparent;
635 | }
636 |
637 | .select2-container--classic .select2-dropdown--above {
638 | border-bottom: none;
639 | }
640 |
641 | .select2-container--classic .select2-dropdown--below {
642 | border-top: none;
643 | }
644 |
645 | .select2-container--classic .select2-results > .select2-results__options {
646 | max-height: 200px;
647 | overflow-y: auto;
648 | }
649 |
650 | .select2-container--classic .select2-results__option[role=group] {
651 | padding: 0;
652 | }
653 |
654 | .select2-container--classic .select2-results__option[aria-disabled=true] {
655 | color: grey;
656 | }
657 |
658 | .select2-container--classic .select2-results__option--highlighted[aria-selected] {
659 | background-color: #3875d7;
660 | color: white;
661 | }
662 |
663 | .select2-container--classic .select2-results__group {
664 | cursor: default;
665 | display: block;
666 | padding: 6px;
667 | }
668 |
669 | .select2-container--classic.select2-container--open .select2-dropdown {
670 | border-color: #5897fb;
671 | }
672 |
673 | button,
674 | input[type="button"],
675 | input[type="reset"],
676 | input[type="submit"],
677 | button {
678 | -webkit-appearance: none;
679 | -moz-appearance: none;
680 | -ms-appearance: none;
681 | -o-appearance: none;
682 | appearance: none;
683 | -webkit-font-smoothing: antialiased;
684 | -moz-osx-font-smoothing: grayscale;
685 | background-color: #dd6a58;
686 | border-radius: 3px;
687 | border: none;
688 | color: #fff;
689 | cursor: pointer;
690 | display: inline-block;
691 | font-family: "Roboto", "Helvetica Neue", "Helvetica", sans-serif;
692 | font-size: 1rem;
693 | font-weight: 600;
694 | line-height: 1;
695 | padding: 0.75em 1em;
696 | text-decoration: none;
697 | user-select: none;
698 | vertical-align: middle;
699 | white-space: nowrap;
700 | }
701 |
702 | button:focus,
703 | button:hover,
704 | input[type="button"]:hover,
705 | input[type="button"]:focus,
706 | input[type="reset"]:hover,
707 | input[type="reset"]:focus,
708 | input[type="submit"]:hover,
709 | input[type="submit"]:focus,
710 | button:hover,
711 | button:focus {
712 | background-color: #c13c27;
713 | color: #fff;
714 | }
715 |
716 | button:disabled,
717 | input[type="button"]:disabled,
718 | input[type="reset"]:disabled,
719 | input[type="submit"]:disabled,
720 | button:disabled {
721 | cursor: not-allowed;
722 | opacity: 0.5;
723 | }
724 |
725 | fieldset {
726 | background-color: #fefdfc;
727 | border: 1px solid #F8E7CF;
728 | margin: 0 0 0.75em;
729 | padding: 1.5em;
730 | }
731 |
732 | input,
733 | label,
734 | select {
735 | display: block;
736 | font-family: "Roboto", "Helvetica Neue", "Helvetica", sans-serif;
737 | font-size: 1rem;
738 | }
739 |
740 | label {
741 | font-weight: 600;
742 | margin-bottom: 0.375em;
743 | }
744 |
745 | label.required::after {
746 | content: "*";
747 | }
748 |
749 | label abbr {
750 | display: none;
751 | }
752 |
753 | input[type="color"],
754 | input[type="date"],
755 | input[type="datetime"],
756 | input[type="datetime-local"],
757 | input[type="email"],
758 | input[type="month"],
759 | input[type="number"],
760 | input[type="password"],
761 | input[type="tel"],
762 | input[type="text"],
763 | input[type="time"],
764 | input[type="url"],
765 | input[type="week"],
766 | input:not([type]),
767 | select[multiple=multiple],
768 | textarea,
769 | textarea {
770 | background-color: #FDFDFD;
771 | border: 1px solid #F8E7CF;
772 | border-radius: 3px;
773 | box-shadow: inset 0 1px 3px rgba(0,0,0,0.06);
774 | box-sizing: border-box;
775 | font-family: "Roboto", "Helvetica Neue", "Helvetica", sans-serif;
776 | font-size: 1rem;
777 | margin-bottom: 0.75em;
778 | padding: 0.5em;
779 | transition: border-color;
780 | width: 100%;
781 | }
782 |
783 | input[type="color"]:hover,
784 | input[type="date"]:hover,
785 | input[type="datetime"]:hover,
786 | input[type="datetime-local"]:hover,
787 | input[type="email"]:hover,
788 | input[type="month"]:hover,
789 | input[type="number"]:hover,
790 | input[type="password"]:hover,
791 | input[type="search"]:hover,
792 | input[type="tel"]:hover,
793 | input[type="text"]:hover,
794 | input[type="time"]:hover,
795 | input[type="url"]:hover,
796 | input[type="week"]:hover,
797 | input:not([type]):hover,
798 | select[multiple=multiple]:hover,
799 | textarea:hover,
800 | textarea:hover {
801 | border-color: #f2d1a2;
802 | }
803 |
804 | input[type="color"]:focus,
805 | input[type="date"]:focus,
806 | input[type="datetime"]:focus,
807 | input[type="datetime-local"]:focus,
808 | input[type="email"]:focus,
809 | input[type="month"]:focus,
810 | input[type="number"]:focus,
811 | input[type="password"]:focus,
812 | input[type="search"]:focus,
813 | input[type="tel"]:focus,
814 | input[type="text"]:focus,
815 | input[type="time"]:focus,
816 | input[type="url"]:focus,
817 | input[type="week"]:focus,
818 | input:not([type]):focus,
819 | select[multiple=multiple]:focus,
820 | textarea:focus,
821 | textarea:focus {
822 | border-color: #dd6a58;
823 | box-shadow: inset 0 1px 3px rgba(0,0,0,0.06),0 0 5px rgba(217,87,67,0.7);
824 | }
825 |
826 | textarea {
827 | resize: vertical;
828 | }
829 |
830 | input[type="search"] {
831 | -webkit-appearance: none;
832 | -moz-appearance: none;
833 | -ms-appearance: none;
834 | -o-appearance: none;
835 | appearance: none;
836 | }
837 |
838 | input[type="checkbox"],
839 | input[type="radio"] {
840 | display: inline;
841 | margin-right: 0.375em;
842 | }
843 |
844 | input[type="file"] {
845 | padding-bottom: 0.75em;
846 | width: 100%;
847 | }
848 |
849 | select {
850 | margin-bottom: 1.5em;
851 | max-width: 100%;
852 | width: auto;
853 | }
854 |
855 | ol,
856 | ul {
857 | list-style-type: none;
858 | margin: 0;
859 | padding: 0;
860 | }
861 |
862 | article ul {
863 | list-style-type: disc;
864 | margin-bottom: 0.75em;
865 | padding-left: 1.5em;
866 | }
867 |
868 | article ol {
869 | list-style-type: none;
870 | margin-bottom: 1.5em;
871 | }
872 |
873 | article ol > li {
874 | counter-increment: customlistcounter;
875 | clear: both;
876 | padding: 0.75em 0 0.75em 2em;
877 | position: relative;
878 | z-index: 1;
879 | }
880 |
881 | article ol > li::before {
882 | position: absolute;
883 | top: 0.95em;
884 | left: 0;
885 | height: 2em;
886 | width: 2em;
887 | content: counter(customlistcounter) " ";
888 | border: 2px solid #F8E7CF;
889 | border-radius: 50%;
890 | color: #b67d47;
891 | float: left;
892 | font-size: 0.75rem;
893 | line-height: 2;
894 | overflow: hidden;
895 | text-align: center;
896 | }
897 |
898 | article ol:first-child {
899 | counter-reset: customlistcounter;
900 | }
901 |
902 | .chapter li {
903 | margin: 0.75em 0;
904 | }
905 |
906 | .chapter ul+.highlight {
907 | margin-top: 1.5em;
908 | }
909 |
910 | dl {
911 | margin-bottom: 0.75em;
912 | }
913 |
914 | dl dt {
915 | font-weight: bold;
916 | margin-top: 0.75em;
917 | }
918 |
919 | dl dd {
920 | margin: 0;
921 | }
922 |
923 | table {
924 | -webkit-font-feature-settings: "kern", "liga", "tnum";
925 | -moz-font-feature-settings: "kern", "liga", "tnum";
926 | -ms-font-feature-settings: "kern", "liga", "tnum";
927 | font-feature-settings: "kern", "liga", "tnum";
928 | border-collapse: collapse;
929 | margin: 0.75em 0;
930 | table-layout: fixed;
931 | width: 100%;
932 | }
933 |
934 | thead {
935 | background-color: #f9e7e4;
936 | }
937 |
938 | th {
939 | border-bottom: 1px solid #eec68c;
940 | font-weight: 600;
941 | text-align: left;
942 | }
943 |
944 | td {
945 | border-bottom: 1px solid #F8E7CF;
946 | }
947 |
948 | td,
949 | th {
950 | padding: 0.75em;
951 | }
952 |
953 | td,
954 | th,
955 | tr {
956 | vertical-align: middle;
957 | }
958 | /*! HiDPI v2.0.1 | MIT License | git.io/hidpi */
959 |
960 | h1 code,
961 | h2 code,
962 | h3 code,
963 | h4 code,
964 | h5 code,
965 | h6 code {
966 | text-transform: none;
967 | }
968 |
969 |
970 | p {
971 | margin: 1.5em 0 0.75em;
972 | line-height: 1.5em;
973 | }
974 |
975 | a {
976 | color: #c7341f;
977 | transition: color 0.1s linear;
978 | text-decoration: underline;
979 | }
980 |
981 | a:active,
982 | a:focus,
983 | a:hover {
984 | color: #9b2918;
985 | cursor: pointer;
986 | }
987 |
988 | a:active {
989 | outline: none;
990 | }
991 |
992 | hr {
993 | border-bottom: 1px solid #F8E7CF;
994 | border-left: none;
995 | border-right: none;
996 | border-top: none;
997 | margin: 1.5em 0;
998 | }
999 |
1000 | img,
1001 | picture {
1002 | margin: 0;
1003 | max-width: 100%;
1004 | }
1005 |
1006 | em {
1007 | font-style: italic;
1008 | }
1009 |
1010 | strong {
1011 | font-weight: bold;
1012 | }
1013 |
1014 | .ds-dropdown-menu {
1015 | background-color: #FFF;
1016 | border-radius: 4px;
1017 | margin: 6px 0 0;
1018 | text-align: left;
1019 | box-shadow: 0 1px 2px rgba(0,0,0,0.5);
1020 | }
1021 |
1022 | .algolia-docsearch-suggestion {
1023 | color: #333;
1024 | cursor: pointer;
1025 | overflow: hidden;
1026 | border-bottom: 1px solid #f2d1a2;
1027 | }
1028 |
1029 | .algolia-docsearch-suggestion--category-header {
1030 | display: none;
1031 | border: 2px solid white;
1032 | background: #dd6a58;
1033 | color: white;
1034 | font-weight: 600;
1035 | padding: 5px 10px;
1036 | text-align: left;
1037 | }
1038 |
1039 | .algolia-docsearch-suggestion__main .algolia-docsearch-suggestion--category-header {
1040 | display: block;
1041 | }
1042 |
1043 | .algolia-docsearch-suggestion--highlight {
1044 | padding: 0;
1045 | color: #EC605E;
1046 | background: none;
1047 | font-weight: 600;
1048 | }
1049 |
1050 | .algolia-docsearch-suggestion--category-header .algolia-docsearch-suggestion--highlight {
1051 | color: inherit;
1052 | background: #eaa398;
1053 | }
1054 |
1055 | .aa-cursor .algolia-docsearch-suggestion--content {
1056 | color: #c13c27;
1057 | }
1058 |
1059 | .aa-cursor .algolia-docsearch-suggestion {
1060 | background: white;
1061 | }
1062 |
1063 | .algolia-docsearch-suggestion--subcategory-column {
1064 | display: none;
1065 | }
1066 |
1067 | .algolia-docsearch-suggestion--text {
1068 | display: none;
1069 | }
1070 |
1071 | .algolia-docsearch-suggestion--no-results .algolia-docsearch-suggestion--text {
1072 | display: block;
1073 | }
1074 |
1075 | .algolia-docsearch-suggestion--content {
1076 | padding: 3px 5px;
1077 | }
1078 |
1079 | .algolia-docsearch-suggestion--subcategory-inline {
1080 | display: inline-block;
1081 | font-weight: bold;
1082 | }
1083 |
1084 | .algolia-docsearch-suggestion--subcategory-inline:after {
1085 | content: " › ";
1086 | }
1087 |
1088 | .algolia-docsearch-suggestion--title {
1089 | display: inline;
1090 | }
1091 |
1092 | .algolia-docsearch-footer {
1093 | border-top: 1px solid #F8E7CF;
1094 | text-align: right;
1095 | font-size: 12px;
1096 | padding: 4px 2px 0 0;
1097 | color: #333;
1098 | }
1099 |
1100 | .algolia-docsearch-footer .algolia-docsearch-footer--logo {
1101 | display: inline-block !important;
1102 | width: 45px;
1103 | height: 16px;
1104 | text-indent: 101%;
1105 | overflow: hidden;
1106 | white-space: nowrap;
1107 | background-image: url("data:image/png;base64,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");
1108 | background-repeat: no-repeat;
1109 | background-size: contain;
1110 | vertical-align: middle;
1111 | }
1112 | @media (min-width: 40em) {
1113 | .ds-dropdown-menu {
1114 | min-width: 100%;
1115 | }
1116 |
1117 | .algolia-docsearch-suggestion--text {
1118 | display: block;
1119 | font-size: 0.9em;
1120 | padding: 2px 0;
1121 | }
1122 | }
1123 | @media (min-width: 53.75em) {
1124 | .ds-dropdown-menu {
1125 | min-width: 600px;
1126 | }
1127 |
1128 | .algolia-docsearch-suggestion {
1129 | display: table;
1130 | width: 100%;
1131 | border-bottom: 1px solid #F8E7CF;
1132 | }
1133 |
1134 | .algolia-docsearch-suggestion--subcategory-column {
1135 | border-right: 1px solid #F8E7CF;
1136 | background: #FFFDF9;
1137 | color: #444;
1138 | display: table-cell;
1139 | overflow: hidden;
1140 | padding: 3px 7px 3px 5px;
1141 | text-align: right;
1142 | text-overflow: ellipsis;
1143 | vertical-align: top;
1144 | width: 135px;
1145 | max-width: 135px;
1146 | min-width: 135px;
1147 | }
1148 |
1149 | .algolia-docsearch-suggestion--subcategory-column-text {
1150 | display: none;
1151 | }
1152 |
1153 | .algolia-docsearch-suggestion__secondary .algolia-docsearch-suggestion--subcategory-column-text {
1154 | display: block;
1155 | }
1156 |
1157 | .algolia-docsearch-suggestion--content {
1158 | display: table-cell;
1159 | padding: 3px 10px;
1160 | }
1161 |
1162 | .algolia-docsearch-suggestion--subcategory-inline {
1163 | display: none;
1164 | }
1165 |
1166 | .algolia-docsearch-suggestion--title {
1167 | font-weight: 600;
1168 | }
1169 |
1170 | .algolia-docsearch-suggestion--text {
1171 | display: block;
1172 | font-weight: normal;
1173 | padding: 2px;
1174 | }
1175 | }
1176 |
1177 | *,
1178 | *:after {
1179 | box-sizing: border-box;
1180 | }
1181 |
1182 | body {
1183 | -webkit-font-smoothing: antialiased;
1184 | -moz-osx-font-smoothing: grayscale;
1185 | background-color: #FDFDFD;
1186 | margin: 0;
1187 | }
1188 | @media screen and (min-width: 53.75em) {
1189 | main {
1190 | display: flex;
1191 | }
1192 | }
1193 |
1194 | .container {
1195 | max-width: 60em;
1196 | margin-left: auto;
1197 | margin-right: auto;
1198 | padding: 0 1em;
1199 | }
1200 |
1201 | .container::after {
1202 | clear: both;
1203 | content: "";
1204 | display: table;
1205 | }
1206 |
1207 | .sidebar {
1208 | padding-top: 0.75em;
1209 | background-color: #FFFDF9;
1210 | border-bottom: 1px solid #F8E7CF;
1211 | position: relative;
1212 | z-index: 1;
1213 | }
1214 | @media screen and (min-width: 53.75em) {
1215 | .sidebar {
1216 | float: left;
1217 | display: block;
1218 | margin-right: 2.35765%;
1219 | width: 27.49666%;
1220 | border-bottom: 0;
1221 | border-right: 1px solid #F8E7CF;
1222 | padding: 3em 1.618em 3em 0;
1223 | }
1224 |
1225 | .sidebar:last-child {
1226 | margin-right: 0;
1227 | }
1228 |
1229 | .sidebar::before {
1230 | position: absolute;
1231 | top: 0;
1232 | right: 0;
1233 | bottom: 0;
1234 | left: -100vw;
1235 | content: "";
1236 | display: block;
1237 | background-color: #FFFDF9;
1238 | z-index: -1;
1239 | }
1240 | }
1241 |
1242 | .sidebar .ember-power-select-trigger {
1243 | margin-bottom: 1em;
1244 | }
1245 |
1246 | article {
1247 | padding: 3em 0;
1248 | @media screen and (min-width: 53.75em) {
1249 | float: left;
1250 | display: block;
1251 | margin-right: 2.35765%;
1252 | width: 70.14568%;
1253 | }
1254 | &:last-child {
1255 | margin-right: 0;
1256 | }
1257 | }
1258 |
1259 | article .edit-page {
1260 | height: 18px;
1261 | width: 24px;
1262 | color: #865931;
1263 | display: inline-block;
1264 | float: right;
1265 | font-size: 1rem;
1266 | margin: 0.5em 0 0;
1267 | opacity: 0.4;
1268 | overflow: hidden;
1269 | }
1270 |
1271 | article .edit-page:hover {
1272 | opacity: 1;
1273 | border-bottom: 0;
1274 | }
1275 | article, h1 {
1276 | margin-top: 0;
1277 | }
1278 |
1279 | article hr + h2,
1280 | article hr + h3,
1281 | article hr + div > h2:first-child,
1282 | article hr + div > h3:first-child {
1283 | margin-top: 0
1284 | }
1285 |
1286 | article h4 {
1287 | margin-top: 1.5em;
1288 | }
1289 |
1290 | article .video {
1291 | position: relative;
1292 | width: 100%;
1293 | height: 0;
1294 | padding-bottom: 56.25%;
1295 | margin-top: 2em;
1296 | }
1297 |
1298 | article .video iframe {
1299 | position: absolute;
1300 | top: 0;
1301 | left: 0;
1302 | width: 100%;
1303 | height: 100%;
1304 | }
1305 |
1306 | article footer {
1307 | border-top: 1px solid #F8E7CF;
1308 | margin-top: 5em;
1309 | padding: 1.5em 0;
1310 | }
1311 |
1312 | article footer::after {
1313 | clear: both;
1314 | content: "";
1315 | display: table;
1316 | }
1317 |
1318 | article footer a {
1319 | text-decoration: underline;
1320 | }
1321 |
1322 | article footer a::after,
1323 | article footer a::before {
1324 | display: inline-block;
1325 | font-weight: 700;
1326 | margin: 0 0.5em;
1327 | transition: transform 200ms;
1328 | }
1329 |
1330 | article footer .previous-guide {
1331 | float: left;
1332 | }
1333 |
1334 | article footer .previous-guide::before {
1335 | content: "\2039";
1336 | }
1337 |
1338 | article footer .previous-guide:hover::before {
1339 | transform: translateX(-0.5em);
1340 | }
1341 |
1342 | article footer .next-guide {
1343 | float: right;
1344 | }
1345 |
1346 | article footer .next-guide::after {
1347 | content: "\203A";
1348 | }
1349 |
1350 | article footer .next-guide:hover::after {
1351 | transform: translateX(0.5em);
1352 | }
1353 |
1354 | article.x404 {
1355 | width: 80%;
1356 | margin: 0 auto;
1357 | }
1358 |
1359 | article.x404 img {
1360 | float: left;
1361 | margin: 1em 0.5em;
1362 | max-width: 300px;
1363 | }
1364 |
1365 | .back-to-top {
1366 | -webkit-transition: opacity 200ms;
1367 | -moz-transition: opacity 200ms;
1368 | transition: opacity 200ms;
1369 | color: #dd6a58;
1370 | display: none;
1371 | margin-left: 1em;
1372 | text-align: center;
1373 | }
1374 | @media screen and (max-width: 74em) {
1375 | .back-to-top {
1376 | height: 1.5em;
1377 | width: 1.5em;
1378 | overflow: hidden;
1379 | }
1380 | }
1381 | @media screen and (max-width: 63em) {
1382 | .back-to-top {
1383 | height: 0;
1384 | }
1385 | }
1386 |
1387 | @import 'table-of-contents';
1388 |
1389 | .old-version-warning {
1390 | background-color: #dd6a58;
1391 | color: #FFFBF5;
1392 | padding: 0.5em;
1393 | border-radius: 3px;
1394 | margin-bottom: 40px;
1395 | }
1396 |
1397 | .old-version-warning .btn {
1398 | float: right;
1399 | font-weight: bold;
1400 | font-size: 12px;
1401 | color: #FFFBF5;
1402 | padding: 0.3em 0.8em;
1403 | background-color: #e69082;
1404 | border-radius: 3px;
1405 | }
1406 |
1407 | .old-version-warning .btn:hover {
1408 | background: #d4442e;
1409 | }
1410 |
1411 | .ds-dropdown-menu {
1412 | right: 0 !important;
1413 | font-size: 0.8rem;
1414 | border-color: #aaa;
1415 | }
1416 | @media (min-width: 53.75em) {
1417 | .ds-dropdown-menu {
1418 | left: auto !important;
1419 | }
1420 | }
1421 | @font-face {
1422 | font-family: 'fontello';
1423 | src: url("../fonts/fontello.eot?32151418");
1424 | src: url("../fonts/fontello.eot?32151418#iefix") format("embedded-opentype"),url("../fonts/fontello.woff2?32151418") format("woff2"),url("../fonts/fontello.woff?32151418") format("woff"),url("../fonts/fontello.ttf?32151418") format("truetype"),url("../fonts/fontello.svg?32151418#fontello") format("svg");
1425 | font-weight: normal;
1426 | font-style: normal;
1427 | }
1428 |
1429 | [class^="icon-"]:before,
1430 | [class*=" icon-"]:before {
1431 | font-family: "fontello";
1432 | font-style: normal;
1433 | font-weight: normal;
1434 | speak: none;
1435 | display: inline-block;
1436 | text-decoration: inherit;
1437 | width: 1em;
1438 | margin-right: 0.2em;
1439 | text-align: center;
1440 | font-variant: normal;
1441 | text-transform: none;
1442 | line-height: 1em;
1443 | margin-left: 0.2em;
1444 | -webkit-font-smoothing: antialiased;
1445 | -moz-osx-font-smoothing: grayscale;
1446 | }
1447 |
1448 | .icon-search:before {
1449 | content: '\e800';
1450 | }
1451 |
1452 | .icon-cancel:before {
1453 | content: '\e801';
1454 | }
1455 |
1456 | .icon-link:before {
1457 | content: '\e802';
1458 | }
1459 |
1460 | .icon-pencil:before {
1461 | content: '\e803';
1462 | }
1463 |
1464 | .icon-fork:before {
1465 | content: '\e804';
1466 | }
1467 |
1468 | .icon-github:before {
1469 | content: '\e805';
1470 | }
1471 |
1472 | .icon-twitter:before {
1473 | content: '\e806';
1474 | }
1475 |
1476 | .icon-gplus:before {
1477 | content: '\e807';
1478 | }
1479 |
1480 | .icon-attention-circled:before {
1481 | content: '\e808';
1482 | }
1483 |
1484 | .icon-link-ext:before {
1485 | content: '\f08e';
1486 | }
1487 |
1488 | .note {
1489 | background: rgba(0,0,0,0.2);
1490 | }
1491 |
1492 | .note::before {
1493 | content: "Note";
1494 | }
1495 |
1496 | .previous-guide {
1497 | float: left;
1498 | border-bottom: 1px solid transparent;
1499 | }
1500 |
1501 | .next-guide {
1502 | float: right;
1503 | border-bottom: 1px solid transparent;
1504 | }
1505 |
1506 | .visually-hidden {
1507 | border: 0 !important;
1508 | clip: rect(0 0 0 0) !important;
1509 | height: 1px !important;
1510 | margin: -1px !important;
1511 | overflow: hidden !important;
1512 | padding: 0 !important;
1513 | position: absolute !important;
1514 | width: 1px !important;
1515 | }
1516 |
1517 | .footer a {
1518 | text-decoration: none;
1519 | }
1520 |
1521 | @import "ember-power-select";
1522 | @import "code-block-file-name";
1523 | @import "prism-overrides";
1524 | @import "search-input";
1525 |
--------------------------------------------------------------------------------
/app/templates/application.hbs:
--------------------------------------------------------------------------------
1 | {{head-layout}}
2 |
3 | {{#es-header}}
4 | {{#es-navbar}}
5 |
8 | {{/es-navbar}}
9 | {{/es-header}}
10 |
11 |
12 | {{outlet}}
13 |
14 |
15 | {{es-footer}}
16 |
--------------------------------------------------------------------------------
/app/templates/components/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ember-learn/guides-app/2e3a25fd3b924d6ced52d15d65f19232cc3145b3/app/templates/components/.gitkeep
--------------------------------------------------------------------------------
/app/templates/components/chapter-links.hbs:
--------------------------------------------------------------------------------
1 | {{#if page.isFirstPage}}
2 | {{#if page.previousSection}}
3 | {{#link-to 'version.show' previousSectionPage.url class="previous-guide"}}{{previousSectionPage.title}}{{/link-to}}
4 | {{/if}}
5 | {{else}}
6 | {{#if page.previousPage}}
7 | {{#link-to 'version.show' page.previousPage.url class="previous-guide"}}{{page.previousPage.title}}{{/link-to}}
8 | {{/if}}
9 | {{/if}}
10 |
11 |
12 | {{#if page.isLastPage}}
13 | {{#if page.nextSection}}
14 | {{#link-to 'version.show' nextSectionPage.url class="next-guide"}}We've finished covering {{page.currentSection.title}}. Next up: {{page.nextSection.title}} - {{nextSectionPage.title}}{{/link-to}}
15 | {{/if}}
16 | {{else}}
17 | {{#link-to 'version.show' page.nextPage.url class="next-guide"}}{{page.nextPage.title}}{{/link-to}}
18 | {{/if}}
19 |
--------------------------------------------------------------------------------
/app/templates/components/dropdown-header.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/templates/components/guides-article.hbs:
--------------------------------------------------------------------------------
1 | {{#unless (eq version currentVersion)}}
2 |
3 | Old Guides - You are viewing the guides for Ember {{version}}.
4 |
5 | {{#link-to 'version.show' 'release' path class="btn"}} VIEW {{currentVersion}} {{/link-to}}
6 |
7 | {{/unless}}
8 |
9 | Edit Page
11 |
12 |
13 | {{page.currentPage.title}}
14 |
15 |
16 |
17 | {{markdown-to-html model.content extensions='showdown-section-groups'}}
18 |
19 | {{chapter-links pages=pages}}
20 |
--------------------------------------------------------------------------------
/app/templates/components/search-input.hbs:
--------------------------------------------------------------------------------
1 |
11 |
12 | {{!-- Search results dropdown --}}
13 | {{#ember-tether
14 | target='#search-input'
15 | targetAttachment='bottom left'
16 | attachment='top left'
17 | constraints=_resultTetherConstraints
18 | class='ds-dropdown-results'
19 | }}
20 | {{#if showDropdown}}
21 |
41 | {{/if}}
42 | {{/ember-tether}}
43 |
--------------------------------------------------------------------------------
/app/templates/components/search-result.hbs:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 | {{sectionTitle}}
6 |
7 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/templates/components/table-of-contents.hbs:
--------------------------------------------------------------------------------
1 | {{!-- #{build_toc_for(pages)} --}}
2 | {{#each data as |page|}}
3 | {{#unless (or page.skipToc (get page 'skip-toc'))}}
4 |
5 | {{#if page.pages}}
6 | {{#cp-panel open=(eq currentSection.id page.id) as |p|}}
7 | {{#if fastboot.isFastBoot}}
8 | {{#link-to 'version.show' page.id activeClass="selected" class="cp-Panel-toggle" data-test-toc-link=page.title}}
9 | {{page.title}}
10 | {{/link-to}}
11 | {{else}}
12 | {{#p.toggle data-test-toc-title=page.title}}
13 | {{page.title}}
14 | {{/p.toggle}}
15 | {{/if}}
16 |
17 | {{#p.body}}
18 | {{table-of-contents data=page.pages currentPage=currentPage level=(inc level)}}
19 | {{/p.body}}
20 | {{/cp-panel}}
21 | {{else}}
22 | {{#link-to 'version.show' page.url activeClass="selected" data-test-toc-link=page.title}}
23 | {{page.title}}
24 | {{/link-to}}
25 | {{/if}}
26 |
27 | {{/unless}}
28 | {{/each}}
29 |
--------------------------------------------------------------------------------
/app/templates/error.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{#if (contains model.errors.0.status (array "404" "403"))}}
3 |
4 | Ack! 404 friend, you're in the wrong place
5 |
6 |
7 | This page wasn't found. If you were looking for documentation, please try
8 | the Guides section of the site. If you expected
9 | something else to be here, please file a ticket .
10 |
11 | {{else}}
12 |
13 | Ack! An unknown error has occured!
14 |
15 |
16 | We're not quite sure what happened. If you were looking for documentation, please try
17 | the Guides section of the site. If you expected
18 | something else to be here, please file a ticket .
19 |
20 | {{/if}}
21 |
22 |
--------------------------------------------------------------------------------
/app/templates/version.hbs:
--------------------------------------------------------------------------------
1 |
16 |
17 | {{outlet}}
18 |
--------------------------------------------------------------------------------
/app/templates/version/index.hbs:
--------------------------------------------------------------------------------
1 | {{guides-article model=model.content pages=model.pages path='index' version=model.version currentVersion=model.currentVersion}}
2 |
--------------------------------------------------------------------------------
/app/templates/version/show.hbs:
--------------------------------------------------------------------------------
1 | {{guides-article model=model.content pages=model.pages path=model.path version=model.version currentVersion=model.currentVersion}}
2 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | # Test against the latest version of this Node.js version
2 | environment:
3 | nodejs_version: "8"
4 |
5 | # Install scripts. (runs after repo cloning)
6 | install:
7 | # Get the latest stable version of Node.js or io.js
8 | - ps: Install-Product node $env:nodejs_version
9 | # install modules
10 | - npm install
11 |
12 | # Post-install test scripts.
13 | test_script:
14 | # Output useful info for debugging.
15 | - node --version
16 | - npm --version
17 | # run tests
18 | - npm test
19 |
20 | # Don't actually build.
21 | build: off
22 |
--------------------------------------------------------------------------------
/config/deploy.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node */
2 | 'use strict';
3 |
4 | let credentials;
5 |
6 | try {
7 | credentials = require('./credentials.json');
8 | } catch (e) {
9 | credentials = {};
10 | }
11 |
12 | module.exports = function(deployTarget) {
13 | let ENV = {
14 | build: {},
15 | 'prember-algolia': {
16 | indexName: credentials.algoliaIndex || process.env.ALGOLIA_INDEX,
17 | applicationId: credentials.algoliaApplication || process.env.ALGOLIA_APPLICATION,
18 | apiKey: credentials.algoliaKey || process.env.ALGOLIA_KEY,
19 | tagsToExclude: '.old-version-warning,.edit-page,code,pre',
20 | cssSelector: 'section',
21 | versionsToIgnore: ['1.x', '2.x'],
22 | versionPattern: /^(v\d+\.\d+\.\d+)\//,
23 | pathPattern: /^v\d+\.\d+\.\d+\/(.*)\/index.html$/,
24 | }
25 | };
26 |
27 | if (deployTarget === 'development') {
28 | ENV.build.environment = 'development';
29 | // configure other plugins for development deploy target here
30 | }
31 |
32 | if (deployTarget === 'staging') {
33 | ENV.build.environment = 'production';
34 | // configure other plugins for staging deploy target here
35 | }
36 |
37 | if (deployTarget === 'production') {
38 | ENV.build.environment = 'production';
39 | // configure other plugins for production deploy target here
40 | }
41 |
42 | // Note: if you need to build some configuration asynchronously, you can return
43 | // a promise that resolves with the ENV object instead of returning the
44 | // ENV object synchronously.
45 | return ENV;
46 | };
47 |
--------------------------------------------------------------------------------
/config/environment.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function(environment) {
4 | let ENV = {
5 | modulePrefix: 'guides-app',
6 | environment,
7 | rootURL: '/',
8 | locationType: 'trailing-history',
9 | historySupportMiddleware: true,
10 | EmberENV: {
11 | FEATURES: {
12 | // Here you can enable experimental features on an ember canary build
13 | // e.g. 'with-controller': true
14 | },
15 | EXTEND_PROTOTYPES: {
16 | // Prevent Ember Data from overriding Date.parse.
17 | Date: false
18 | }
19 | },
20 |
21 | APP: {
22 | // Here you can pass flags/options to your application instance
23 | // when it is created
24 | },
25 |
26 | fastboot: {
27 | hostWhitelist: [/^localhost:\d+$/, /^127\.0\.0\.1:\d+$/]
28 | },
29 |
30 | showdown: {
31 | ghCompatibleHeaderId: true,
32 | prefixHeaderId: 'toc_'
33 | },
34 |
35 | 'ember-body-class': {
36 | includeRouteName: false
37 | },
38 |
39 | 'ember-algolia': {
40 | algoliaId: 'Y1OMR4C7MF',
41 | algoliaKey: '5d01c83734dc36754d9e94cbf6f8964d'
42 | },
43 |
44 | metricsAdapters: [
45 | {
46 | name: 'GoogleAnalytics',
47 | environments: ['production'],
48 | config: {
49 | id: 'UA-27675533-1',
50 | require: ['linkid']
51 | }
52 | },
53 | ],
54 |
55 | 'ember-meta': {
56 | description: 'Ember.js helps developers be more productive out of the box. Designed with developer ergonomics in mind, its friendly APIs help you get your job done—fast.',
57 | imgSrc: '/images/logos/ember.png',
58 | siteName: 'Ember',
59 | title: 'Ember Guides',
60 | twitterUsername: '@emberjs',
61 | url: 'https://guides.emberjs.com/'
62 | },
63 |
64 | deprecationsGuideURL: 'https://www.emberjs.com/deprecations/'
65 | };
66 |
67 | if (environment === 'development') {
68 | // ENV.APP.LOG_RESOLVER = true;
69 | // ENV.APP.LOG_ACTIVE_GENERATION = true;
70 | // ENV.APP.LOG_TRANSITIONS = true;
71 | // ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
72 | // ENV.APP.LOG_VIEW_LOOKUPS = true;
73 | }
74 |
75 | if (environment === 'test') {
76 | // Testem prefers this...
77 | ENV.locationType = 'none';
78 |
79 | // keep test console output quieter
80 | ENV.APP.LOG_ACTIVE_GENERATION = false;
81 | ENV.APP.LOG_VIEW_LOOKUPS = false;
82 |
83 | ENV.APP.rootElement = '#ember-testing';
84 | ENV.APP.autoboot = false;
85 |
86 | ENV['ember-tether'] = {
87 | bodyElementId: 'ember-testing'
88 | };
89 |
90 | }
91 |
92 | if (environment === 'production') {
93 | // here you can enable a production-specific feature
94 | }
95 |
96 | return ENV;
97 | };
98 |
--------------------------------------------------------------------------------
/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 | const isCI = !!process.env.CI;
10 | const isProduction = process.env.EMBER_ENV === 'production';
11 |
12 | if (isCI || isProduction) {
13 | browsers.push('ie 11');
14 | }
15 |
16 | module.exports = {
17 | browsers
18 | };
19 |
--------------------------------------------------------------------------------
/ember-cli-build.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const EmberApp = require('ember-cli/lib/broccoli/ember-app');
4 |
5 | module.exports = function(defaults) {
6 | let app = new EmberApp(defaults, {
7 | 'ember-prism': {
8 | 'theme': 'okaidia',
9 | 'components': [
10 | 'apacheconf',
11 | 'bash',
12 | 'css',
13 | 'handlebars',
14 | 'http',
15 | 'javascript',
16 | 'json',
17 | 'markup-templating',
18 | 'ruby',
19 | 'scss',
20 | ],
21 | 'plugins': ['line-numbers', 'normalize-whitespace']
22 | },
23 | fingerprint: {
24 | extensions: ['js', 'css', 'map'],
25 | }
26 | });
27 |
28 | app.import('node_modules/compare-versions/index.js');
29 |
30 | return app.toTree();
31 | };
32 |
--------------------------------------------------------------------------------
/lib/content-guides-generator/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const BroccoliMergeTrees = require('broccoli-merge-trees');
4 | const Funnel = require('broccoli-funnel');
5 | const StaticSiteJson = require('broccoli-static-site-json');
6 | const walkSync = require('walk-sync');
7 | const writeFile = require('broccoli-file-creator');
8 | const yaml = require('js-yaml');
9 |
10 | const { readFileSync } = require('fs');
11 | const { Serializer } = require('jsonapi-serializer');
12 | const { extname } = require('path');
13 |
14 | const guidesSrcPkg = 'node_modules/@ember-learn/guides-source';
15 | const guidesSourcePublic = new Funnel(`${guidesSrcPkg}/public`);
16 |
17 | const VersionsSerializer = new Serializer('version', {
18 | attributes: [
19 | 'allVersions',
20 | 'currentVersion',
21 | ],
22 | });
23 |
24 | const versions = yaml.safeLoad(readFileSync(`${guidesSrcPkg}/versions.yml`, 'utf8'));
25 |
26 | let premberVersions = [...versions.allVersions, 'release'];
27 |
28 | const urls = premberVersions.map(version => `/${version}`);
29 |
30 | premberVersions.forEach((premberVersion) => {
31 | const filesVersion = ['current', 'release'].includes(premberVersion) ? versions.currentVersion : premberVersion;
32 | const paths = walkSync(`${guidesSrcPkg}/guides/${filesVersion}`);
33 |
34 | const mdFiles = paths.
35 | filter(path => extname(path) === '.md')
36 | .map(path => path.replace(/\.md/, ''))
37 | .map(path => path.replace(/\/index$/, ''));
38 |
39 | mdFiles.forEach((file) => {
40 | urls.push(`/${premberVersion}/${file}`)
41 | })
42 | });
43 |
44 | // setting an ID so that it's not undefined
45 | versions.id = 'versions';
46 |
47 | const jsonTrees = versions.allVersions.map((version) => new StaticSiteJson(`${guidesSrcPkg}/guides/${version}`, {
48 | contentFolder: `content/${version}`,
49 | contentTypes: ['content', 'description'],
50 | type: 'contents',
51 | attributes: ['canonical', 'redirect'],
52 | }));
53 |
54 | var versionsFile = writeFile('/content/versions.json', JSON.stringify(VersionsSerializer.serialize(versions)));
55 |
56 | module.exports = {
57 | name: 'content-docs-generator',
58 |
59 | isDevelopingAddon() {
60 | return true;
61 | },
62 |
63 | urlsForPrember() {
64 | return urls;
65 | },
66 |
67 | treeForPublic() {
68 | return new BroccoliMergeTrees([versionsFile, guidesSourcePublic, ...jsonTrees]);
69 | }
70 | };
71 |
--------------------------------------------------------------------------------
/lib/content-guides-generator/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "content-guides-generator",
3 | "keywords": [
4 | "ember-addon",
5 | "prember-plugin"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "guides-app",
3 | "version": "0.1.0",
4 | "private": true,
5 | "description": "Ember app that powers https://guides.emberjs.com",
6 | "repository": "https://github.com/ember-learn/guides-app",
7 | "license": "MIT",
8 | "author": "Chris Manson ",
9 | "directories": {
10 | "doc": "doc",
11 | "test": "tests"
12 | },
13 | "scripts": {
14 | "build": "ember build",
15 | "build-production": "ember build -e production",
16 | "lint:js": "eslint ./*.js app blueprints config lib server tests",
17 | "start": "ember serve",
18 | "test": "ember test"
19 | },
20 | "devDependencies": {
21 | "@ember-learn/guides-source": "^3.7.0",
22 | "algoliasearch": "^3.32.0",
23 | "broccoli-asset-rev": "^3.0.0",
24 | "broccoli-merge-trees": "^3.0.2",
25 | "broccoli-static-site-json": "^3.0.0",
26 | "compare-versions": "3.4.0",
27 | "ember-ajax": "^4.0.2",
28 | "ember-auto-import": "^1.2.19",
29 | "ember-body-class": "^1.1.3",
30 | "ember-cli": "~3.7.1",
31 | "ember-cli-app-version": "^3.0.0",
32 | "ember-cli-babel": "^7.4.1",
33 | "ember-cli-dependency-checker": "^3.1.0",
34 | "ember-cli-deploy": "^1.0.2",
35 | "ember-cli-deploy-build": "^1.1.1",
36 | "ember-cli-deploy-prember-algolia": "^1.0.1",
37 | "ember-cli-eslint": "^4.2.1",
38 | "ember-cli-fastboot": "^2.0.4",
39 | "ember-cli-head": "^0.4.0",
40 | "ember-cli-htmlbars": "^3.0.1",
41 | "ember-cli-htmlbars-inline-precompile": "^2.1.0",
42 | "ember-cli-inject-live-reload": "^2.0.1",
43 | "ember-cli-netlify": "0.1.0",
44 | "ember-cli-qunit": "^4.4.0",
45 | "ember-cli-sass": "^8.0.1",
46 | "ember-cli-shims": "^1.2.0",
47 | "ember-cli-showdown": "^4.4.4",
48 | "ember-cli-sri": "^2.1.0",
49 | "ember-cli-uglify": "^2.0.0",
50 | "ember-collapsible-panel": "^3.2.1",
51 | "ember-composable-helpers": "^2.1.0",
52 | "ember-data": "~3.7.0",
53 | "ember-export-application-global": "^2.0.0",
54 | "ember-href-to": "^2.0.1",
55 | "ember-load-initializers": "^1.0.0",
56 | "ember-maybe-import-regenerator": "^0.1.6",
57 | "ember-meta": "^0.5.0",
58 | "ember-metrics": "^0.13.0",
59 | "ember-percy": "^1.5.0",
60 | "ember-power-select": "^2.2.1",
61 | "ember-prism": "^0.4.0",
62 | "ember-resolver": "^5.0.1",
63 | "ember-source": "~3.5.0",
64 | "ember-styleguide": "^2.5.0",
65 | "ember-test-selectors": "^2.0.0",
66 | "ember-tether": "^1.0.0",
67 | "eslint-plugin-ember": "^6.2.0",
68 | "loader.js": "^4.2.3",
69 | "normalize.css": "^8.0.1",
70 | "percy-client": "^3.0.3",
71 | "prember": "^1.0.2",
72 | "qunit-dom": "^0.8.4",
73 | "showdown-section-groups": "^0.3.0"
74 | },
75 | "engines": {
76 | "node": "^4.5 || 6.* || >= 7.*"
77 | },
78 | "ember-addon": {
79 | "paths": [
80 | "lib/content-guides-generator"
81 | ]
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/public/fonts/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "",
3 | "css_prefix_text": "icon-",
4 | "css_use_suffix": false,
5 | "hinting": true,
6 | "units_per_em": 1000,
7 | "ascent": 850,
8 | "glyphs": [
9 | {
10 | "uid": "9dd9e835aebe1060ba7190ad2b2ed951",
11 | "css": "search",
12 | "code": 59392,
13 | "src": "fontawesome"
14 | },
15 | {
16 | "uid": "5211af474d3a9848f67f945e2ccaf143",
17 | "css": "cancel",
18 | "code": 59393,
19 | "src": "fontawesome"
20 | },
21 | {
22 | "uid": "0ddd3e8201ccc7d41f7b7c9d27eca6c1",
23 | "css": "link",
24 | "code": 59394,
25 | "src": "fontawesome"
26 | },
27 | {
28 | "uid": "d35a1d35efeb784d1dc9ac18b9b6c2b6",
29 | "css": "pencil",
30 | "code": 59395,
31 | "src": "fontawesome"
32 | },
33 | {
34 | "uid": "bc4b94dd7a9a1dd2e02f9e4648062596",
35 | "css": "fork",
36 | "code": 59396,
37 | "src": "fontawesome"
38 | },
39 | {
40 | "uid": "5e0a374728ffa8d0ae1f331a8f648231",
41 | "css": "github",
42 | "code": 59397,
43 | "src": "fontawesome"
44 | },
45 | {
46 | "uid": "627abcdb627cb1789e009c08e2678ef9",
47 | "css": "twitter",
48 | "code": 59398,
49 | "src": "fontawesome"
50 | },
51 | {
52 | "uid": "0350d80455823796cce38d84b2b91ba6",
53 | "css": "gplus",
54 | "code": 59399,
55 | "src": "custom_icons",
56 | "selected": true,
57 | "svg": {
58 | "path": "M801.9 509.5Q801.9 625.6 753.3 716.2T615 858 409 909Q325.9 909 250 876.7T119.4 789.6 32.4 659 0 500 32.4 341 119.4 210.4 250 123.3 409 91Q568.6 91 683 198.1L572 304.7Q506.7 241.6 409 241.6 340.4 241.6 282.1 276.2T189.7 370.3 155.7 500 189.7 629.7 282.1 723.8 409 758.4Q455.4 758.4 494.1 745.5T558 713.4 601.8 669.6 629.2 623.3 641.2 582H409V441.4H795.2Q801.9 476.6 801.9 509.5ZM1285.7 441.4V558.6H1169.1V675.2H1051.9V558.6H935.3V441.4H1051.9V324.8H1169.1V441.4H1285.7Z",
59 | "width": 1285.7142857142858
60 | },
61 | "search": [
62 | "glyph"
63 | ]
64 | },
65 | {
66 | "uid": "b035c28eba2b35c6ffe92aee8b0df507",
67 | "css": "attention-circled",
68 | "code": 59400,
69 | "src": "fontawesome"
70 | },
71 | {
72 | "uid": "e15f0d620a7897e2035c18c80142f6d9",
73 | "css": "link-ext",
74 | "code": 61582,
75 | "src": "fontawesome"
76 | }
77 | ]
78 | }
--------------------------------------------------------------------------------
/public/fonts/fontello.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ember-learn/guides-app/2e3a25fd3b924d6ced52d15d65f19232cc3145b3/public/fonts/fontello.eot
--------------------------------------------------------------------------------
/public/fonts/fontello.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Copyright (C) 2016 by original authors @ fontello.com
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/public/fonts/fontello.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ember-learn/guides-app/2e3a25fd3b924d6ced52d15d65f19232cc3145b3/public/fonts/fontello.ttf
--------------------------------------------------------------------------------
/public/fonts/fontello.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ember-learn/guides-app/2e3a25fd3b924d6ced52d15d65f19232cc3145b3/public/fonts/fontello.woff
--------------------------------------------------------------------------------
/public/fonts/fontello.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ember-learn/guides-app/2e3a25fd3b924d6ced52d15d65f19232cc3145b3/public/fonts/fontello.woff2
--------------------------------------------------------------------------------
/public/images/logos/ember.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ember-learn/guides-app/2e3a25fd3b924d6ced52d15d65f19232cc3145b3/public/images/logos/ember.png
--------------------------------------------------------------------------------
/public/images/logos/search-by-algolia.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # http://www.robotstxt.org
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/static.json:
--------------------------------------------------------------------------------
1 | {
2 | "https_only": true,
3 | "root": "dist",
4 | "error_page": "_empty.html",
5 | "force_redirect": true,
6 | "redirects": {
7 | "/": {
8 | "url": "/release/"
9 | },
10 | "/current/(.*)": {
11 | "url": "/release/$1"
12 | }
13 | },
14 | "headers": {
15 | "/**/*.html": {
16 | "Cache-Control": "public, max-age=3600"
17 | },
18 | "/content/**": {
19 | "Cache-Control": "public, max-age=3600"
20 | },
21 | "/assets/**": {
22 | "Cache-Control": "public, max-age=31536000"
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/testem.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | test_page: 'tests/index.html?hidepassed',
3 | disable_watching: true,
4 | launch_in_ci: [
5 | 'Chrome'
6 | ],
7 | launch_in_dev: [
8 | 'Chrome'
9 | ],
10 | browser_args: {
11 | Chrome: {
12 | mode: 'ci',
13 | args: [
14 | // --no-sandbox is needed when running Chrome inside a container
15 | process.env.TRAVIS ? '--no-sandbox' : null,
16 |
17 | '--disable-gpu',
18 | '--headless',
19 | '--remote-debugging-port=0',
20 | '--window-size=1440,900'
21 | ].filter(Boolean)
22 | }
23 | }
24 | };
25 |
--------------------------------------------------------------------------------
/tests/acceptance/cookbook-test.js:
--------------------------------------------------------------------------------
1 | import { click, currentURL, visit } from '@ember/test-helpers';
2 | import { module, test } from 'qunit';
3 | import { setupApplicationTest } from 'ember-qunit';
4 |
5 | module('Acceptance | cookbook', function(hooks) {
6 | setupApplicationTest(hooks);
7 |
8 | /*
9 | Cookbook gets its own tests because it has one additional layer of nesting than
10 | the rest of the guides
11 | */
12 |
13 | test('visiting /cookbook', async function(assert) {
14 | await visit('/v1.10.0/cookbook/');
15 | assert.equal(currentURL(), '/v1.10.0/cookbook/');
16 | await click('.next-guide')
17 | assert.equal(currentURL(), '/v1.10.0/cookbook/contributing');
18 | await click('.next-guide')
19 | assert.equal(currentURL(), '/v1.10.0/cookbook/contributing/understanding_the_cookbook_format');
20 | await click('.previous-guide')
21 | assert.equal(currentURL(), '/v1.10.0/cookbook/contributing');
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/tests/acceptance/current-url-test.js:
--------------------------------------------------------------------------------
1 | import { currentURL, visit } from '@ember/test-helpers';
2 | import { module, test } from 'qunit';
3 |
4 | import { setupApplicationTest } from 'ember-qunit';
5 |
6 | module('Acceptance | current url', function(hooks) {
7 | setupApplicationTest(hooks);
8 |
9 | test('visiting /release-url', async function(assert) {
10 | await visit('/release');
11 | let page = this.owner.lookup('service:page');
12 | let currentVersion = page.get('currentVersion');
13 | currentVersion = currentVersion.slice(currentVersion.indexOf('v') + 1 || 0, currentVersion.lastIndexOf('.') === currentVersion.indexOf('.') ? currentVersion.length : currentVersion.lastIndexOf('.'))
14 | assert.dom('.ember-basic-dropdown-trigger').hasText(currentVersion);
15 | });
16 |
17 | test('visiting / redirects you to /release', async function(assert) {
18 | await visit('/');
19 | let page = this.owner.lookup('service:page');
20 | assert.equal(currentURL(), "/release");
21 |
22 | let currentVersion = page.get('currentVersion');
23 | currentVersion = currentVersion.slice(currentVersion.indexOf('v') + 1 || 0, currentVersion.lastIndexOf('.') === currentVersion.indexOf('.') ? currentVersion.length : currentVersion.lastIndexOf('.'))
24 | assert.dom('.ember-basic-dropdown-trigger').hasText(currentVersion);
25 | });
26 | });
27 |
--------------------------------------------------------------------------------
/tests/acceptance/error-page-test.js:
--------------------------------------------------------------------------------
1 | import { module, test } from 'qunit';
2 | import { visit, currentURL } from '@ember/test-helpers';
3 | import { setupApplicationTest } from 'ember-qunit';
4 |
5 | module('Acceptance | error page', function(hooks) {
6 | setupApplicationTest(hooks);
7 |
8 | test('visiting a non-existent page shows the 404 error-page', async function(assert) {
9 | await visit('/v1.12.0/nonsense/route/');
10 |
11 | assert.equal(currentURL(), '/v1.12.0/nonsense/route/');
12 | assert.dom('[data-test-error-page]').exists();
13 | assert.dom('[data-test-error-message]').hasText(`Ack! 404 friend, you're in the wrong place`);
14 | });
15 | });
16 |
--------------------------------------------------------------------------------
/tests/acceptance/meta-data-test.js:
--------------------------------------------------------------------------------
1 | import { click, currentURL, visit } from '@ember/test-helpers';
2 | import { module, test } from 'qunit';
3 | import { setupApplicationTest } from 'ember-qunit';
4 |
5 | module('Acceptance | meta data', function(hooks) {
6 | setupApplicationTest(hooks);
7 |
8 | test('meta data title and description', async function(assert) {
9 | await visit('/release/');
10 | await click('[data-test-toc-title="Routing"]')
11 | await click('[data-test-toc-link="Defining Your Routes"]')
12 |
13 | assert.equal(currentURL(), '/release/routing/defining-your-routes');
14 |
15 | // lookup title from service because testem modifies title https://github.com/testem/testem/issues/195
16 | let headData = this.owner.lookup('service:head-data');
17 | let title = headData.title;
18 |
19 | let description = document.head.querySelector('meta[name="description"]');
20 |
21 | assert.ok(title);
22 | assert.ok(description);
23 |
24 | assert.equal(title,
25 | 'Defining Your Routes - Routing - Ember Guides');
26 | assert.ok(description.content.startsWith('When your application starts, the router matches the current URL to the routes'));
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/tests/acceptance/previous-next-links-test.js:
--------------------------------------------------------------------------------
1 | import { click, currentURL, visit } from '@ember/test-helpers';
2 | import { module, test } from 'qunit';
3 | import { setupApplicationTest } from 'ember-qunit';
4 |
5 | module('Acceptance | previous next links', function(hooks) {
6 | setupApplicationTest(hooks);
7 |
8 | test('navigation by previous and next links', async function(assert) {
9 | await visit('/v2.17.0/models/');
10 | assert.equal(currentURL(), '/v2.17.0/models/');
11 | await click('.next-guide')
12 | assert.equal(currentURL(), '/v2.17.0/models/defining-models');
13 | await click('.next-guide')
14 | assert.equal(currentURL(), '/v2.17.0/models/finding-records');
15 | await click('.previous-guide')
16 | assert.equal(currentURL(), '/v2.17.0/models/defining-models');
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/tests/acceptance/table-of-contents-test.js:
--------------------------------------------------------------------------------
1 | import { click, currentURL, visit } from '@ember/test-helpers';
2 | import { module, test } from 'qunit';
3 | import { setupApplicationTest } from 'ember-qunit';
4 |
5 | module('Acceptance | table of contents', function(hooks) {
6 | setupApplicationTest(hooks);
7 |
8 | test('navigation by TOC', async function(assert) {
9 | await visit('/v2.17.0/');
10 | await click('[data-test-toc-title="Routing"]')
11 | await click('[data-test-toc-link="Defining Your Routes"]')
12 | assert.equal(currentURL(), '/v2.17.0/routing/defining-your-routes');
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/tests/acceptance/version-menu-test.js:
--------------------------------------------------------------------------------
1 | import { currentURL, visit } from '@ember/test-helpers';
2 | import { module, test } from 'qunit';
3 | import { setupApplicationTest } from 'ember-qunit';
4 | import { selectChoose } from 'ember-power-select/test-support';
5 |
6 | module('Acceptance | version menu when changing versions', function(hooks) {
7 | setupApplicationTest(hooks);
8 |
9 | test('stays on index page', async function(assert) {
10 | await visit('/v2.17.0/');
11 | await selectChoose('.ember-basic-dropdown-trigger', '2.10');
12 | assert.equal(currentURL(), '/v2.10.0');
13 | });
14 |
15 | test('stays on same section', async function(assert) {
16 | await visit('/v1.13.0/getting-started/');
17 | await selectChoose('.ember-basic-dropdown-trigger', '1.12');
18 | assert.equal(currentURL(), '/v1.12.0/getting-started');
19 | });
20 |
21 | test('stays on same section and page', async function(assert) {
22 | await visit('/v3.0.0/object-model/classes-and-instances/');
23 | await selectChoose('.ember-basic-dropdown-trigger', '3.1');
24 | assert.equal(currentURL(), '/v3.1.0/object-model/classes-and-instances');
25 | });
26 |
27 | test("redirects to index page if current section/page doesn't exist in new version", async function(assert) {
28 | await visit('/v1.10.0/getting-started/using-fixtures/');
29 | await selectChoose('.ember-basic-dropdown-trigger', '1.13');
30 | assert.equal(currentURL(), '/v1.13.0');
31 | });
32 | });
33 |
--------------------------------------------------------------------------------
/tests/acceptance/visual-regression-test.js:
--------------------------------------------------------------------------------
1 | import { visit } from '@ember/test-helpers';
2 | import { module, test } from 'qunit';
3 | import { setupApplicationTest } from 'ember-qunit';
4 | import { get } from '@ember/object';
5 | import { percySnapshot } from 'ember-percy';
6 |
7 | module('Acceptance | visual regression', function(hooks) {
8 | setupApplicationTest(hooks);
9 |
10 | test(`visiting visual regressions with Percy`, async function(assert) {
11 | assert.expect(0);
12 | await visit('/release');
13 |
14 | let store = this.owner.lookup('service:store');
15 | let pages = store.peekAll('page');
16 |
17 | await pages.reduce(async (prev, section) => {
18 | await prev;
19 |
20 | return section.get('pages').reduce(async (prev, page) => {
21 | await prev;
22 |
23 | let url = get(page, 'url');
24 |
25 | await visit(`/release/${url}`);
26 |
27 | let name = `/${page.url}/index.html`;
28 |
29 | if (page.url.endsWith('index')) {
30 | name = `/${page.url}.html`;
31 | } else if (page.url.endsWith('index/')) {
32 | name = '/index.html';
33 | }
34 |
35 | await percySnapshot(name);
36 | }, Promise.resolve());
37 | }, Promise.resolve());
38 | });
39 | });
40 |
--------------------------------------------------------------------------------
/tests/helpers/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ember-learn/guides-app/2e3a25fd3b924d6ced52d15d65f19232cc3145b3/tests/helpers/.gitkeep
--------------------------------------------------------------------------------
/tests/helpers/start-app.js:
--------------------------------------------------------------------------------
1 | import Application from '../../app';
2 | import config from '../../config/environment';
3 | import { merge } from '@ember/polyfills';
4 | import { run } from '@ember/runloop';
5 | import './percy/register-helpers';
6 |
7 | export default function startApp(attrs) {
8 | let attributes = merge({}, config.APP);
9 | attributes.autoboot = true;
10 | attributes = merge(attributes, attrs); // use defaults, but you can override;
11 |
12 | return run(() => {
13 | let application = Application.create(attributes);
14 | application.setupForTesting();
15 | application.injectTestHelpers();
16 | return application;
17 | });
18 | }
19 |
--------------------------------------------------------------------------------
/tests/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | {{content-for "head"}}
9 | {{content-for "test-head"}}
10 |
11 |
12 |
13 |
14 |
15 | {{content-for "head-footer"}}
16 | {{content-for "test-head-footer"}}
17 |
18 |
19 | {{content-for "body"}}
20 | {{content-for "test-body"}}
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | {{content-for "body-footer"}}
29 | {{content-for "test-body-footer"}}
30 |
31 |
32 |
--------------------------------------------------------------------------------
/tests/integration/components/dropdown-header-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 'htmlbars-inline-precompile';
5 |
6 | module('Integration | Component | dropdown-header', function(hooks) {
7 | setupRenderingTest(hooks);
8 |
9 | test('it renders', async function(assert) {
10 | // Set any properties with this.set('myProperty', 'value');
11 | // Handle any actions with this.set('myAction', function(val) { ... });
12 |
13 | await render(hbs`{{dropdown-header}}`);
14 |
15 | assert.equal(this.element.textContent.trim(), '');
16 |
17 | // Template block usage:
18 | await render(hbs`
19 | {{#dropdown-header}}
20 | template block text
21 | {{/dropdown-header}}
22 | `);
23 |
24 | assert.equal(this.element.textContent.trim(), 'template block text');
25 | });
26 | });
27 |
--------------------------------------------------------------------------------
/tests/integration/components/search-input-test.js:
--------------------------------------------------------------------------------
1 | import { module, test } from 'qunit';
2 | import { setupRenderingTest } from 'ember-qunit';
3 | import { fillIn } from '@ember/test-helpers';
4 | import hbs from 'htmlbars-inline-precompile';
5 | import { set } from '@ember/object';
6 |
7 | module('Integration | Component | search input', function(hooks) {
8 | setupRenderingTest(hooks);
9 |
10 | test('no search hits display no results', async function(assert) {
11 |
12 | let searchService = this.owner.lookup('service:search');
13 |
14 | set(searchService, 'doSearch', () => {
15 | return [];
16 | });
17 |
18 | await this.render(hbs`{{search-input}}`);
19 |
20 | await fillIn('#search-input', 'model');
21 |
22 | assert.dom('.algolia-docsearch-suggestion--noresults').exists();
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/tests/integration/helpers/shorten-version-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 'htmlbars-inline-precompile';
5 |
6 | module('Integration | Helper | shorten-version', function(hooks) {
7 | setupRenderingTest(hooks);
8 |
9 | test('it shortens version v3.2.0 to 3.2', async function(assert) {
10 | this.set('inputValue', 'v3.2.0');
11 | await render(hbs`{{shorten-version inputValue}}`);
12 | assert.dom(this.element).hasText('3.2');
13 | });
14 |
15 | test('it keeps version 3.2 without changes', async function(assert) {
16 | this.set('inputValue', '3.2');
17 | await render(hbs`{{shorten-version inputValue}}`);
18 | assert.dom(this.element).hasText('3.2');
19 | });
20 | });
21 |
--------------------------------------------------------------------------------
/tests/test-helper.js:
--------------------------------------------------------------------------------
1 | import Application from '../app';
2 | import config from '../config/environment';
3 | import { setApplication } from '@ember/test-helpers';
4 | import { start } from 'ember-qunit';
5 |
6 | setApplication(Application.create(config.APP));
7 |
8 | start();
9 |
--------------------------------------------------------------------------------
/tests/unit/services/head-data-test.js:
--------------------------------------------------------------------------------
1 | import { module, test } from 'qunit';
2 | import { setupTest } from 'ember-qunit';
3 |
4 | module('Unit | Service | head data', function(hooks) {
5 | setupTest(hooks);
6 |
7 | test('title with currentPage and currentSelect details', function(assert) {
8 |
9 | let headDataService = this.owner.lookup('service:head-data');
10 | let pageService = this.owner.lookup('service:page');
11 |
12 | assert.equal(headDataService.title, 'Ember Guides', 'Default title without currentPage nor currentSelection');
13 |
14 | let currentPage = {
15 | title: 'CurrentPage title'
16 | }
17 | pageService.set('currentPage', currentPage);
18 |
19 | assert.equal(headDataService.title, 'Ember Guides', 'Default title without currentSelection');
20 |
21 | let currentSection = {
22 | title: 'CurrentSection title'
23 | }
24 | pageService.set('currentSection', currentSection);
25 |
26 | assert.equal(headDataService.title, 'CurrentPage title - CurrentSection title - Ember Guides', 'Title with currentPage and currentSelection');
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/tests/unit/services/search-test.js:
--------------------------------------------------------------------------------
1 | import { module, test } from 'qunit';
2 | import { setupTest } from 'ember-qunit';
3 |
4 | module('Unit | Service | search', function(hooks) {
5 | setupTest(hooks);
6 |
7 | // Replace this with your real tests.
8 | test('it exists', function(assert) {
9 | let service = this.owner.lookup('service:search');
10 | assert.ok(service);
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/vendor/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ember-learn/guides-app/2e3a25fd3b924d6ced52d15d65f19232cc3145b3/vendor/.gitkeep
--------------------------------------------------------------------------------
/vendor/ember-cli-spinkit/styles/spinkit-cube-grid.css:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | * Usage:
4 | *
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | *
17 | */
18 | .sk-cube-grid {
19 | width: 40px;
20 | height: 40px;
21 | margin: 40px auto;
22 | /*
23 | * Spinner positions
24 | * 1 2 3
25 | * 4 5 6
26 | * 7 8 9
27 | */ }
28 | .sk-cube-grid .sk-cube {
29 | width: 33.33%;
30 | height: 33.33%;
31 | background-color: #f16f58;
32 | float: left;
33 | -webkit-animation: sk-cubeGridScaleDelay 1.3s infinite ease-in-out;
34 | animation: sk-cubeGridScaleDelay 1.3s infinite ease-in-out; }
35 | .sk-cube-grid .sk-cube1 {
36 | -webkit-animation-delay: 0.2s;
37 | animation-delay: 0.2s; }
38 | .sk-cube-grid .sk-cube2 {
39 | -webkit-animation-delay: 0.3s;
40 | animation-delay: 0.3s; }
41 | .sk-cube-grid .sk-cube3 {
42 | -webkit-animation-delay: 0.4s;
43 | animation-delay: 0.4s; }
44 | .sk-cube-grid .sk-cube4 {
45 | -webkit-animation-delay: 0.1s;
46 | animation-delay: 0.1s; }
47 | .sk-cube-grid .sk-cube5 {
48 | -webkit-animation-delay: 0.2s;
49 | animation-delay: 0.2s; }
50 | .sk-cube-grid .sk-cube6 {
51 | -webkit-animation-delay: 0.3s;
52 | animation-delay: 0.3s; }
53 | .sk-cube-grid .sk-cube7 {
54 | -webkit-animation-delay: 0.0s;
55 | animation-delay: 0.0s; }
56 | .sk-cube-grid .sk-cube8 {
57 | -webkit-animation-delay: 0.1s;
58 | animation-delay: 0.1s; }
59 | .sk-cube-grid .sk-cube9 {
60 | -webkit-animation-delay: 0.2s;
61 | animation-delay: 0.2s; }
62 |
63 | @-webkit-keyframes sk-cubeGridScaleDelay {
64 | 0%, 70%, 100% {
65 | -webkit-transform: scale3D(1, 1, 1);
66 | transform: scale3D(1, 1, 1); }
67 | 35% {
68 | -webkit-transform: scale3D(0, 0, 1);
69 | transform: scale3D(0, 0, 1); } }
70 |
71 | @keyframes sk-cubeGridScaleDelay {
72 | 0%, 70%, 100% {
73 | -webkit-transform: scale3D(1, 1, 1);
74 | transform: scale3D(1, 1, 1); }
75 | 35% {
76 | -webkit-transform: scale3D(0, 0, 1);
77 | transform: scale3D(0, 0, 1); } }
78 |
--------------------------------------------------------------------------------
/vendor/ember-cli-spinkit/templates/components/spinkit-cube-grid.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------