Two ember versions locally, different ports
This commit is contained in:
parent
d54f413f7d
commit
790515b024
63 changed files with 24414 additions and 0 deletions
20
ember-ui-modern/.editorconfig
Normal file
20
ember-ui-modern/.editorconfig
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# EditorConfig helps developers define and maintain consistent
|
||||||
|
# coding styles between different editors and IDEs
|
||||||
|
# editorconfig.org
|
||||||
|
|
||||||
|
root = true
|
||||||
|
|
||||||
|
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.hbs]
|
||||||
|
insert_final_newline = false
|
||||||
|
|
||||||
|
[*.{diff,md}]
|
||||||
|
trim_trailing_whitespace = false
|
15
ember-ui-modern/.ember-cli.js
Normal file
15
ember-ui-modern/.ember-cli.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { setEdition } = require('@ember/edition-utils');
|
||||||
|
|
||||||
|
setEdition('octane');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
Ember CLI sends analytics information by default. The data is completely
|
||||||
|
anonymous, but there are times when you might want to disable this behavior.
|
||||||
|
|
||||||
|
Setting `disableAnalytics` to true will prevent any data from being sent.
|
||||||
|
*/
|
||||||
|
"disableAnalytics": false
|
||||||
|
}
|
20
ember-ui-modern/.eslintignore
Normal file
20
ember-ui-modern/.eslintignore
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# unconventional js
|
||||||
|
/blueprints/*/files/
|
||||||
|
/vendor/
|
||||||
|
|
||||||
|
# compiled output
|
||||||
|
/dist/
|
||||||
|
/tmp/
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/bower_components/
|
||||||
|
/node_modules/
|
||||||
|
|
||||||
|
# misc
|
||||||
|
/coverage/
|
||||||
|
!.*
|
||||||
|
|
||||||
|
# ember-try
|
||||||
|
/.node_modules.ember-try/
|
||||||
|
/bower.json.ember-try
|
||||||
|
/package.json.ember-try
|
58
ember-ui-modern/.eslintrc.js
Normal file
58
ember-ui-modern/.eslintrc.js
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
parser: 'babel-eslint',
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 2018,
|
||||||
|
sourceType: 'module'
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
'ember'
|
||||||
|
],
|
||||||
|
extends: [
|
||||||
|
'eslint:recommended',
|
||||||
|
'plugin:ember/recommended'
|
||||||
|
],
|
||||||
|
env: {
|
||||||
|
browser: true
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
},
|
||||||
|
overrides: [
|
||||||
|
// node files
|
||||||
|
{
|
||||||
|
files: [
|
||||||
|
'.ember-cli.js',
|
||||||
|
'.eslintrc.js',
|
||||||
|
'.template-lintrc.js',
|
||||||
|
'ember-cli-build.js',
|
||||||
|
'testem.js',
|
||||||
|
'blueprints/*/index.js',
|
||||||
|
'config/**/*.js',
|
||||||
|
'lib/*/index.js',
|
||||||
|
'server/**/*.js'
|
||||||
|
],
|
||||||
|
excludedFiles: [
|
||||||
|
'app/**',
|
||||||
|
],
|
||||||
|
parserOptions: {
|
||||||
|
sourceType: 'script',
|
||||||
|
ecmaVersion: 2015
|
||||||
|
},
|
||||||
|
env: {
|
||||||
|
browser: false,
|
||||||
|
node: true
|
||||||
|
},
|
||||||
|
plugins: ['node'],
|
||||||
|
rules: Object.assign({}, require('eslint-plugin-node').configs.recommended.rules, {
|
||||||
|
// add your custom rules and overrides for node files here
|
||||||
|
|
||||||
|
// this can be removed once the following is fixed
|
||||||
|
// https://github.com/mysticatea/eslint-plugin-node/issues/77
|
||||||
|
'node/no-unpublished-require': 'off'
|
||||||
|
}),
|
||||||
|
extends: [
|
||||||
|
'plugin:node/recommended'
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
25
ember-ui-modern/.gitignore
vendored
Normal file
25
ember-ui-modern/.gitignore
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# compiled output
|
||||||
|
/dist/
|
||||||
|
/tmp/
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/bower_components/
|
||||||
|
/node_modules/
|
||||||
|
|
||||||
|
# misc
|
||||||
|
/.env*
|
||||||
|
/.pnp*
|
||||||
|
/.sass-cache
|
||||||
|
/connect.lock
|
||||||
|
/coverage/
|
||||||
|
/libpeerconnection.log
|
||||||
|
/npm-debug.log*
|
||||||
|
/testem.log
|
||||||
|
/yarn-error.log
|
||||||
|
|
||||||
|
# ember-try
|
||||||
|
/.node_modules.ember-try/
|
||||||
|
/bower.json.ember-try
|
||||||
|
/package.json.ember-try
|
8
ember-ui-modern/.template-lintrc.js
Normal file
8
ember-ui-modern/.template-lintrc.js
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
extends: 'recommended',
|
||||||
|
rules: {
|
||||||
|
'no-implicit-this': true,
|
||||||
|
}
|
||||||
|
};
|
27
ember-ui-modern/.travis.yml
Normal file
27
ember-ui-modern/.travis.yml
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
---
|
||||||
|
language: node_js
|
||||||
|
node_js:
|
||||||
|
- "8"
|
||||||
|
|
||||||
|
sudo: false
|
||||||
|
dist: trusty
|
||||||
|
|
||||||
|
addons:
|
||||||
|
chrome: stable
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- $HOME/.npm
|
||||||
|
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
# See https://git.io/vdao3 for details.
|
||||||
|
- JOBS=1
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- npm config set spin false
|
||||||
|
|
||||||
|
script:
|
||||||
|
- npm run lint:hbs
|
||||||
|
- npm run lint:js
|
||||||
|
- npm test
|
3
ember-ui-modern/.watchmanconfig
Normal file
3
ember-ui-modern/.watchmanconfig
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"ignore_dirs": ["tmp", "dist"]
|
||||||
|
}
|
62
ember-ui-modern/README.md
Normal file
62
ember-ui-modern/README.md
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
# Sortable Recipes
|
||||||
|
|
||||||
|
This README outlines the details of collaborating on this Ember application.
|
||||||
|
A short introduction of this app could easily go here.
|
||||||
|
|
||||||
|
This example apps uses:
|
||||||
|
|
||||||
|
* Ember-Sortable
|
||||||
|
* Ember-Concurrency
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
You will need the following things properly installed on your computer.
|
||||||
|
|
||||||
|
* [Git](https://git-scm.com/)
|
||||||
|
* [Node.js](https://nodejs.org/) (with npm)
|
||||||
|
* [Ember CLI](https://ember-cli.com/)
|
||||||
|
* [Google Chrome](https://google.com/chrome/)
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
* `git clone <repository-url>` this repository
|
||||||
|
* `cd sortable-recipes`
|
||||||
|
* `npm install`
|
||||||
|
|
||||||
|
## Running / Development
|
||||||
|
|
||||||
|
* `ember serve`
|
||||||
|
* Visit your app at [http://localhost:4200](http://localhost:4200).
|
||||||
|
* Visit your tests at [http://localhost:4200/tests](http://localhost:4200/tests).
|
||||||
|
|
||||||
|
### Code Generators
|
||||||
|
|
||||||
|
Make use of the many generators for code, try `ember help generate` for more details
|
||||||
|
|
||||||
|
### Running Tests
|
||||||
|
|
||||||
|
* `ember test`
|
||||||
|
* `ember test --server`
|
||||||
|
|
||||||
|
### Linting
|
||||||
|
|
||||||
|
* `npm run lint:hbs`
|
||||||
|
* `npm run lint:js`
|
||||||
|
* `npm run lint:js -- --fix`
|
||||||
|
|
||||||
|
### Building
|
||||||
|
|
||||||
|
* `ember build` (development)
|
||||||
|
* `ember build --environment production` (production)
|
||||||
|
|
||||||
|
### Deploying
|
||||||
|
|
||||||
|
Specify what it takes to deploy your app.
|
||||||
|
|
||||||
|
## Further Reading / Useful Links
|
||||||
|
|
||||||
|
* [ember.js](https://emberjs.com/)
|
||||||
|
* [ember-cli](https://ember-cli.com/)
|
||||||
|
* Development Browser Extensions
|
||||||
|
* [ember inspector for chrome](https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi)
|
||||||
|
* [ember inspector for firefox](https://addons.mozilla.org/en-US/firefox/addon/ember-inspector/)
|
5
ember-ui-modern/app/adapters/application.js
Normal file
5
ember-ui-modern/app/adapters/application.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import JSONAPIAdapter from '@ember-data/adapter/json-api';
|
||||||
|
|
||||||
|
export default class ApplicationAdapter extends JSONAPIAdapter {
|
||||||
|
host = 'http://localhost:8000/';
|
||||||
|
}
|
15
ember-ui-modern/app/adapters/meal.js
Normal file
15
ember-ui-modern/app/adapters/meal.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import ApplicationAdapter from './application';
|
||||||
|
|
||||||
|
export default class MealAdapter extends ApplicationAdapter {
|
||||||
|
async findRecord(store, model, id) {
|
||||||
|
let result = await fetch(`${this.host}meal/${id}`);
|
||||||
|
return await result.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
async queryRecord(store, model, query) {
|
||||||
|
if (query === 'random') {
|
||||||
|
let result = await fetch(`${this.host}meals/random`);
|
||||||
|
return await result.json();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
ember-ui-modern/app/app.js
Normal file
12
ember-ui-modern/app/app.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import Application from '@ember/application';
|
||||||
|
import Resolver from './resolver';
|
||||||
|
import loadInitializers from 'ember-load-initializers';
|
||||||
|
import config from './config/environment';
|
||||||
|
|
||||||
|
export default class App extends Application {
|
||||||
|
modulePrefix = config.modulePrefix;
|
||||||
|
podModulePrefix = config.podModulePrefix;
|
||||||
|
Resolver = Resolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadInitializers(App, config.modulePrefix);
|
3
ember-ui-modern/app/components/header-nav-link.hbs
Normal file
3
ember-ui-modern/app/components/header-nav-link.hbs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<a href={{@href}} class="block mt-4 md:inline-block md:mt-0 text-teal-200 hover:text-white focus:text-white mr-4" data-test-id="header-nav-link">
|
||||||
|
{{yield}}
|
||||||
|
</a>
|
42
ember-ui-modern/app/components/header-nav.hbs
Normal file
42
ember-ui-modern/app/components/header-nav.hbs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
<nav class="flex items-center justify-between flex-wrap bg-teal-500 p-6">
|
||||||
|
<div class="flex items-center flex-shrink-0 text-white mr-6">
|
||||||
|
<LinkTo @route="index" class="flex border border-transparent hover:border-white focus:border-white rounded px-4 py-2" data-test-id="branding-link">
|
||||||
|
<svg class="fill-current h-8 w-8 mr-2" width="54" height="54" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M12 0c6.623 0 12 5.377 12 12s-5.377 12-12 12-12-5.377-12-12 5.377-12 12-12zm6.997 20.486c2.444-2.019 4.003-5.072 4.003-8.486 0-6.071-4.929-11-11-11s-11 4.929-11 11c0 4.27 2.439 7.975 5.998 9.798v-3.228c0-.691-.441-.917-1.384-1.673-.698-.56-1.177-1.433-1.089-2.322.252-2.537.862-7.575.862-7.575l.909.003-.597 5.997h1.291l.005-6h1l-.002 6h1.003l-.001-6h1l.004 6 1.34.002-.675-6.002h.887c.002.011.675 5.008.951 7.55.098.902-.409 1.792-1.121 2.356-.95.751-1.382.967-1.382 1.669v4.243c.649.12 1.318.182 2.001.182 1.409 0 2.756-.265 3.994-.749l.001-3.251h-2.467c.802-6.996 3.103-12 4.66-12 .447 0 .804.357.807.851.008 1.164.004 6.814.002 12.635zm-7.563-6.486h-5.845c-.067.642-.26 1.387.651 2.117.938.754 1.758 1.231 1.758 2.453v3.678c.326.128.66.24 1.001.337v-4.01c0-1.237.811-1.7 1.761-2.453.944-.747.75-1.464.674-2.122zm6.561 7.222l.002-13.029c-1.14 1.352-2.563 4.206-3.31 9.809h2.308l-.001 3.8c.345-.176.679-.37 1.001-.58z"/>
|
||||||
|
</svg>
|
||||||
|
<span class="font-semibold text-xl tracking-tight">
|
||||||
|
Sortable Recipes
|
||||||
|
</span>
|
||||||
|
</LinkTo>
|
||||||
|
</div>
|
||||||
|
<div class="block md:hidden">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
{{on "click" this.toggle}}
|
||||||
|
class="flex items-center px-3 py-2 border rounded text-teal-200 border-teal-400 hover:text-white hover:border-white"
|
||||||
|
data-test-id="toggle-menu">
|
||||||
|
<svg class="fill-current h-3 w-3" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><title>Menu</title><path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z"/></svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="w-full block flex-grow md:flex md:items-center md:w-auto {{if this.hideLinks "hidden"}}" data-test-id="nav-links">
|
||||||
|
<div class="text-sm md:flex-grow">
|
||||||
|
<HeaderNavLink @href="https://github.com/adopted-ember-addons/ember-sortable">
|
||||||
|
Ember-Sortable
|
||||||
|
</HeaderNavLink>
|
||||||
|
<HeaderNavLink @href="https://tailwindcss.com/docs/responsive-design">
|
||||||
|
TailwindCSS
|
||||||
|
</HeaderNavLink>
|
||||||
|
<HeaderNavLink @href="https://www.themealdb.com/">
|
||||||
|
TheMealDB
|
||||||
|
</HeaderNavLink>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="https://gitlab.com/gaiety/sortable-recipes" class="inline-block text-sm px-4 py-2 leading-none border rounded text-white border-white hover:border-transparent hover:text-teal-500 hover:bg-white hover:border-transparent focus:text-teal-500 focus:bg-white mt-4 md:mt-0" data-test-id="fork-link">
|
||||||
|
<svg class="fill-current h-8 w-8 inline-block" width="54" height="54" viewBox="0 0 586 559" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M461.48,298.35,443.7,243.72a7.72,7.72,0,0,0-.43-1.47L407.6,132.45a14.18,14.18,0,0,0-13.54-9.67,13.94,13.94,0,0,0-13.38,9.75l-34,104.63H239.37L205.32,132.53A13.94,13.94,0,0,0,192,122.78h-.08a14.22,14.22,0,0,0-13.5,9.76L142.72,242.47c0,.1-.08.18-.11.28l-18.1,55.61a20.29,20.29,0,0,0,7.37,22.71L288.26,434.7a8,8,0,0,0,9.45-.05l0,0L454.12,321.07A20.28,20.28,0,0,0,461.48,298.35ZM227.73,253.22l43.59,134.16L166.68,253.22Zm87,134.19,41.8-128.62,1.8-5.57h61.1L324.76,374.5Zm79.47-244.58,30.63,94.33H363.52ZM341.49,253.16l-30.37,93.46L293,402.28,244.58,253.16ZM191.85,142.83l30.69,94.33H161.27Zm-50.56,165.3a4.31,4.31,0,0,1-1.56-4.83L153.17,262l98.57,126.37Zm303.43,0L334.26,388.34l.37-.48L432.83,262l13.44,41.28A4.31,4.31,0,0,1,444.72,308.12Z"/>
|
||||||
|
</svg>
|
||||||
|
Fork on Gitlab
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
12
ember-ui-modern/app/components/header-nav.js
Normal file
12
ember-ui-modern/app/components/header-nav.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import Component from '@glimmer/component';
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
|
||||||
|
export default class HeaderNavComponent extends Component {
|
||||||
|
@tracked hideLinks = true;
|
||||||
|
|
||||||
|
@action
|
||||||
|
toggle() {
|
||||||
|
this.hideLinks = !this.hideLinks;
|
||||||
|
}
|
||||||
|
}
|
23
ember-ui-modern/app/components/loading-indicator.hbs
Normal file
23
ember-ui-modern/app/components/loading-indicator.hbs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{{!https://samherbert.net/svg-loaders/}}
|
||||||
|
<svg class="fill-current text-teal-500 w-full h-8 my-4" viewBox="0 0 135 140" xmlns="http://www.w3.org/2000/svg" data-test-id="loading-indicator">
|
||||||
|
<rect y="10" width="15" height="120" rx="6">
|
||||||
|
<animate attributeName="height" begin="0.5s" dur="1s" values="120;110;100;90;80;70;60;50;40;140;120" calcMode="linear" repeatCount="indefinite" />
|
||||||
|
<animate attributeName="y" begin="0.5s" dur="1s" values="10;15;20;25;30;35;40;45;50;0;10" calcMode="linear" repeatCount="indefinite" />
|
||||||
|
</rect>
|
||||||
|
<rect x="30" y="10" width="15" height="120" rx="6">
|
||||||
|
<animate attributeName="height" begin="0.25s" dur="1s" values="120;110;100;90;80;70;60;50;40;140;120" calcMode="linear" repeatCount="indefinite" />
|
||||||
|
<animate attributeName="y" begin="0.25s" dur="1s" values="10;15;20;25;30;35;40;45;50;0;10" calcMode="linear" repeatCount="indefinite" />
|
||||||
|
</rect>
|
||||||
|
<rect x="60" width="15" height="140" rx="6">
|
||||||
|
<animate attributeName="height" begin="0s" dur="1s" values="120;110;100;90;80;70;60;50;40;140;120" calcMode="linear" repeatCount="indefinite" />
|
||||||
|
<animate attributeName="y" begin="0s" dur="1s" values="10;15;20;25;30;35;40;45;50;0;10" calcMode="linear" repeatCount="indefinite" />
|
||||||
|
</rect>
|
||||||
|
<rect x="90" y="10" width="15" height="120" rx="6">
|
||||||
|
<animate attributeName="height" begin="0.25s" dur="1s" values="120;110;100;90;80;70;60;50;40;140;120" calcMode="linear" repeatCount="indefinite" />
|
||||||
|
<animate attributeName="y" begin="0.25s" dur="1s" values="10;15;20;25;30;35;40;45;50;0;10" calcMode="linear" repeatCount="indefinite" />
|
||||||
|
</rect>
|
||||||
|
<rect x="120" y="10" width="15" height="120" rx="6">
|
||||||
|
<animate attributeName="height" begin="0.5s" dur="1s" values="120;110;100;90;80;70;60;50;40;140;120" calcMode="linear" repeatCount="indefinite" />
|
||||||
|
<animate attributeName="y" begin="0.5s" dur="1s" values="10;15;20;25;30;35;40;45;50;0;10" calcMode="linear" repeatCount="indefinite" />
|
||||||
|
</rect>
|
||||||
|
</svg>
|
11
ember-ui-modern/app/components/meal-add.hbs
Normal file
11
ember-ui-modern/app/components/meal-add.hbs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{{#if this.fetchMeal.isRunning}}
|
||||||
|
<LoadingIndicator />
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
{{on "click" this.addMeal}}
|
||||||
|
class="w-full bg-teal-500 hover:bg-teal-400 focus:bg-teal-400 text-white font-bold mt-4 py-2 px-4 border-b-4 border-teal-700 hover:border-teal-500 focus:border-teal-500 rounded"
|
||||||
|
data-test-id="meal-add-button">
|
||||||
|
Add Another Meal
|
||||||
|
</button>
|
17
ember-ui-modern/app/components/meal-add.js
Normal file
17
ember-ui-modern/app/components/meal-add.js
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import Component from '@glimmer/component';
|
||||||
|
import { inject as service } from '@ember/service';
|
||||||
|
import { task } from 'ember-concurrency';
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
|
||||||
|
export default class MealAddComponent extends Component {
|
||||||
|
@service store;
|
||||||
|
|
||||||
|
@(task(function * () {
|
||||||
|
return yield this.store.queryRecord('meal', 'random');
|
||||||
|
})) fetchMeal;
|
||||||
|
|
||||||
|
@action
|
||||||
|
async addMeal() {
|
||||||
|
await this.fetchMeal.perform();
|
||||||
|
}
|
||||||
|
}
|
21
ember-ui-modern/app/components/meal-item.hbs
Normal file
21
ember-ui-modern/app/components/meal-item.hbs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<LinkTo @route="meal" @model={{@meal}} class="block bg-white border border-gray-400 focus:border-teal-500 focus:shadow-sm focus:bg-teal-100 outline-none" data-test-id="meal-link">
|
||||||
|
<div class="max-w-sm w-full lg:max-w-full lg:flex">
|
||||||
|
<div class="h-48 lg:h-auto lg:w-48 flex-none">
|
||||||
|
<img src={{@meal.thumbnailUrl}} alt="" role="presentation" class="h-full w-full object-cover" data-test-id="meal-preview-image">
|
||||||
|
</div>
|
||||||
|
<div class="p-4 flex flex-col justify-between leading-normal">
|
||||||
|
<div class="mb-8">
|
||||||
|
<div class="text-gray-900 font-bold text-xl mb-2" data-test-id="meal-name">
|
||||||
|
{{@meal.name}}
|
||||||
|
</div>
|
||||||
|
<p class="text-gray-700 text-base" data-test-id="meal-ingredients-list">
|
||||||
|
{{@meal.ingredientsList}}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div data-test-id="meal-tags">
|
||||||
|
<MealTag>{{@meal.category}}</MealTag>
|
||||||
|
<MealTag>{{@meal.area}}</MealTag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</LinkTo>
|
17
ember-ui-modern/app/components/meal-list.hbs
Normal file
17
ember-ui-modern/app/components/meal-list.hbs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<div class="rounded-md shadow-md bg-gray-200">
|
||||||
|
<SortableGroup
|
||||||
|
@model={{this.sortedItems}}
|
||||||
|
@onChange={{action this.reorderMeals}}
|
||||||
|
as |group|>
|
||||||
|
{{#each group.model as |meal|}}
|
||||||
|
<group.item
|
||||||
|
@model={{meal}}
|
||||||
|
data-test-id="meal-item"
|
||||||
|
as |item|>
|
||||||
|
<item.handle>
|
||||||
|
<MealItem @meal={{meal}} {{on "click" this.openMealDetails}} />
|
||||||
|
</item.handle>
|
||||||
|
</group.item>
|
||||||
|
{{/each}}
|
||||||
|
</SortableGroup>
|
||||||
|
</div>
|
34
ember-ui-modern/app/components/meal-list.js
Normal file
34
ember-ui-modern/app/components/meal-list.js
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import Component from '@glimmer/component';
|
||||||
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { A } from '@ember/array';
|
||||||
|
import { inject as service } from '@ember/service';
|
||||||
|
|
||||||
|
export default class MealListComponent extends Component {
|
||||||
|
@service store;
|
||||||
|
@tracked items = A([]);
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(...arguments);
|
||||||
|
this.assignExistingItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
get sortedItems() {
|
||||||
|
return this.items.sortBy('listOrder');
|
||||||
|
}
|
||||||
|
|
||||||
|
async assignExistingItems() {
|
||||||
|
let items = await this.store.peekAll('meal');
|
||||||
|
this.items = items;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
async reorderMeals(reorderedMeals) {
|
||||||
|
let orderedIds = reorderedMeals.map(meal => meal.id);
|
||||||
|
|
||||||
|
for (let index = 0; index < orderedIds.length; index++) {
|
||||||
|
let meal = await this.store.peekRecord('meal', orderedIds[index]);
|
||||||
|
meal.listOrder = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
ember-ui-modern/app/components/meal-tag.hbs
Normal file
3
ember-ui-modern/app/components/meal-tag.hbs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<span class="inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2" data-test-id="meal-tag">
|
||||||
|
#{{yield}}
|
||||||
|
</span>
|
23
ember-ui-modern/app/controllers/index.js
Normal file
23
ember-ui-modern/app/controllers/index.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import Controller from '@ember/controller';
|
||||||
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
import { A } from '@ember/array';
|
||||||
|
import { inject as service } from '@ember/service';
|
||||||
|
|
||||||
|
export default class IndexController extends Controller {
|
||||||
|
@service store;
|
||||||
|
@tracked items = A([]);
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(...arguments);
|
||||||
|
this.assignExistingItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
async assignExistingItems() {
|
||||||
|
let items = await this.store.peekAll('meal');
|
||||||
|
this.items = items;
|
||||||
|
}
|
||||||
|
|
||||||
|
get userHasMeals() {
|
||||||
|
return this.items.length >= 1;
|
||||||
|
}
|
||||||
|
}
|
25
ember-ui-modern/app/index.html
Normal file
25
ember-ui-modern/app/index.html
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<title>Sortable Recipes</title>
|
||||||
|
<meta name="description" content="">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
|
{{content-for "head"}}
|
||||||
|
|
||||||
|
<link integrity="" rel="stylesheet" href="{{rootURL}}assets/vendor.css">
|
||||||
|
<link integrity="" rel="stylesheet" href="{{rootURL}}assets/sortablerecipes.css">
|
||||||
|
|
||||||
|
{{content-for "head-footer"}}
|
||||||
|
</head>
|
||||||
|
<body class="bg-gray-100">
|
||||||
|
{{content-for "body"}}
|
||||||
|
|
||||||
|
<script src="{{rootURL}}assets/vendor.js"></script>
|
||||||
|
<script src="{{rootURL}}assets/sortablerecipes.js"></script>
|
||||||
|
|
||||||
|
{{content-for "body-footer"}}
|
||||||
|
</body>
|
||||||
|
</html>
|
22
ember-ui-modern/app/models/meal.js
Normal file
22
ember-ui-modern/app/models/meal.js
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import DS from 'ember-data';
|
||||||
|
const { Model, attr } = DS;
|
||||||
|
|
||||||
|
export default class MealModel extends Model {
|
||||||
|
@attr alternateDrink;
|
||||||
|
@attr area;
|
||||||
|
@attr category;
|
||||||
|
@attr dateModified;
|
||||||
|
@attr ingredients;
|
||||||
|
@attr instructions;
|
||||||
|
@attr name;
|
||||||
|
@attr sourceUrl;
|
||||||
|
@attr tags;
|
||||||
|
@attr thumbnailUrl;
|
||||||
|
@attr youtubeUrl;
|
||||||
|
|
||||||
|
@attr('number', { defaultValue: Infinity }) listOrder;
|
||||||
|
|
||||||
|
get ingredientsList() {
|
||||||
|
return this.ingredients.map(ingredient => ingredient.name).join(', ');
|
||||||
|
}
|
||||||
|
}
|
4
ember-ui-modern/app/resolver.js
Normal file
4
ember-ui-modern/app/resolver.js
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import Resolver from 'ember-resolver';
|
||||||
|
|
||||||
|
export default Resolver;
|
||||||
|
|
11
ember-ui-modern/app/router.js
Normal file
11
ember-ui-modern/app/router.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import EmberRouter from '@ember/routing/router';
|
||||||
|
import config from './config/environment';
|
||||||
|
|
||||||
|
export default class Router extends EmberRouter {
|
||||||
|
location = config.locationType;
|
||||||
|
rootURL = config.rootURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Router.map(function() {
|
||||||
|
this.route('meal', { path: '/:id' });
|
||||||
|
});
|
7
ember-ui-modern/app/routes/meal.js
Normal file
7
ember-ui-modern/app/routes/meal.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import Route from '@ember/routing/route';
|
||||||
|
|
||||||
|
export default class MealRoute extends Route {
|
||||||
|
model({ id }) {
|
||||||
|
return this.store.findRecord('meal', id);
|
||||||
|
}
|
||||||
|
}
|
15
ember-ui-modern/app/styles/app.css
Normal file
15
ember-ui-modern/app/styles/app.css
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
@import "tailwindcss/base";
|
||||||
|
|
||||||
|
@import "tailwindcss/components";
|
||||||
|
@import "components.css";
|
||||||
|
|
||||||
|
@import "tailwindcss/utilities";
|
||||||
|
@import "utilities.css";
|
||||||
|
|
||||||
|
.sortable-item {
|
||||||
|
transition: all .125s;
|
||||||
|
}
|
||||||
|
.sortable-item.is-dragging {
|
||||||
|
transition-duration: 0s;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
0
ember-ui-modern/app/styles/components.css
Normal file
0
ember-ui-modern/app/styles/components.css
Normal file
0
ember-ui-modern/app/styles/utilities.css
Normal file
0
ember-ui-modern/app/styles/utilities.css
Normal file
11
ember-ui-modern/app/tailwind/config.js
Normal file
11
ember-ui-modern/app/tailwind/config.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
/*global module*/
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
theme: {
|
||||||
|
extend: {}
|
||||||
|
},
|
||||||
|
variants: {
|
||||||
|
borderWidth: ['responsive', 'hover', 'focus'],
|
||||||
|
},
|
||||||
|
plugins: []
|
||||||
|
}
|
11
ember-ui-modern/app/templates/application.hbs
Normal file
11
ember-ui-modern/app/templates/application.hbs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<HeaderNav />
|
||||||
|
|
||||||
|
<div class="flex p-4">
|
||||||
|
<div class="w-2/6">
|
||||||
|
<MealList />
|
||||||
|
<MealAdd />
|
||||||
|
</div>
|
||||||
|
<div class="w-4/6 pl-4">
|
||||||
|
{{outlet}}
|
||||||
|
</div>
|
||||||
|
</div>
|
17
ember-ui-modern/app/templates/index.hbs
Normal file
17
ember-ui-modern/app/templates/index.hbs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{{#if this.userHasMeals}}
|
||||||
|
<h1 class="text-5xl -mt-4 text-teal-500 font-hairline">
|
||||||
|
Great, you have meals!
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<p class="text-gray-700 text-base">
|
||||||
|
You can see more details of any meal by clicking on them. You may also reorder meals via drag and drop (or your keyboard).
|
||||||
|
</p>
|
||||||
|
{{else}}
|
||||||
|
<h1 class="text-5xl -mt-4 text-teal-500 font-hairline">
|
||||||
|
Welcome to Sortable Recipes!
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<p class="text-gray-700 text-base">
|
||||||
|
Add some recipes to get started.
|
||||||
|
</p>
|
||||||
|
{{/if}}
|
14
ember-ui-modern/app/templates/meal.hbs
Normal file
14
ember-ui-modern/app/templates/meal.hbs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<h1 class="text-5xl -mt-4 text-teal-500 font-hairline">
|
||||||
|
{{@model.name}}
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<img src={{@model.thumbnailUrl}} alt="" role="presentation" class="float-right w-1/3 rounded-lg ml-8 mb-4 shadow-lg border-8 border-white">
|
||||||
|
|
||||||
|
<p class="text-gray-700 text-base whitespace-pre-line">
|
||||||
|
{{@model.instructions}}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="mt-4">
|
||||||
|
<MealTag>{{@model.category}}</MealTag>
|
||||||
|
<MealTag>{{@model.area}}</MealTag>
|
||||||
|
</div>
|
54
ember-ui-modern/config/environment.js
Normal file
54
ember-ui-modern/config/environment.js
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = function(environment) {
|
||||||
|
let ENV = {
|
||||||
|
modulePrefix: 'sortablerecipes',
|
||||||
|
environment,
|
||||||
|
rootURL: '/',
|
||||||
|
locationType: 'auto',
|
||||||
|
EmberENV: {
|
||||||
|
FEATURES: {
|
||||||
|
// Here you can enable experimental features on an ember canary build
|
||||||
|
// e.g. EMBER_MODULE_UNIFICATION: true
|
||||||
|
},
|
||||||
|
EXTEND_PROTOTYPES: {
|
||||||
|
// Prevent Ember Data from overriding Date.parse.
|
||||||
|
Date: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
APP: {
|
||||||
|
// Here you can pass flags/options to your application instance
|
||||||
|
// when it is created
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (environment === 'development') {
|
||||||
|
ENV['ember-cli-mirage'] = {
|
||||||
|
enabled: false
|
||||||
|
};
|
||||||
|
// ENV.APP.LOG_RESOLVER = true;
|
||||||
|
// ENV.APP.LOG_ACTIVE_GENERATION = true;
|
||||||
|
// ENV.APP.LOG_TRANSITIONS = true;
|
||||||
|
// ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
|
||||||
|
// ENV.APP.LOG_VIEW_LOOKUPS = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (environment === 'test') {
|
||||||
|
// Testem prefers this...
|
||||||
|
ENV.locationType = 'none';
|
||||||
|
|
||||||
|
// keep test console output quieter
|
||||||
|
ENV.APP.LOG_ACTIVE_GENERATION = false;
|
||||||
|
ENV.APP.LOG_VIEW_LOOKUPS = false;
|
||||||
|
|
||||||
|
ENV.APP.rootElement = '#ember-testing';
|
||||||
|
ENV.APP.autoboot = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (environment === 'production') {
|
||||||
|
// here you can enable a production-specific feature
|
||||||
|
}
|
||||||
|
|
||||||
|
return ENV;
|
||||||
|
};
|
5
ember-ui-modern/config/optional-features.json
Normal file
5
ember-ui-modern/config/optional-features.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"application-template-wrapper": false,
|
||||||
|
"jquery-integration": false,
|
||||||
|
"template-only-glimmer-components": true
|
||||||
|
}
|
18
ember-ui-modern/config/targets.js
Normal file
18
ember-ui-modern/config/targets.js
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const browsers = [
|
||||||
|
'last 1 Chrome versions',
|
||||||
|
'last 1 Firefox versions',
|
||||||
|
'last 1 Safari versions'
|
||||||
|
];
|
||||||
|
|
||||||
|
const isCI = !!process.env.CI;
|
||||||
|
const isProduction = process.env.EMBER_ENV === 'production';
|
||||||
|
|
||||||
|
if (isCI || isProduction) {
|
||||||
|
browsers.push('ie 11');
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
browsers
|
||||||
|
};
|
36
ember-ui-modern/ember-cli-build.js
Normal file
36
ember-ui-modern/ember-cli-build.js
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const EmberApp = require('ember-cli/lib/broccoli/ember-app');
|
||||||
|
const isProduction = EmberApp.env() === 'production';
|
||||||
|
|
||||||
|
const purgeCSS = {
|
||||||
|
module: require('@fullhuman/postcss-purgecss'),
|
||||||
|
options: {
|
||||||
|
content: [
|
||||||
|
// add extra paths here for components/controllers which include tailwind classes
|
||||||
|
'./app/index.html',
|
||||||
|
'./app/templates/**/*.hbs'
|
||||||
|
],
|
||||||
|
defaultExtractor: content => content.match(/[A-Za-z0-9-_:/]+/g) || []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function(defaults) {
|
||||||
|
let app = new EmberApp(defaults, {
|
||||||
|
postcssOptions: {
|
||||||
|
compile: {
|
||||||
|
plugins: [
|
||||||
|
{
|
||||||
|
module: require('postcss-import'),
|
||||||
|
options: {
|
||||||
|
path: ['node_modules']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
require('tailwindcss')('./app/tailwind/config.js'),
|
||||||
|
...isProduction ? [purgeCSS] : []
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return app.toTree();
|
||||||
|
};
|
6
ember-ui-modern/jsconfig.json
Normal file
6
ember-ui-modern/jsconfig.json
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"experimentalDecorators": true
|
||||||
|
},
|
||||||
|
"exclude": ["node_modules", "dist"]
|
||||||
|
}
|
12
ember-ui-modern/mirage/config.js
Normal file
12
ember-ui-modern/mirage/config.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
export default function() {
|
||||||
|
this.urlPrefix = 'http://localhost:8000/';
|
||||||
|
|
||||||
|
this.get('/meals/random', (schema) => {
|
||||||
|
let id = 'random';
|
||||||
|
schema.meals.create({id});
|
||||||
|
return schema.meals.find(id);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.get('/meal/:id');
|
||||||
|
}
|
||||||
|
|
5
ember-ui-modern/mirage/factories/meal.js
Normal file
5
ember-ui-modern/mirage/factories/meal.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { Factory } from 'ember-cli-mirage';
|
||||||
|
|
||||||
|
export default Factory.extend({
|
||||||
|
ingredients: Object.freeze([]),
|
||||||
|
});
|
9
ember-ui-modern/mirage/scenarios/default.js
Normal file
9
ember-ui-modern/mirage/scenarios/default.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
export default function(/* server */) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
Seed your development database using your factories.
|
||||||
|
This data will not be loaded in your tests.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// server.createList('post', 10);
|
||||||
|
}
|
4
ember-ui-modern/mirage/serializers/application.js
Normal file
4
ember-ui-modern/mirage/serializers/application.js
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import { JSONAPISerializer } from 'ember-cli-mirage';
|
||||||
|
|
||||||
|
export default JSONAPISerializer.extend({
|
||||||
|
});
|
23208
ember-ui-modern/package-lock.json
generated
Normal file
23208
ember-ui-modern/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
59
ember-ui-modern/package.json
Normal file
59
ember-ui-modern/package.json
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
{
|
||||||
|
"name": "sortablerecipes",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"description": "Sort and view random recipes from MealDB",
|
||||||
|
"repository": "",
|
||||||
|
"license": "MIT",
|
||||||
|
"author": "",
|
||||||
|
"directories": {
|
||||||
|
"doc": "doc",
|
||||||
|
"test": "tests"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "ember build",
|
||||||
|
"lint:hbs": "ember-template-lint .",
|
||||||
|
"lint:js": "eslint .",
|
||||||
|
"start": "ember serve --port 4201",
|
||||||
|
"test": "ember test"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@ember/edition-utils": "^1.2.0",
|
||||||
|
"@ember/optional-features": "^1.3.0",
|
||||||
|
"@fullhuman/postcss-purgecss": "^2.0.6",
|
||||||
|
"@glimmer/component": "^1.0.0",
|
||||||
|
"babel-eslint": "^10.0.3",
|
||||||
|
"broccoli-asset-rev": "^3.0.0",
|
||||||
|
"ember-auto-import": "^1.5.3",
|
||||||
|
"ember-cli": "3.16.0",
|
||||||
|
"ember-cli-app-version": "^3.2.0",
|
||||||
|
"ember-cli-babel": "^7.18.0",
|
||||||
|
"ember-cli-dependency-checker": "^3.2.0",
|
||||||
|
"ember-cli-htmlbars": "^4.2.3",
|
||||||
|
"ember-cli-inject-live-reload": "^2.0.2",
|
||||||
|
"ember-cli-mirage": "^1.1.6",
|
||||||
|
"ember-cli-postcss": "^5.0.0",
|
||||||
|
"ember-cli-sri": "^2.1.1",
|
||||||
|
"ember-cli-uglify": "^3.0.0",
|
||||||
|
"ember-concurrency": "^1.1.5",
|
||||||
|
"ember-data": "~3.16.0",
|
||||||
|
"ember-export-application-global": "^2.0.1",
|
||||||
|
"ember-load-initializers": "^2.1.1",
|
||||||
|
"ember-maybe-import-regenerator": "^0.1.6",
|
||||||
|
"ember-qunit": "^4.6.0",
|
||||||
|
"ember-resolver": "^7.0.0",
|
||||||
|
"ember-sortable": "^2.1.3",
|
||||||
|
"ember-source": "^3.16.3",
|
||||||
|
"ember-template-lint": "^2.0.1",
|
||||||
|
"eslint": "^6.8.0",
|
||||||
|
"eslint-plugin-ember": "^7.8.1",
|
||||||
|
"eslint-plugin-node": "^11.0.0",
|
||||||
|
"loader.js": "^4.7.0",
|
||||||
|
"postcss-import": "^12.0.1",
|
||||||
|
"qunit-dom": "^1.0.0",
|
||||||
|
"tailwindcss": "^1.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "8.* || >= 10.*"
|
||||||
|
}
|
||||||
|
}
|
3
ember-ui-modern/public/robots.txt
Normal file
3
ember-ui-modern/public/robots.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# http://www.robotstxt.org
|
||||||
|
User-agent: *
|
||||||
|
Disallow:
|
25
ember-ui-modern/testem.js
Normal file
25
ember-ui-modern/testem.js
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
module.exports = {
|
||||||
|
test_page: 'tests/index.html?hidepassed',
|
||||||
|
disable_watching: true,
|
||||||
|
launch_in_ci: [
|
||||||
|
'Chrome'
|
||||||
|
],
|
||||||
|
launch_in_dev: [
|
||||||
|
'Chrome'
|
||||||
|
],
|
||||||
|
browser_args: {
|
||||||
|
Chrome: {
|
||||||
|
ci: [
|
||||||
|
// --no-sandbox is needed when running Chrome inside a container
|
||||||
|
process.env.CI ? '--no-sandbox' : null,
|
||||||
|
|
||||||
|
'--headless',
|
||||||
|
'--disable-dev-shm-usage',
|
||||||
|
'--disable-software-rasterizer',
|
||||||
|
'--mute-audio',
|
||||||
|
'--remote-debugging-port=0',
|
||||||
|
'--window-size=1440,900'
|
||||||
|
].filter(Boolean)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
33
ember-ui-modern/tests/index.html
Normal file
33
ember-ui-modern/tests/index.html
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<title>Sortable Recipes Tests</title>
|
||||||
|
<meta name="description" content="">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
|
{{content-for "head"}}
|
||||||
|
{{content-for "test-head"}}
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="{{rootURL}}assets/vendor.css">
|
||||||
|
<link rel="stylesheet" href="{{rootURL}}assets/sortablerecipes.css">
|
||||||
|
<link rel="stylesheet" href="{{rootURL}}assets/test-support.css">
|
||||||
|
|
||||||
|
{{content-for "head-footer"}}
|
||||||
|
{{content-for "test-head-footer"}}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{{content-for "body"}}
|
||||||
|
{{content-for "test-body"}}
|
||||||
|
|
||||||
|
<script src="/testem.js" integrity=""></script>
|
||||||
|
<script src="{{rootURL}}assets/vendor.js"></script>
|
||||||
|
<script src="{{rootURL}}assets/test-support.js"></script>
|
||||||
|
<script src="{{rootURL}}assets/sortablerecipes.js"></script>
|
||||||
|
<script src="{{rootURL}}assets/tests.js"></script>
|
||||||
|
|
||||||
|
{{content-for "body-footer"}}
|
||||||
|
{{content-for "test-body-footer"}}
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupRenderingTest } from 'ember-qunit';
|
||||||
|
import { render } from '@ember/test-helpers';
|
||||||
|
import { hbs } from 'ember-cli-htmlbars';
|
||||||
|
|
||||||
|
module('Integration | Component | header-nav-link', function(hooks) {
|
||||||
|
setupRenderingTest(hooks);
|
||||||
|
|
||||||
|
test('it renders link with href', async function(assert) {
|
||||||
|
await render(hbs`
|
||||||
|
<HeaderNavLink @href="foo">
|
||||||
|
bar
|
||||||
|
</HeaderNavLink>
|
||||||
|
`);
|
||||||
|
|
||||||
|
assert.dom('[data-test-id=header-nav-link]').hasAttribute('href', 'foo');
|
||||||
|
assert.dom('[data-test-id=header-nav-link]').includesText('bar');
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,40 @@
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupRenderingTest } from 'ember-qunit';
|
||||||
|
import { render, click } from '@ember/test-helpers';
|
||||||
|
import { hbs } from 'ember-cli-htmlbars';
|
||||||
|
|
||||||
|
module('Integration | Component | header-nav', function(hooks) {
|
||||||
|
setupRenderingTest(hooks);
|
||||||
|
|
||||||
|
test('it renders branding', async function(assert) {
|
||||||
|
await render(hbs`<HeaderNav />`);
|
||||||
|
|
||||||
|
assert.dom('[data-test-id=branding-link]').hasTagName('a');
|
||||||
|
assert.dom('[data-test-id=branding-link]').includesText('Sortable Recipes');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it renders fork link', async function(assert) {
|
||||||
|
await render(hbs`<HeaderNav />`);
|
||||||
|
|
||||||
|
assert.dom('[data-test-id=fork-link]').hasTagName('a');
|
||||||
|
assert.dom('[data-test-id=fork-link]').includesText('Fork');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it renders links', async function(assert) {
|
||||||
|
await render(hbs`<HeaderNav />`);
|
||||||
|
|
||||||
|
assert.dom('[data-test-id=nav-links] a').exists();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it can toggle link visibility', async function(assert) {
|
||||||
|
await render(hbs`<HeaderNav />`);
|
||||||
|
|
||||||
|
assert.dom('[data-test-id=nav-links]').hasClass('hidden');
|
||||||
|
|
||||||
|
await click('[data-test-id=toggle-menu]');
|
||||||
|
assert.dom('[data-test-id=nav-links]').doesNotHaveClass('hidden');
|
||||||
|
|
||||||
|
await click('[data-test-id=toggle-menu]');
|
||||||
|
assert.dom('[data-test-id=nav-links]').hasClass('hidden');
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupRenderingTest } from 'ember-qunit';
|
||||||
|
import { render } from '@ember/test-helpers';
|
||||||
|
import { hbs } from 'ember-cli-htmlbars';
|
||||||
|
|
||||||
|
module('Integration | Component | loading-indicator', function(hooks) {
|
||||||
|
setupRenderingTest(hooks);
|
||||||
|
|
||||||
|
test('it renders', async function(assert) {
|
||||||
|
await render(hbs`<LoadingIndicator />`);
|
||||||
|
|
||||||
|
assert.dom('[data-test-id=loading-indicator]').hasTagName('svg');
|
||||||
|
assert.dom('[data-test-id=loading-indicator] animate').exists();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupRenderingTest } from 'ember-qunit';
|
||||||
|
import { setupMirage } from 'ember-cli-mirage/test-support';
|
||||||
|
import { render, click } from '@ember/test-helpers';
|
||||||
|
import { hbs } from 'ember-cli-htmlbars';
|
||||||
|
|
||||||
|
module('Integration | Component | meal-add', function(hooks) {
|
||||||
|
setupRenderingTest(hooks);
|
||||||
|
setupMirage(hooks);
|
||||||
|
|
||||||
|
test('it adds a new meal (meal) when button is clicked', async function(assert) {
|
||||||
|
await render(hbs`<MealAdd />`);
|
||||||
|
let store = this.owner.lookup('service:store');
|
||||||
|
|
||||||
|
await click('[data-test-id=meal-add-button]');
|
||||||
|
let randomMeal = await store.findRecord('meal', 'random');
|
||||||
|
|
||||||
|
assert.ok(randomMeal);
|
||||||
|
assert.equal(store.peekAll('meal').length, 1);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,54 @@
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupRenderingTest } from 'ember-qunit';
|
||||||
|
import { setupMirage } from 'ember-cli-mirage/test-support';
|
||||||
|
import { render } from '@ember/test-helpers';
|
||||||
|
import { hbs } from 'ember-cli-htmlbars';
|
||||||
|
|
||||||
|
module('Integration | Component | meal-preview', function(hooks) {
|
||||||
|
setupRenderingTest(hooks);
|
||||||
|
setupMirage(hooks);
|
||||||
|
|
||||||
|
hooks.beforeEach(initMeal);
|
||||||
|
|
||||||
|
test('it renders a wrapper href', async function(assert) {
|
||||||
|
await render(hbs`<MealItem @meal={{meal}} />`);
|
||||||
|
|
||||||
|
assert.dom('[data-test-id=meal-link]').hasTagName('a');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it renders meal preview image', async function(assert) {
|
||||||
|
await render(hbs`<MealItem @meal={{meal}} />`);
|
||||||
|
|
||||||
|
assert.dom('[data-test-id=meal-preview-image]').hasAttribute('src', 'image.jpg');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it renders meal data as text', async function(assert) {
|
||||||
|
await render(hbs`<MealItem @meal={{meal}} />`);
|
||||||
|
|
||||||
|
assert.dom('[data-test-id=meal-name]').hasText('Cookies');
|
||||||
|
assert.dom('[data-test-id=meal-ingredients-list]').hasText('Love, Chocolate');
|
||||||
|
assert.dom('[data-test-id=meal-tags]').includesText('Home');
|
||||||
|
assert.dom('[data-test-id=meal-tags]').includesText('Desserts');
|
||||||
|
});
|
||||||
|
|
||||||
|
async function initMeal() {
|
||||||
|
let store = this.owner.lookup('service:store');
|
||||||
|
this.server.create('meal', {
|
||||||
|
area: 'Home',
|
||||||
|
category: 'Desserts',
|
||||||
|
id: 1,
|
||||||
|
ingredients: [
|
||||||
|
{
|
||||||
|
name: 'Love',
|
||||||
|
measure: 'Infinity',
|
||||||
|
}, {
|
||||||
|
name: 'Chocolate',
|
||||||
|
measure: 'As Much As You Desire',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
name: 'Cookies',
|
||||||
|
thumbnailUrl: 'image.jpg',
|
||||||
|
});
|
||||||
|
this.set('meal', await store.findRecord('meal', 1));
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,70 @@
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupRenderingTest } from 'ember-qunit';
|
||||||
|
import { setupMirage } from 'ember-cli-mirage/test-support';
|
||||||
|
import { render, find, findAll, focus, triggerKeyEvent } from '@ember/test-helpers';
|
||||||
|
import { drag } from 'ember-sortable/test-support/helpers';
|
||||||
|
import { hbs } from 'ember-cli-htmlbars';
|
||||||
|
|
||||||
|
module('Integration | Component | meal-list', function(hooks) {
|
||||||
|
setupRenderingTest(hooks);
|
||||||
|
setupMirage(hooks);
|
||||||
|
|
||||||
|
hooks.beforeEach(initMeals);
|
||||||
|
|
||||||
|
test('it renders existing meals into a list', async function(assert) {
|
||||||
|
await render(hbs`<MealList />`);
|
||||||
|
|
||||||
|
assert.dom('[data-test-id=meal-item]').exists({ count: 2 });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it can focus meal wrappers', async function(assert) {
|
||||||
|
await render(hbs`<MealList />`);
|
||||||
|
|
||||||
|
await focus('[data-sortable-handle]');
|
||||||
|
|
||||||
|
assert.equal(find('[data-sortable-handle]'), document.activeElement);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it can reorder meals via keyboard shortcuts', async function(assert) {
|
||||||
|
await render(hbs`<MealList />`);
|
||||||
|
|
||||||
|
assert.dom(findAll('[data-test-id=meal-name]')[0]).includesText('Meal 1');
|
||||||
|
assert.dom(findAll('[data-test-id=meal-name]')[1]).includesText('Meal 2');
|
||||||
|
|
||||||
|
await focus('[data-sortable-handle]'); // Not technically required, but emulates user interaction
|
||||||
|
await triggerKeyEvent('[data-sortable-handle]', 'keydown', 'Enter');
|
||||||
|
await triggerKeyEvent('[data-sortable-handle]', 'keydown', 'ArrowDown');
|
||||||
|
await triggerKeyEvent('[data-sortable-handle]', 'keydown', 'Enter');
|
||||||
|
|
||||||
|
assert.dom(findAll('[data-test-id=meal-name]')[0]).includesText('Meal 2');
|
||||||
|
assert.dom(findAll('[data-test-id=meal-name]')[1]).includesText('Meal 1');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it can drag and drop meals', async function(assert) {
|
||||||
|
await render(hbs`<MealList />`);
|
||||||
|
|
||||||
|
assert.dom(findAll('[data-test-id=meal-name]')[0]).includesText('Meal 1');
|
||||||
|
assert.dom(findAll('[data-test-id=meal-name]')[1]).includesText('Meal 2');
|
||||||
|
|
||||||
|
await drag('mouse', '[data-sortable-handle]', () => { return { dy: 100, dx: 0 } });
|
||||||
|
|
||||||
|
assert.dom(findAll('[data-test-id=meal-name]')[0]).includesText('Meal 2');
|
||||||
|
assert.dom(findAll('[data-test-id=meal-name]')[1]).includesText('Meal 1');
|
||||||
|
});
|
||||||
|
|
||||||
|
async function initMeals() {
|
||||||
|
let store = this.owner.lookup('service:store');
|
||||||
|
let meal = {
|
||||||
|
area: 'area',
|
||||||
|
category: 'category',
|
||||||
|
ingredients: [
|
||||||
|
{ name: 'Love', measure: 'Infinity' },
|
||||||
|
{ name: 'Chocolate', measure: 'As much as you like!' },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
this.server.create('meal', Object.assign({}, meal, { name: 'Meal 1', id: 1 }));
|
||||||
|
this.server.create('meal', Object.assign({}, meal, { name: 'Meal 2', id: 2 }));
|
||||||
|
await store.findRecord('meal', 1);
|
||||||
|
await store.findRecord('meal', 2);
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupRenderingTest } from 'ember-qunit';
|
||||||
|
import { render } from '@ember/test-helpers';
|
||||||
|
import { hbs } from 'ember-cli-htmlbars';
|
||||||
|
|
||||||
|
module('Integration | Component | meal-tag', function(hooks) {
|
||||||
|
setupRenderingTest(hooks);
|
||||||
|
|
||||||
|
test('it renders with hashtag', async function(assert) {
|
||||||
|
await render(hbs`
|
||||||
|
<MealTag>foo</MealTag>
|
||||||
|
`);
|
||||||
|
|
||||||
|
assert.dom('[data-test-id="meal-tag"]').includesText('#foo');
|
||||||
|
});
|
||||||
|
});
|
8
ember-ui-modern/tests/test-helper.js
Normal file
8
ember-ui-modern/tests/test-helper.js
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import Application from '../app';
|
||||||
|
import config from '../config/environment';
|
||||||
|
import { setApplication } from '@ember/test-helpers';
|
||||||
|
import { start } from 'ember-qunit';
|
||||||
|
|
||||||
|
setApplication(Application.create(config.APP));
|
||||||
|
|
||||||
|
start();
|
12
ember-ui-modern/tests/unit/adapters/application-test.js
Normal file
12
ember-ui-modern/tests/unit/adapters/application-test.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupTest } from 'ember-qunit';
|
||||||
|
|
||||||
|
module('Unit | Adapter | application', function(hooks) {
|
||||||
|
setupTest(hooks);
|
||||||
|
|
||||||
|
// Replace this with your real tests.
|
||||||
|
test('it exists', function(assert) {
|
||||||
|
let adapter = this.owner.lookup('adapter:application');
|
||||||
|
assert.ok(adapter);
|
||||||
|
});
|
||||||
|
});
|
12
ember-ui-modern/tests/unit/adapters/meal-test.js
Normal file
12
ember-ui-modern/tests/unit/adapters/meal-test.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupTest } from 'ember-qunit';
|
||||||
|
|
||||||
|
module('Unit | Adapter | meal', function(hooks) {
|
||||||
|
setupTest(hooks);
|
||||||
|
|
||||||
|
// Replace this with your real tests.
|
||||||
|
test('it exists', function(assert) {
|
||||||
|
let adapter = this.owner.lookup('adapter:meal');
|
||||||
|
assert.ok(adapter);
|
||||||
|
});
|
||||||
|
});
|
12
ember-ui-modern/tests/unit/controllers/index-test.js
Normal file
12
ember-ui-modern/tests/unit/controllers/index-test.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupTest } from 'ember-qunit';
|
||||||
|
|
||||||
|
module('Unit | Controller | index', function(hooks) {
|
||||||
|
setupTest(hooks);
|
||||||
|
|
||||||
|
// Replace this with your real tests.
|
||||||
|
test('it exists', function(assert) {
|
||||||
|
let controller = this.owner.lookup('controller:index');
|
||||||
|
assert.ok(controller);
|
||||||
|
});
|
||||||
|
});
|
30
ember-ui-modern/tests/unit/models/meal-test.js
Normal file
30
ember-ui-modern/tests/unit/models/meal-test.js
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupTest } from 'ember-qunit';
|
||||||
|
|
||||||
|
module('Unit | Model | meal', function(hooks) {
|
||||||
|
setupTest(hooks);
|
||||||
|
|
||||||
|
test('it exists', function(assert) {
|
||||||
|
let store = this.owner.lookup('service:store');
|
||||||
|
let model = store.createRecord('meal', {});
|
||||||
|
|
||||||
|
assert.ok(model);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it creates comma separated ingredients list', function(assert) {
|
||||||
|
let store = this.owner.lookup('service:store');
|
||||||
|
let model = store.createRecord('meal', {
|
||||||
|
ingredients: [
|
||||||
|
{
|
||||||
|
name: 'Love',
|
||||||
|
measure: 'Infinity',
|
||||||
|
}, {
|
||||||
|
name: 'Chocolate',
|
||||||
|
measure: 'As Much As You Desire',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(model.ingredientsList, 'Love, Chocolate');
|
||||||
|
});
|
||||||
|
});
|
11
ember-ui-modern/tests/unit/routes/meal-test.js
Normal file
11
ember-ui-modern/tests/unit/routes/meal-test.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupTest } from 'ember-qunit';
|
||||||
|
|
||||||
|
module('Unit | Route | meal', function(hooks) {
|
||||||
|
setupTest(hooks);
|
||||||
|
|
||||||
|
test('it exists', function(assert) {
|
||||||
|
let route = this.owner.lookup('route:meal');
|
||||||
|
assert.ok(route);
|
||||||
|
});
|
||||||
|
});
|
|
@ -78,6 +78,10 @@
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section data-background-iframe="http://localhost:4200/52958" data-background-interactive>
|
<section data-background-iframe="http://localhost:4200/52958" data-background-interactive>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section data-background-iframe="http://localhost:4201/52958" data-background-interactive>
|
||||||
|
<p>Latest ember-sortable</p>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Add table
Reference in a new issue