├── .editorconfig ├── .ember-cli ├── .eslintrc.js ├── .gitattributes ├── .gitignore ├── .npmignore ├── .travis.yml ├── .watchmanconfig ├── LICENSE.md ├── README.md ├── addon ├── .gitkeep ├── components │ ├── markdown-menu-item.js │ └── markdown-menu.js ├── helpers │ ├── get-markdown-content.js │ ├── get-markdown-file.js │ └── get-markdown-tree.js ├── services │ └── markdown-resolver.js ├── templates │ └── components │ │ ├── markdown-menu-item.hbs │ │ └── markdown-menu.hbs └── utils │ └── computed-fallback-action.js ├── app ├── .gitkeep ├── components │ ├── markdown-menu-item.js │ └── markdown-menu.js ├── helpers │ ├── get-markdown-content.js │ ├── get-markdown-file.js │ └── get-markdown-tree.js ├── services │ └── markdown-resolver.js └── styles │ └── app.scss ├── blueprints └── ember-cli-markdown-resolver │ └── index.js ├── config ├── ember-try.js └── environment.js ├── ember-cli-build.js ├── index.js ├── package.json ├── testem.js ├── tests ├── .eslintrc.js ├── dummy │ ├── app │ │ ├── app.js │ │ ├── components │ │ │ ├── .gitkeep │ │ │ ├── markdown-content.js │ │ │ ├── ui-button-link-to.js │ │ │ ├── ui-button-link.js │ │ │ ├── ui-button.js │ │ │ ├── ui-navbar.js │ │ │ └── ui-section.js │ │ ├── controllers │ │ │ └── .gitkeep │ │ ├── guides │ │ │ ├── components.md │ │ │ ├── components │ │ │ │ └── markdown-menu.md │ │ │ ├── examples.md │ │ │ ├── examples │ │ │ │ ├── ember-cli-showdown.md │ │ │ │ └── ember-collapsible-panel.md │ │ │ ├── fragment-identifiers.md │ │ │ ├── index.md │ │ │ ├── install.md │ │ │ ├── not-in-tree.md │ │ │ ├── usage.md │ │ │ └── usage │ │ │ │ ├── files.md │ │ │ │ └── trees.md │ │ ├── helpers │ │ │ └── .gitkeep │ │ ├── index.html │ │ ├── initializers │ │ │ └── showdown.js │ │ ├── instance-initializers │ │ │ ├── head-data.js │ │ │ └── inject-config.js │ │ ├── mixins │ │ │ └── ui │ │ │ │ ├── align-mixin.js │ │ │ │ ├── color-mixin.js │ │ │ │ ├── depth-mixin.js │ │ │ │ ├── font-size-mixin.js │ │ │ │ ├── padding-mixin.js │ │ │ │ └── size-mixin.js │ │ ├── models │ │ │ └── .gitkeep │ │ ├── resolver.js │ │ ├── router.js │ │ ├── routes │ │ │ ├── .gitkeep │ │ │ ├── application.js │ │ │ ├── guides.js │ │ │ └── guides │ │ │ │ ├── index.js │ │ │ │ └── single.js │ │ ├── styles │ │ │ ├── app.scss │ │ │ ├── components │ │ │ │ ├── _.scss │ │ │ │ ├── _config.scss │ │ │ │ ├── buttons │ │ │ │ │ └── _.scss │ │ │ │ ├── footer │ │ │ │ │ └── _.scss │ │ │ │ ├── markdown │ │ │ │ │ ├── _.scss │ │ │ │ │ ├── _menu.scss │ │ │ │ │ └── _prettyprint.scss │ │ │ │ ├── navbar │ │ │ │ │ └── _.scss │ │ │ │ └── sections │ │ │ │ │ └── _.scss │ │ │ ├── framework │ │ │ │ ├── _colors.scss │ │ │ │ ├── _fonts.scss │ │ │ │ ├── _grid.scss │ │ │ │ ├── _mixins.scss │ │ │ │ ├── _reset.scss │ │ │ │ ├── _type.scss │ │ │ │ └── _utility.scss │ │ │ ├── main │ │ │ │ ├── _.scss │ │ │ │ └── _config.scss │ │ │ └── routes │ │ │ │ └── _.scss │ │ ├── templates │ │ │ ├── application.hbs │ │ │ ├── components │ │ │ │ ├── .gitkeep │ │ │ │ ├── ui-button.hbs │ │ │ │ ├── ui-footer.hbs │ │ │ │ └── ui-navbar.hbs │ │ │ ├── error.hbs │ │ │ ├── guides.hbs │ │ │ ├── guides │ │ │ │ └── single.hbs │ │ │ ├── head.hbs │ │ │ └── index.hbs │ │ └── utils │ │ │ └── property-class-name-binding.js │ ├── config │ │ ├── environment.js │ │ └── targets.js │ └── public │ │ ├── crossdomain.xml │ │ ├── images │ │ ├── facebook.jpg │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon.ico │ │ ├── logo-black.svg │ │ └── logo-white.svg │ │ └── robots.txt ├── helpers │ ├── destroy-app.js │ ├── module-for-acceptance.js │ ├── resolver.js │ └── start-app.js ├── index.html ├── integration │ └── .gitkeep ├── test-helper.js └── unit │ └── .gitkeep ├── vendor └── .gitkeep └── yarn.lock /.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 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | ecmaVersion: 2017, 5 | sourceType: 'module' 6 | }, 7 | extends: 'eslint:recommended', 8 | env: { 9 | browser: true 10 | }, 11 | rules: { 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | tests/dummy/* linguist-vendored 2 | -------------------------------------------------------------------------------- /.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 | 20 | # ember-try 21 | .node_modules.ember-try/ 22 | bower.json.ember-try 23 | package.json.ember-try 24 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /bower_components 2 | /config/ember-try.js 3 | /dist 4 | /tests 5 | /tmp 6 | **/.gitkeep 7 | .bowerrc 8 | .editorconfig 9 | .ember-cli 10 | .gitignore 11 | .eslintrc.js 12 | .watchmanconfig 13 | .travis.yml 14 | bower.json 15 | ember-cli-build.js 16 | testem.js 17 | /DEBUG 18 | Icon^M^M 19 | Icon* 20 | 21 | # ember-try 22 | .node_modules.ember-try/ 23 | bower.json.ember-try 24 | package.json.ember-try 25 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: node_js 3 | node_js: 4 | # we recommend testing addons with the same minimum supported node version as Ember CLI 5 | # so that your addon works for all apps 6 | - "6" 7 | 8 | sudo: false 9 | dist: trusty 10 | 11 | addons: 12 | chrome: stable 13 | 14 | cache: 15 | yarn: true 16 | 17 | env: 18 | global: 19 | # See https://git.io/vdao3 for details. 20 | - JOBS=1 21 | matrix: 22 | # we recommend new addons test the current and previous LTS 23 | # as well as latest stable release (bonus points to beta/canary) 24 | - EMBER_TRY_SCENARIO=ember-lts-2.12 25 | - EMBER_TRY_SCENARIO=ember-lts-2.16 26 | - EMBER_TRY_SCENARIO=ember-release 27 | - EMBER_TRY_SCENARIO=ember-beta 28 | - EMBER_TRY_SCENARIO=ember-canary 29 | - EMBER_TRY_SCENARIO=ember-default 30 | 31 | matrix: 32 | fast_finish: true 33 | allow_failures: 34 | - env: EMBER_TRY_SCENARIO=ember-canary 35 | 36 | before_install: 37 | - curl -o- -L https://yarnpkg.com/install.sh | bash 38 | - export PATH=$HOME/.yarn/bin:$PATH 39 | 40 | install: 41 | - yarn install --no-lockfile --non-interactive 42 | 43 | script: 44 | # Usually, it's ok to finish the test scenario without reverting 45 | # to the addon's original dependency state, skipping "cleanup". 46 | - node_modules/.bin/ember try:one $EMBER_TRY_SCENARIO --skip-cleanup 47 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | { 2 | "ignore_dirs": ["tmp", "dist"] 3 | } 4 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | Ember CLI Markdown Resolver 4 | ====== 5 | [![Build Status](https://travis-ci.org/willviles/ember-cli-markdown-resolver.svg)](https://travis-ci.org/willviles/ember-cli-markdown-resolver) [![Ember Observer Score](http://emberobserver.com/badges/ember-cli-markdown-resolver.svg)](http://emberobserver.com/addons/ember-cli-markdown-resolver) [![Download count all time](https://img.shields.io/npm/dt/ember-cli-markdown-resolver.svg)]((https://www.npmjs.com/package/ember-cli-markdown-resolver)) [![npm](https://img.shields.io/npm/v/ember-cli-markdown-resolver.svg)](https://www.npmjs.com/package/ember-cli-markdown-resolver) 6 | 7 | Ember CLI Markdown Resolver is the quickest way to include static markdown content in your Ember.js application using [Broccoli Markdown Resolver](https://github.com/willviles/broccoli-markdown-resolver). 8 | 9 | ## Installation 10 | 11 | ``` 12 | ember install ember-cli-markdown-resolver 13 | ``` 14 | 15 | ## Configuration 16 | 17 | The addon requires you specify the locations of markdown files: 18 | 19 | ```js 20 | // config/environment.js 21 | 22 | ENV['ember-cli-markdown-resolver'] = { 23 | folders: { 24 | 'guides': 'app/guides' 25 | } 26 | }; 27 | ``` 28 | 29 | And to populate your folder with markdown content: 30 | 31 | ```shell 32 | . 33 | └── app/ 34 | └── guides/ 35 | ├── quick-start.md 36 | ├── examples.md 37 | └── examples/ 38 | └── first.md 39 | ``` 40 | 41 | ## Usage 42 | 43 | Ember CLI Markdown Resolver enables markdown content to be retrieved via the `markdownResolver` service. 44 | 45 | ### `this.get('markdownResolver').file(type, path)` 46 | 47 | The `file` method returns promisified markdown content, allowing the content to be chainable via `.then()`. 48 | 49 | ```js 50 | // routes/guides/single.js 51 | 52 | import Route from '@ember/routing/route'; 53 | import { get } from '@ember/object'; 54 | import { inject } from '@ember/service'; 55 | 56 | export default Route.extend({ 57 | markdownResolver: inject(), 58 | 59 | model({ path }) { 60 | return get(this, 'markdownResolver').file('guides', path); 61 | } 62 | }); 63 | ``` 64 | 65 | Each markdown file exposes the path, raw content, frontmatter attributes and its children. 66 | 67 | ```hbs 68 | 69 | 70 | {{model.content}} 71 | {{model.path}} 72 | {{model.attributes}} 73 | {{model.children}} 74 | ``` 75 | 76 | ### `this.get('markdownResolver').tree(type)` 77 | 78 | The `tree` method returns a tree object for a given folder, allowing menu interfaces to be built from the markdown file structure. 79 | 80 | ```js 81 | // routes/guides.js 82 | 83 | import Route from '@ember/routing/route'; 84 | import { get } from '@ember/object'; 85 | import { inject } from '@ember/service'; 86 | 87 | export default Route.extend({ 88 | markdownResolver: inject(), 89 | 90 | model() { 91 | return get(this, 'markdownResolver').tree('guides'); 92 | } 93 | }); 94 | ``` 95 | 96 | Adding an `order` value to a file's frontmatter will automatically order files within the tree. 97 | 98 | ```md 99 | --- 100 | title: Quick Start 101 | order: 0 102 | --- 103 | 104 | Lorem ipsum dolor sit amet... 105 | ``` 106 | 107 | Additionally, adding a `fragmentIdLinks` object to a file's frontmatter will generate a list local fragment identifier links which are used within the `{{markdown-menu-item}}` component. This is handy when you want to link to several individual sections of a large parent markdown file instead of having individual child markdown files. 108 | 109 | The `fragmentIdLinks` object expects child key-value pairs where each `key` represents the hash fragment id link and each `value` represents the text label to be shown as a child on the `{{markdown-menu}}` component. 110 | 111 | ```md 112 | --- 113 | title: Fragment Identifier Links 114 | order: 4 115 | fragmentIdLinks: 116 | iamsectionone: "Section One" 117 | section-two: "Section Two" 118 | --- 119 | 120 | ### I am section one 121 | Lorem ipsum dolor sit amet... 122 | 123 | Lorem ipsum dolor sit amet... 124 | ``` 125 | 126 | By default, when you click on each `fragmentIdLinks` child link within the `{{markdown-menu-item}}` component it will update the url hash. You can easily override this default behavior by passing an `onClick` closure action into the `{{markdown-menu}}` component. 127 | 128 | ```hbs 129 | {{!-- templates/guides.hbs --}} 130 | {{markdown-menu onClick=(action "clickedMenuItemLink")}} 131 | ``` 132 | 133 | ```js 134 | // controllers/guides.js 135 | import Controller from '@ember/controller'; 136 | 137 | export default Controller.extend({ 138 | actions: { 139 | clickedMenuItemLink(fragmentIdLink) { 140 | document.querySelector(`#${fragmentIdLink}`).scrollIntoView({ 141 | behavior: 'smooth' 142 | }); 143 | } 144 | } 145 | }); 146 | ``` 147 | 148 | The addon ships with a `markdown-menu` component which builds a nested list from your file tree and can be styled using your own css. 149 | 150 | ```hbs 151 | 152 | 153 | {{markdown-menu 154 | title="My Markdown Menu" 155 | tree=model}} 156 | {{outlet}} 157 | ``` 158 | 159 | ## Helpers 160 | 161 | Ember CLI Markdown Resolver defines the following template helpers: 162 | 163 | ```hbs 164 | 165 | {{get (get-markdown-file 'guides' 'nested/page-slug') 'title'}} 166 | 167 | 168 | {{my-render-component content=(get-markdown-content 'guides' 'nested/page-slug')}} 169 | 170 | 171 | {{markdown-menu tree=(get-markdown-tree 'guides')}} 172 | ``` 173 | 174 | ## Demo 175 | 176 | Check out the [Ember CLI Markdown Resolver guides](https://willviles.github.io/ember-cli-markdown-resolver), which is generated using the addon. 177 | 178 | Code for the guides can be found [here](https://github.com/willviles/ember-cli-markdown-resolver/tree/master/tests/dummy). 179 | 180 | ## Node Version 181 | 182 | Ember CLI Markdown Resolver currently supports Node >=6. 183 | 184 | ## Contributing 185 | 186 | ### Installation 187 | 188 | * `git clone https://github.com/willviles/ember-cli-markdown-resolver.git` 189 | * `cd ember-cli-markdown-resolver` 190 | * `yarn install` 191 | 192 | ### Running 193 | 194 | * `ember serve` 195 | * Visit your app at [http://localhost:4200](http://localhost:4200). 196 | 197 | ### Running Tests 198 | 199 | * `yarn test` (Runs `ember try:each` to test your addon against multiple Ember versions) 200 | * `ember test` 201 | * `ember test --server` 202 | 203 | ### Building 204 | 205 | * `ember build` 206 | 207 | For more information on using ember-cli, visit [https://ember-cli.com/](https://ember-cli.com/). 208 | -------------------------------------------------------------------------------- /addon/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willviles/ember-cli-markdown-resolver/46e56e04d3bf9508f56e7844030f865f7e0fd788/addon/.gitkeep -------------------------------------------------------------------------------- /addon/components/markdown-menu-item.js: -------------------------------------------------------------------------------- 1 | import Component from '@ember/component'; 2 | import { computed, get } from '@ember/object'; 3 | import { empty } from '@ember/object/computed'; 4 | 5 | import layout from 'ember-cli-markdown-resolver/templates/components/markdown-menu-item'; 6 | 7 | export default Component.extend({ 8 | layout, 9 | tagName: 'li', 10 | classNames: ['markdown-menu-item'], 11 | 12 | itemPath: computed('item.path', 'treePath', function() { 13 | let itemPath = get(this, 'item.path'), 14 | treePath = get(this, 'treePath'); 15 | if (!itemPath) { return; } 16 | return itemPath.replace(`${treePath}/`, ''); 17 | }), 18 | 19 | noContent: empty('item.content'), 20 | 21 | actions: { 22 | onClick(fragmentIdLink) { 23 | let onClick = get(this, 'onClick'); 24 | 25 | if (onClick) { 26 | onClick(fragmentIdLink); 27 | } 28 | } 29 | } 30 | }); 31 | -------------------------------------------------------------------------------- /addon/components/markdown-menu.js: -------------------------------------------------------------------------------- 1 | import Component from '@ember/component'; 2 | import { scheduleOnce } from '@ember/runloop'; 3 | import { or } from '@ember/object/computed'; 4 | import fallbackAction from 'ember-cli-markdown-resolver/utils/computed-fallback-action'; 5 | 6 | import layout from 'ember-cli-markdown-resolver/templates/components/markdown-menu'; 7 | 8 | export default Component.extend({ 9 | layout, 10 | classNames: ['markdown-menu'], 11 | 12 | menuTitle: or('title', 'tree.name'), 13 | 14 | // Actions 15 | onClick: fallbackAction(function(fragmentIdLink) { 16 | if (fragmentIdLink && typeof fragmentIdLink === "string" && fragmentIdLink.length) { 17 | scheduleOnce('afterRender', this, () => { 18 | location.hash = fragmentIdLink; 19 | }); 20 | } else { 21 | location.hash = ""; 22 | } 23 | }) 24 | }); 25 | -------------------------------------------------------------------------------- /addon/helpers/get-markdown-content.js: -------------------------------------------------------------------------------- 1 | import Helper from '@ember/component/helper'; 2 | import { get } from '@ember/object'; 3 | import { inject as service } from '@ember/service'; 4 | 5 | export default Helper.extend({ 6 | 7 | markdownResolver: service(), 8 | 9 | compute([tree, file]) { 10 | let md = get(this, 'markdownResolver')._file(tree, file); 11 | return get(md, 'content'); 12 | } 13 | 14 | }); 15 | -------------------------------------------------------------------------------- /addon/helpers/get-markdown-file.js: -------------------------------------------------------------------------------- 1 | import Helper from '@ember/component/helper'; 2 | import { get } from '@ember/object'; 3 | import { inject as service } from '@ember/service'; 4 | 5 | export default Helper.extend({ 6 | 7 | markdownResolver: service(), 8 | 9 | compute([tree, file]) { 10 | return get(this, 'markdownResolver')._file(tree, file); 11 | } 12 | 13 | }); 14 | -------------------------------------------------------------------------------- /addon/helpers/get-markdown-tree.js: -------------------------------------------------------------------------------- 1 | import Helper from '@ember/component/helper'; 2 | import { get } from '@ember/object'; 3 | import { inject as service } from '@ember/service'; 4 | 5 | export default Helper.extend({ 6 | 7 | markdownResolver: service(), 8 | 9 | compute([tree]) { 10 | return get(this, 'markdownResolver')._tree(tree); 11 | } 12 | 13 | }); 14 | -------------------------------------------------------------------------------- /addon/services/markdown-resolver.js: -------------------------------------------------------------------------------- 1 | import Service from '@ember/service'; 2 | import { 3 | getOwner 4 | } from '@ember/application'; 5 | import { 6 | A 7 | } from "@ember/array" 8 | import { 9 | computed, 10 | get, 11 | getWithDefault, 12 | set 13 | } from '@ember/object'; 14 | import { 15 | files, 16 | trees 17 | } from 'ember-cli-markdown-resolver/files'; 18 | import RSVP from 'rsvp'; 19 | 20 | const { 21 | resolve 22 | } = RSVP; 23 | 24 | export default Service.extend({ 25 | 26 | config: computed(function() { 27 | return getOwner(this).resolveRegistration('config:environment')['ember-cli-markdown-resolver'] || {} 28 | }), 29 | 30 | files: computed(function() { 31 | return A(files); 32 | }), 33 | 34 | trees: computed(function() { 35 | return Object.keys(trees).reduce((allTrees, key) => { 36 | allTrees[key] = { 37 | name: this.getTreeName(key), 38 | path: key, 39 | files: this.orderFiles(trees[key]) 40 | }; 41 | return allTrees; 42 | }, {}); 43 | }), 44 | 45 | _file(tree, file) { 46 | tree = this.getPathFromTreeName(tree); 47 | return get(this, 'files').findBy('path', `${tree}/${file}`); 48 | }, 49 | 50 | file(tree, file) { 51 | return resolve(this._file(tree, file)); 52 | }, 53 | 54 | _tree(tree) { 55 | tree = this.getPathFromTreeName(tree); 56 | return getWithDefault(this, `trees.${tree}`, []); 57 | }, 58 | 59 | tree(tree) { 60 | return resolve(this._tree(tree)); 61 | }, 62 | 63 | getTreeName(path) { 64 | let folders = get(this, 'config.folders'); 65 | return Object.keys(folders).find(key => { 66 | return folders[key] === path; 67 | }); 68 | }, 69 | 70 | getPathFromTreeName(treeName) { 71 | return get(this, `config.folders.${treeName}`); 72 | }, 73 | 74 | orderFiles(files) { 75 | files = A(files).sortBy('attributes.order').filter((file) => { 76 | let attrs = get(file, 'attributes'); 77 | if (attrs.hasOwnProperty('inTree') && !get(attrs, 'inTree')) { 78 | return; 79 | } 80 | return file; 81 | }); 82 | 83 | files.forEach(file => { 84 | let children = get(file, 'children'); 85 | if (children) { 86 | set(file, 'children', this.orderFiles(children)); 87 | } 88 | }); 89 | 90 | return files; 91 | } 92 | 93 | }); 94 | -------------------------------------------------------------------------------- /addon/templates/components/markdown-menu-item.hbs: -------------------------------------------------------------------------------- 1 | {{#unless noContent}} 2 | {{link-to item.attributes.title linkTo itemPath click=(action "onClick")}} 3 | {{else}} 4 | {{item.attributes.title}} 5 | {{/unless}} 6 | 7 | {{#if item.attributes.fragmentIdLinks}} 8 | 15 | {{/if}} 16 | 17 | {{#if item.children}} 18 | 25 | {{/if}} -------------------------------------------------------------------------------- /addon/templates/components/markdown-menu.hbs: -------------------------------------------------------------------------------- 1 | {{#if tree}} 2 |
3 | {{menuTitle}} 4 |
5 | 10 | {{/if}} -------------------------------------------------------------------------------- /addon/utils/computed-fallback-action.js: -------------------------------------------------------------------------------- 1 | import { computed } from '@ember/object'; 2 | 3 | export default function computedFallbackAction(fallback) { 4 | return computed({ 5 | get() { 6 | return fallback.bind(this); 7 | }, 8 | set(_, v) { 9 | return v === undefined ? fallback.bind(this) : v; 10 | } 11 | }); 12 | } 13 | -------------------------------------------------------------------------------- /app/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willviles/ember-cli-markdown-resolver/46e56e04d3bf9508f56e7844030f865f7e0fd788/app/.gitkeep -------------------------------------------------------------------------------- /app/components/markdown-menu-item.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-cli-markdown-resolver/components/markdown-menu-item'; 2 | -------------------------------------------------------------------------------- /app/components/markdown-menu.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-cli-markdown-resolver/components/markdown-menu'; 2 | -------------------------------------------------------------------------------- /app/helpers/get-markdown-content.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-cli-markdown-resolver/helpers/get-markdown-content'; 2 | -------------------------------------------------------------------------------- /app/helpers/get-markdown-file.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-cli-markdown-resolver/helpers/get-markdown-file'; 2 | -------------------------------------------------------------------------------- /app/helpers/get-markdown-tree.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-cli-markdown-resolver/helpers/get-markdown-tree'; 2 | -------------------------------------------------------------------------------- /app/services/markdown-resolver.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-cli-markdown-resolver/services/markdown-resolver'; 2 | -------------------------------------------------------------------------------- /app/styles/app.scss: -------------------------------------------------------------------------------- 1 | @import "sassdash"; 2 | -------------------------------------------------------------------------------- /blueprints/ember-cli-markdown-resolver/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node:true */ 2 | /* globals module */ 3 | 4 | module.exports = { 5 | normalizeEntityName: function() {} 6 | }; 7 | -------------------------------------------------------------------------------- /config/ember-try.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | module.exports = { 3 | useYarn: true, 4 | scenarios: [ 5 | { 6 | name: 'ember-lts-2.12', 7 | npm: { 8 | devDependencies: { 9 | 'ember-source': '~2.12.0' 10 | } 11 | } 12 | }, 13 | { 14 | name: 'ember-lts-2.16', 15 | npm: { 16 | devDependencies: { 17 | 'ember-source': '~2.16.0' 18 | } 19 | } 20 | }, 21 | { 22 | name: 'ember-release', 23 | bower: { 24 | dependencies: { 25 | 'ember': 'components/ember#release' 26 | }, 27 | resolutions: { 28 | 'ember': 'release' 29 | } 30 | }, 31 | npm: { 32 | devDependencies: { 33 | 'ember-source': null 34 | } 35 | } 36 | }, 37 | { 38 | name: 'ember-beta', 39 | bower: { 40 | dependencies: { 41 | 'ember': 'components/ember#beta' 42 | }, 43 | resolutions: { 44 | 'ember': 'beta' 45 | } 46 | }, 47 | npm: { 48 | devDependencies: { 49 | 'ember-source': null 50 | } 51 | } 52 | }, 53 | { 54 | name: 'ember-canary', 55 | bower: { 56 | dependencies: { 57 | 'ember': 'components/ember#canary' 58 | }, 59 | resolutions: { 60 | 'ember': 'canary' 61 | } 62 | }, 63 | npm: { 64 | devDependencies: { 65 | 'ember-source': null 66 | } 67 | } 68 | }, 69 | { 70 | name: 'ember-default', 71 | npm: { 72 | devDependencies: {} 73 | } 74 | } 75 | ] 76 | }; 77 | -------------------------------------------------------------------------------- /config/environment.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 'use strict'; 3 | 4 | module.exports = function(/* environment, appConfig */) { 5 | return { }; 6 | }; 7 | -------------------------------------------------------------------------------- /ember-cli-build.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 'use strict'; 3 | 4 | const path = require('path'); 5 | const EmberAddon = require('ember-cli/lib/broccoli/ember-addon'); 6 | 7 | module.exports = function(defaults) { 8 | let app = new EmberAddon(defaults, { 9 | 'ember-cli-markdown-resolver': { 10 | 'test-app-path': path.join('tests', 'dummy') 11 | } 12 | }); 13 | 14 | /* 15 | This build file specifies the options for the dummy test app of this 16 | addon, located in `/tests/dummy` 17 | This build file does *not* influence how the addon or the app using it 18 | behave. You most likely want to be modifying `./index.js` or app's build file 19 | */ 20 | 21 | return app.toTree(); 22 | }; 23 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 'use strict'; 3 | 4 | const MarkdownResolver = require('broccoli-markdown-resolver'); 5 | const MergeTrees = require('broccoli-merge-trees'); 6 | const fs = require('fs'); 7 | const path = require('path'); 8 | 9 | module.exports = { 10 | name: 'ember-cli-markdown-resolver', 11 | 12 | included(app) { 13 | this.addonConfig = this.getAddonConfig(app); 14 | this.testAppPath = this.getTestAppPath(); 15 | return this._super.included.apply(this, arguments); 16 | }, 17 | 18 | treeForAddon(tree) { 19 | 20 | let folders = Object.keys(this.addonConfig.folders || {}).reduce((folders, key) => { 21 | return [ 22 | ...folders, 23 | this.addonConfig.folders[key] 24 | ]; 25 | }, []); 26 | 27 | let mdPaths = folders.reduce((paths, folder) => { 28 | let folderPathSegments = folder.split('/'), 29 | folderPath = path.join(this.app.project.root, this.testAppPath, ...folderPathSegments), 30 | folderExists = fs.existsSync(folderPath); 31 | 32 | return folderExists ? 33 | [...paths, folderPath] : 34 | [...paths]; 35 | }, []); 36 | 37 | if (mdPaths.length > 0) { 38 | 39 | let mdFiles = new MarkdownResolver(mdPaths, { 40 | basePath: path.join(this.app.project.root, this.testAppPath), 41 | outputFile: 'files.js', 42 | trimExtensions: true 43 | }); 44 | 45 | tree = new MergeTrees([tree, mdFiles]); 46 | } 47 | 48 | return this._super.treeForAddon.call(this, tree); 49 | }, 50 | 51 | getAddonConfig(app) { 52 | return this.app.project.config(app.env)[this.name] || {}; 53 | }, 54 | 55 | getTestAppPath() { 56 | let configPath = this.app.options.configPath; 57 | return (typeof configPath === 'string' || configPath instanceof String) ? './tests/dummy' : ''; 58 | } 59 | }; 60 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ember-cli-markdown-resolver", 3 | "version": "0.1.3", 4 | "description": "Ember CLI addon for resolving markdown files in custom folders and retrieving content via a service.", 5 | "keywords": [ 6 | "ember-addon", 7 | "markdown", 8 | "md", 9 | "resolver", 10 | "frontmatter", 11 | "content" 12 | ], 13 | "license": "MIT", 14 | "author": { 15 | "name": "Will Viles", 16 | "email": "will@vil.es", 17 | "url": "willviles.com" 18 | }, 19 | "directories": { 20 | "doc": "doc", 21 | "test": "tests" 22 | }, 23 | "repository": { 24 | "type": "git", 25 | "url": "git+https://github.com/willviles/ember-cli-markdown-resolver.git" 26 | }, 27 | "scripts": { 28 | "build": "ember build", 29 | "start": "ember server", 30 | "test": "ember try:each", 31 | "deploy": "ember github-pages:commit --message \"Deploy gh-pages from commit $(git rev-parse HEAD)\"; git push; git checkout master" 32 | }, 33 | "dependencies": { 34 | "broccoli-funnel": "^2.0.1", 35 | "broccoli-markdown-resolver": "^0.0.1", 36 | "broccoli-merge-trees": "^2.0.0", 37 | "ember-cli-babel": "^6.6.0", 38 | "ember-cli-htmlbars": "^2.0.1" 39 | }, 40 | "devDependencies": { 41 | "broccoli-asset-rev": "^2.4.5", 42 | "ember-ajax": "^3.0.0", 43 | "ember-cli": "~2.17.1", 44 | "ember-cli-dependency-checker": "^2.0.0", 45 | "ember-cli-document-title": "^0.3.3", 46 | "ember-cli-eslint": "^4.2.1", 47 | "ember-cli-github-pages": "^0.1.2", 48 | "ember-cli-google-fonts": "^2.14.1", 49 | "ember-cli-head": "^0.3.1", 50 | "ember-cli-htmlbars-inline-precompile": "^1.0.0", 51 | "ember-cli-inject-live-reload": "^1.4.1", 52 | "ember-cli-qunit": "^4.1.1", 53 | "ember-cli-sass": "~6.2.0", 54 | "ember-cli-sassdash": "^0.2.3", 55 | "ember-cli-shims": "^1.2.0", 56 | "ember-cli-showdown": "^4.1.0", 57 | "ember-cli-sri": "^2.1.0", 58 | "ember-cli-uglify": "^2.0.0", 59 | "ember-code-prettify": "^0.0.1", 60 | "ember-data": "^2.15.0", 61 | "ember-disable-prototype-extensions": "^1.1.2", 62 | "ember-export-application-global": "^2.0.0", 63 | "ember-load-initializers": "^1.0.0", 64 | "ember-resolver": "^4.0.0", 65 | "ember-source": "~2.12.0", 66 | "ember-try": "0.2.22", 67 | "loader.js": "^4.2.3" 68 | }, 69 | "engines": { 70 | "node": "6.* || >= 7.*" 71 | }, 72 | "ember-addon": { 73 | "configPath": "tests/dummy/config" 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /testem.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | test_page: 'tests/index.html?hidepassed', 4 | disable_watching: true, 5 | launch_in_ci: [ 6 | 'Chrome' 7 | ], 8 | launch_in_dev: [ 9 | 'Chrome' 10 | ], 11 | browser_args: { 12 | Chrome: { 13 | mode: 'ci', 14 | args: [ 15 | // --no-sandbox is needed when running Chrome inside a container 16 | process.env.TRAVIS ? '--no-sandbox' : null, 17 | 18 | '--disable-gpu', 19 | '--headless', 20 | '--remote-debugging-port=0', 21 | '--window-size=1440,900' 22 | ].filter(Boolean) 23 | } 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /tests/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | embertest: true 4 | } 5 | }; 6 | -------------------------------------------------------------------------------- /tests/dummy/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 | -------------------------------------------------------------------------------- /tests/dummy/app/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willviles/ember-cli-markdown-resolver/46e56e04d3bf9508f56e7844030f865f7e0fd788/tests/dummy/app/components/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/components/markdown-content.js: -------------------------------------------------------------------------------- 1 | import { computed, get } from '@ember/object'; 2 | import { scheduleOnce } from '@ember/runloop'; 3 | import { inject } from '@ember/service'; 4 | // import { htmlSafe } from '@ember/string'; 5 | import ShowdownComponent from 'ember-cli-showdown/components/markdown-to-html'; 6 | 7 | export default ShowdownComponent.extend({ 8 | codePrettify: inject(), 9 | 10 | classNames: ['markdown-content'], 11 | 12 | html: computed('markdown', 'converter', function() { 13 | scheduleOnce('afterRender', this, function() { 14 | get(this, 'codePrettify').prettify(); 15 | }); 16 | 17 | return this._super(...arguments); 18 | }).readOnly(), 19 | 20 | }); 21 | -------------------------------------------------------------------------------- /tests/dummy/app/components/ui-button-link-to.js: -------------------------------------------------------------------------------- 1 | import Mixin from '@ember/object/mixin'; 2 | import LinkComponent from '@ember/routing/link-component'; 3 | 4 | import { DefaultButtonMixin } from 'dummy/components/ui-button'; 5 | 6 | export let LinkToButtonMixin = Mixin.create( 7 | DefaultButtonMixin, { 8 | classNames: ['btn-link-to'] 9 | }); 10 | 11 | export default LinkComponent.extend(LinkToButtonMixin); 12 | -------------------------------------------------------------------------------- /tests/dummy/app/components/ui-button-link.js: -------------------------------------------------------------------------------- 1 | import Component from '@ember/component'; 2 | 3 | import { DefaultButtonMixin } from 'dummy/components/ui-button'; 4 | 5 | const ButtonLinkComponent = Component.extend( 6 | DefaultButtonMixin, { 7 | 8 | tagName: 'a', 9 | classNames: ['btn-link'], 10 | attributeBindings: ['target', 'href'] 11 | }); 12 | 13 | ButtonLinkComponent.reopenClass({ 14 | positionalParams: ['linkTitle'] 15 | }); 16 | 17 | export default ButtonLinkComponent; 18 | -------------------------------------------------------------------------------- /tests/dummy/app/components/ui-button.js: -------------------------------------------------------------------------------- 1 | import Component from '@ember/component'; 2 | import Mixin from '@ember/object/mixin'; 3 | 4 | import AlignMixin from 'dummy/mixins/ui/align-mixin'; 5 | import ColorMixin from 'dummy/mixins/ui/color-mixin'; 6 | import DepthMixin from 'dummy/mixins/ui/depth-mixin'; 7 | import FontSizeMixin from 'dummy/mixins/ui/font-size-mixin'; 8 | import PaddingMixin from 'dummy/mixins/ui/padding-mixin'; 9 | import layout from 'dummy/templates/components/ui-button'; 10 | 11 | export let DefaultButtonMixin = Mixin.create( 12 | AlignMixin, 13 | ColorMixin, 14 | DepthMixin, 15 | FontSizeMixin, 16 | PaddingMixin, { 17 | 18 | layout, 19 | 20 | tagName: 'button', 21 | classNames: ['button'], 22 | classNameBindings: ['inline', 'rounded'], 23 | attributeBindings: ['name:data-button'], 24 | 25 | rounded: true 26 | }); 27 | 28 | 29 | export default Component.extend(DefaultButtonMixin); 30 | -------------------------------------------------------------------------------- /tests/dummy/app/components/ui-navbar.js: -------------------------------------------------------------------------------- 1 | import Component from '@ember/component'; 2 | 3 | export default Component.extend({ 4 | tagName: 'nav', 5 | classNames: ['navbar'], 6 | classNameBindings: ['fixed:fixed:unfixed'], 7 | attributeBindings: ['name:data-name'], 8 | 9 | fixed: true 10 | }) 11 | -------------------------------------------------------------------------------- /tests/dummy/app/components/ui-section.js: -------------------------------------------------------------------------------- 1 | import Component from '@ember/component'; 2 | import Mixin from '@ember/object/mixin'; 3 | 4 | import AlignMixin from 'dummy/mixins/ui/align-mixin'; 5 | import ColorMixin from 'dummy/mixins/ui/color-mixin'; 6 | import DepthMixin from 'dummy/mixins/ui/depth-mixin'; 7 | import FontSizeMixin from 'dummy/mixins/ui/font-size-mixin'; 8 | import PaddingMixin from 'dummy/mixins/ui/padding-mixin'; 9 | 10 | export const DefaultSectionBaseLayer = Mixin.create( 11 | AlignMixin, 12 | ColorMixin, 13 | DepthMixin, 14 | FontSizeMixin, 15 | PaddingMixin, { 16 | 17 | classNames: ['section'], 18 | name: '' 19 | 20 | }) 21 | 22 | export default Component.extend(DefaultSectionBaseLayer, { 23 | tagName: 'section', 24 | attributeBindings: ['name:data-section'] 25 | 26 | }); 27 | -------------------------------------------------------------------------------- /tests/dummy/app/controllers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willviles/ember-cli-markdown-resolver/46e56e04d3bf9508f56e7844030f865f7e0fd788/tests/dummy/app/controllers/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/guides/components.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Components 3 | order: 2 4 | --- 5 | -------------------------------------------------------------------------------- /tests/dummy/app/guides/components/markdown-menu.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: markdown-menu 3 | order: 0 4 | --- 5 | 6 | 7 | [→ addon/components/markdown-menu.js](https://github.com/willviles/ember-cli-markdown-resolver/blob/master/addon/components/markdown-menu.js) 8 | 9 | 10 | Ember CLI Markdown Resolver defines a `markdown-menu` component for creating nested menus from your markdown file trees and can be styled using your own css. It uses a `markdown-menu-item` component to loop through each level of nesting. 11 | 12 | ```hbs 13 | 14 | 15 | {{markdown-menu title="My Markdown Menu" tree=model}} 16 | {{outlet}} 17 | ``` 18 | 19 | ##### Styles 20 | 21 | 22 | [→ tests/dummy/app/styles/components/markdown/_menu.scss](https://github.com/willviles/ember-cli-markdown-resolver/blob/master/tests/dummy/app/styles/components/markdown/_menu.scss) 23 | 24 | 25 | The simple menu on this page has been styled using the following css. 26 | 27 | ```css 28 | .markdown-menu { 29 | .markdown-menu-title { 30 | font-weight: 800; 31 | font-size: 1.1em; 32 | text-transform: capitalize; 33 | margin-bottom: .75em; 34 | } 35 | & > ul { 36 | a { 37 | padding: .5em 0; 38 | &:hover { 39 | font-weight: 800; 40 | } 41 | &.active { 42 | color: red; 43 | font-weight: 800; 44 | } 45 | } 46 | ul { 47 | margin-left: 1em; 48 | } 49 | } 50 | } 51 | 52 | ``` 53 | -------------------------------------------------------------------------------- /tests/dummy/app/guides/examples.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Examples 3 | order: 3 4 | --- 5 | -------------------------------------------------------------------------------- /tests/dummy/app/guides/examples/ember-cli-showdown.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ember-cli-showdown 3 | order: 0 4 | --- 5 | 6 | Example coming soon. 7 | -------------------------------------------------------------------------------- /tests/dummy/app/guides/examples/ember-collapsible-panel.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ember-collapsible-panel 3 | order: 1 4 | --- 5 | 6 | Example coming soon. 7 | -------------------------------------------------------------------------------- /tests/dummy/app/guides/fragment-identifiers.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Fragment Identifier Links 3 | order: 4 4 | fragmentIdLinks: 5 | iamsectionone: "Section One" 6 | section-two: "Section Two" 7 | --- 8 | 9 | * [Section One Link](#iamsectionone) 10 | * [Section Two Link](#section-two) 11 | 12 | ### I am Section One 13 | 14 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum aliquam dictum quam. Donec lobortis purus ut sagittis laoreet. Sed nisl metus, vulputate ut nunc a, pretium sodales lorem. Phasellus ultricies ipsum et sapien auctor, eget auctor lacus luctus. Suspendisse vitae ligula at leo sagittis rhoncus. Nulla porta auctor ex eu dictum. Morbi ut ante sit amet dui tincidunt commodo eu id mauris. Integer eu cursus tortor. Morbi vehicula ultrices fringilla. Fusce vitae ante sit amet turpis cursus cursus. Vivamus sagittis rutrum gravida. Donec finibus arcu eu quam consequat convallis vitae non odio. Cras lorem sapien, vestibulum nec ornare eu, rutrum id quam. Maecenas at arcu consectetur, suscipit lectus sit amet, porta turpis. Suspendisse tortor turpis, cursus vel diam id, accumsan convallis odio. 15 | 16 | Curabitur tristique tellus vel metus dictum, vel vehicula elit aliquet. Ut iaculis est in tellus varius lacinia. Nam consectetur venenatis molestie. Aliquam euismod massa pulvinar arcu finibus, in rutrum nunc bibendum. Cras at porttitor nisl, et finibus justo. Fusce volutpat elementum consectetur. Mauris ut massa ac magna mollis malesuada. Vivamus non egestas justo. Pellentesque convallis, lacus sit amet pulvinar dapibus, dui lorem condimentum eros, in tempus nulla nibh eu magna. Phasellus et eros id libero suscipit condimentum. Pellentesque tristique risus et bibendum volutpat. Nullam eget maximus ex. Aliquam lobortis, augue vel viverra pharetra, leo nisi mollis libero, id tincidunt nisl augue vel ligula. 17 | 18 | Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nunc eget sodales neque. Etiam a lectus tempor, euismod elit id, porta ipsum. Suspendisse luctus, lacus sit amet finibus ultrices, nisi eros ornare ex, eu sollicitudin nisi elit sit amet est. Nulla quis dignissim nisi. Proin sit amet eleifend ligula. Nunc nec tristique elit. Donec facilisis efficitur condimentum. 19 | 20 | Sed maximus quam et nulla consectetur interdum. Fusce lobortis quis odio eget egestas. Vestibulum diam est, tincidunt non maximus at, mattis nec tellus. Quisque egestas finibus massa et sagittis. Morbi quis dui ut enim pharetra fermentum. Ut a venenatis quam. Curabitur suscipit mi at est mattis convallis. Nullam vel pellentesque ligula. Praesent id sapien vitae nulla rhoncus aliquam. Aenean vitae lobortis dolor, sit amet feugiat nulla. Nulla cursus a mi at dictum. Nulla eu ipsum consectetur, ornare lorem ac, varius massa. Fusce tincidunt risus nec consectetur bibendum. Etiam lorem turpis, mollis ac est id, tristique aliquam lorem. Sed vestibulum ante ut nisi condimentum consectetur. 21 | 22 | Ut fermentum eros bibendum scelerisque aliquam. Interdum et malesuada fames ac ante ipsum primis in faucibus. Sed laoreet laoreet nisl vitae maximus. Curabitur feugiat, enim et pretium suscipit, lectus mauris sollicitudin quam, et pretium lacus lorem et mi. Vivamus sapien enim, iaculis non finibus a, rutrum ut quam. Aliquam pellentesque elit a dignissim fringilla. Fusce volutpat pellentesque porttitor. Phasellus facilisis efficitur nibh, ut venenatis neque congue in. Aliquam eget cursus ligula. 23 | 24 | ### I am Section Two 25 | 26 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum aliquam dictum quam. Donec lobortis purus ut sagittis laoreet. Sed nisl metus, vulputate ut nunc a, pretium sodales lorem. Phasellus ultricies ipsum et sapien auctor, eget auctor lacus luctus. Suspendisse vitae ligula at leo sagittis rhoncus. Nulla porta auctor ex eu dictum. Morbi ut ante sit amet dui tincidunt commodo eu id mauris. Integer eu cursus tortor. Morbi vehicula ultrices fringilla. Fusce vitae ante sit amet turpis cursus cursus. Vivamus sagittis rutrum gravida. Donec finibus arcu eu quam consequat convallis vitae non odio. Cras lorem sapien, vestibulum nec ornare eu, rutrum id quam. Maecenas at arcu consectetur, suscipit lectus sit amet, porta turpis. Suspendisse tortor turpis, cursus vel diam id, accumsan convallis odio. 27 | 28 | Curabitur tristique tellus vel metus dictum, vel vehicula elit aliquet. Ut iaculis est in tellus varius lacinia. Nam consectetur venenatis molestie. Aliquam euismod massa pulvinar arcu finibus, in rutrum nunc bibendum. Cras at porttitor nisl, et finibus justo. Fusce volutpat elementum consectetur. Mauris ut massa ac magna mollis malesuada. Vivamus non egestas justo. Pellentesque convallis, lacus sit amet pulvinar dapibus, dui lorem condimentum eros, in tempus nulla nibh eu magna. Phasellus et eros id libero suscipit condimentum. Pellentesque tristique risus et bibendum volutpat. Nullam eget maximus ex. Aliquam lobortis, augue vel viverra pharetra, leo nisi mollis libero, id tincidunt nisl augue vel ligula. 29 | 30 | Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nunc eget sodales neque. Etiam a lectus tempor, euismod elit id, porta ipsum. Suspendisse luctus, lacus sit amet finibus ultrices, nisi eros ornare ex, eu sollicitudin nisi elit sit amet est. Nulla quis dignissim nisi. Proin sit amet eleifend ligula. Nunc nec tristique elit. Donec facilisis efficitur condimentum. 31 | 32 | Sed maximus quam et nulla consectetur interdum. Fusce lobortis quis odio eget egestas. Vestibulum diam est, tincidunt non maximus at, mattis nec tellus. Quisque egestas finibus massa et sagittis. Morbi quis dui ut enim pharetra fermentum. Ut a venenatis quam. Curabitur suscipit mi at est mattis convallis. Nullam vel pellentesque ligula. Praesent id sapien vitae nulla rhoncus aliquam. Aenean vitae lobortis dolor, sit amet feugiat nulla. Nulla cursus a mi at dictum. Nulla eu ipsum consectetur, ornare lorem ac, varius massa. Fusce tincidunt risus nec consectetur bibendum. Etiam lorem turpis, mollis ac est id, tristique aliquam lorem. Sed vestibulum ante ut nisi condimentum consectetur. 33 | 34 | Ut fermentum eros bibendum scelerisque aliquam. Interdum et malesuada fames ac ante ipsum primis in faucibus. Sed laoreet laoreet nisl vitae maximus. Curabitur feugiat, enim et pretium suscipit, lectus mauris sollicitudin quam, et pretium lacus lorem et mi. Vivamus sapien enim, iaculis non finibus a, rutrum ut quam. Aliquam pellentesque elit a dignissim fringilla. Fusce volutpat pellentesque porttitor. Phasellus facilisis efficitur nibh, ut venenatis neque congue in. Aliquam eget cursus ligula. 35 | -------------------------------------------------------------------------------- /tests/dummy/app/guides/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Ember CLI Markdown Resolver 3 | inTree: false 4 | --- 5 | 6 | Ember CLI Markdown Resolver is the quickest way to include static markdown content in your Ember.js application using [Broccoli Markdown Resolver](https://github.com/willviles/broccoli-markdown-resolver). 7 | 8 | ##### Demo 9 | 10 | These guides are generated using the Ember CLI Markdown Resolver addon and the source code can be found here: 11 | 12 | 13 | [→ https://github.com/willviles/ember-cli-markdown-resolver/tree/master/tests/dummy](https://github.com/willviles/ember-cli-markdown-resolver/tree/master/tests/dummy) 14 | 15 | -------------------------------------------------------------------------------- /tests/dummy/app/guides/install.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation 3 | order: 0 4 | inTree: true 5 | --- 6 | 7 | ``` 8 | ember install ember-cli-markdown-resolver 9 | ``` 10 | 11 | #### Configuration 12 | 13 | The addon requires you specify the locations of markdown files: 14 | 15 | ```js 16 | // config/environment.js 17 | 18 | ENV['ember-cli-markdown-resolver'] = { 19 | folders: { 20 | 'guides': 'app/guides' 21 | } 22 | }; 23 | ``` 24 | 25 | And to populate your folder with markdown content: 26 | 27 | ```shell 28 | . 29 | └── app/ 30 | └── guides/ 31 | ├── quick-start.md 32 | ├── examples.md 33 | └── examples/ 34 | └── first.md 35 | ``` 36 | -------------------------------------------------------------------------------- /tests/dummy/app/guides/not-in-tree.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Not In Tree 3 | inTree: false 4 | --- 5 | 6 | This file is not included in the results of `this.get('markdownResolver').tree(type)` 7 | -------------------------------------------------------------------------------- /tests/dummy/app/guides/usage.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Usage 3 | order: 1 4 | --- 5 | 6 | Ember CLI Markdown Resolver enables markdown content to be retrieved via the `markdownResolver` service. 7 | 8 | The service exposes two methods for accessing markdown data. 9 | 10 | - Files 11 | - Trees 12 | -------------------------------------------------------------------------------- /tests/dummy/app/guides/usage/files.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Files 3 | order: 0 4 | --- 5 | 6 | #### `this.get('markdownResolver').file(type, path)` 7 | 8 | 9 | [→ addon/services/markdown-resolver.js#L45-L48](https://github.com/willviles/ember-cli-markdown-resolver/blob/master/addon/services/markdown-resolver.js#L45-L48) 10 | 11 | 12 | The `file` method returns promisified markdown content, allowing the content to be chainable via `.then()`. 13 | 14 | ```js 15 | // routes/guides/single.js 16 | 17 | import Route from '@ember/routing/route'; 18 | import { inject } from '@ember/service'; 19 | 20 | export default Route.extend({ 21 | markdownResolver: inject(), 22 | 23 | model({ path }) { 24 | return get(this, 'markdownResolver').file('guides', path); 25 | } 26 | }); 27 | ``` 28 | 29 | Each markdown file exposes the path, raw content, frontmatter attributes and its children. 30 | 31 | ```hbs 32 | 33 | 34 | {{model.content}} 35 | {{model.path}} 36 | {{model.attributes}} 37 | {{model.children}} 38 | ``` 39 | -------------------------------------------------------------------------------- /tests/dummy/app/guides/usage/trees.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Trees 3 | order: 1 4 | --- 5 | 6 | #### `this.get('markdownResolver').tree(type)` 7 | 8 | 9 | [→ addon/services/markdown-resolver.js#L50-L54](https://github.com/willviles/ember-cli-markdown-resolver/blob/master/addon/services/markdown-resolver.js#L50-L54) 10 | 11 | 12 | The `tree` method returns a tree object for a given folder, allowing menu interfaces to be built from the markdown file structure. 13 | 14 | ```js 15 | // routes/guides.js 16 | 17 | import Route from '@ember/routing/route'; 18 | import { inject } from '@ember/service'; 19 | 20 | export default Route.extend({ 21 | markdownResolver: inject(), 22 | 23 | model({ path }) { 24 | return get(this, 'markdownResolver').tree('guides'); 25 | } 26 | }); 27 | ``` 28 | 29 | Adding an `order` value to a file's frontmatter will automatically order files within the tree. 30 | 31 | ```md 32 | --- 33 | title: Quick Start 34 | order: 0 35 | --- 36 | 37 | Lorem ipsum dolor sit amet... 38 | ``` 39 | -------------------------------------------------------------------------------- /tests/dummy/app/helpers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willviles/ember-cli-markdown-resolver/46e56e04d3bf9508f56e7844030f865f7e0fd788/tests/dummy/app/helpers/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{content-for "head"}} 9 | 10 | 11 | 12 | 13 | {{content-for "head-footer"}} 14 | 15 | 16 | {{content-for "body"}} 17 | 18 | 19 | 20 | 21 | {{content-for "body-footer"}} 22 | 23 | 24 | -------------------------------------------------------------------------------- /tests/dummy/app/initializers/showdown.js: -------------------------------------------------------------------------------- 1 | import showdown from 'showdown'; 2 | 3 | export function initialize() { 4 | showdown.extension('prettify', function() { 5 | return [{ 6 | type: 'output', 7 | filter(source) { 8 | return source.replace(/(]*>)?[\n\s]?]*)>/gi, (match, pre, codeClass) => { 9 | return pre ? 10 | `
` :
11 |             ` `;
12 |         });
13 |       }
14 |     }];
15 |   });
16 | }
17 | 
18 | export default {
19 |   name: 'register-showdown-extensions',
20 |   initialize
21 | };
22 | 


--------------------------------------------------------------------------------
/tests/dummy/app/instance-initializers/head-data.js:
--------------------------------------------------------------------------------
 1 | import { get, set, setProperties } from '@ember/object';
 2 | import { assign } from '@ember/polyfills';
 3 | import Route from '@ember/routing/route';
 4 | import Router from '@ember/routing/router';
 5 | import { inject } from '@ember/service';
 6 | import { typeOf } from '@ember/utils';
 7 | 
 8 | 
 9 | export function initialize() {
10 | 
11 |   Router.reopen({
12 |     headData: inject(),
13 |     setTitle(title) { set(get(this, 'headData'), 'title', title); }
14 |   });
15 | 
16 |   Route.reopen({
17 |     headData: inject(),
18 |     afterModel(model) {
19 |       this._super(...arguments);
20 |       if (typeOf(this.metadata) === 'function') {
21 |         const metadata = this.metadata(model);
22 |         const url = get(this, 'routeURL');
23 |         setProperties(get(this, 'headData'), assign(metadata, { url }));
24 |       }
25 |     }
26 |   });
27 | 
28 | }
29 | 
30 | export default {
31 |   name: 'head-data',
32 |   initialize
33 | };
34 | 


--------------------------------------------------------------------------------
/tests/dummy/app/instance-initializers/inject-config.js:
--------------------------------------------------------------------------------
 1 | import Component from '@ember/component';
 2 | import Controller from '@ember/controller';
 3 | import { computed } from '@ember/object';
 4 | import Mixin from '@ember/object/mixin';
 5 | import Route from '@ember/routing/route';
 6 | import ENV from 'dummy/config/environment';
 7 | 
 8 | const { rootURL } = ENV;
 9 | 
10 | export function initialize(appInstance) {
11 |   let fastbootService = appInstance.lookup('service:fastboot');
12 |   let isFastBoot = fastbootService && fastbootService.get('isFastBoot');
13 | 
14 |   let baseURL;
15 | 
16 |   if (isFastBoot) {
17 |     let protocol = fastbootService.get('request.protocol');
18 |     let host = fastbootService.get('request.host');
19 |     baseURL = `${protocol}://${host}`;
20 | 
21 |   } else {
22 |     let pathArray = window.location.href.split('/');
23 |     baseURL = `${pathArray[0]}//${pathArray[2]}`;
24 | 
25 |   }
26 | 
27 |   let URLMixin = Mixin.create({
28 |     baseURL, rootURL
29 |   });
30 | 
31 |   let RouteURLMixin = Mixin.create({
32 |     routeURL: computed(function() {
33 |       return isFastBoot ?
34 |         `${baseURL}${rootURL}${fastbootService.get('request.path')}` :
35 |         window.location.href;
36 |     })
37 | 
38 |   });
39 | 
40 |   Component.reopen(URLMixin);
41 |   Controller.reopen(URLMixin);
42 |   Route.reopen(URLMixin, RouteURLMixin);
43 | 
44 | }
45 | 
46 | export default {
47 |   name: 'urls',
48 |   initialize
49 | };
50 | 


--------------------------------------------------------------------------------
/tests/dummy/app/mixins/ui/align-mixin.js:
--------------------------------------------------------------------------------
 1 | import Mixin from '@ember/object/mixin';
 2 | 
 3 | import propertyClassNameBinding from 'dummy/utils/property-class-name-binding';
 4 | 
 5 | export default Mixin.create({
 6 | 
 7 |   classNameBindings: ['_align'],
 8 | 
 9 |   align: false,
10 |   _align: propertyClassNameBinding('align')
11 | 
12 | });
13 | 


--------------------------------------------------------------------------------
/tests/dummy/app/mixins/ui/color-mixin.js:
--------------------------------------------------------------------------------
 1 | import Mixin from '@ember/object/mixin';
 2 | 
 3 | import propertyClassNameBinding from 'dummy/utils/property-class-name-binding';
 4 | 
 5 | export default Mixin.create({
 6 | 
 7 |   classNameBindings: ['_bg', '_bgHover', '_color', '_colorHover'],
 8 | 
 9 |   bg: false,
10 |   _bg: propertyClassNameBinding('bg'),
11 | 
12 |   bgHover: false,
13 |   _bgHover: propertyClassNameBinding('bgHover'),
14 | 
15 |   color: false,
16 |   _color: propertyClassNameBinding('color'),
17 | 
18 |   colorHover: false,
19 |   _colorHover: propertyClassNameBinding('colorHover')
20 | 
21 | });
22 | 


--------------------------------------------------------------------------------
/tests/dummy/app/mixins/ui/depth-mixin.js:
--------------------------------------------------------------------------------
 1 | import Mixin from '@ember/object/mixin';
 2 | 
 3 | import propertyClassNameBinding from 'dummy/utils/property-class-name-binding';
 4 | 
 5 | export default Mixin.create({
 6 | 
 7 |   classNameBindings: ['_depth'],
 8 | 
 9 |   depth: false,
10 |   _depth: propertyClassNameBinding('depth')
11 | 
12 | });
13 | 


--------------------------------------------------------------------------------
/tests/dummy/app/mixins/ui/font-size-mixin.js:
--------------------------------------------------------------------------------
 1 | import Mixin from '@ember/object/mixin';
 2 | 
 3 | import propertyClassNameBinding from 'dummy/utils/property-class-name-binding';
 4 | 
 5 | export default Mixin.create({
 6 | 
 7 |   classNameBindings: ['_fontSize'],
 8 | 
 9 |   fontSize: false,
10 |   _fontSize: propertyClassNameBinding('fontSize')
11 | 
12 | });
13 | 


--------------------------------------------------------------------------------
/tests/dummy/app/mixins/ui/padding-mixin.js:
--------------------------------------------------------------------------------
 1 | import Mixin from '@ember/object/mixin';
 2 | 
 3 | import propertyClassNameBinding from 'dummy/utils/property-class-name-binding';
 4 | 
 5 | export default Mixin.create({
 6 | 
 7 |   classNameBindings: ['_padding'],
 8 | 
 9 |   padding: false,
10 |   _padding: propertyClassNameBinding('padding', {
11 |     values: ['top', 'right', 'bottom', 'left']
12 |   })
13 | 
14 | });
15 | 


--------------------------------------------------------------------------------
/tests/dummy/app/mixins/ui/size-mixin.js:
--------------------------------------------------------------------------------
 1 | import Mixin from '@ember/object/mixin';
 2 | 
 3 | import propertyClassNameBinding from 'dummy/utils/property-class-name-binding';
 4 | 
 5 | export default Mixin.create({
 6 | 
 7 |   classNameBindings: ['_size'],
 8 | 
 9 |   size: false,
10 |   _size: propertyClassNameBinding('size')
11 | 
12 | });
13 | 


--------------------------------------------------------------------------------
/tests/dummy/app/models/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/willviles/ember-cli-markdown-resolver/46e56e04d3bf9508f56e7844030f865f7e0fd788/tests/dummy/app/models/.gitkeep


--------------------------------------------------------------------------------
/tests/dummy/app/resolver.js:
--------------------------------------------------------------------------------
1 | import Resolver from 'ember-resolver';
2 | 
3 | export default Resolver;
4 | 


--------------------------------------------------------------------------------
/tests/dummy/app/router.js:
--------------------------------------------------------------------------------
 1 | import EmberRouter from '@ember/routing/router';
 2 | import config from './config/environment';
 3 | 
 4 | const Router = EmberRouter.extend({
 5 |   location: config.locationType,
 6 |   rootURL: config.rootURL
 7 | });
 8 | 
 9 | Router.map(function() {
10 |   this.route('guides', function() {
11 |     this.route('single', { path: '/*path' });
12 |   });
13 | 
14 |   this.route('error', { path: '/*type' });
15 | });
16 | 
17 | export default Router;
18 | 


--------------------------------------------------------------------------------
/tests/dummy/app/routes/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/willviles/ember-cli-markdown-resolver/46e56e04d3bf9508f56e7844030f865f7e0fd788/tests/dummy/app/routes/.gitkeep


--------------------------------------------------------------------------------
/tests/dummy/app/routes/application.js:
--------------------------------------------------------------------------------
 1 | import Route from '@ember/routing/route';
 2 | import { getProperties } from '@ember/object';
 3 | 
 4 | export default Route.extend({
 5 |   title(tokens) {
 6 |     return tokens.length ?
 7 |       `${tokens.join(' – ')} – Ember CLI Markdown Resolver` :
 8 |       'Ember CLI Markdown Resolver';
 9 |   },
10 | 
11 |   metadata() {
12 |     let { baseURL, rootURL } = getProperties(this, 'baseURL', 'rootURL');
13 |     return {
14 |       appName: `Ember CLI Markdown Resolver`,
15 |       description: `The quickest way to include static markdown content in your Ember.js application. Ember CLI Markdown Resolver is an addon for resolving markdown files in custom folders and retrieving content via a service.`,
16 |       keywords: `ember.js, ember-addon, markdown, md, resolver, frontmatter, content`,
17 |       image: `${baseURL}${rootURL}images/facebook.jpg`,
18 |       favicon: `${baseURL}${rootURL}images/favicon`
19 |     };
20 |   },
21 | })
22 | 


--------------------------------------------------------------------------------
/tests/dummy/app/routes/guides.js:
--------------------------------------------------------------------------------
 1 | import Route from '@ember/routing/route';
 2 | import { get } from '@ember/object';
 3 | import { inject } from '@ember/service';
 4 | import RSVP from 'rsvp';
 5 | 
 6 | const { hash } = RSVP;
 7 | 
 8 | export default Route.extend({
 9 | 
10 |   titleToken: 'Guides',
11 | 
12 |   markdownResolver: inject(),
13 | 
14 |   model() {
15 |     return hash({
16 |       tree: get(this, 'markdownResolver').tree('guides')
17 |     });
18 |   },
19 | 
20 |   setupController(controller, model) {
21 |     controller.setProperties(model);
22 |   }
23 | 
24 | });
25 | 


--------------------------------------------------------------------------------
/tests/dummy/app/routes/guides/index.js:
--------------------------------------------------------------------------------
 1 | import Route from '@ember/routing/route';
 2 | import { get } from '@ember/object';
 3 | import { inject } from '@ember/service';
 4 | import RSVP from 'rsvp';
 5 | 
 6 | const { hash } = RSVP;
 7 | 
 8 | export default Route.extend({
 9 | 
10 |   titleToken: 'Introduction',
11 | 
12 |   templateName: 'guides.single',
13 | 
14 |   markdownResolver: inject(),
15 | 
16 |   model() {
17 |     return hash({
18 |       guide: get(this, 'markdownResolver').file('guides', 'index')
19 |     });
20 |   },
21 | 
22 |   setupController(controller, model) {
23 |     controller.setProperties(model);
24 |   }
25 | 
26 | });
27 | 


--------------------------------------------------------------------------------
/tests/dummy/app/routes/guides/single.js:
--------------------------------------------------------------------------------
 1 | import Route from '@ember/routing/route';
 2 | import { get } from '@ember/object';
 3 | import { inject } from '@ember/service';
 4 | import RSVP from 'rsvp';
 5 | 
 6 | const { hash } = RSVP;
 7 | 
 8 | export default Route.extend({
 9 | 
10 |   titleToken({ guide }) {
11 |     return get(guide, 'attributes.title');
12 |   },
13 | 
14 |   markdownResolver: inject(),
15 | 
16 |   model({ path }) {
17 |     return hash({
18 |       guide: get(this, 'markdownResolver').file('guides', path)
19 |     });
20 |   },
21 | 
22 |   afterModel({ guide }) {
23 |     if (!guide) {
24 |       this.transitionTo('error', { type: '404' });
25 |     }
26 |   },
27 | 
28 |   setupController(controller, model) {
29 |     controller.setProperties(model);
30 |   }
31 | 
32 | });
33 | 


--------------------------------------------------------------------------------
/tests/dummy/app/styles/app.scss:
--------------------------------------------------------------------------------
 1 | @import 'framework/reset';
 2 | @import 'framework/mixins';
 3 | @import 'sassdash';
 4 | 
 5 | @import 'main/config';
 6 | @import 'components/config';
 7 | 
 8 | @import 'framework/grid';
 9 | @import 'framework/fonts';
10 | @import 'framework/type';
11 | @import 'framework/colors';
12 | @import 'framework/utility';
13 | 
14 | @import 'components/_';
15 | @import 'main/_';
16 | @import 'routes/_';
17 | 


--------------------------------------------------------------------------------
/tests/dummy/app/styles/components/_.scss:
--------------------------------------------------------------------------------
1 | @import 'buttons/_';
2 | @import 'footer/_';
3 | @import 'markdown/_';
4 | @import 'navbar/_';
5 | @import 'sections/_';
6 | 


--------------------------------------------------------------------------------
/tests/dummy/app/styles/components/_config.scss:
--------------------------------------------------------------------------------
 1 | // Components config
 2 | 
 3 | $--navbar: (
 4 |   height: (50px, 50px, 60px, 70px, 90px),
 5 |   background-color: _get($--colors, 'black'),
 6 |   color: _get($--colors, 'white'),
 7 |   item-horiz-padding: (.5rem, .5rem, .66rem, .75rem, .9rem),
 8 |   fixed: false
 9 | );
10 | 
11 | $--buttons: (
12 |   font-size: (.7rem, 1rem, 1.2rem, 1.5rem, 2rem),
13 |   padding: (.5rem, .75rem, 1rem, 2rem, 3rem),
14 |   padding-horiz-ratio: 1.5,
15 |   line-height: (160%, 150%, 140%, 130%, 120%),
16 |   border-radius: .25rem,
17 |   disabled-bg: rgba(_get($--colors, 'lt-gray'), .33),
18 |   disabled-color: rgba(_get($--colors, 'black'), .5)
19 | );
20 | 
21 | $--sections: (
22 |   font-size: (.7rem, .9rem, 1rem, 1.1rem, 1.2rem),
23 |   padding: (3rem, 5rem, 7rem, 10rem, 20rem)
24 | );
25 | 


--------------------------------------------------------------------------------
/tests/dummy/app/styles/components/buttons/_.scss:
--------------------------------------------------------------------------------
 1 | //----------------------------------------------------------------------
 2 | 
 3 | // Buttons
 4 | //
 5 | 
 6 | button {
 7 |   border: none;
 8 |   padding: 0 0 0 0;
 9 |   background-color: transparent;
10 |   cursor: pointer;
11 |   color: inherit;
12 |   font-size: 100%;
13 |   font-family: inherit;
14 |   font-style: inherit;
15 | 
16 |   &:focus { outline: 0; }
17 |   &.active {
18 |     font-weight: bold;
19 |     text-decoration: underline;
20 |   }
21 | 
22 | }
23 | 
24 | .button {
25 |   display: inline-flex;
26 |   align-items: center;
27 |   cursor: pointer;
28 |   justify-content: center;
29 | 
30 |   &.align-left { justify-content: left; }
31 |   &.align-right { justify-content: right; }
32 | 
33 |   &.rounded {
34 |     border-radius: _get($--buttons, 'border-radius');
35 |   }
36 | 
37 |   &:not(.inline) {
38 |     display: flex;
39 |     width: 100%;
40 |     box-sizing: border-box;
41 |   }
42 | 
43 |   &.transparent {
44 |     background-color: rgba(white, 0);
45 |     color: inherit !important;
46 |   }
47 | 
48 |   @for $i from 1 through length(_get($--grid, 'breakpoints')) {
49 |     $breakpoints: _keys(_get($--grid, 'breakpoints'));
50 |     $breakpoint: nth($breakpoints, $i);
51 | 
52 |     line-height: nth(_get($--buttons, 'line-height'), $i);
53 | 
54 |     &.padding-#{$breakpoint} {
55 |       $padding: nth(_get($--buttons, 'padding'), $i);
56 |       $horiz-ratio: _get($--buttons, 'padding-horiz-ratio');
57 |       padding: $padding #{$padding * $horiz-ratio};
58 |     }
59 | 
60 |     &.font-size-#{$breakpoint} {
61 |       $font-size: nth(_get($--buttons, 'font-size'), $i);
62 |       font-size: $font-size;
63 |     }
64 |   }
65 | 
66 |   @each $name, $hex in $--colors {
67 |     &.bg-#{$name}:not([class*=' bg-hover']):not(:disabled) {
68 |       &:hover { background-color: darken($hex, 5%) !important; }
69 |     }
70 |   }
71 | 
72 |   &:disabled {
73 |     background-color: _get($--buttons, 'disabled-bg') !important;
74 |     color: _get($--buttons, 'disabled-color') !important;
75 |     cursor: auto !important;
76 |   }
77 | 
78 |   &.pending {
79 |     background-color: _get($--buttons, 'pending-bg') !important;
80 |     color: _get($--buttons, 'pending-color') !important;
81 |     cursor: auto;
82 |   }
83 | }
84 | 


--------------------------------------------------------------------------------
/tests/dummy/app/styles/components/footer/_.scss:
--------------------------------------------------------------------------------
 1 | footer {
 2 |   padding: 1rem 0 2rem 0;
 3 |   ul {
 4 |     li {
 5 |       display: inline-block;
 6 |       font-size: _get($--type, 'small');
 7 |       margin: .5em .5em;
 8 |       & > a {
 9 |         &.active, &:hover {
10 |           @include set-font('header');
11 |         }
12 |         &.active {
13 |           text-decoration: underline;
14 |         }
15 |       }
16 |     }
17 |   }
18 | }
19 | 


--------------------------------------------------------------------------------
/tests/dummy/app/styles/components/markdown/_.scss:
--------------------------------------------------------------------------------
  1 | @import 'menu';
  2 | @import 'prettyprint';
  3 | 
  4 | article, .markdown-content {
  5 |   h1, h2, h3, h4, h5, h6 {
  6 |     @include set-font('header');
  7 |     margin-bottom: 1em;
  8 |   }
  9 |   p {
 10 |     a {
 11 |       @include set-font('header');
 12 |       &:hover {
 13 |         text-decoration: underline;
 14 |       }
 15 |     }
 16 |   }
 17 |   .codelink {
 18 |     display: block;
 19 |     background: _get($--colors, 'lt-gray');
 20 |     color: inherit;
 21 |     padding: .2em .5em;
 22 |     border-radius: .25rem;
 23 |     white-space: nowrap;
 24 |     overflow-x: scroll;
 25 |     a {
 26 |       font-size: .8em;
 27 |     }
 28 |   }
 29 |   & > ul, & > ol {
 30 |     @include media-breakpoint-up('sm') {
 31 |       padding-left: _get($--grid, 'margin');
 32 |       padding-right: _get($--grid, 'margin');
 33 |     }
 34 |   }
 35 |   ul, ol {
 36 |     font-size: 1.2rem;
 37 |     ul, ol {
 38 |       margin-left: 2rem;
 39 |       font-size: 0.8em;
 40 |     }
 41 |     li {
 42 |       line-height: 2em;
 43 |       list-style-position: inside;
 44 |       & > p {
 45 |         display: inline-block;
 46 |         font-size: inherit;
 47 |       }
 48 |     }
 49 |   }
 50 |   ol {
 51 |     li {
 52 |       list-style-type: decimal-leading-zero;
 53 |       list-style-position: inside;
 54 |     }
 55 |   }
 56 |   ul {
 57 |     li {
 58 |       &:not(.task-list-item) {
 59 |         list-style-type: circle;
 60 |       }
 61 |       &.task-list-item {
 62 |         [type="checkbox"] {
 63 |           margin-right: 1em;
 64 |         }
 65 |       }
 66 |     }
 67 |   }
 68 |   pre {
 69 |     & > ul, & > ol {
 70 |       font-size: 1rem;
 71 |       li {
 72 |         line-height: 1.5em;
 73 |       }
 74 |     }
 75 |   }
 76 |   blockquote {
 77 |     position: relative;
 78 |     margin-bottom: 3rem;
 79 |     padding-bottom: 2rem;
 80 |     p {
 81 |       font-size: 1.33em;
 82 |     }
 83 |     &:before {
 84 |       content: '“';
 85 |       font-size: 4em;
 86 |       opacity: .5;
 87 |     }
 88 |     &:after {
 89 |       content: '';
 90 |       position: absolute;
 91 |       top: 100%; left: 0;
 92 |       height: 3px; width: 4em;
 93 |       background-color: rgba(_get($--colors, 'black'), 0.33);
 94 |     }
 95 |     p {
 96 |       margin-top: -1em;
 97 |     }
 98 |     @include media-breakpoint-up('md') {
 99 |       margin-left: -#{_get($--grid, 'margin')};
100 |       margin-right: -#{_get($--grid, 'margin')};
101 |     }
102 |   }
103 | }
104 | 


--------------------------------------------------------------------------------
/tests/dummy/app/styles/components/markdown/_menu.scss:
--------------------------------------------------------------------------------
 1 | .markdown-menu {
 2 |   .markdown-menu-title {
 3 |     font-weight: 800;
 4 |     font-size: 1.1em;
 5 |     text-transform: capitalize;
 6 |     margin-bottom: .75em;
 7 |   }
 8 |   & > ul {
 9 |     a {
10 |       padding: .5em 0;
11 |       &[href] {
12 |         &:hover {
13 |           font-weight: 800;
14 |         }
15 |         &.active {
16 |           color: _get($--colors, 'red');
17 |           font-weight: 800;
18 |         }
19 |       }
20 |       &:not([href]):focus {
21 |         outline: 0;
22 |       }
23 |     }
24 |     ul {
25 |       margin-left: 1em;
26 |     }
27 |   }
28 | }
29 | 


--------------------------------------------------------------------------------
/tests/dummy/app/styles/components/markdown/_prettyprint.scss:
--------------------------------------------------------------------------------
 1 | .prettyprint {
 2 | 
 3 |   @at-root pre#{&} {
 4 |     background: _get($--colors, 'gray');
 5 |     color: _get($--colors, 'white');
 6 |     margin: 0 0 2em 0;
 7 |     padding: 1em;
 8 |   }
 9 | 
10 |   @at-root code#{&} {
11 |     background: _get($--colors, 'lt-gray');
12 |     color: inherit;
13 |     padding: .2em .5em;
14 |   }
15 | 
16 |   font-family: Menlo, Monaco, Consolas, monospace;
17 |   border: 0 !important;
18 |   border-radius: .25rem;
19 |   overflow-x: scroll;
20 | 
21 |   li {
22 |     padding-left: .5em;
23 |     padding-right: .5em;
24 |     line-height: 1.5em;
25 |     // &.L4, &.L9 {
26 |     //   list-style-type: none !important;
27 |     // }
28 |   }
29 | 
30 |   // Hide the text until it's prettyprinted
31 |   &:not(.prettyprinted) {
32 |     & > code {
33 |       visibility: hidden;
34 |     }
35 |   }
36 | }
37 | 


--------------------------------------------------------------------------------
/tests/dummy/app/styles/components/navbar/_.scss:
--------------------------------------------------------------------------------
  1 | .navbar, .navbar > .container {
  2 |   display: flex;
  3 |   align-items: stretch;
  4 | }
  5 | 
  6 | .navbar {
  7 | 
  8 |   &:not(.unfixed) {
  9 |     position: fixed;
 10 |     z-index: 60;
 11 |     top: 0; left: 0; width: 100%;
 12 |   }
 13 | 
 14 |   background-color: _get($--navbar, 'background-color');
 15 |   color: _get($--navbar, 'color');
 16 | 
 17 |   @for $i from length(_get($--grid, 'breakpoints'))*-1 through -1 {
 18 |     $breakpoints: _keys(_get($--grid, 'breakpoints'));
 19 |     $breakpoint: nth($breakpoints, abs($i));
 20 |     @include media-breakpoint-down($breakpoint) {
 21 |       height: nth(_get($--navbar, 'height'), abs($i));
 22 |     }
 23 |   }
 24 | 
 25 |   & > .container {
 26 |     flex-grow: 1;
 27 |   }
 28 |   .navbar-content {
 29 |     display: flex;
 30 |     flex-grow: 1;
 31 |     & > * {
 32 |       display: flex;
 33 |       align-items: stretch;
 34 |     }
 35 |     .left, .right, .center {
 36 |       flex-grow: 1;
 37 |       & > * {
 38 |         display: inline-flex;
 39 |       }
 40 |       a {
 41 |         display: inline-flex;
 42 |         align-items: center;
 43 |         &.active {
 44 |           text-decoration: underline;
 45 |           @include set-font('header');
 46 |         }
 47 |       }
 48 |       ul li {
 49 |         display: inline-flex;
 50 |         align-items: stretch;
 51 |         a {
 52 |           @for $i from 1 through length(_get($--grid, 'breakpoints')) {
 53 |             $breakpoints: _keys(_get($--grid, 'breakpoints'));
 54 |             $breakpoint: nth($breakpoints, $i);
 55 |             @include media-breakpoint-down($breakpoint) {
 56 |               padding-left: nth(_get($--navbar, 'item-horiz-padding'), $i);
 57 |               padding-right: nth(_get($--navbar, 'item-horiz-padding'), $i);
 58 |             }
 59 |           }
 60 |         }
 61 |       }
 62 |     }
 63 |     .left {
 64 |       justify-content: flex-start;
 65 |       @include media-breakpoint-down('sm') {
 66 |         flex-basis: 100%;
 67 |         // justify-content: center;
 68 |       }
 69 |     }
 70 |     .center {
 71 |       justify-content: center;
 72 |     }
 73 |     .right {
 74 |       justify-content: flex-end;
 75 |     }
 76 |     // Custom components
 77 |     .unauthenticated {
 78 |       a {
 79 |         display: inline-flex;
 80 |         align-items: center;
 81 |         padding-left: .3em;
 82 |         padding-right: .3em;
 83 |       }
 84 |       & > span {
 85 |         align-self: center;
 86 |       }
 87 |     }
 88 |     .logo {
 89 |       @include media-breakpoint-down('sm') {
 90 |         flex-grow: 1;
 91 |       }
 92 |       img {
 93 |         max-height: 33%;
 94 |         @include media-breakpoint-down('lg') {
 95 |           max-height: 45%;
 96 |         }
 97 |         @include media-breakpoint-down('sm') {
 98 |           margin: auto;
 99 |           max-height: 66%;
100 |         }
101 |       }
102 |     }
103 |     .burger {
104 |       font-size: 2rem;
105 |       padding: 0 _get($--grid, 'gutter');
106 |       &.left {
107 |         margin-left: -#{_get($--grid, 'margin')};
108 |         padding-left: _get($--grid, 'margin');
109 |       }
110 |       &:not(.left) {
111 |         margin-right: -#{_get($--grid, 'margin')};
112 |         padding-right: _get($--grid, 'margin');
113 |       }
114 |     }
115 |   }
116 | }
117 | 


--------------------------------------------------------------------------------
/tests/dummy/app/styles/components/sections/_.scss:
--------------------------------------------------------------------------------
 1 | .section {
 2 |   @for $i from 1 through length(_get($--grid, 'breakpoints')) {
 3 |     $breakpoints: _keys(_get($--grid, 'breakpoints'));
 4 |     $breakpoint: nth($breakpoints, $i);
 5 |     $padding: nth(_get($--sections, 'padding'), $i);
 6 | 
 7 |     &.padding-#{$breakpoint}, &.padding-top-#{$breakpoint} {
 8 |       padding-top: $padding;
 9 | 
10 |       @include media-breakpoint-down('lg') {
11 |         padding-top: $padding * 0.8;
12 |       }
13 | 
14 |       @include media-breakpoint-down('md') {
15 |         padding-top: $padding * 0.6;
16 |       }
17 | 
18 |       @include media-breakpoint-down('sm') {
19 |         padding-top: $padding * 0.4;
20 |       }
21 | 
22 |       @include media-breakpoint-down('xs') {
23 |         padding-top: _get($--grid, 'gutter') * 2;
24 |       }
25 |     }
26 | 
27 |     &.padding-#{$breakpoint}, &.padding-bottom-#{$breakpoint} {
28 |       padding-bottom: $padding;
29 | 
30 |       @include media-breakpoint-down('lg') {
31 |         padding-bottom: $padding * 0.8;
32 |       }
33 | 
34 |       @include media-breakpoint-down('md') {
35 |         padding-bottom: $padding * 0.6;
36 |       }
37 | 
38 |       @include media-breakpoint-down('sm') {
39 |         padding-bottom: $padding * 0.4;
40 |       }
41 | 
42 |       @include media-breakpoint-down('xs') {
43 |         padding-bottom: _get($--grid, 'gutter') * 2;
44 |       }
45 |     }
46 | 
47 |     &.font-size-#{$breakpoint} {
48 |       $font-size: nth(_get($--sections, 'font-size'), $i);
49 |       font-size: $font-size;
50 |     }
51 |   }
52 | }
53 | 


--------------------------------------------------------------------------------
/tests/dummy/app/styles/framework/_colors.scss:
--------------------------------------------------------------------------------
 1 | //----------------------------------------------------------------------
 2 | 
 3 | // Colors
 4 | //
 5 | 
 6 | @each $name, $hex in $--colors {
 7 |   // Give each color a unique color class
 8 |   .color-#{$name} { color: $hex !important; }
 9 |   // Give each color a unique bg class
10 |   .bg-#{$name} { background-color: $hex !important; }
11 |   // Give each color a unique bg hover class
12 |   .bg-hover-#{$name}:hover { background-color: $hex !important; }
13 |   // Give each color a unique color hover class
14 |   .color-hover-#{$name}:hover { color: $hex !important; }
15 | }
16 | 


--------------------------------------------------------------------------------
/tests/dummy/app/styles/framework/_fonts.scss:
--------------------------------------------------------------------------------
 1 | //----------------------------------------------------------------------
 2 | 
 3 | // Fonts
 4 | //
 5 | 
 6 | // Give each font style a class
 7 | @each $name, $styles in $--font-styles {
 8 |   .font-#{$name} { @include set-font($name); }
 9 | }
10 | 


--------------------------------------------------------------------------------
/tests/dummy/app/styles/framework/_grid.scss:
--------------------------------------------------------------------------------
  1 | //----------------------------------------------------------------------
  2 | 
  3 | // Grid
  4 | //
  5 | 
  6 | $grid-columns: _get($--grid, 'columns') !default;
  7 | $gutter-width: _get($--grid, 'gutter') !default;
  8 | $outer-margin: _get($--grid, 'margin') !default;
  9 | $breakpoints: _get($--grid, 'breakpoints') !default;
 10 | $flexboxgrid-max-width: _get($--grid, 'max-width') !default;
 11 | 
 12 | $gutter-compensation: $gutter-width * .5 * -1;
 13 | $half-gutter-width: $gutter-width * .5;
 14 | 
 15 | .flex {
 16 |   display: flex;
 17 | }
 18 | 
 19 | .inline-flex {
 20 |   display: inline-flex;
 21 | }
 22 | 
 23 | .wrapper {
 24 |   box-sizing: border-box;
 25 |   max-width: $flexboxgrid-max-width;
 26 |   margin: 0 auto;
 27 | }
 28 | 
 29 | .container, .container-fluid {
 30 |   margin-right: auto;
 31 |   margin-left: auto;
 32 |   padding-right: $outer-margin;
 33 |   padding-left: $outer-margin;
 34 | }
 35 | 
 36 | .row, .row-fluid {
 37 |   box-sizing: border-box;
 38 |   @include flexbox();
 39 |   @include flex(0, 1, auto);
 40 |   @include flex-direction(row);
 41 |   @include flex-wrap(wrap);
 42 | }
 43 | 
 44 | .row {
 45 |   margin-right: $gutter-compensation;
 46 |   margin-left: $gutter-compensation;
 47 | }
 48 | 
 49 | .row.reverse {
 50 |   @include flex-direction(row-reverse);
 51 | }
 52 | 
 53 | .col.reverse {
 54 |   @include flex-direction(column-reverse);
 55 | }
 56 | 
 57 | @mixin flexboxgrid-sass-col-common {
 58 |   box-sizing: border-box;
 59 | 
 60 |   // split @include flex(0, 0, auto) into individual props
 61 |   @include flex-grow(0);
 62 |   @include flex-shrink(0);
 63 | 
 64 |   // we leave @include flex-basis(auto) out of common because
 65 |   // in some spots we need it and some we dont
 66 |   // more why here: https://github.com/kristoferjoseph/flexboxgrid/issues/126
 67 | 
 68 |   padding-right: $half-gutter-width;
 69 |   padding-left: $half-gutter-width;
 70 | }
 71 | 
 72 | @each $value in $breakpoints {
 73 | 
 74 |   $name: nth($value, 1);
 75 |   $breakpoint: nth($value, 2);
 76 | 
 77 |   // If is smallest breakpoint
 78 |   @if index(map-keys($breakpoints), $name) == 1 {
 79 | 
 80 |     .col-#{$name} {
 81 |       @include flexboxgrid-sass-col-common;
 82 |       @include flex-basis(auto);
 83 |     }
 84 |     @for $i from 1 through $grid-columns {
 85 |       .col.#{$name}#{$i} {
 86 |         @include flexboxgrid-sass-col-common;
 87 |         @include flex-basis(100% / $grid-columns * $i);
 88 |         max-width: 100% / $grid-columns * $i;
 89 |       }
 90 |     }
 91 |     @for $i from 0 through $grid-columns {
 92 |       .col.offset-#{$name}#{$i} {
 93 |         @include flexboxgrid-sass-col-common;
 94 |         @if $i == 0 {
 95 |           margin-left: 0;
 96 |         } @else {
 97 |           margin-left: 100% / $grid-columns * $i;
 98 |         }
 99 |       }
100 |     }
101 |     .col.#{$name} {
102 |       @include flex-grow(1);
103 |       @include flex-basis(0);
104 |       max-width: 100%;
105 |       margin-left: _get($--grid, 'gutter') / 2;
106 |       margin-right: _get($--grid, 'gutter') / 2;
107 |     }
108 |     .start-#{$name} {
109 |       @include justify-content(flex-start);
110 |       text-align: start;
111 |     }
112 | 
113 |     .center-#{$name} {
114 |       @include justify-content(center);
115 |       text-align: center;
116 |     }
117 | 
118 |     .end-#{$name} {
119 |       @include justify-content(flex-end);
120 |       text-align: end;
121 |     }
122 | 
123 |     .top-#{$name} {
124 |       @include align-items(flex-start);
125 |     }
126 | 
127 |     .middle-#{$name} {
128 |       @include align-items(center);
129 |     }
130 | 
131 |     .bottom-#{$name} {
132 |       @include align-items(flex-end);
133 |     }
134 | 
135 |     .stretch-#{name} {
136 |       @include align-items(stretch);
137 |     }
138 | 
139 |     .around-#{$name} {
140 |       @include justify-content(space-around);
141 |     }
142 | 
143 |     .between-#{$name} {
144 |       @include justify-content(space-between);
145 |     }
146 | 
147 |     .first-#{$name} {
148 |       order: -1;
149 |     }
150 | 
151 |     .last-#{$name} {
152 |       order: 1;
153 |     }
154 | 
155 |   // Otherwise, let's use
156 | 
157 |   } @else {
158 | 
159 |     $size: nth($breakpoint, 1);
160 |     $container: nth($breakpoint, 2);
161 | 
162 |     @include media-breakpoint-up($name) {
163 |       .container {
164 |         max-width: $container;
165 |       }
166 | 
167 |       .col.#{$name} {
168 |         @include flexboxgrid-sass-col-common;
169 |         @include flex-basis(auto);
170 |       }
171 |       @for $i from 1 through $grid-columns {
172 |         .col.#{$name}#{$i} {
173 |           @include flexboxgrid-sass-col-common;
174 |           @include flex-basis(100% / $grid-columns * $i);
175 |           max-width: 100% / $grid-columns * $i;
176 |         }
177 |       }
178 |       @for $i from 0 through $grid-columns {
179 |         .col.offset-#{$name}#{$i} {
180 |           @include flexboxgrid-sass-col-common;
181 |           @if $i == 0 {
182 |             margin-left: 0;
183 |           } @else {
184 |             margin-left: 100% / $grid-columns * $i;
185 |           }
186 |         }
187 |       }
188 |       .col.#{$name} {
189 |         @include flex-grow(1);
190 |         @include flex-basis(0);
191 |         max-width: 100%;
192 |       }
193 |       .start-#{$name} {
194 |         @include justify-content(flex-start);
195 |         text-align: start;
196 |       }
197 | 
198 |       .center-#{$name} {
199 |         @include justify-content(center);
200 |         text-align: center;
201 |       }
202 | 
203 |       .end-#{$name} {
204 |         @include justify-content(flex-end);
205 |         text-align: end;
206 |       }
207 | 
208 |       .top-#{$name} {
209 |         @include align-items(flex-start);
210 |       }
211 | 
212 |       .middle-#{$name} {
213 |         @include align-items(center);
214 |       }
215 | 
216 |       .bottom-#{$name} {
217 |         @include align-items(flex-end);
218 |       }
219 | 
220 |       .around-#{$name} {
221 |         @include justify-content(space-around);
222 |       }
223 | 
224 |       .between-#{$name} {
225 |         @include justify-content(space-between);
226 |       }
227 | 
228 |       .first-#{$name} {
229 |         order: -1;
230 |       }
231 | 
232 |       .last-#{$name} {
233 |         order: 1;
234 |       }
235 |     }
236 |   }
237 | }
238 | 
239 | //----------------------------------------------------------------------
240 | 
241 | // Responsive classes
242 | //
243 | // Hide elements responsively using classes.
244 | 
245 | @each $name, $value in _get($--grid, 'breakpoints') {
246 | 
247 |   .hide-#{$name} {
248 |     @include media-breakpoint-only($name) {
249 |       display: none !important;
250 |     }
251 |   }
252 | 
253 |   .hide-#{$name}-up {
254 |     @include media-breakpoint-up($name) {
255 |       display: none !important;
256 |     }
257 |   }
258 |   .hide-#{$name}-down {
259 |     @include media-breakpoint-down($name) {
260 |       display: none !important;
261 |     }
262 |   }
263 | 
264 | }
265 | 


--------------------------------------------------------------------------------
/tests/dummy/app/styles/framework/_mixins.scss:
--------------------------------------------------------------------------------
  1 | //----------------------------------------------------------------------
  2 | 
  3 | // Map Reverse
  4 | //
  5 | // Reverse the order of a sass map.
  6 | //
  7 | // values: Sass Map
  8 | 
  9 | @function _map-reverse($map) {
 10 |   $result: null;
 11 | 
 12 |   @if type-of($map) == "map" {
 13 |     $keys: map-keys($map);
 14 |     $map-reversed: ();
 15 | 
 16 |     @for $i from length($keys) through 1 {
 17 |       $map-reversed: map-merge(
 18 |           $map-reversed,
 19 |           (nth($keys, $i): _get($map, nth($keys, $i)))
 20 |       );
 21 |     }
 22 | 
 23 |     @if type-of($map-reversed) == "map" {
 24 |       $result: $map-reversed;
 25 |     } @else {
 26 |       @warn 'There was an error reversing the order of "#{$map}"';
 27 |     }
 28 |   } @else {
 29 |     @warn '"#{$map}" is not a valid map';
 30 |   }
 31 | 
 32 |   @return $result;
 33 | }
 34 | 
 35 | //----------------------------------------------------------------------
 36 | 
 37 | // Background
 38 | //
 39 | // Adds a background
 40 | //
 41 | // Values: file, width, height, position
 42 | // Default: row
 43 | //
 44 | // @include bg('image.jpg' 1440px 900px center);
 45 | 
 46 | @mixin bg($values) {
 47 |   $file: nth($values, 1);
 48 |   $width: nth($values, 2);
 49 |   $height: nth($values, 3);
 50 |   $position: nth($values, 4);
 51 | 
 52 |   background-image: url($file);
 53 |   background-repeat: no-repeat;
 54 |   background-position: $position;
 55 |   background-size: $width $height;
 56 | }
 57 | 
 58 | //----------------------------------------------------------------------
 59 | 
 60 | // Retina Background
 61 | //
 62 | // Adds a retina background
 63 | //
 64 | // Values: file, width, type height, position
 65 | // Default: row
 66 | //
 67 | // @include bg2x('image' 'jpg' 1440px 900px center);
 68 | 
 69 | @mixin bg2x($values) {
 70 |   $file: nth($values, 1);
 71 |   $extension: nth($values, 2);
 72 |   $width: nth($values, 3);
 73 |   $height: nth($values, 4);
 74 |   $position: nth($values, 5);
 75 | 
 76 |   background-image: url($file + '.' + $extension);
 77 |   background-repeat: no-repeat;
 78 |   background-position: $position;
 79 |   @media (min-resolution: 2dppx) {
 80 |     & {
 81 |       background-image: url($file + '@2x.' + $extension);
 82 |       background-size: $width $height;
 83 |     }
 84 |   }
 85 | }
 86 | 
 87 | //----------------------------------------------------------------------
 88 | 
 89 | // Flexbox Containers
 90 | //
 91 | // The 'flex' value causes an element to generate a block-level flex
 92 | // container box.
 93 | //
 94 | // The 'inline-flex' value causes an element to generate a inline-level
 95 | // flex container box.
 96 | //
 97 | // display: flex | inline-flex
 98 | //
 99 | // http://w3.org/tr/css3-flexbox/#flex-containers
100 | //
101 | // (Placeholder selectors for each type, for those who rather @extend)
102 | 
103 | @mixin flexbox {
104 | 	display: -webkit-box;
105 | 	display: -webkit-flex;
106 | 	display: -moz-flex;
107 | 	display: -ms-flexbox;
108 | 	display: flex;
109 | }
110 | 
111 | %flexbox { @include flexbox; }
112 | 
113 | //----------------------------------
114 | 
115 | @mixin inline-flex {
116 | 	display: -webkit-inline-box;
117 | 	display: -webkit-inline-flex;
118 | 	display: -moz-inline-flex;
119 | 	display: -ms-inline-flexbox;
120 | 	display: inline-flex;
121 | }
122 | 
123 | %inline-flex { @include inline-flex; }
124 | 
125 | //----------------------------------------------------------------------
126 | 
127 | // Flexbox Direction
128 | //
129 | // The 'flex-direction' property specifies how flex items are placed in
130 | // the flex container, by setting the direction of the flex container's
131 | // main axis. This determines the direction that flex items are laid out in.
132 | //
133 | // Values: row | row-reverse | column | column-reverse
134 | // Default: row
135 | //
136 | // http://w3.org/tr/css3-flexbox/#flex-direction-property
137 | 
138 | @mixin flex-direction($value: row) {
139 | 	@if $value == row-reverse {
140 | 		-webkit-box-direction: reverse;
141 | 		-webkit-box-orient: horizontal;
142 | 	} @else if $value == column {
143 | 		-webkit-box-direction: normal;
144 | 		-webkit-box-orient: vertical;
145 | 	} @else if $value == column-reverse {
146 | 		-webkit-box-direction: reverse;
147 | 		-webkit-box-orient: vertical;
148 | 	} @else {
149 | 		-webkit-box-direction: normal;
150 | 		-webkit-box-orient: horizontal;
151 | 	}
152 | 	-webkit-flex-direction: $value;
153 | 	-moz-flex-direction: $value;
154 | 	-ms-flex-direction: $value;
155 | 	flex-direction: $value;
156 | }
157 | 	// Shorter version:
158 | 	@mixin flex-dir($args...) { @include flex-direction($args...); }
159 | 
160 | //----------------------------------------------------------------------
161 | 
162 | // Flexbox Wrap
163 | //
164 | // The 'flex-wrap' property controls whether the flex container is single-line
165 | // or multi-line, and the direction of the cross-axis, which determines
166 | // the direction new lines are stacked in.
167 | //
168 | // Values: nowrap | wrap | wrap-reverse
169 | // Default: nowrap
170 | //
171 | // http://w3.org/tr/css3-flexbox/#flex-wrap-property
172 | 
173 | @mixin flex-wrap($value: nowrap) {
174 | 	// No Webkit Box fallback.
175 | 	-webkit-flex-wrap: $value;
176 | 	-moz-flex-wrap: $value;
177 | 	@if $value == nowrap {
178 | 		-ms-flex-wrap: none;
179 | 	} @else {
180 | 		-ms-flex-wrap: $value;
181 | 	}
182 | 	flex-wrap: $value;
183 | }
184 | 
185 | //----------------------------------------------------------------------
186 | 
187 | // Flexbox Flow (shorthand)
188 | //
189 | // The 'flex-flow' property is a shorthand for setting the 'flex-direction'
190 | // and 'flex-wrap' properties, which together define the flex container's
191 | // main and cross axes.
192 | //
193 | // Values:  | 
194 | // Default: row nowrap
195 | //
196 | // http://w3.org/tr/css3-flexbox/#flex-flow-property
197 | 
198 | @mixin flex-flow($values: (row nowrap)) {
199 | 	// No Webkit Box fallback.
200 | 	-webkit-flex-flow: $values;
201 | 	-moz-flex-flow: $values;
202 | 	-ms-flex-flow: $values;
203 | 	flex-flow: $values;
204 | }
205 | 
206 | //----------------------------------------------------------------------
207 | 
208 | // Flexbox Order
209 | //
210 | // The 'order' property controls the order in which flex items appear within
211 | // their flex container, by assigning them to ordinal groups.
212 | //
213 | // Default: 0
214 | //
215 | // http://w3.org/tr/css3-flexbox/#order-property
216 | 
217 | @mixin order($int: 0) {
218 | 	-webkit-box-ordinal-group: $int + 1;
219 | 	-webkit-order: $int;
220 | 	-moz-order: $int;
221 | 	-ms-flex-order: $int;
222 | 	order: $int;
223 | }
224 | 
225 | //----------------------------------------------------------------------
226 | 
227 | // Flexbox Grow
228 | //
229 | // The 'flex-grow' property sets the flex grow factor. Negative numbers
230 | // are invalid.
231 | //
232 | // Default: 0
233 | //
234 | // http://w3.org/tr/css3-flexbox/#flex-grow-property
235 | 
236 | @mixin flex-grow($int: 0) {
237 | 	-webkit-box-flex: $int;
238 | 	-webkit-flex-grow: $int;
239 | 	-moz-flex-grow: $int;
240 | 	-ms-flex-positive: $int;
241 | 	flex-grow: $int;
242 | }
243 | 
244 | //----------------------------------------------------------------------
245 | 
246 | // Flexbox Shrink
247 | //
248 | // The 'flex-shrink' property sets the flex shrink factor. Negative numbers
249 | // are invalid.
250 | //
251 | // Default: 1
252 | //
253 | // http://w3.org/tr/css3-flexbox/#flex-shrink-property
254 | 
255 | @mixin flex-shrink($int: 1) {
256 | 	-webkit-flex-shrink: $int;
257 | 	-moz-flex-shrink: $int;
258 | 	-ms-flex-negative: $int;
259 | 	flex-shrink: $int;
260 | }
261 | 
262 | //----------------------------------------------------------------------
263 | 
264 | // Flexbox Basis
265 | //
266 | // The 'flex-basis' property sets the flex basis. Negative lengths are invalid.
267 | //
268 | // Values: Like "width"
269 | // Default: auto
270 | //
271 | // http://www.w3.org/TR/css3-flexbox/#flex-basis-property
272 | 
273 | @mixin flex-basis($value: auto) {
274 | 	-webkit-flex-basis: $value;
275 | 	-moz-flex-basis: $value;
276 | 	-ms-flex-preferred-size: $value;
277 | 	flex-basis: $value;
278 | }
279 | 
280 | //----------------------------------------------------------------------
281 | 
282 | // Flexbox "Flex" (shorthand)
283 | //
284 | // The 'flex' property specifies the components of a flexible length: the
285 | // flex grow factor and flex shrink factor, and the flex basis. When an
286 | // element is a flex item, 'flex' is consulted instead of the main size
287 | // property to determine the main size of the element. If an element is
288 | // not a flex item, 'flex' has no effect.
289 | //
290 | // Values: none |   || 
291 | // Default: See individual properties (1 1 0).
292 | //
293 | // http://w3.org/tr/css3-flexbox/#flex-property
294 | 
295 | @mixin flex($fg: 1, $fs: null, $fb: null) {
296 | 
297 | 	// Set a variable to be used by box-flex properties
298 | 	$fg-boxflex: $fg;
299 | 
300 | 	// Box-Flex only supports a flex-grow value so let's grab the
301 | 	// first item in the list and just return that.
302 | 	@if type-of($fg) == 'list' {
303 | 		$fg-boxflex: nth($fg, 1);
304 | 	}
305 | 
306 | 	-webkit-box-flex: $fg-boxflex;
307 | 	-webkit-flex: $fg $fs $fb;
308 | 	-moz-box-flex: $fg-boxflex;
309 | 	-moz-flex: $fg $fs $fb;
310 | 	-ms-flex: $fg $fs $fb;
311 | 	flex: $fg $fs $fb;
312 | }
313 | 
314 | //----------------------------------------------------------------------
315 | 
316 | // Flexbox Justify Content
317 | //
318 | // The 'justify-content' property aligns flex items along the main axis
319 | // of the current line of the flex container. This is done after any flexible
320 | // lengths and any auto margins have been resolved. Typically it helps distribute
321 | // extra free space leftover when either all the flex items on a line are
322 | // inflexible, or are flexible but have reached their maximum size. It also
323 | // exerts some control over the alignment of items when they overflow the line.
324 | //
325 | // Note: 'space-*' values not supported in older syntaxes.
326 | //
327 | // Values: flex-start | flex-end | center | space-between | space-around
328 | // Default: flex-start
329 | //
330 | // http://w3.org/tr/css3-flexbox/#justify-content-property
331 | 
332 | @mixin justify-content($value: flex-start) {
333 | 	@if $value == flex-start {
334 | 		-webkit-box-pack: start;
335 | 		-ms-flex-pack: start;
336 | 	} @else if $value == flex-end {
337 | 		-webkit-box-pack: end;
338 | 		-ms-flex-pack: end;
339 | 	} @else if $value == space-between {
340 | 		-webkit-box-pack: justify;
341 | 		-ms-flex-pack: justify;
342 | 	} @else if $value == space-around {
343 | 		-ms-flex-pack: distribute;
344 | 	} @else {
345 | 		-webkit-box-pack: $value;
346 | 		-ms-flex-pack: $value;
347 | 	}
348 | 	-webkit-justify-content: $value;
349 | 	-moz-justify-content: $value;
350 | 	justify-content: $value;
351 | }
352 | 	// Shorter version:
353 | 	@mixin flex-just($args...) { @include justify-content($args...); }
354 | 
355 | //----------------------------------------------------------------------
356 | 
357 | // Flexbox Align Items
358 | //
359 | // Flex items can be aligned in the cross axis of the current line of the
360 | // flex container, similar to 'justify-content' but in the perpendicular
361 | // direction. 'align-items' sets the default alignment for all of the flex
362 | // container's items, including anonymous flex items. 'align-self' allows
363 | // this default alignment to be overridden for individual flex items. (For
364 | // anonymous flex items, 'align-self' always matches the value of 'align-items'
365 | // on their associated flex container.)
366 | //
367 | // Values: flex-start | flex-end | center | baseline | stretch
368 | // Default: stretch
369 | //
370 | // http://w3.org/tr/css3-flexbox/#align-items-property
371 | 
372 | @mixin align-items($value: stretch) {
373 | 	@if $value == flex-start {
374 | 		-webkit-box-align: start;
375 | 		-ms-flex-align: start;
376 | 	} @else if $value == flex-end {
377 | 		-webkit-box-align: end;
378 | 		-ms-flex-align: end;
379 | 	} @else {
380 | 		-webkit-box-align: $value;
381 | 		-ms-flex-align: $value;
382 | 	}
383 | 	-webkit-align-items: $value;
384 | 	-moz-align-items: $value;
385 | 	align-items: $value;
386 | }
387 | 
388 | //----------------------------------
389 | 
390 | // Flexbox Align Self
391 | //
392 | // Values: auto | flex-start | flex-end | center | baseline | stretch
393 | // Default: auto
394 | 
395 | @mixin align-self($value: auto) {
396 | 	// No Webkit Box Fallback.
397 | 	-webkit-align-self: $value;
398 | 	-moz-align-self: $value;
399 | 	@if $value == flex-start {
400 | 		-ms-flex-item-align: start;
401 | 	} @else if $value == flex-end {
402 | 		-ms-flex-item-align: end;
403 | 	} @else {
404 | 		-ms-flex-item-align: $value;
405 | 	}
406 | 	align-self: $value;
407 | }
408 | 
409 | //----------------------------------------------------------------------
410 | 
411 | // Flexbox Align Content
412 | //
413 | // The 'align-content' property aligns a flex container's lines within the
414 | // flex container when there is extra space in the cross-axis, similar to
415 | // how 'justify-content' aligns individual items within the main-axis. Note,
416 | // this property has no effect when the flexbox has only a single line.
417 | //
418 | // Values: flex-start | flex-end | center | space-between | space-around | stretch
419 | // Default: stretch
420 | //
421 | // http://w3.org/tr/css3-flexbox/#align-content-property
422 | 
423 | @mixin align-content($value: stretch) {
424 | 	// No Webkit Box Fallback.
425 | 	-webkit-align-content: $value;
426 | 	-moz-align-content: $value;
427 | 	@if $value == flex-start {
428 | 		-ms-flex-line-pack: start;
429 | 	} @else if $value == flex-end {
430 | 		-ms-flex-line-pack: end;
431 | 	} @else {
432 | 		-ms-flex-line-pack: $value;
433 | 	}
434 | 	align-content: $value;
435 | }
436 | 
437 | //----------------------------------------------------------------------
438 | 
439 | // Breakpoint Mixins
440 | 
441 | @function breakpoint-next($name, $breakpoints: _get($--grid, 'breakpoints'), $breakpoint-names: map-keys($breakpoints)) {
442 |   $n: index($breakpoint-names, $name);
443 |   @return if($n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null);
444 | }
445 | 
446 | // Minimum breakpoint width. Null for the smallest (first) breakpoint.
447 | //
448 | //    >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px))
449 | //    576px
450 | @function breakpoint-min($name, $breakpoints: _get($--grid, 'breakpoints')) {
451 |   $breakpoint: _get($breakpoints, $name);
452 |   $min: nth($breakpoint, 1);
453 |   @return if($min != 0, $min, null);
454 | }
455 | 
456 | // Maximum breakpoint width. Null for the largest (last) breakpoint.
457 | // The maximum value is calculated as the minimum of the next one less 0.1.
458 | //
459 | //    >> breakpoint-max(sm, (xs: 0, sm: 576px, md: 768px))
460 | //    767px
461 | @function breakpoint-max($name, $breakpoints: _get($--grid, 'breakpoints')) {
462 |   $next: breakpoint-next($name, $breakpoints);
463 |   @return if($next, breakpoint-min($next, $breakpoints) - 1px, null);
464 | }
465 | 
466 | // Media of at least the minimum breakpoint width. No query for the smallest breakpoint.
467 | // Makes the @content apply to the given breakpoint and wider.
468 | @mixin media-breakpoint-up($name, $breakpoints: _get($--grid, 'breakpoints')) {
469 |   $min: breakpoint-min($name, $breakpoints);
470 |   @if $min {
471 |     @media (min-width: $min) {
472 |       @content;
473 |     }
474 |   } @else {
475 |     @content;
476 |   }
477 | }
478 | 
479 | // Media of at most the maximum breakpoint width. No query for the largest breakpoint.
480 | // Makes the @content apply to the given breakpoint and narrower.
481 | @mixin media-breakpoint-down($name, $breakpoints: _get($--grid, 'breakpoints')) {
482 |   $max: breakpoint-max($name, $breakpoints);
483 |   @if $max {
484 |     @media (max-width: $max) {
485 |       @content;
486 |     }
487 |   } @else {
488 |     @content;
489 |   }
490 | }
491 | 
492 | // Media that spans multiple breakpoint widths.
493 | // Makes the @content apply between the min and max breakpoints
494 | @mixin media-breakpoint-between($lower, $upper, $breakpoints: _get($--grid, 'breakpoints')) {
495 |   @include media-breakpoint-up($lower, $breakpoints) {
496 |     @include media-breakpoint-down($upper, $breakpoints) {
497 |       @content;
498 |     }
499 |   }
500 | }
501 | 
502 | // Media between the breakpoint's minimum and maximum widths.
503 | // No minimum for the smallest breakpoint, and no maximum for the largest one.
504 | // Makes the @content apply only to the given breakpoint, not viewports any wider or narrower.
505 | @mixin media-breakpoint-only($name, $breakpoints: _get($--grid, 'breakpoints')) {
506 |   @include media-breakpoint-between($name, $name, $breakpoints) {
507 |     @content;
508 |   }
509 | }
510 | 
511 | //----------------------------------------------------------------------
512 | 
513 | // Button style mixin
514 | // Generate coloured buttons with modular hover color states.
515 | 
516 | @mixin btn-style($name, $normal, $hover) {
517 |   .btn, .btn-round {
518 |     &.btn--#{$name} {
519 |       color: nth($normal, 1) !important;
520 |       background-color: nth($normal, 2);
521 |       &:hover {
522 |         color: nth($hover, 1) !important;
523 |         background-color: nth($hover, 2);
524 |       }
525 |     }
526 | 
527 |     &.btn--hover-#{$name}:hover {
528 |       color: nth($normal, 1) !important;
529 |       background-color: nth($normal, 2) !important;
530 |     }
531 |   }
532 | 
533 | }
534 | 
535 | //----------------------------------------------------------------------
536 | 
537 | // Responsive Font Scale
538 | // Set a responsive font scale which weights down across breakpoints.
539 | 
540 | @mixin responsive-font-scale($fontsize: 1rem, $ratio: 1, $breakpoints: _get($--grid, 'breakpoints')) {
541 | 
542 |   $breakpoints: _map-reverse($breakpoints);
543 | 
544 |   @each $breakpoint in $breakpoints {
545 |     $name: nth($breakpoint, 1);
546 |     $i: index(map-keys($breakpoints), $name);
547 | 
548 |     // Ensure we're not setting a responsive scale on the largest breakpoint
549 |     @if $i != 1 {
550 | 
551 |       // Get the total number of breakpoints
552 |       $n: length($breakpoints);
553 | 
554 |       // Get decimal representation of breakpoint increment
555 |       $b: $i / $n;
556 | 
557 |       // Get full intended decrement across all breakpoints
558 |       $d: 1 - $ratio;
559 | 
560 |       // Get decrement for just this breakpoint
561 |       $bd: $d * $b;
562 | 
563 |       // Represent the proper value
564 |       $br: 1 - $bd;
565 | 
566 |       // Get the responsive fontsize
567 |       $rf: $fontsize * $br;
568 | 
569 |       @include media-breakpoint-down($name) {
570 |         font-size: $rf;
571 |       }
572 |     }
573 |   }
574 | 
575 | }
576 | 
577 | //----------------------------------------------------------------------
578 | 
579 | // Font mixins
580 | // Get and set fonts using the
581 | 
582 | @function font($name, $fonts: $--font-faces) {
583 |   $font: _get($fonts, $name);
584 |   @if $font == null {
585 |     @error "Font isn't defined.";
586 |   } @else {
587 |     $family: _get($font, 'family');
588 |     $type: _get($font, 'type');
589 |     @return '#{$family}', #{$type};
590 |   }
591 | }
592 | 
593 | // Set Font
594 | @mixin set-font($font, $font-styles: $--font-styles) {
595 | 
596 |   $setup: _get($font-styles, $font);
597 | 
598 |   $family: _get($setup, 'family');
599 |   @if $family != null { font-family: $family; }
600 | 
601 |   $style: _get($setup, 'style');
602 |   @if $style != null { font-style: $style; }
603 | 
604 |   $weight: _get($setup, 'weight');
605 |   @if $weight != null { font-weight: $weight; }
606 | 
607 |   $spacing: _get($setup, 'letter-spacing');
608 |   @if $spacing != null { letter-spacing: $spacing; }
609 | 
610 |   $text-transform: _get($setup, 'text-transform');
611 |   @if $text-transform != null { text-transform: $text-transform; }
612 | 
613 | }
614 | 


--------------------------------------------------------------------------------
/tests/dummy/app/styles/framework/_reset.scss:
--------------------------------------------------------------------------------
 1 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
 2 |     margin: 0;
 3 |     padding: 0;
 4 |     border: 0;
 5 |     font: inherit;
 6 |     vertical-align: baseline;
 7 |   }
 8 | 
 9 |   // HTML5 display-role reset for older browsers
10 |   article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {
11 |     display: block;
12 |   }
13 |   body {
14 |     line-height: 1;
15 |   }
16 |   ol, ul {
17 |     list-style: none;
18 |   }
19 |   blockquote, q {
20 |     quotes: none;
21 |   }
22 |   blockquote {
23 |     &:before, &:after {
24 |       content: "";
25 |       content: none;
26 |     }
27 |   }
28 |   q {
29 |     &:before, &:after {
30 |       content: "";
31 |       content: none;
32 |     }
33 |   }
34 |   table {
35 |     border-collapse: collapse;
36 |     border-spacing: 0;
37 |   }
38 | 


--------------------------------------------------------------------------------
/tests/dummy/app/styles/framework/_type.scss:
--------------------------------------------------------------------------------
 1 | //----------------------------------------------------------------------
 2 | 
 3 | // Type
 4 | //
 5 | 
 6 | $html: _get($--type, 'html');
 7 | $headers: _get($--type, 'headers');
 8 | $breakpoints: map-reverse(_get($--grid, 'breakpoints'));
 9 | $paragraph: _get($--type, 'p');
10 | $small: _get($--type, 'small');
11 | 
12 | 
13 | html{
14 |   font-size: nth($html, 1);
15 |   line-height: nth($html, 2);
16 | 
17 |   @include responsive-font-scale(nth($html, 1), nth($html, 3));
18 | }
19 | 
20 | @each $size, $value in $headers {
21 | 
22 |   $fontsize: nth($value, 1);
23 |   $ratio: nth($value, 3);
24 | 
25 |   #{$size} {
26 |     font-size: $fontsize;
27 |     line-height: nth($value, 2);
28 |     margin: $fontsize;
29 | 
30 |     @include responsive-font-scale($fontsize, $ratio);
31 | 
32 |   }
33 | 
34 | }
35 | 
36 | small { font-size: $small; }
37 | 
38 | p {
39 |   font-size: nth($paragraph, 1);
40 |   line-height: nth($paragraph, 2);
41 |   padding-bottom: nth($paragraph, 3);
42 | }
43 | 
44 | article {
45 |   // padding: 0 _get($--grid, 'margin') _get($--grid, 'margin') _get($--grid, 'margin');
46 |   p {
47 |     font-size: 1.1em;
48 |   }
49 | }
50 | 


--------------------------------------------------------------------------------
/tests/dummy/app/styles/framework/_utility.scss:
--------------------------------------------------------------------------------
  1 | //----------------------------------------------------------------------
  2 | 
  3 | // Alignment classes
  4 | //
  5 | // Align element content using classes.
  6 | 
  7 | .align-left { text-align: left; }
  8 | .align-right { text-align: right; }
  9 | .align-center { text-align: center; }
 10 | .float-left { float: left !important; }
 11 | .float-right { float: right !important; }
 12 | 
 13 | //----------------------------------------------------------------------
 14 | 
 15 | // Depth classes
 16 | //
 17 | // Add depth to elements using classes.
 18 | 
 19 | $depth-color: _get($--colors, 'gray');
 20 | 
 21 | $--depths: (
 22 |   xs: #{0 1px 2px 0 rgba($depth-color, 0.1),
 23 |         0 2px 6px 0 rgba($depth-color, 0.1)},
 24 |   sm: #{0 1px 3px 0 rgba($depth-color, 0.2),
 25 |         0 2px 8px 0 rgba($depth-color, 0.1)},
 26 |   md: #{0 1px 4px 0 rgba($depth-color, 0.3),
 27 |         0 3px 12px 0 rgba($depth-color, 0.1)},
 28 |   lg: #{0 8px 17px 0 rgba($depth-color, 0.2),
 29 |         0 6px 20px 0 rgba($depth-color, 0.19)},
 30 |   xl: #{0 12px 15px 0 rgba($depth-color, 0.24),
 31 |         0 17px 50px 0 rgba($depth-color, 0.19)}
 32 | );
 33 | 
 34 | @each $name, $depth in $--depths {
 35 |   &.depth-#{$name} {
 36 |     box-shadow: $depth;
 37 |   }
 38 |   &.hover-depth-#{$name}:hover {
 39 |     box-shadow: $depth;
 40 |   }
 41 | }
 42 | 
 43 | .depth-none {
 44 |   box-shadow: none !important;
 45 | }
 46 | 
 47 | .depth-xs {
 48 |   box-shadow: 0 1px 2px 0 rgba($depth-color, 0.1), 0 2px 6px 0 rgba($depth-color, 0.1);
 49 | }
 50 | 
 51 | .depth-sm {
 52 |   box-shadow: 0 1px 3px 0 rgba($depth-color, 0.2), 0 2px 8px 0 rgba($depth-color, 0.1);
 53 | }
 54 | 
 55 | .depth-md {
 56 |   box-shadow: 0 1px 4px 0 rgba($depth-color, 0.3), 0 3px 12px 0 rgba($depth-color, 0.1);
 57 | }
 58 | 
 59 | .depth-lg {
 60 |   box-shadow: 0 8px 17px 0 rgba($depth-color, 0.2), 0 6px 20px 0 rgba($depth-color, 0.19);
 61 | }
 62 | 
 63 | .depth-xl {
 64 |   box-shadow: 0 12px 15px 0 rgba($depth-color, 0.24), 0 17px 50px 0 rgba($depth-color, 0.19);
 65 | }
 66 | 
 67 | //----------------------------------------------------------------------
 68 | 
 69 | // Responsive media
 70 | //
 71 | // Responsive images and embedded video
 72 | 
 73 | img.responsive-img,
 74 | video.responsive-video {
 75 |   max-width: 100%;
 76 |   height: auto;
 77 |   &.fullwidth {
 78 |     min-width: 100%;
 79 |   }
 80 | }
 81 | 
 82 | .container-video {
 83 |   position: relative;
 84 |   padding-bottom: 56.25%;
 85 |   height: 0;
 86 |   overflow: hidden;
 87 | 
 88 |   iframe, object, embed {
 89 |     position: absolute;
 90 |     top: 0;
 91 |     left: 0;
 92 |     width: 100%;
 93 |     height: 100%;
 94 |   }
 95 | }
 96 | 
 97 | 
 98 | //----------------------------------------------------------------------
 99 | 
100 | // Truncate
101 | //
102 | // Truncate element text in the UI.
103 | 
104 | .truncate {
105 |   display: block;
106 |   white-space: nowrap;
107 |   overflow: hidden;
108 |   text-overflow: ellipsis;
109 | }
110 | 
111 | //----------------------------------------------------------------------
112 | 
113 | // Clearfix
114 | //
115 | // Using flexbox should remove the need for clearfix, but you can use it to ensure elements float correctly.
116 | 
117 | .clearfix {
118 |   clear: both;
119 |   &:before, &:after {
120 |     flex-basis: 0;
121 |     order: 1;
122 |   }
123 | }
124 | 


--------------------------------------------------------------------------------
/tests/dummy/app/styles/main/_.scss:
--------------------------------------------------------------------------------
 1 | //----------------------------------------------------------------------
 2 | 
 3 | // Main
 4 | //
 5 | 
 6 | * {
 7 |   &::selection {
 8 |     color: _get($--main, 'selection-color');
 9 |     background-color: _get($--main, 'selection-background-color');
10 |   }
11 | }
12 | 
13 | html {
14 |   @include set-font('content');
15 | }
16 | 
17 | body {
18 |   overflow-x: hidden;
19 |   overflow-y: auto;
20 |   -webkit-font-smoothing: antialiased;
21 | 
22 |   color: _get($--main, 'body-color');
23 |   background-color: _get($--main, 'body-background-color');
24 | 
25 |   &.no-scroll { overflow: hidden; }
26 | 
27 | }
28 | 
29 | //----------------------------------------------------------------------
30 | 
31 | // Headers
32 | // Add header styles.
33 | 
34 | h1, h2, h3, h4, h5, h6 {
35 |   @include set-font('display');
36 | 
37 |   // Ensure there's a margin on each header
38 |   margin: .5em 0;
39 | 
40 |   // Other styles to attach to all headers
41 |   a { font-weight: inherit; }
42 | }
43 | 
44 | //----------------------------------------------------------------------
45 | 
46 | // Links
47 | // Add link styles.
48 | 
49 | a {
50 |   text-decoration: none;
51 |   &, &:visited, &:active { display: inline-block; color: inherit; }
52 | }
53 | 
54 | //----------------------------------------------------------------------
55 | 
56 | // Type
57 | // Defaults for type styles
58 | 
59 | i { font-style: italic; }
60 | b { font-weight: 700; }
61 | em { font-style: italic; }
62 | strong { font-weight: 500; }
63 | .uppercase { text-transform: uppercase !important; }
64 | 


--------------------------------------------------------------------------------
/tests/dummy/app/styles/main/_config.scss:
--------------------------------------------------------------------------------
  1 | // Main config
  2 | 
  3 | $--grid: (
  4 |   // Set the number of columns you want to use on your layout.
  5 |   columns: 12,
  6 |   // Set the gutter between columns.
  7 |   gutter: 1rem,
  8 |   // Set a margin for the container sides.
  9 |   margin: 2rem,
 10 |   // Define breakpoints.
 11 |   breakpoints: (
 12 |     xs: default, // Less than 576px wide - Portrait phones
 13 |     sm: 576px 540px, // Between 576 and 767 - Landscape Phones
 14 |     md: 768px 720px, // Between 768 and 991 - Tablets
 15 |     lg: 992px 960px, // Between 992 and 1199 - Desktops
 16 |     xl: 1280px 1024px // 1200 upwards - Extra large devices
 17 |   ),
 18 |   // Max width of container
 19 |   max-width: 1024px
 20 | );
 21 | 
 22 | $--font-faces: (
 23 |   'overpass': (
 24 |     family: 'Overpass',
 25 |     type: sans-serif
 26 |   )
 27 | );
 28 | 
 29 | $--font-styles: (
 30 |   'display': (
 31 |     family: font('overpass'),
 32 |     style: normal,
 33 |     weight: 300,
 34 |     letter-spacing: -.02em
 35 |   ),
 36 |   'header': (
 37 |     family: font('overpass'),
 38 |     style: normal,
 39 |     weight: 800,
 40 |     letter-spacing: -0.01em
 41 |   ),
 42 |   'content': (
 43 |     family: font('overpass'),
 44 |     transform: inherit,
 45 |     weight: 400,
 46 |     letter-spacing: 0em
 47 |   )
 48 | );
 49 | 
 50 | $--type: (
 51 |   // HTML Base Font
 52 |   // @params font-size, line-height, responsive-ratio
 53 |   html: (15px, 150%, 1.1),
 54 | 
 55 |   // Headers
 56 |   // @params font-size, line-height, responsive-ratio
 57 |   headers: (
 58 |     h1: (3.33rem, 110%, 0.6),
 59 |     h2: (2rem, 120%, 0.8),
 60 |     h3: (1.66rem, 130%, 0.85),
 61 |     h4: (1.33rem, 140%, 0.9),
 62 |     h5: (1.2rem, 160%, 0.95),
 63 |     h6: (1rem, 180%, 1)
 64 |   ),
 65 | 
 66 |   // Paragraph
 67 |   // @params font-size, line-height, padding-bottom
 68 |   p: (1rem, 200%, 1em),
 69 | 
 70 |   // Small
 71 |   // @params font-size
 72 |   small: 0.9em
 73 | );
 74 | 
 75 | $--colors: (
 76 |   // Monochrome
 77 |   'white': white,
 78 |   'black': black,
 79 | 
 80 |   // Mid tones
 81 |   'gray': #2f3640,
 82 |   'lt-gray': darken(white, 5%),
 83 |   'mid-gray': darken(white, 33%),
 84 | 
 85 |   // Success, Error & Warning
 86 |   'green': #2ecc71,
 87 |   'red': #EF2038,
 88 |   'yellow': #FFDF2E
 89 | );
 90 | 
 91 | $--main: (
 92 |   body-color: _get($--colors, 'black'),
 93 |   body-background-color: _get($--colors, 'white'),
 94 |   selection-background-color: _get($--colors, 'black'),
 95 |   selection-color: _get($--colors, 'white')
 96 | );
 97 | 
 98 | $--easing: (
 99 |   'cubic': (
100 |     in: cubic-bezier(0.550, 0.055, 0.675, 0.190),
101 |     out: cubic-bezier(0.215, 0.610, 0.355, 1.000),
102 |     in-out: cubic-bezier(0.645, 0.045, 0.355, 1.000)
103 |   ),
104 |   'expo': (
105 |     in: cubic-bezier(0.950, 0.050, 0.795, 0.035),
106 |     out: cubic-bezier(0.190, 1.000, 0.220, 1.000),
107 |     in-out: cubic-bezier(1.000, 0.000, 0.000, 1.000)
108 |   ),
109 |   'back': (
110 |     in: cubic-bezier(0.600, -0.280, 0.735, 0.045),
111 |     out: cubic-bezier(0.175, 0.885, 0.320, 1.275),
112 |     in-out: cubic-bezier(0.680, -0.550, 0.265, 1.550)
113 |   ),
114 |   'jump': (
115 |     out: cubic-bezier(.25,1.4,.55,.99),
116 |     in-out: cubic-bezier(.87,-.41,.19,1.44),
117 |   ),
118 |   'leap': (
119 |     out: cubic-bezier(.25,1.9,.55,.99),
120 |     in-out: cubic-bezier(.78,-0.81,.27,1.7)
121 |   )
122 | 
123 | );
124 | 


--------------------------------------------------------------------------------
/tests/dummy/app/styles/routes/_.scss:
--------------------------------------------------------------------------------
 1 | [data-section="index"] {
 2 |   img {
 3 |     width: 66%;
 4 |     max-width: 480px;
 5 |     min-width: 320px;
 6 |   }
 7 | }
 8 | 
 9 | .valign-section {
10 |   display: flex;
11 |   height: 100vh;
12 |   padding: 0 0 0 0 !important;
13 |   & > div {
14 |     margin: auto;
15 |   }
16 | }
17 | 


--------------------------------------------------------------------------------
/tests/dummy/app/templates/application.hbs:
--------------------------------------------------------------------------------
1 | {{outlet}}
2 | 


--------------------------------------------------------------------------------
/tests/dummy/app/templates/components/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/willviles/ember-cli-markdown-resolver/46e56e04d3bf9508f56e7844030f865f7e0fd788/tests/dummy/app/templates/components/.gitkeep


--------------------------------------------------------------------------------
/tests/dummy/app/templates/components/ui-button.hbs:
--------------------------------------------------------------------------------
1 | {{#if linkTitle}}{{linkTitle}}{{else}}{{yield}}{{/if}}
2 | 


--------------------------------------------------------------------------------
/tests/dummy/app/templates/components/ui-footer.hbs:
--------------------------------------------------------------------------------
 1 | 
2 |
3 |
4 |
5 | 6 |
7 | 17 |
18 | 19 |
20 | 21 | 2017 - Ember CLI Markdown Resolver.
22 | Made for the awesome Ember.js community by Will Viles. 23 |
24 |
25 | 26 |
27 |
28 |
29 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/components/ui-navbar.hbs: -------------------------------------------------------------------------------- 1 |
2 | 29 |
30 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/error.hbs: -------------------------------------------------------------------------------- 1 |

Uh-oh

2 |

3 | 404 4 |

5 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/guides.hbs: -------------------------------------------------------------------------------- 1 | {{ui-navbar fixed=false}} 2 | 3 | {{#ui-section padding="xs"}} 4 |
5 |
6 |
7 |
8 | {{markdown-menu tree=tree linkTo='guides.single'}} 9 |
10 |
11 |
12 |
13 |
14 |
15 | {{outlet}} 16 |
17 |
18 |
19 |
20 |
21 |
22 | {{/ui-section}} 23 | 24 | {{partial 'components/ui-footer'}} -------------------------------------------------------------------------------- /tests/dummy/app/templates/guides/single.hbs: -------------------------------------------------------------------------------- 1 | {{#if guide.content}} 2 |
3 | {{#if guide.attributes.title}} 4 |

{{guide.attributes.title}}

5 |
6 |
7 | {{/if}} 8 | {{markdown-content guide.content extensions="prettify"}} 9 |
10 | {{/if}} 11 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/head.hbs: -------------------------------------------------------------------------------- 1 | {{!-- 2 | Add content you wish automatically added to the documents head 3 | here. The 'model' available in this template can be populated by 4 | setting values on the 'head-data' service. 5 | --}} 6 | 7 | {{model.title}} 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/index.hbs: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | {{#ui-section name="index" align="center" padding="md"}} 5 | 6 |
7 | Ember CLI Markdown Resolver 8 | 9 |


10 | 11 |
12 | The quickest way to include static markdown content in your Ember.js application. 13 |
14 | 15 |

16 | 17 | {{ui-button-link-to 'View the Guides' 'guides' 18 | bg="black" 19 | bgHover="red" 20 | color="white" 21 | inline=true 22 | padding="md" 23 | depth="md" }} 24 |   25 | {{ui-button-link 'GitHub' 26 | href="https://github.com/willviles/ember-cli-markdown-resolver" 27 | target="_blank" 28 | bg="black" 29 | bgHover="red" 30 | color="white" 31 | inline=true 32 | padding="md" 33 | depth="md" }} 34 |
35 | 36 | {{/ui-section}} 37 | 38 |
39 |
40 | -------------------------------------------------------------------------------- /tests/dummy/app/utils/property-class-name-binding.js: -------------------------------------------------------------------------------- 1 | import { assign } from '@ember/polyfills'; 2 | import { computed, get } from '@ember/object'; 3 | import { dasherize } from '@ember/string'; 4 | import { typeOf } from '@ember/utils'; 5 | 6 | export default function(property, opts) { 7 | return computed(property, function() { 8 | let value = get(this, property); 9 | 10 | opts = assign({ 11 | prefix: dasherize(property), 12 | values: false 13 | }, opts); 14 | 15 | if (typeOf(value) === 'string') { 16 | return `${opts.prefix}-${value}`; 17 | } else if (typeOf(value) === 'boolean') { 18 | return value; 19 | } else if (typeOf(value) === 'object') { 20 | if (typeOf(opts.values) === 'array') { 21 | return opts.values.reduce((arr, key) => { 22 | return value[key] ? 23 | [...arr, `${opts.prefix}-${key}-${value[key]}`] : 24 | [...arr]; 25 | }, []).join(' '); 26 | } else { 27 | return; 28 | } 29 | 30 | } 31 | }); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /tests/dummy/config/environment.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 'use strict'; 3 | 4 | module.exports = function(environment) { 5 | let ENV = { 6 | modulePrefix: 'dummy', 7 | environment, 8 | rootURL: '/', 9 | locationType: 'auto', 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 | 27 | // @addon Ember CLI Markdown Resolver 28 | // @url https://github.com/willviles/ember-cli-markdown-resolver 29 | 30 | ENV['ember-cli-markdown-resolver'] = { 31 | folders: { 32 | guides: 'app/guides' 33 | } 34 | }; 35 | 36 | // @addon Ember Code Prettify 37 | // @url https://github.com/willviles/ember-code-prettify 38 | 39 | ENV['ember-code-prettify'] = { 40 | languages: ['css', 'yaml'], 41 | skin: 'desert' 42 | }; 43 | 44 | ENV['googleFonts'] = [ 45 | 'Overpass:300,400,800' 46 | ]; 47 | 48 | if (environment === 'development') { 49 | // ENV.APP.LOG_RESOLVER = true; 50 | // ENV.APP.LOG_ACTIVE_GENERATION = true; 51 | // ENV.APP.LOG_TRANSITIONS = true; 52 | // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; 53 | // ENV.APP.LOG_VIEW_LOOKUPS = true; 54 | } 55 | 56 | if (environment === 'test') { 57 | // Testem prefers this... 58 | ENV.locationType = 'none'; 59 | 60 | // keep test console output quieter 61 | ENV.APP.LOG_ACTIVE_GENERATION = false; 62 | ENV.APP.LOG_VIEW_LOOKUPS = false; 63 | 64 | ENV.APP.rootElement = '#ember-testing'; 65 | } 66 | 67 | if (environment === 'production') { 68 | ENV.locationType = 'hash'; 69 | ENV.rootURL = '/ember-cli-markdown-resolver/'; 70 | 71 | } 72 | 73 | return ENV; 74 | }; 75 | -------------------------------------------------------------------------------- /tests/dummy/config/targets.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | module.exports = { 3 | browsers: [ 4 | 'ie 9', 5 | 'last 1 Chrome versions', 6 | 'last 1 Firefox versions', 7 | 'last 1 Safari versions' 8 | ] 9 | }; 10 | -------------------------------------------------------------------------------- /tests/dummy/public/crossdomain.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 15 | 16 | -------------------------------------------------------------------------------- /tests/dummy/public/images/facebook.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willviles/ember-cli-markdown-resolver/46e56e04d3bf9508f56e7844030f865f7e0fd788/tests/dummy/public/images/facebook.jpg -------------------------------------------------------------------------------- /tests/dummy/public/images/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willviles/ember-cli-markdown-resolver/46e56e04d3bf9508f56e7844030f865f7e0fd788/tests/dummy/public/images/favicon-16x16.png -------------------------------------------------------------------------------- /tests/dummy/public/images/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willviles/ember-cli-markdown-resolver/46e56e04d3bf9508f56e7844030f865f7e0fd788/tests/dummy/public/images/favicon-32x32.png -------------------------------------------------------------------------------- /tests/dummy/public/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willviles/ember-cli-markdown-resolver/46e56e04d3bf9508f56e7844030f865f7e0fd788/tests/dummy/public/images/favicon.ico -------------------------------------------------------------------------------- /tests/dummy/public/images/logo-black.svg: -------------------------------------------------------------------------------- 1 | ember-cli-markdown-resolver_logo -------------------------------------------------------------------------------- /tests/dummy/public/images/logo-white.svg: -------------------------------------------------------------------------------- 1 | ember-cli-markdown-resolver_logo 2 | -------------------------------------------------------------------------------- /tests/dummy/public/robots.txt: -------------------------------------------------------------------------------- 1 | # http://www.robotstxt.org 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /tests/helpers/destroy-app.js: -------------------------------------------------------------------------------- 1 | import { run } from '@ember/runloop'; 2 | 3 | export default function destroyApp(application) { 4 | run(application, 'destroy'); 5 | } 6 | -------------------------------------------------------------------------------- /tests/helpers/module-for-acceptance.js: -------------------------------------------------------------------------------- 1 | import { module } from 'qunit'; 2 | import { resolve } from 'rsvp'; 3 | import startApp from '../helpers/start-app'; 4 | import destroyApp from '../helpers/destroy-app'; 5 | 6 | export default function(name, options = {}) { 7 | module(name, { 8 | beforeEach() { 9 | this.application = startApp(); 10 | 11 | if (options.beforeEach) { 12 | return options.beforeEach.apply(this, arguments); 13 | } 14 | }, 15 | 16 | afterEach() { 17 | let afterEach = options.afterEach && options.afterEach.apply(this, arguments); 18 | return resolve(afterEach).then(() => destroyApp(this.application)); 19 | } 20 | }); 21 | } 22 | -------------------------------------------------------------------------------- /tests/helpers/resolver.js: -------------------------------------------------------------------------------- 1 | import Resolver from '../../resolver'; 2 | import config from '../../config/environment'; 3 | 4 | const resolver = Resolver.create(); 5 | 6 | resolver.namespace = { 7 | modulePrefix: config.modulePrefix, 8 | podModulePrefix: config.podModulePrefix 9 | }; 10 | 11 | export default resolver; 12 | -------------------------------------------------------------------------------- /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 | 6 | export default function startApp(attrs) { 7 | let attributes = merge({}, config.APP); 8 | attributes = merge(attributes, attrs); // use defaults, but you can override; 9 | 10 | return run(() => { 11 | let application = Application.create(attributes); 12 | application.setupForTesting(); 13 | application.injectTestHelpers(); 14 | return application; 15 | }); 16 | } 17 | -------------------------------------------------------------------------------- /tests/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dummy Tests 7 | 8 | 9 | 10 | {{content-for "head"}} 11 | {{content-for "test-head"}} 12 | 13 | 14 | 15 | 16 | 17 | {{content-for "head-footer"}} 18 | {{content-for "test-head-footer"}} 19 | 20 | 21 | {{content-for "body"}} 22 | {{content-for "test-body"}} 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | {{content-for "body-footer"}} 31 | {{content-for "test-body-footer"}} 32 | 33 | 34 | -------------------------------------------------------------------------------- /tests/integration/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willviles/ember-cli-markdown-resolver/46e56e04d3bf9508f56e7844030f865f7e0fd788/tests/integration/.gitkeep -------------------------------------------------------------------------------- /tests/test-helper.js: -------------------------------------------------------------------------------- 1 | import Application from '../app'; 2 | import { setApplication } from '@ember/test-helpers'; 3 | import { start } from 'ember-qunit'; 4 | 5 | setApplication(Application.create({ autoboot: false })); 6 | 7 | start(); 8 | -------------------------------------------------------------------------------- /tests/unit/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willviles/ember-cli-markdown-resolver/46e56e04d3bf9508f56e7844030f865f7e0fd788/tests/unit/.gitkeep -------------------------------------------------------------------------------- /vendor/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willviles/ember-cli-markdown-resolver/46e56e04d3bf9508f56e7844030f865f7e0fd788/vendor/.gitkeep --------------------------------------------------------------------------------