├── .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 |
6 | {{search-input projectVersion=page.currentVersion}} 7 |
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 |
2 |
3 | 4 | {{yield}} 5 | 6 |
7 |
8 |
-------------------------------------------------------------------------------- /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 | 22 | {{#dropdown-header}} 23 | Search Results 24 | {{/dropdown-header}} 25 | 26 | {{#each searchService.results as |result|}} 27 | {{search-result result=result}} 28 | {{else}} 29 |
30 |
31 |

No results found. Try searching the deprecations guide.

32 |
33 |
34 | {{/each}} 35 |
36 | 37 | Search Powered by Algolia 38 | 39 |
40 |
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 | --------------------------------------------------------------------------------