New test (#10)

* Add new test instructions

* update readme

* update reame, add sample video, additional cleanup of starting markup

* add more example clarity

* fix styles for initial columns

* fix port in readme
This commit is contained in:
Aaron Tidwell
2018-01-17 16:41:14 -05:00
committed by GitHub
parent 118e11d8d2
commit a9de43b294
21 changed files with 392 additions and 1025 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
node_modules

View File

@@ -1,50 +1,19 @@
Front-End Coding Challenge Setup
=== ---
### Premise - Fork this repository
Its not always easy to evaluate a candidates technical abilities. While we love writing tests here, we hate asking people to take them during an interview. More importantly, we hate asking people to “white-board” solutions. - Clone this repository to your local environment
- Run `npm install` to install dependencies
- Run `npm start` to start the static server
- Open `http://localhost:8080`
We—as an industry—can do better. So, just how can we do better? Instructions
---
### Solution - The full specifications and an example video of a finished test are on the page when you launch your browser.
We developed this coding challenge to help us better gauge your technical abilities. This challenge:
* can be completed on your own time Submit
* where you are most comfortable ---
* on equipment youre accustomed to
* using the tools youre proficient with
Basically, you have access to all the things that allow you to work best. - Submit a Pull Request back to this repository with your completed challenge code.
- Please complete within 24 hours.
We hope youll enjoy working through this challenge as much as weve enjoyed creating it for you.
### Guidelines
Because were awful developers, this project isnt quite ready to release. There are some broken pieces that wed like you to fix. To do that, youll need to:
1. Fork this project.
2. Fix any problems you find with it.
3. Open a PR with your changes.
4. You have 24-hours.
Our awesome design team provided the following images to demonstrate what the site should look like: http://imgur.com/a/dDuKc
### FAQ
**Q: What am I supposed to focus on?**
A: The entire project. There are problems with everything, its up to you to find them and fix them.
**Q: How do I know if Ive completed the challenge?**
A: You dont. But, thats because _we_ dont know either.
**Q: I cant get past X, what do I do?**
A: Google is your friend.
**Q: How long should this take?**
A: That really depends on you.
**Q: Can I rewrite this in React?**
A: While React is a very popular library today, all of our code is written in Angular and we'd like to see your competency with our stack.

View File

@@ -1,34 +0,0 @@
{
"name": "frontend-developer-challenge",
"description": "Sheesh. There's a lot wrong with this project.",
"main": "index.js",
"authors": [
"Ryan Provost"
],
"license": "ISC",
"keywords": [
"frontend",
"challenge"
],
"homepage": "https://github.com/rprovost/code-test-creation",
"private": true,
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"angular": "^1.5.7",
"font-awesome": "fontawesome#^4.6.3",
"weather-icons": "^2.0.10",
"express": "^4.14.0"
},
"devDependencies": {
"angular-mocks": "^1.5.7",
"hammerjs": "^2.0.8",
"d3": "^4.2.2",
"react": "^15.3.0"
}
}

View File

@@ -1,144 +0,0 @@
'use strict';
const gulp = require('gulp');
const pkg = require('./package.json');
const plugins = require('gulp-load-plugins')();
const browserSync = require('browser-sync').create();
const karmaServer = require('karma').Server;
gulp.task('build', ['build:html', 'build:js', 'build:json', 'build:sass', 'build:libs']);
gulp.task('watch2', ['build', 'watch:tests', 'watch:src', 'serve']);
/***
* Output a summary of unit test code coverage
**/
gulp.task('test:coverage', (done) => {
new KarmaServer({
configFile: __dirname + '/karma.conf.js',
singleRun: true,
reporters: ['coverage'],
coverageReporter: {
type: ['text-summary']
}
}, done).start();
return;
});
/***
* Generate an HTML report that details coverage
**/
gulp.task('test:report', (done) => {
new karmaServer({
configFile: __dirname + '/karma.conf.js',
singleRun: true,
reporters: ['coverage'],
coverageReporter: {
type: ['html']
}
}, done).start();
return;
});
/***
* Run the project with BrowserSync
**/
gulp.task('serve', () => {
browserSync.init({
server: {
baseDir: "./dist"
}
});
gulp.watch(['./dist/**/*.js', './dist/**/*.html'], browserSync.reload);
});
/***
* Reload or stream changes to browsers with BrowserSync
**/
gulp.task('watch:src', () => {
gulp.watch('./src/**/*.scss', ['build:sass']);
gulp.watch('./src/**/*.js', ['lint', 'build:js'], browserSync.reload);
gulp.watch('./src/**/*.json', ['build:json'], browserSync.reload);
gulp.watch('./src/**/*.html', ['build:html'], browserSync.reload);
});
/***
* Run test suite when affected source files change
**/
gulp.task('watch:tests',
function (done) {
new karmaServer({
configFile: __dirname + '/karma.conf.js',
singleRun: false,
reporters: ['progress'],
}, Done).start();
});
/***
* ESLint
**/
gulp.task(
'lint', () => {
let eslint = plugins.eslint;
gulp.src(['./src/**/*.js'])
.pipe(eslint())
.pipe(eslint.format())
.pipe(eslint.failAfterError());
});
/***
* Copy the HTML files into the DIST folder
**/
gulp.task('build:html', () => {
gulp.src('./src/**/*.html')
.pipe(gulp.dest('./dist'));
});
/***
* Copy the JSON files into the DIST folder
**/
gulp.task('build:json', () => {
gulp.src('./src/**/*.json')
.pipe(gulp.dest('./dist'));
});
/***
* Build all Sass files into a single css file
**/
gulp.task('build:sass', () => {
gulp.src('./src/app.scss')
.pipe(plugins.sass.sync())
.pipe(plugins.rename(pkg.name + '.css'))
.pipe(gulp.dest('./dist'))
.pipe(browserSync.stream());
});
/***
* Build all JS files into a single application file
**/
gulp.task('build:js', () => {
let filename = pkg.name + '.js';
let filenameMinified = pkg.name + '.min.js';
gulp.src(['!./src/**/*.spec.js', './src/**/*.js'])
// .pipe(plugins.plumber())
.pipe(plugins.concat(filename))
.pipe(gulp.dest('./dist'))
});
/***
* Copy all dependencies into the DIST folder
**/
gulp.task('build:libs', () => {
gulp.src('./bower.json')
.pipe(plugins.mainBowerFiles({
overrides: {
"font-awesome": { main: ['./css/font-awesome.css'] }
}
}))
.pipe(gulp.dest('./dist/libs'));
});

View File

@@ -1,16 +0,0 @@
module.exports = function(config) {
config.set({
browsers: ['Chrome'],
frameworks: ['jasmine'],
files: [
{pattern: 'src/**/*.json', included: false},
'node_modules/karma-read-json/karma-read-json.js',
'bower_components/angular/angular.js',
'bower_components/angular-mocks/angular-mocks.js',
'src/**/*.js'
],
preprocessors: {
'src/**/*.js': ['coverage']
},
});
};

View File

@@ -1,45 +1,14 @@
{ {
"name": "frontend-developer-challenge", "name": "frontend-test",
"version": "1.0.0", "version": "1.0.0",
"description": "Sheesh. There's a lot wrong with this project.", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "start": "node ./node_modules/node-static/bin/cli.js ./public"
}, },
"repository": { "author": "",
"type": "git",
"url": "git+https://github.com/rprovost/code-test-creation.git"
},
"keywords": [
"frontend",
"challenge"
],
"author": "Ryan Provost",
"license": "ISC", "license": "ISC",
"bugs": {
"url": "https://github.com/rprovost/code-test-creation/issues"
},
"homepage": "https://github.com/rprovost/code-test-creation#readme",
"devDependencies": { "devDependencies": {
"browser-sync": "^2.13.0", "node-static": "^0.7.10"
"express": "^4.14.0", }
"gulp": "^3.9.1",
"gulp-concat": "^2.6.0",
"gulp-eslint": "^3.0.1",
"gulp-load-plugins": "^1.2.4",
"gulp-main-bower-files": "^1.5.2",
"gulp-plumber": "^1.1.0",
"gulp-rename": "^1.2.2",
"gulp-sass": "^2.3.2",
"istanbul": "^0.4.4",
"jasmine-core": "^2.4.1",
"karma": "^1.1.1",
"karma-chrome-launcher": "^1.0.1",
"karma-coverage": "^1.1.1",
"karma-coverage-es6": "^0.2.7",
"karma-jasmine": "^1.0.2",
"karma-phantomjs-launcher": "^1.0.1",
"karma-read-json": "^1.1.0"
},
"dependencies": {}
} }

18
public/css/app.css Normal file
View File

@@ -0,0 +1,18 @@
#tag-browser {
width: 75%;
padding: 1em;
margin: 1em auto;
border: 1px solid black;
position: relative;
}
#tag-browser .clear-button {
position: absolute;
top: 1em;;
right: 1em;
}
#tag-browser .active {
background: purple;
color: white;
}

143
public/index.html Normal file
View File

@@ -0,0 +1,143 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.2/css/bulma.css">
<link rel="stylesheet" type="text/css" href="/css/app.css">
<title>WBDL Front-End Coding Challenge</title>
</head>
<body>
<div class="container">
<h1 class="title">
WBDL Front-End Coding Challenge
</h1>
<div id="tag-browser">
<h2 class="title">tag browser</h2>
<a class="button clear-button">
Clear
</a>
<div class="columns">
<div class="column is-one-fifth">
<div class="content">
<h3 class="subtitle">Tag List</h3>
</div>
<ul class="tag-list">
<li><span class="tag is-link">drama</span></li>
<li><span class="tag is-link active">selected-tag</span></li>
<li><span class="tag is-link">comedy</span></li>
<li><span class="tag is-link">fantasy</span></li>
</ul>
</div>
<div class="column content">
<h3 class="subtitle">[SELECTED TAG]</h3>
<ul class="matching-items-list">
<li>A Series Title</li>
<li>Another Title</li>
<li class="active">Example style of the selected Title!</li>
<li>Some other Title</li>
</ul>
</div>
<div class="column is-half selected-item">
<div class="content">
<h3 class="subtitle">[SELECTED SERIES TITLE]</h3>
<img src="http://via.placeholder.com/350x350" />
<p>
The description for the series goes here. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam semper, nunc viverra aliquam ultricies, lacus lorem semper mi, mattis convallis risus nisi id nunc. Pellentesque ultrices quis urna nec malesuada. In hac habitasse platea dictumst. Maecenas vitae lacus bibendum, lobortis mauris eget, lobortis ligula.
</p>
</div>
<ul>
<li><strong>Rating:</strong> <span>TV-14</span></li>
<li><strong>Native Language Title:</strong> <span>원라인</span></li>
<li><strong>Source Country:</strong> <span>Korea</span></li>
<li><strong>Type:</strong> <span>Series</span></li>
<li><strong>Episodes:</strong> <span>10</span></li>
</ul>
</div>
</div>
</div>
<hr />
<div class="content">
<h3 class="subtitle">Specification</h3>
<p>
Create a series/movie tag browser using the provided data.
</p>
<hr />
The tag list
<ol>
<li>Render a list of all the tags from all the series into the '.tag-list' ul.</li>
<li>There should not be duplicate tags</li>
<li>The list should be alphabetized</li>
</ol>
The Series List
<ol>
<li>When a tag is selected (clicked), render the list of series with the matching tag into the '.matching-items-list' ul</li>
</ol>
The Selected Series Data
<ol>
<li>When a series is selected (clicked), render the data for that series into the '.selected-item' div</li>
</ol>
The Clear Button
<ol>
<li>When the clear button is clicked, clear the selected tag, clear the series list, and clear all series data. Essentially, reset the widget.</li>
</ol>
</div>
<hr />
<div class="content">
<h3 class="subtitle">Dependencies</h3>
<ol>
<li><a href="http://bulma.io" target="_new">Bulma</a> is included on the page and provides basic styling. You may add any new styles you need or remove this dependency if desired.</li>
<li><a href="http://jquery.com" target="_new">jQuery</a> is included on the page. While we typically use Angular or Vue.js here at WBDL, it is important to be familiar with plain vanilla javascript (in this case, with jquery for convenience). Please <strong>do not</strong> add additional libraries to the page (react, angular, vue, etc).</li>
</ol>
</div>
<hr />
<div class="content">
<h3 class="subtitle">What are we looking for?</h3>
<ol>
<li>How do you work with a dataset?</li>
<li>How do you handle templating/dom manipulation without a framework?</li>
<li>What strategies do you employ for event binding?</li>
<li>How do you organize a class containing the different methods for performing these tasks?</li>
</ol>
<h3 class="subtitle">Some Tips</h3>
<ol>
<li>There are two titles with the same name: <strong>The Bride of the Water God (Habaek)</strong>. You will want to base your event handling on the IDs to diferentiate between these. (perhaps using something like a data- attribute)</li>
<li>It will probably create more complexity to try to break this into multiple sub-components. I wouldn't recommend it unless you are very ambitious.</li>
<li>Do not worry about browser support outside of the latest version of chrome.</li>
</ol>
<h3>Bonus</h3>
<ol>
<li>It doesn't have to be pretty, but bonus points for doing some interesting styling or animations</li>
<li>Bonus for rendering semantically correct markup (anchors, etc)</li>
<li>Bonus: Render "No Tag Selected" and "No Series Selected" text when there is not a selected tag/series.</li>
<li>Bonus: Disable the "clear" button when there is not a selected tag/series</li>
</ol>
<h3>Completed Sample Video</h3>
<video preload="auto" controls>
<source src="/sample.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
<hr />
</div>
<script src="https://code.jquery.com/jquery-3.2.1.js"></script>
<script type="module">
import TagBrowserWidget from '/js/app.js';
const myWidget = new TagBrowserWidget({
element: document.getElementById('tag-browser')
});
</script>
</body>
</html>

48
public/js/app.js Normal file
View File

@@ -0,0 +1,48 @@
export default class TagBrowserWidget {
constructor(config) {
this.config = config;
this.fetchData()
//use .bind because native promises change the "this" context
.then(this.setData.bind(this))
.then(this.getElements.bind(this))
.then(this.bindEventListeners.bind(this))
.then(this.render.bind(this));
console.log('Widget Instance Created');
}
fetchData() {
return new Promise((resolve, reject) => {
//ajax the data and resolve the promise when it comes back
$.get('/js/data.json', resolve);
});
}
setData(data) {
this.data = data;
console.log('Data fetched', this.data);
}
getElements() {
this.tagList = this.config.element.querySelectorAll('.tag-list')[0];
//find and store other elements you need
}
bindEventListeners() {
this.tagList.addEventListener('click', this.tagListClicked.bind(this));
//bind the additional event listener for clicking on a series title
}
render() {
//render the list of tags from this.data into this.tagList
}
tagListClicked(event) {
console.log('tag list (or child) clicked', event);
//check to see if it was a tag that was clicked and render
//the list of series that have the matching tags
}
}

162
public/js/data.json Normal file
View File

@@ -0,0 +1,162 @@
[
{
"type": "series",
"rating": "TV-14",
"episodes": 10,
"id": 5140,
"tags": ["melodrama", "romance", "time travel"],
"sourceCountry": "Korea",
"description":
"Kang Shin Woo (Lee Jung Shin, My Sassy Girl) is a math teacher who never forgot how he didn't buck up the courage to confess his feelings for the girl of his dreams back in high school. Now an eerie twist of fate will pull him back into the past and finds himself face-to-face with a familiar face.His first love is none other than Han Ji Soo (Lee Yeol Eum, Monster). A kind and attractive student, she harbors a painful secret. Since Shin Woo didn't end up with her the first time, he knows that this is his second shot at love. Unfortunately for him, he's got stiff competition: his younger self, Kang Shin woo (Seo Ji Hoon, Solomon's Perjury). Will Shin Woo fight for his teenage heart or for his own? It's a battle between two men from two different times, yet only one can win out.Based on the webtoon “Aeganjang” by Kim Hee Ran and Kim Byung Gwan, Longing Heart is directed by Min Yeon Hong and adapted by Park Ga Yeon.",
"title": "Longing Heart",
"nativeLanguageTitle": "애간장",
"thumbnail":
"https://imgix-media.dramafever.com/asset/series/5140/5a53d48d/box.jpg?w=350"
},
{
"type": "series",
"rating": "TV-14",
"episodes": 75,
"id": 4922,
"tags": [
"melodrama",
"historical",
"romance",
"war",
"fantasy",
"period drama",
"based on a novel"
],
"sourceCountry": "China",
"description":
"Prince Sheng Muyun (Huang Xuan, Imperial Doctress, Les Interprètes) is hated in the palace. The child of the human king and a spirit mother, he is considered unfit to lead the Duan dynasty because prophecy says his leadership will destroy the world. When his father and brothers die, he is pushed to lead. But Sheng Muyun doesnt care about the throne. His only interest is the mysterious woman (Janice Man) he sees inside a magical gem.Upon learning of a horrible truth, Sheng Muyun escapes the palace, leaving the throne to his uncle. But the prophecy has something else in mind.Heye Shuo Feng (Zhou Yi Wei) is the leader of the nomadic tribes. Brave and insightful, he is a worthy opponent, even for an empire. When he sees the prince has left the castle, he launches an all-out attack. His goal is to give the nomadic people their own land, and he is willing to see the Duan fall to make that happen.Han Jiang Muru (Shawn Dou, Princess Agents) is the son of an exiled general. Because of a prophecy that declared him a future monarch, he was abandoned by his own father, who was loyal to no one but the royal family. Han Jiang Muru knows neither his destiny nor Yu Ning Su (Xu Lu, Singles Villa), the woman destined to become Empress.When Muru Han Jiang reluctantly joins forces with the returning Prince Sheng Muyun to regain his throne, the prophecies start coming true. But this prophecy is a storm, and storms end in disaster.Tribes and Empires: The Storm of Prophecy is directed by Cao Dun. The drama is based on the hit novel of the same name by Jin Hezai. It first aired in 2017.",
"title": "Tribes and Empires: The Storm of Prophecy - 九州·海上牧云记",
"nativeLanguageTitle": "九州·海上牧雲記",
"thumbnail":
"https://imgix-media.dramafever.com/asset/series/4922/5a270d40/box.jpg?w=350"
},
{
"type": "movie",
"rating": "TV-14",
"episodes": 1,
"id": 5133,
"tags": [
"mystery",
"thriller",
"action",
"crime",
"comedy",
"feature film"
],
"sourceCountry": "Korea",
"description":
"College student Min Jae (Im Si Wan, Incomplete Life: Misaeng) is a small-time swindler. He meets forger Suk Goo (Jin Goo, Descendants of the Sun), who is a higher-end thief. Min Jae robs some of Suk Goos money and soon finds himself at the mercy of Ji Won (Park Byung Eun, Queen of Mystery), Suk Goos vicious enforcer. Suk Goo has an eye for talent. Instead of punishing the young crook, he decides to enlist Min Jae into his fraud syndicate. They work well together, but rifts soon develop between Suk Goo and Ji Won. Min Jae gets caught in the middle. With the law on their tail and distrust between them, the three men soon learn that the difference between friend and enemy is just one, thin line.One-Line is directed by Yang Kyung Mo. It released in 2017.",
"title": "One-Line",
"nativeLanguageTitle": "원라인",
"thumbnail":
"https://imgix-media.dramafever.com/asset/series/5133/5a251634/box.jpg?w=350"
},
{
"type": "series",
"rating": "TV-14",
"episodes": 10,
"id": 4062,
"tags": ["romantic comedy", "romance", "fantasy"],
"sourceCountry": "Korea",
"description":
"This is the original version of The Bride of the Water God that the 2017 remake is based on.",
"title": "The Bride of the Water God (Habaek)",
"nativeLanguageTitle": "하백의 신부 2000",
"thumbnail":
"https://imgix-media.dramafever.com/asset/series/5060/5a53e295/box.jpg?w=350"
},
{
"type": "series",
"rating": "TV-14",
"episodes": 16,
"id": 5116,
"tags": ["romantic comedy", "romance", "comedy"],
"sourceCountry": "Korea",
"description":
"Attention drama fans! The first 5 episodes of Revolutionary Love are now free to watch! Sign up for Premium to enjoy full access to all of your favorite dramas!In this comedic tale of riches to rags, Byun Hyuk (Choi Si Won, She Was Pretty) is the narcissistic and carefree heir to Gangsu Group, but also a die-hard romantic who chooses the ordinary life after meeting the girl of his dreams.His lofty ideas of romance and the belief that people are inherently good adds to his naïveté, which spurs him to leave his opulent living quarters and move into a cramped studio apartment and actually work to make a living. His zero life experience pales in comparison to the girl he hopes to woo, Baek Joon (Kang So Ra, Jeju Island Gatsby). A college grad unable to land a full-time position, Baek Joon has to work numerous part-time jobs in order to make ends meet. Her strong-willed, optimistic outlook on life keeps her afloat, but no amount of positivity can prepare her for the seemingly incompetent Byun Hyuk.If there's anyone who can keep Byun Hyuk in line, it's his secretary, Kwon Jae Hoon (Gong Myung, The Bride of the Water God). Handsome and mature, Jae Hoon dreams of rising above his humble roots and someday living the life of luxury Byun Hyuk has left behind. Too bad that caring for an immature heir is a 24/7 gig.Revolutionary Love (alternatively known as Byun Hyuk's Love) is directed by Song Hyun Wook (My Shy Boss, Another Oh Hae Young) and written by Joo Hyun (Ms. Temper and Nam Jung Gi).",
"title": "Revolutionary Love",
"nativeLanguageTitle": "변혁의 사랑",
"thumbnail":
"https://imgix-media.dramafever.com/asset/series/5116/59d29387/box.jpg?w=350"
},
{
"type": "series",
"rating": "TV-14",
"episodes": 40,
"id": 5104,
"tags": ["romance", "comedy", "drama", "romantic comedy"],
"sourceCountry": "Korea",
"description":
"Attention drama fans! The first 10 episodes of Temperature of Love are now free to watch! Sign up for Premium to enjoy full access to all of your favorite dramas!Seo Hyun Jin (Doctor Romantic, Another Oh Hae Young) and Yang Se Jong (Duel, Saimdang: Lights Diary) star in a romantic-comedy about the perils of finding love in a digital world. But when the young writer and aspiring cook finally meet in real life after getting acquainted online, they quickly find out how little they actually know about one another.Lee Hyun Soo (Seo Hyun Jin) is confident, honest and the graduate of a prestigious university. After 10 years as an assistant writer, she is finally getting some well-earned recognition as a screenwriter, and unlike the theatrics in dramas, the pragmatic writer doesn't believe in concepts such as \"love at first sight.\"French food chef Jung Sun (Yang Se Jong) is the owner of the highly-regarded restaurant Good Soup. He is competitive, charming and immensely talented. Having attended culinary school in Paris, Jung Sun is also very confident in his own intuition and doesnt believe in the traditional hierarchy typically found in the kitchen. Past his exterior confidence, though, is a man scarred by his relationship with his mother, who lives her life with cold practicality, whereas he lives on passion and instinct.Hyun Soo and Jung Sun meet in an online forum under the usernames “Jane” and “Good Soup,\" respectively. In spite of their opposing personalities, they begin chatting and falling for each other. But online forums can only tell you so much about a person.Ji Hong Ah (Jo Bo Ah from Sweet Stranger and Me) is the daughter of a successful CEO, and is also an aspiring drama writer. Unlike her friend, she has little need for money and lives life with the knowledge that everything will be handed to her. Whenever she is with Hyun Soo, she gets all the attention--until she meets and falls in love with respected chef Jung Sun, that is.Park Jung Woo (Kim Jae Wookfrom Voice) is the CEO of a successful entertainment agency. A huge fan of Jung Suns cooking, Park Jung Woo was actually the primary investor in Good Soup. He shares a good relationship with Jung Soo, until he falls for Hyun Soo and starts seeing the chef as a rival.Together, these four wildly different friends and budding lovers try to navigate life, butting heads with each other along the way. But even in the digital age, Google cant provide all the answers. As they soon learn, online-only acquaintances cant handle the temperature of love.Temperature of Love is directed by Nam Gun (Daebak). The series is based on the 2013 novel “Nice Soup Does Not Answer the Phone” by screenwriter Ha Myung Hee (Doctor Crush, Can We Get Married). The series reunites Seo Hyun JIn and Yang Se Jong, who last worked together on Doctor Romantic.",
"title": "Temperature of Love",
"nativeLanguageTitle": "사랑의 온도",
"thumbnail":
"https://imgix-media.dramafever.com/asset/series/5104/59c9102d/box.jpg?w=350"
},
{
"type": "series",
"rating": "TV-14",
"episodes": 40,
"id": 5101,
"tags": ["romance", "medical"],
"sourceCountry": "Korea",
"description":
" Attention drama fans! The first 10 episodes of Hospital Ship are now free to watch! Sign up for Premium to enjoy full access to all of your favorite dramas!Ha Ji Won (The Time That I Loved You, 7000 Days, Secret Garden), Kang Min Hyuk (The Entertainer, Heirs) and Lee Seo Won (Lovely Love Lie, Uncontrollably Fond) star in a medical drama about a group of doctors who go above and beyond to fulfill their duties. When three very different doctors join forces aboard a traveling hospital ship, they learn the only challenge more daunting than medicine is getting along with your colleagues.Too many live without quality healthcare. In order to change that, a caring humanitarian starts a hospital ship, a traveling medical center for dedicated doctors to reach their patients. These excellent doctors quickly discover that the seas aren't the only challenge in the workplace.Song Eun Jae (Ha Ji Won) is an immensely talented surgeon. There was a time when the hospital ship was just used for standard checkups and administering medicine. With Song Eun Jae on board, it can provide complicated surgery. She has seen a lot of success as a surgeon, but also a lot of struggles in her family life. When an unfortunate incident leads her to a ship instead of a prestigious hospital, she has little compassion for the stubborn elderly patients.Kwak Hyun (Kang Min Hyuk) is the emotional opposite of his senior doctor, Song Eun Jae. Growing up with a father who is a lauded humanitarian, Kwak Hyun strives to be a warm and caring person. He heals not just with medicine but a smile. It seems natural that he work at his fathers ship, but Kwak Hyun also has some emotional scars. He cannot match Song Eun Jaes medical skills, but he is infinitely better at connecting with patients.Kim Jae Geol (Lee Seo Won) has Hallyu looks and an extensive lineage in medicine. His father is a respected doctor. Growing up, his dad always preferred his brilliant brother, which led Jae Geol to become a loner at heart. His father was obsessed with western medicine. As a form of rebellion, Kim Jae Gol studied oriental medicine, much to his fathers disapproval. His goal in boarding the ship was to escape his fathers shadow. At the ship, however, he must work under Song Eun Jae, who is just as strict, emotionless and disdainful of oriental medicine.Now these three doctors have to put aside their polar opposite personalities in order to treat their patients. As they all soon learn, working for your fellow humans has its own way of bringing people together. Hospital Ship is directed by Park Jae Bum (A New Leaf, I Miss You) and written by Yoon Sun Joo (Secret Door).New episodes added every Wednesday and Thursday for Premium users only. Available to all users one week later.",
"title": "Hospital Ship",
"nativeLanguageTitle": "병원선",
"thumbnail":
"https://imgix-media.dramafever.com/asset/series/5101/59c90bc4/box.jpg?w=350"
},
{
"type": "series",
"rating": "TV-Y",
"episodes": 20,
"id": 4274,
"tags": [
"romantic comedy",
"comedy",
"family relationships",
"Staff Favorites"
],
"sourceCountry": "Korea",
"description":
"A worthy successor to the international hit Boys Over Flowers, Heirs follows a group of privileged, elite high school students as they are groomed to take over their families' business empires. These wealthy students seem to have everything under controlexcept their love lives. Kim Tan (Lee Min Ho) is heir to the Empire Group sent to study abroad in the U.S. In reality it's a form of exile, as his elder half-brother back home (Choi Jin Hyuk) schemes to take over the family business. While in the States, Kim Tan bumps into Cha Eun Sang (Park Shin Hye), who's arrived from Korea in search of her older sister. He feels himself falling for her, never realizing that she's the daughter of his family's housekeeper. When his fiancée Rachel Yoo (Kim Ji Won) arrives to bring him back to Korea, his heart is torn between love and duty. Meanwhile, Rachel's half-brother Choi Young Do (Kim Woo Bin) develops his own crush on Eun Sang. Who said being a rich, beautiful high school student was easy?",
"title": "Heirs",
"nativeLanguageTitle": "왕관을 쓰려는자, 그무게를 견뎌라-상속자들",
"thumbnail":
"https://imgix-media.dramafever.com/asset/series/4274/59c90be3/box.jpg?w=350"
},
{
"type": "series",
"rating": "TV-14",
"episodes": 16,
"id": 5060,
"tags": ["romantic comedy", "romance", "fantasy", "based on a manga"],
"sourceCountry": "Korea",
"description":
" Attention drama fans! The first 5 episodes of The Bride of the Water God (Habaek) are now free to watch! Sign up for Premium to enjoy full access to all of your favorite dramas!Nam Joo Hyuk (Weightlifting Fairy Kim Bok Joo, Scarlet Heart: Ryeo) and Shin Se Kyung (Six Flying Dragons) star in a modern retelling of a supernatural romance. When the god of water descends upon Earth and seeks the help of his destined bride, he first has to convince her that he isnt a delusional maniac.Habaek (Nam Joo Hyuk) is a water god. Dont let the legends fool you, though. Gone are the days of gods being old men in robes. Habaek is a chic youth with impeccable fashion and flawless hair. He is also narcissistic and wants his heavenly throne at all costs. Habaek comes to Earth to find a magical stone that will grant him the power he wants. And he expects his destined bride and servant to help him. Just one problem, though: His bride does not believe he even exists.So Ah (Shin Se Kyung) is a psychiatrist. She has her own practice, but she is also buried in debt. Her family is allegedly cursed to serve the gods forever. However, So Ah is a realist with no time for superstition. So when the doctor meets a man who claims to be the legendary water god and who expects her to serve him as his bride, her diagnosis is that he is simply delusional.And before Habaek can convince his wife of who he is and what he needs, some of his “friends” join him on Earth.Hoo Ye (Im Ju Hwan from Uncontrollably Fond) is a demigod. A CEO of a resort, Hoo Ye also happens to fall in love with So Ah and therefore becomes Habaeks main rival. Moo Ra (f(x) and Heirs Krystal Jung) is a water goddess. A beautiful and famous actress, Moo Ra has a one-sided love with Habaek and understandably dislikes his wife. Bi Ryeom (Gong Myung of 5urprise and Drinking Solo) is a wind god who secretly loves Moo Ra and holds a grudge against the man that she loves.With all these people gunning for them, it is now up to Habaek and So Ah to find the magical stone and restore a balance of power in the heavens. If they can stop bickering first, that is.Directed by Kim Byung Soo (Nine, Queen In Hyuns Man) and written by Jung Yoon Jung (Incomplete Life (Misaeng), Arang and the Magistrate), The Bride of the Water God is a modern take on the popular historical fantasy manhwa Bride of the Water God. The dramas original broadcast period is from July 03, 2017 to August 22, 2017 on tvN.",
"title": "The Bride of the Water God (Habaek)",
"nativeLanguageTitle": "하백의 신부 2017",
"thumbnail":
"https://imgix-media.dramafever.com/asset/series/5060/5a53e295/box.jpg?w=350"
},
{
"type": "series",
"rating": "TV-14",
"episodes": 16,
"id": 5059,
"tags": ["romance"],
"sourceCountry": "Korea",
"description":
"Attention drama fans! The first 5 episodes of Strongest Deliveryman are now free to watch! Sign up for Premium to enjoy full access to all of your favorite dramas!Go Kyung Pyo (Flower Boy Next Door, Jealousy Incarnate) and Chae Soo Bin(Moonlight Drawn by Clouds) star in a drama about two people who find both love and success, but only after lifting some heavy burdens. When two fearless and dedicated delivery workers are born without a silver spoon in their mouths, they are convinced to overcome their obstacles and make it to the top.Choi Kang Soo (Go Kyung Pyo) is a deliveryman. In spite of his humble beginnings, Choi Kang Soo is fearless and gives it all in everything he does. He dreams of becoming a CEO of a delivery app company someday, but life just throws more than a few roadblocks in his way. Lee Dan Ah (Chae Soo Bin) is another delivery worker. She hates her current socioeconomic status so much that she, like many young people, calls her country “Hell Joseon.” Lee Dan Ah is so focused on making money and changing her life that she has no time for men. But when she comes across the charming Choi Kang Soo, her attitude is due to be moved.Together, Choi Kang Soo and Lee Dan Ah have a budding competition and romance in their quest for glory. And, for them, glory means being like rich folk Lee Jin Yoon (Go Won Heefrom Tabloid Truth) and Oh Jin Gyoo (Kim Sun Ho from Chief Kim). They compete to conquer life but, as our two delivery workers soon learn, being the strongest does not guarantee sucess.Also known as “Best Deliveryman,” Strongest Deliveryman is written by Lee Jung Woo (Joseon Gunman) and directed by Jun Woo Sung. ",
"title": "Strongest Deliveryman",
"nativeLanguageTitle": "최강 배달꾼",
"thumbnail":
"https://imgix-media.dramafever.com/asset/series/5059/59c90ecd/box.jpg?w=350"
}
]

BIN
public/sample.mp4 Normal file

Binary file not shown.

View File

@@ -1,68 +0,0 @@
angular.module('weather', [])
.controller('forecast', ['$http', '$scope', function($http, $scope){
const _this = this;
let default_city = 'New York, NY';
// recall the existing city or display the default
$scope.name = $scope.name || default_city;
// holds the 48 conditions and their corresponding icons
_this.conditions = new Array(12);
/***
* there are 48 different condition codes that the api can return
* this method makes those conditions and their corresponding icon mapping
* available to the rest of the controller
**/
var GetConditionMap = function() {
var success = function(response) {
_this.conditions = response.data;
};
const error = function(response) {
};
$http.get('conditions.json').then(success, error);
}
/***
* this method is expected to set the forecast objects
**/
$scope.getWeather = function(city) {
var success = function(response) {
var data = response.data.query.results.channel;
$scope.location = data.location;
$scope.item = data.item;
};
let Error = function(response) {
};
$http.get(`http://query.yahooapis.com/v1/public/yql?q=select * from weather.forecast where woeid in (select woeid from geo.places(1) where text="${city}")&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys`)
.then(success, Error);
}
/***
* this method is expected to return the icon for the corresponding condition code
* from the codeToCondition map file
**/
$scope.getIcon = function(code) {
return _this.conditions.filter(condition => condition.code == code)[0].icon;
};
/***
* load the condition code map
* this maps the condition code returned from the api to the corresponding icon
*/
setTimeout(GetConditionMap,
5000);
/***
* load weather for the default city
*/
// $scope.getWeather(name);
}]);

View File

@@ -1,4 +0,0 @@
@import "styles/colors";
@import "styles/page"
@import "styles/menu";
@import "styles/weather";

View File

@@ -1,116 +0,0 @@
// testing controller
describe('The weather app', function() {
var $httpBackend,
$scope,
;
// Set up the module
beforeEach(module('weather'));
beforeEach(inject(function($injector) {
$httpBackend = $injector.get('$httpBackend');
$scope = $injector.get('$rootScope');
var $controller = $injector.get('$controller');
createController = function() {
return $controller('forecast', {'$scope' : $scope });
};
}));
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
describe('condition map', function(){
beforeEach(function(){
});
it('should throw an error when the condition map cannot be loaded.', function(){
$httpBackend.whenGET(/conditions/).respond(200, {});
$httpBackend.whenGET(/query.yahooapis.com/).respond(200, readJSON('./src/forecast.json'));
var controller = createController();
expect(controller.conditions).not.toBe(undefined);
expect( controller.conditions.length ).toBe(0);
expect(controller.conditions.length).toBe(0);
expect(controller.conditions[1]).toBe(undefined);
});
it('should load all known conditions.', function(){
$httpBackend.whenGET(/conditions/).respond(200, readJSON('./src/conditions.json'));
$httpBackend.whenGET(/query.yahooapis.com/).respond(200, readJSON('./src/forecast.json'));
var controller = createController();
expect(controller.conditions).not.toBe(undefined);
expect(controller.conditions.length).toBe(0);
$httpBackend.flush();
expect(controller.conditions.length).toBe(49);
expect(controller.conditions[1].code).toBe(1);
expect(controller.conditions[1].icon).toBe('wi-storm-showers');
});
});
describe('with condition map successfully loaded', function() {
beforeEach(function(){
});
it('should gracefully handle a weather forecast that cannot be loaded.', function() {
$httpBackend.whenGET(/query.yahooapis.com/).respond(500, {});
var controller = createController();
$httpBackend.flush() ;
expect($scope.item).toBe(undefined);
expect($scope.location).toBe(undefined);
});
it('should load a weather forecast for a default location.', function() {
$httpBackend.whenGET(/query.yahooapis.com/).respond(200, readJSON('./src/forecast.json'));
var controller = createController();
expect($scope.item).toBe(undefined);
expect($scope.location).toBe(undefined);
$httpBackend.flush();
expect( $scope.item ).not.toBe(undefined);
expect($scope.location).not.toBe(undefined);
expect($scope.location.city).toBe('New York');
// expect($scope.item.condition.code).toBe('29');
});
});
describe('with condition map and forecast successfully loaded', function() {
beforeEach(function(){
$httpBackend.whenGET(/conditions/).respond(200, readJSON('./src/conditions.json'));
$httpBackend.whenGET(/query.yahooapis.com/).respond(readJSON('./src/forecast.json'));
var controller = createController();
$httpBackend.flush();
});
it('should provide an icon for the provided weather code.', function(){
var icon = $scope.getIcon('29');
expect(icon).toBe('wi-night-partly-cloudy');
});
});
});

View File

@@ -1,51 +0,0 @@
[
{ "code": 0, "icon": "wi-tornado", "text": "tornado" },
{ "code": 1, "icon": "wi-storm-showers", "text": "tropical storm" },
{ "code": 2, "icon": "wi-hurricane", "text": "hurricane" },
{ "code": 3, "icon": "wi-thunderstorm", "text": "severe thunderstorms" },
{ "code": 4, "icon": "wi-day-sunny", "text": "thunderstorms" },
{ "code": 5, "icon": "wi-sleet", "text": "mixed rain and snow" },
{ "code": 6, "icon": "wi-sleet", "text": "mixed rain and sleet" },
{ "code": 7, "icon": "wi-sleet", "text": "mixed snow and sleet" },
{ "code": 8, "icon": "wi-rain-mix", "text": "freezing drizzle" },
{ "code": 9, "icon": "wi-rain", "text": "drizzle" },
{ "code": 10, "icon": "wi-rain-mix", "text": "freezing rain" },
{ "code": 11, "icon": "wi-showers", "text": "showers" },
{ "code": 12, "icon": "wi-showers", "text": "showers" },
{ "code": 13, "icon": "wi-snow", "text": "snow flurries" },
{ "code": 14, "icon": "wi-snow", "text": "light snow showers" },
{ "code": 15, "icon": "wi-snow", "text": "blowing snow" },
{ "code": 16, "icon": "wi-snow", "text": "snow" },
{ "code": 17, "icon": "wi-hail", "text": "hail" },
{ "code": 18, "icon": "wi-sleet", "text": "sleet" },
{ "code": 19, "icon": "wi-dust", "text": "dust" },
{ "code": 20, "icon": "wi-fog", "text": "foggy" },
{ "code": 21, "icon": "wi-day-haze", "text": "haze" },
{ "code": 22, "icon": "wi-smoke", "text": "smoky" },
{ "code": 23, "icon": "wi-day-windy", "text": "blustery" },
{ "code": 24, "icon": "wi-day-windy", "text": "windy" },
{ "code": 25, "icon": "wi-thermometer-exterior", "text": "cold" },
{ "code": 26, "icon": "wi-cloudy", "text": "cloudy" },
{ "code": 27, "icon": "wi-night-cloudy", "text": "mostly cloudy (night)" },
{ "code": 28, "icon": "wi-day-cloudy", "text": "mostly cloudy (day)" },
{ "code": 29, "icon": "wi-night-partly-cloudy", "text": "partly cloudy (night)" },
{ "code": 30, "icon": "wi-day-cloudy", "text": "partly cloudy (day)" },
{ "code": 31, "icon": "wi-night-clear", "text": "clear (night)" },
{ "code": 32, "icon": "wi-day-sunny", "text": "sunny" },
{ "code": 33, "icon": "", "text": "fair (night)" },
{ "code": 34, "icon": "", "text": "fair (day)" },
{ "code": 35, "icon": "wi-day-rain-mix", "text": "mixed rain and hail" },
{ "code": 36, "icon": "wi-hot", "text": "hot" },
{ "code": 37, "icon": "wi-thunderstorm", "text": "isolated thunderstorms" },
{ "code": 38, "icon": "wi-thunderstorm", "text": "scattered thunderstorms" },
{ "code": 39, "icon": "wi-thunderstorm", "text": "scattered thunderstorms" },
{ "code": 40, "icon": "wi-thunderstorm", "text": "scattered showers" },
{ "code": 41, "icon": "wi-snow", "text": "heavy snow" },
{ "code": 42, "icon": "wi-snow", "text": "scattered snow showers" },
{ "code": 43, "icon": "wi-snow", "text": "heavy snow" },
{ "code": 44, "icon": "wi-cloud", "text": "partly cloudy" },
{ "code": 45, "icon": "wi-storm-showers", "text": "thundershowers" },
{ "code": 46, "icon": "wi-snow", "text": "snow showers" },
{ "code": 47, "icon": "wi-thunderstorm", "text": "isolated thundershowers" },
{ "code": 3200, "icon": "wi-na", "text": "not available" }
]

View File

@@ -1,138 +0,0 @@
{
"query": {
"count": 1,
"created": "2016-07-13T02:37:36Z",
"lang": "en-US",
"results": {
"channel": {
"units": {
"distance": "mi",
"pressure": "in",
"speed": "mph",
"temperature": "F"
},
"title": "Yahoo! Weather - New York, NY, US",
"link": "http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-2459115/",
"description": "Yahoo! Weather for New York, NY, US",
"language": "en-us",
"lastBuildDate": "Tue, 12 Jul 2016 10:37 PM EDT",
"ttl": "60",
"location": {
"city": "New York",
"country": "United States",
"region": " NY"
},
"wind": {
"chill": "75",
"direction": "180",
"speed": "22"
},
"atmosphere": {
"humidity": "73",
"pressure": "1016.0",
"rising": "0",
"visibility": "16.1"
},
"astronomy": {
"sunrise": "5:36 am",
"sunset": "8:27 pm"
},
"image": {
"title": "Yahoo! Weather",
"width": "142",
"height": "18",
"link": "http://weather.yahoo.com",
"url": "http://l.yimg.com/a/i/brand/purplelogo//uh/us/news-wea.gif"
},
"item": {
"title": "Conditions for New York, NY, US at 09:00 PM EDT",
"lat": "40.71455",
"long": "-74.007118",
"link": "http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-2459115/",
"pubDate": "Tue, 12 Jul 2016 09:00 PM EDT",
"condition": {
"code": "29",
"date": "Tue, 12 Jul 2016 09:00 PM EDT",
"temp": "75",
"text": "Partly Cloudy"
},
"forecast": [{
"code": "30",
"date": "12 Jul 2016",
"day": "Tue",
"high": "81",
"low": "69",
"text": "Partly Cloudy"
}, {
"code": "47",
"date": "13 Jul 2016",
"day": "Wed",
"high": "83",
"low": "71",
"text": "Scattered Thunderstorms"
}, {
"code": "4",
"date": "14 Jul 2016",
"day": "Thu",
"high": "85",
"low": "74",
"text": "Thunderstorms"
}, {
"code": "4",
"date": "15 Jul 2016",
"day": "Fri",
"high": "92",
"low": "77",
"text": "Thunderstorms"
}, {
"code": "30",
"date": "16 Jul 2016",
"day": "Sat",
"high": "85",
"low": "75",
"text": "Partly Cloudy"
}, {
"code": "30",
"date": "17 Jul 2016",
"day": "Sun",
"high": "87",
"low": "75",
"text": "Partly Cloudy"
}, {
"code": "4",
"date": "18 Jul 2016",
"day": "Mon",
"high": "85",
"low": "74",
"text": "Thunderstorms"
}, {
"code": "4",
"date": "19 Jul 2016",
"day": "Tue",
"high": "85",
"low": "74",
"text": "Thunderstorms"
}, {
"code": "4",
"date": "20 Jul 2016",
"day": "Wed",
"high": "84",
"low": "73",
"text": "Thunderstorms"
}, {
"code": "30",
"date": "21 Jul 2016",
"day": "Thu",
"high": "84",
"low": "73",
"text": "Partly Cloudy"
}],
"description": "<![CDATA[<img src=\"http://l.yimg.com/a/i/us/we/52/29.gif\"/>\n<BR />\n<b>Current Conditions:</b>\n<BR />Partly Cloudy\n<BR />\n<BR />\n<b>Forecast:</b>\n<BR /> Tue - Partly Cloudy. High: 81Low: 69\n<BR /> Wed - Scattered Thunderstorms. High: 83Low: 71\n<BR /> Thu - Thunderstorms. High: 85Low: 74\n<BR /> Fri - Thunderstorms. High: 92Low: 77\n<BR /> Sat - Partly Cloudy. High: 85Low: 75\n<BR />\n<BR />\n<a href=\"http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-2459115/\">Full Forecast at Yahoo! Weather</a>\n<BR />\n<BR />\n(provided by <a href=\"http://www.weather.com\" >The Weather Channel</a>)\n<BR />\n]]>",
"guid": {
"isPermaLink": "false"
}
}
}
}
}
}

View File

@@ -1,76 +0,0 @@
<!DOCTYPE html>
<html ng-app="weather">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Weather or Not</title>
<link rel="stylesheet" href="./libs/weather-icons/css/weather-icons.css">
<link rel="stylesheet" href="./libs/font-awesome/css/font-awesome.css">
<link rel="stylesheet" href="//fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="frontend-developer-challenge.css">
<script src="./libs/angular/angular.js"></script>
<script src="frontend-developer-challenge.js"></script>
</head>
<body ng-controller="forecast" ng-class="theme">
<div class="menu" ng-class="{'open': showMenu}">
<div class="tab" ng-click="showMenu == !showMenu">
<i class="material-icons open">menu</i>
<i class="material-icons close">close</i>
</div>
<h1>Select a City</h2>
<form name="city" ng-submit="getWeather(name); showMenu = false;">
<input ng-model="name" autocomplete="off" onfocus="this.select();" ng-class="theme" required>
<div ng-messages="city.name.$error" ng-show="city.name.$dirty">
We can't find weather for you if you don't give us a city to lookup.
</div>
</form>
<h2>Theme</h1>
<ul class="theme">
<li class="Color mojo" ng-click="theme='mojo'">&nbsp;</li>
<li class="color governor-bay" ng-click="theme='governor-bay'"></li>
<li class="color bluewood" ng-click="theme='bluewood'"></li>
<li class="color fire-bush" ng-click="theme='fire-bush'"></li>
<li class="color thunder" ng-click="theme='thunder'"></li>
<li class="color burnt-sienna" ng-click="theme='burnt-sienna'"></li>
<li class="color wine-berry" ng-click="theme='wine-berries"></li>
<li class="color tom-thumb" ng-click="theme='tom-thumb'"></li>
<li class="color vistas" ng-click="theme='vista'"></li>
</ul>
</div>
<div class="weather">
<ul class="forecast">
<li class="day now">
<div class="icon">
<i class="wi" ng-class="getIcon(item.condition.code)"></i>
</div>
<div class="temp">{{item.condition.temp}}<i class="wi wi-celsius"></i></div>
<div class="name">Now</div>
<div class="text">{{ item.condition.text }}</div>
</li>
<li class="day future" ng-repeat="forecast in item.forecast | limitTo:4">
<div class="icon">
<i class="wi" ng-class="getIcon(forecast.code)"></i>
</div>
<div class="temp">
<span class="high"><span ng-bind="forecast.high">{{ forecast.high }}</span><i class="wi wi-degrees"></i></span>
<span class="low"><span ng-bind="forecast.low"></span><i class="wi wi-degrees"></i></span>
</div>
<div class="name" ng-bind="forecast"></div>
<div class="text" ng-bind="forecast.text"></div>
</li>
</ul>
<div class="city">"{{ location.city }}, {{ location.region }}</div>
</div>
</body>
</html>

View File

@@ -1,11 +0,0 @@
// define theme colors
$mojo: rgb(195, 77, 64);
$governor-bay: rgb(66,66,186);
$bluewood: rgb(46, 60,86);
$fire-bush: rgb(229, 156, 47);
$burnt-sienna: rgb(234,114, 76);
$wine-berry: rgb(92, 37,51);
$tom-thumb: rgb(45, 68, 47);
$thunder: rgb(65, 47, 63);
$vista: rgb(141, 211, 151);
;

View File

@@ -1,109 +0,0 @@
.menu {
background-color: rgba(255, 255, 255, 0.8);
height: 100%;
left: -20em;
min-width: 200px;
padding: 0 1em;
position: fixed;
transition: all .6s cubic-bezier(.9,0,.33,1) .2s;
width: 20em;
z-index: 1;
// styles for the hamburger
.tab {
position: absolute;
width: 50px;
height: 50px;
right: -50px;
cursor: pointer;
padding: 7px 9px;
border-left: 0;
border-radius: 10px 10px 10px 10px;
transition: right .6s cubic-bezier(.9,0,.33,1) .2s;
i {
position: absolute;
top: 7px;
left: 9px;
transition: opacity .6s cubic-bezier(.9,0,.33,1) .2s;
font-size: 36px;
}
.open {
color: rgba(255, 255, 255, 0.4);
opacity: 1;
}
.close {
color: rgba(0, 0, 0, 0.4);
opacity: 0;
}
}
input {
background-color: rgba(0,0,0,0);
border-bottom-color: rgba($mojo, .6);
border-width: 0 0 2px 0;
font-size: 1.25em;
font-style: italic;
width: 250px;
text-transform: capitalize;
transition: border-bottom-color .6s ease;
&.mojo {border-bottom-color: rgba($mojo, .6);}
&.governor-bay {border-bottom-color: rgba($governor-bay, .6);}
&.bluewood {border-bottom-color: rgba($bluewood, .6);}
&.fire-bush {border-bottom-color: rgba($fire-bush, .6);}
&.burnt-sienna {border-bottom-color: rgba($burnt-sienna, .6);}
&.wine-berry {border-bottom-color: rgba($wine-berry, .6);}
&.tom-thumb {border-bottom-color: rgba($tom-thumb, .6);}
&.thunder {border-bottom-color: rgba($thunder, .6);}
&.vista {border-bottom-color: rgba($vista, .6);}
}
// styles for the theme selector
.theme{
border-radius: 15px;
overflow: hidden;
width: 75%;
margin: auto;
padding: 0;
.color {
width: 33%;
margin: 1px;
height: 60px;
position: relative;
float: left;
cursor: move;
&:after {content: "\00a0";}
&.mojo {background: $mojo;}
&.governor-bay {background: $governor-bay;}
&.bluewood {background: $bluewood;}
&.fire-bush {background: $fire-bush;}
&.burnt-sienna {background: $burnt-sienna;}
&.wine-berry {background: $wine-berry;}
&.tom-thumb {background: $tom-thumb;}
&.thunder {background: $thunder;}
&.vista {background: $vista;}
}
}
// styles when menu is open
&.open {
left: 0;
box-shadow: 0 0 20px 10px rgba(27, 255, 34, 0.3);
.tab {
top: 25px;
right: 0px;
.open {opacity: 0;}
.close {opacity: 1;}
}
}
}

View File

@@ -1,49 +0,0 @@
// breakpoints
$tiny: 25em;
$small: 42em;
$medium: 75em;
$large: 90em;
$xlarge: 120em;
html {
height: 100%;
}
*:focus {outline: none;}
*,::after,::before {
box-sizing: inherit
}
li {list-style-type: none;}
html {
font-size: 100%;
height: 100%
}
body {
background: $mojo;
box-sizing: border-box;
font-family: 'HelveticaNeue-UltraLight', 'Helvetica Neue UltraLight', 'Helvetica Neue', 'Open-Light', sans-serif;
font-weight: 400;
line-height: 1.5;
margin: 0;
padding: 0;
height: auto;
min-height: 100vh;
position: relative;
transition: background-color .6s ease;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
&.mojo {background: $mojo;}
&.governor-bay {background: $governor-bay;}
&.bluewood {background: $mojo;}
&.fire-bush {background: $fire-bush;}
&.burnt-sienna {background: $burnt-sienna;}
&.wine-berry {background: $wine-berry;}
&.tom-thumb {background: $tom-thumb;}
&.thunder {background: $thunder;}
&.vista {background: $vista;}
}

View File

@@ -1,127 +0,0 @@
.weather {
padding: 15% 10% 0;
position: relative;
.city {
COLORS: rgba(255, 255, 255, 0.4);
font-weight: bold;
font-size: .8em;
width: 80%;
margin: 5% auto;
TEXT-align: center;
}
.forecast {
width: 80%;
margin: auto;
padding: 0;
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
.day {
display: flex;
flex-wrap: nowrap;
justify-content: center;
align-items: center;
padding: 0;
margin: 0;
width: 20%;
min-width: 150px;
text-align: center;
color: rgba(255, 255, 255, 0.7);
div {
width: 100%;
}
.icon {
font-size: 3em;
Padding-Bottom: 25px;
}
.temp {
font-size: 2em;
font-weight: bold;
.low {
opacity: .4;
font-size: .8em;
}
}
.name {
font-size: 1.5em;
}
.text {
white-space: nowrap;
}
&.now {
.icon {
font-size: 8em;
padding-bottom: 0;
}
.name {
font-size: 2.5em;
}
.text {
font-size: 1.5em;
}
}
}
}
@media screen and (max-width: $medium) {
padding: 5vh;
.forecast {
width: 100%;
.day {
line-height: 1.25;
&:nth-child(4) {
padding-top: 15px;
}
&.now {
width: 100%;
padding-bottom: 40px;
.icon{
line-height: 1.5;
}
}
}
}
}
@media screen and (max-width: $small) and (max-width: 600px) {
.forecast {
.day {
padding-bottom: 40px;
line-height: 1.25;
&:nth-child(3) {
padding-bottom: 75px;
}
&.future {
width: 50%;
}
}
}
}
@media screen and (max-width: $tiny) {
.forecast {
.day {
&.future {
width: 100%;
}
}
}
}
}