diff --git a/README.md b/README.md index 7fad321..35f2f07 100644 --- a/README.md +++ b/README.md @@ -1 +1,50 @@ -# front-end-coding-challenge \ No newline at end of file +Front-End Coding Challenge +=== + +### Premise +It’s 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. + +We—as an industry—can do better. So, just how can we do better? + +### Solution +We developed this coding challenge to help us better gauge your technical abilities. This challenge: + +* can be completed on your own time +* where you are most comfortable +* on equipment you’re accustomed to +* using the tools you’re proficient with + +Basically, you have access to all the things that allow you to work best. + +We hope you’ll enjoy working through this challenge as much as we’ve enjoyed creating it for you. + +### Guidelines +Because we’re awful developers, this project isn’t quite ready to release. There are some broken pieces that we’d like you to fix. To do that, you’ll 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, it’s up to you to find them and fix them. + +**Q: How do I know if I’ve completed the challenge?** + +A: You don’t. But, that’s because _we_ don’t know either. + +**Q: I can’t 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 competancy with our stack. diff --git a/bower.json b/bower.json new file mode 100644 index 0000000..913c70a --- /dev/null +++ b/bower.json @@ -0,0 +1,34 @@ +{ + "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" + } +} diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..572db9e --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,144 @@ +'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')); +}); diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 0000000..b6eaefd --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,16 @@ +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'] + }, + }); +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..0c4fe52 --- /dev/null +++ b/package.json @@ -0,0 +1,45 @@ +{ + "name": "frontend-developer-challenge", + "version": "1.0.0", + "description": "Sheesh. There's a lot wrong with this project.", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/rprovost/code-test-creation.git" + }, + "keywords": [ + "frontend", + "challenge" + ], + "author": "Ryan Provost", + "license": "ISC", + "bugs": { + "url": "https://github.com/rprovost/code-test-creation/issues" + }, + "homepage": "https://github.com/rprovost/code-test-creation#readme", + "devDependencies": { + "browser-sync": "^2.13.0", + "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": {} +} diff --git a/src/app.js b/src/app.js new file mode 100644 index 0000000..30945e6 --- /dev/null +++ b/src/app.js @@ -0,0 +1,68 @@ +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); +}]); diff --git a/src/app.scss b/src/app.scss new file mode 100644 index 0000000..8f9fda8 --- /dev/null +++ b/src/app.scss @@ -0,0 +1,4 @@ +@import "styles/colors"; +@import "styles/page" +@import "styles/menu"; +@import "styles/weather"; diff --git a/src/app.spec.js b/src/app.spec.js new file mode 100644 index 0000000..c6a8fd0 --- /dev/null +++ b/src/app.spec.js @@ -0,0 +1,116 @@ +// 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'); + }); + }); +}); \ No newline at end of file diff --git a/src/conditions.json b/src/conditions.json new file mode 100644 index 0000000..dd5d609 --- /dev/null +++ b/src/conditions.json @@ -0,0 +1,51 @@ +[ + { "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" } +] \ No newline at end of file diff --git a/src/forecast.json b/src/forecast.json new file mode 100644 index 0000000..86fd7a8 --- /dev/null +++ b/src/forecast.json @@ -0,0 +1,138 @@ +{ + "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": "\n
\nCurrent Conditions:\n
Partly Cloudy\n
\n
\nForecast:\n
Tue - Partly Cloudy. High: 81Low: 69\n
Wed - Scattered Thunderstorms. High: 83Low: 71\n
Thu - Thunderstorms. High: 85Low: 74\n
Fri - Thunderstorms. High: 92Low: 77\n
Sat - Partly Cloudy. High: 85Low: 75\n
\n
\nFull Forecast at Yahoo! Weather\n
\n
\n(provided by The Weather Channel)\n
\n]]>", + "guid": { + "isPermaLink": "false" + } + } + } + } + } +} \ No newline at end of file diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..a73ac41 --- /dev/null +++ b/src/index.html @@ -0,0 +1,76 @@ + + + + + + Weather or Not + + + + + + + + + + + + + + +
+ + +
"{{ location.city }}, {{ location.region }}
+
+ + + \ No newline at end of file diff --git a/src/styles/colors.scss b/src/styles/colors.scss new file mode 100644 index 0000000..2a3da90 --- /dev/null +++ b/src/styles/colors.scss @@ -0,0 +1,11 @@ +// 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); +; \ No newline at end of file diff --git a/src/styles/menu.scss b/src/styles/menu.scss new file mode 100644 index 0000000..94e9c97 --- /dev/null +++ b/src/styles/menu.scss @@ -0,0 +1,109 @@ +.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;} + } + } +} \ No newline at end of file diff --git a/src/styles/page.scss b/src/styles/page.scss new file mode 100644 index 0000000..849773e --- /dev/null +++ b/src/styles/page.scss @@ -0,0 +1,49 @@ +// 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;} +} diff --git a/src/styles/weather.scss b/src/styles/weather.scss new file mode 100644 index 0000000..edab0aa --- /dev/null +++ b/src/styles/weather.scss @@ -0,0 +1,127 @@ +.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%; + } + } + } + } +} \ No newline at end of file