├── LICENSE
├── README.md
├── bower.json
├── css
└── weather7.css
├── gulpfile.js
├── img
├── delete.svg
├── icon.png
└── yahoo-logo.png
├── index.html
├── js
└── weather7.js
├── manifest.php
├── package.json
└── src
├── jade
└── index.jade
└── less
└── weather7.less
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Vladimir Kharlampidi
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://david-dm.org/nolimits4web/weather7-material#info=devDependencies)
2 | [](https://flattr.com/submit/auto?user_id=nolimits4web&url=https://github.com/nolimits4web/weather7-material/&title=Weather7&language=JavaScript&tags=github&category=software)
3 |
4 | # Weather7-Material
5 |
6 | Weather7 is the simple weather webapp that demonstrates how easy to create fully functioning Android Material app with Framework7. With PhoneGap you can easily convert it to native Android app.
7 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Weather7 Material",
3 | "repository": {
4 | "type": "git",
5 | "url": "https://github.com/nolimits4web/Weather7-Material.git"
6 | },
7 | "description": "Framework7 weather demo app in Material style",
8 | "version": "1.0.0",
9 | "author": "Vladimir Kharlampidi",
10 | "homepage": "http://www.idangero.us/framework7",
11 | "keywords": ["mobile", "framework", "android", "material", "google", "cordova", "phonegap", "native", "touch", "appstore", "app", "f7", "framework7"],
12 | "main": "./",
13 | "license": ["MIT"],
14 | "ignore": [
15 | ".*",
16 | "gulpfile.js",
17 | "node_modules",
18 | "package.json",
19 | "libs"
20 | ],
21 | "dependencies": {
22 | "framework7": "~1.2.0"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/css/weather7.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | overflow: hidden;
4 | height: 100%;
5 | width: 100%;
6 | }
7 | /*==============================
8 | Homepage places list
9 | ==============================*/
10 | .places-list {
11 | margin: 0;
12 | }
13 | .places-list .item-after {
14 | font-size: 24px;
15 | max-height: none;
16 | color: rgba(0, 0, 0, 0.54);
17 | }
18 | .places-list .city {
19 | font-size: 20px;
20 | position: relative;
21 | overflow: hidden;
22 | max-width: 100%;
23 | text-overflow: ellipsis;
24 | white-space: nowrap;
25 | }
26 | .places-list .country {
27 | font-size: 14px;
28 | color: rgba(0, 0, 0, 0.54);
29 | }
30 | .places-list .list-block-label {
31 | text-align: center;
32 | opacity: 0.6;
33 | }
34 | .places-list .item-link .item-inner {
35 | background: none;
36 | padding-right: 16px;
37 | }
38 | .places-list .icon-delete {
39 | width: 24px;
40 | height: 24px;
41 | background: url(../img/delete.svg);
42 | opacity: 0.54;
43 | }
44 | .places-list .swipeout-actions-right a.swipeout-delete {
45 | background: #d3d3d3;
46 | }
47 | .places-list .item-link-more {
48 | position: absolute;
49 | width: 24px;
50 | height: 24px;
51 | right: 16px;
52 | top: 50%;
53 | margin-top: -12px;
54 | text-align: right;
55 | }
56 | .places-list .list-block ul:empty:after {
57 | display: none;
58 | }
59 | /*==============================
60 | Search popup styling
61 | ==============================*/
62 | .popup .searchbar-input {
63 | height: 38px;
64 | }
65 | .popup .searchbar {
66 | height: 100%;
67 | }
68 | .popup .list-block {
69 | margin: 0;
70 | }
71 | .popup .list-block span {
72 | font-size: 14px;
73 | color: rgba(0, 0, 0, 0.54);
74 | margin-left: 5px;
75 | }
76 | .popup .list-block .item-link .item-inner {
77 | background: none;
78 | }
79 | .popup .preloader {
80 | position: absolute;
81 | right: 40px;
82 | width: 24px;
83 | height: 24px;
84 | top: 50%;
85 | margin-top: -12px;
86 | opacity: 0.8;
87 | pointer-events: none;
88 | display: none;
89 | }
90 | /*==============================
91 | Details page styles
92 | ==============================*/
93 | .detail-page-header {
94 | background: #222;
95 | height: -webkit-calc(100vw / 4 * 3);
96 | height: calc(100vw / 4 * 3);
97 | max-height: -webkit-calc(100vh - 56px);
98 | max-height: calc(100vh - 56px);
99 | background-size: cover;
100 | background-position: center;
101 | position: relative;
102 | color: #fff;
103 | overflow: hidden;
104 | }
105 | .detail-page-header .detail-page-header-overlay {
106 | background: linear-gradient(to top, rgba(0, 0, 0, 0.85), rgba(0, 0, 0, 0) 50%);
107 | position: absolute;
108 | left: 0;
109 | top: 0;
110 | width: 100%;
111 | height: 100%;
112 | }
113 | .detail-temp {
114 | font-size: 112px;
115 | line-height: 100px;
116 | font-weight: 300;
117 | position: absolute;
118 | left: 16px;
119 | bottom: 16px;
120 | }
121 | .detail-condition {
122 | text-align: center;
123 | position: absolute;
124 | right: 16px;
125 | bottom: 16px;
126 | font-size: 20px;
127 | font-weight: 300;
128 | z-index: 2;
129 | }
130 | .detail-condition:before {
131 | content: '';
132 | left: 50%;
133 | top: 50%;
134 | width: 0%;
135 | height: 0%;
136 | border-radius: 100%;
137 | box-shadow: 0px 0px 50px 20px rgba(0, 0, 0, 0.2);
138 | position: absolute;
139 | z-index: -1;
140 | }
141 | .list-block.forecast-list {
142 | margin: 0;
143 | }
144 | .list-block.forecast-list ul:before,
145 | .list-block.forecast-list ul:after {
146 | display: none;
147 | }
148 | .list-block.forecast-list span {
149 | display: inline-block;
150 | }
151 | .list-block.forecast-list .item-inner {
152 | padding-top: 16px;
153 | padding-bottom: 16px;
154 | }
155 | .list-block.forecast-list .item-after {
156 | display: block;
157 | text-align: right;
158 | color: rgba(0, 0, 0, 0.87);
159 | height: auto;
160 | max-height: none;
161 | }
162 | .list-block.forecast-list .state {
163 | display: block;
164 | }
165 | .list-block.forecast-list .date {
166 | font-size: 14px;
167 | color: rgba(0, 0, 0, 0.54);
168 | }
169 | .list-block.forecast-list .temps span {
170 | width: 30px;
171 | }
172 | .list-block.forecast-list .temps span.low {
173 | color: rgba(0, 0, 0, 0.54);
174 | }
175 | /*==============================
176 | Tablet
177 | ==============================*/
178 | @media (min-width: 720px) {
179 | .views .page {
180 | background: #eee;
181 | }
182 | .views .navbar {
183 | background-color: transparent !important;
184 | pointer-events: none;
185 | overflow: visible;
186 | }
187 | .views .navbar .left {
188 | pointer-events: auto;
189 | }
190 | .views .navbar .center {
191 | display: block;
192 | max-width: -webkit-calc(100% - 80% - 56px - 16px);
193 | max-width: -calc(100% - 80% - 56px - 16px);
194 | }
195 | .views .navbar-inner {
196 | overflow: visible;
197 | }
198 | .views .list-block {
199 | background: #fff;
200 | border-radius: 3px;
201 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
202 | width: 60%;
203 | margin: 32px auto;
204 | }
205 | .views .list-block ul:before {
206 | display: none;
207 | }
208 | .views .list-block:first-child {
209 | margin-top: 0;
210 | }
211 | .views .list-block .list-block-label {
212 | margin: 0;
213 | padding: 16px 0;
214 | font-size: 0;
215 | }
216 | .views .list-block.forecast-list {
217 | margin: 0 auto 32px;
218 | }
219 | .floating-button {
220 | left: 80%;
221 | margin-left: 32px;
222 | top: 76px;
223 | }
224 | .fake-navbar {
225 | height: 104px;
226 | position: absolute;
227 | left: 0;
228 | top: 0;
229 | width: 100%;
230 | }
231 | .detail-page-header {
232 | width: 60%;
233 | height: -webkit-calc(60vw / 16 * 9);
234 | height: calc(60vw / 16 * 9);
235 | margin-left: auto;
236 | margin-right: auto;
237 | border-radius: 3px 3px 0 0;
238 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
239 | z-index: 1;
240 | max-height: none;
241 | }
242 | .detail-page-header + .list-block {
243 | border-radius: 0 0 3px 3px;
244 | z-index: 2;
245 | position: relative;
246 | }
247 | }
248 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | (function(){
2 | 'use strict';
3 | var gulp = require('gulp'),
4 | connect = require('gulp-connect'),
5 | open = require('gulp-open'),
6 | less = require('gulp-less'),
7 | jade = require('gulp-jade'),
8 | path = require('path'),
9 | fs = require('fs'),
10 | paths = {
11 | root: './',
12 | css: 'css/',
13 | js: 'js/',
14 | source: {
15 | less: 'src/less/',
16 | jade: 'src/jade/'
17 | }
18 | },
19 | app = {
20 | filename: 'weather7',
21 | pkg: require('./bower.json'),
22 | banner: [
23 | '/**',
24 | ' * <%= pkg.name %> <%= pkg.version %>',
25 | ' * <%= pkg.description %>',
26 | ' * ',
27 | ' * <%= pkg.homepage %>',
28 | ' * ',
29 | ' * Copyright <%= date.year %>, <%= pkg.author %>',
30 | ' * The iDangero.us',
31 | ' * http://www.idangero.us/',
32 | ' * ',
33 | ' * Licensed under <%= pkg.license.join(" & ") %>',
34 | ' * ',
35 | ' * Released on: <%= date.month %> <%= date.day %>, <%= date.year %>',
36 | ' */',
37 | ''].join('\n'),
38 | date: {
39 | year: new Date().getFullYear(),
40 | month: ('January February March April May June July August September October November December').split(' ')[new Date().getMonth()],
41 | day: new Date().getDate()
42 | },
43 |
44 | };
45 |
46 | /* ==================================================================
47 | Build App
48 | ================================================================== */
49 | gulp.task('styles', function (cb) {
50 | gulp.src([paths.source.less + app.filename + '.less'])
51 | .pipe(less({
52 | paths: [ path.join(__dirname, 'less', 'includes') ]
53 | }))
54 | .pipe(gulp.dest(paths.css))
55 | .pipe(connect.reload())
56 | .on('end', function () {
57 | cb();
58 | });
59 | });
60 | gulp.task('jade', function (cb) {
61 | gulp.src([paths.source.jade + '*.jade'])
62 | .pipe(jade({
63 | pretty: true,
64 | }))
65 | .pipe(gulp.dest(paths.root))
66 | .pipe(connect.reload())
67 | .on('end', function () {
68 | cb();
69 | });
70 | });
71 |
72 | gulp.task('build', ['styles', 'jade'], function (cb) {
73 | cb();
74 | });
75 |
76 | /* =================================
77 | Watch
78 | ================================= */
79 | gulp.task('watch', function () {
80 | gulp.watch(paths.source.less + '*.less', [ 'styles' ]);
81 | gulp.watch(paths.source.jade + '*.jade', [ 'jade' ]);
82 |
83 | gulp.watch(paths.css + '*.css', function () {
84 | gulp.src(paths.css)
85 | .pipe(connect.reload());
86 | });
87 | gulp.watch(paths.js + '*.js', function () {
88 | gulp.src(paths.js)
89 | .pipe(connect.reload());
90 | });
91 | gulp.watch(paths.root + '*.html', function () {
92 | gulp.src(paths.root)
93 | .pipe(connect.reload());
94 | });
95 |
96 | });
97 |
98 | gulp.task('connect', function () {
99 | return connect.server({
100 | root: [ paths.root ],
101 | livereload: true,
102 | port:'3000'
103 | });
104 | });
105 |
106 | gulp.task('open', function () {
107 | return gulp.src(paths.root + 'index.html').pipe(open({ uri: 'http://localhost:3000/index.html'}));
108 | });
109 |
110 | gulp.task('server', [ 'watch', 'connect', 'open' ]);
111 |
112 | gulp.task('default', [ 'server' ]);
113 |
114 | gulp.task('test', [ 'build' ]);
115 | })();
--------------------------------------------------------------------------------
/img/delete.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/img/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/framework7io/Weather7-Material/59a2cf234d2537521946e4bd8eb69e44fb6924cb/img/icon.png
--------------------------------------------------------------------------------
/img/yahoo-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/framework7io/Weather7-Material/59a2cf234d2537521946e4bd8eb69e44fb6924cb/img/yahoo-logo.png
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Weather7
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
37 |
38 |
61 |
62 |
71 |
89 |
125 |
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/js/weather7.js:
--------------------------------------------------------------------------------
1 | // Initialize your app
2 | var myApp = new Framework7({
3 | modalTitle: 'Weather7',
4 | material: true,
5 | materialPageLoadDelay: 200
6 | });
7 | // Export selectors engine
8 | var $$ = Dom7;
9 |
10 | // Register required Template7 helpers, before templates compilation
11 | Template7.registerHelper('dayOfWeek', function (date) {
12 | date = new Date(date);
13 | var days = ('Sunday Monday Tuesday Wednesday Thursday Friday Saturday').split(' ');
14 | return days[date.getDay()];
15 | });
16 | Template7.registerHelper('formatedDated', function (date) {
17 | date = new Date(date);
18 | var months = 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'.split(' ');
19 | return months[date.getMonth()] + ' ' + date.getDate() + ' ' + date.getFullYear();
20 | });
21 | // Fickr API Key. CHANGE TO YOUR OWN!!!
22 | var flickrAPIKey = '664c33273570a6c80067779f55f548d1';
23 |
24 | // Templates using Template7 template engine
25 | myApp.searchResultsTemplate = Template7.compile($$('#search-results-template').html());
26 | myApp.homeItemsTemplate = Template7.compile($$('#home-items-template').html());
27 | myApp.detailsTemplate = Template7.compile($$('#details-template').html());
28 |
29 | // Add view
30 | var mainView = myApp.addView('.view-main');
31 |
32 | // Search Locations
33 | var searchTimeout;
34 |
35 | myApp.searchLocation = function (search) {
36 | if (search.trim() === '') {
37 | $$('.popup .search-results').html('');
38 | return;
39 | }
40 | var query = encodeURIComponent('select * from geo.places where text="' + search + '"');
41 | var q = 'http://query.yahooapis.com/v1/public/yql?q=' + query + '&format=json';
42 | if (searchTimeout) clearTimeout(searchTimeout);
43 | $$('.popup .preloader').show();
44 | searchTimeout = setTimeout(function () {
45 | $$.get(q, function (results) {
46 | var html = '';
47 | results = JSON.parse(results);
48 | $$('.popup .preloader').hide();
49 | if (results.query.count > 0) {
50 | var places = results.query.results.place;
51 | html = myApp.searchResultsTemplate(places);
52 | }
53 | $$('.popup .search-results').html(html);
54 | });
55 | }, 300);
56 | };
57 |
58 | // Handle search results
59 | var mySearchbar = myApp.searchbar('.searchbar', {
60 | customSearch: true,
61 | onDisable: function (s) {
62 | $$('.popup input[type="search"]')[0].blur();
63 | myApp.closeModal('.popup');
64 | },
65 | onSearch: function (s, q) {
66 | myApp.searchLocation(s.query);
67 | },
68 | onClear: function (s) {
69 | $$('.popup .search-results').html('');
70 | }
71 | });
72 | $$('.popup').on('open', function () {
73 | mySearchbar.enable();
74 | });
75 | $$('.popup').on('opened', function () {
76 | $$('.popup input[type="search"]')[0].focus();
77 | });
78 | $$('.popup .search-results').on('click', 'li', function () {
79 | var li = $$(this);
80 | var woeid = li.attr('data-woeid');
81 | var city = li.attr('data-city');
82 | var country = li.attr('data-country');
83 | var places;
84 | if (localStorage.w7Places) places = JSON.parse(localStorage.w7Places);
85 | else places = [];
86 | places.push({
87 | woeid: li.attr('data-woeid'),
88 | city: li.attr('data-city'),
89 | country: li.attr('data-country')
90 | });
91 | localStorage.w7Places = JSON.stringify(places);
92 | myApp.updateWeatherData(function () {
93 | myApp.buildWeatherHTML();
94 | });
95 | });
96 | // Get locations weather data
97 | myApp.updateWeatherData = function (callback) {
98 | var woeids = [];
99 | if (!localStorage.w7Places) return;
100 | var places = JSON.parse(localStorage.w7Places);
101 | if (places.length === 0) {
102 | localStorage.w7Data = JSON.stringify([]);
103 | return;
104 | }
105 | if (!navigator.onLine) {
106 | myApp.alert('You need internet connection to update weather data');
107 | }
108 | for (var i = 0; i < places.length; i++) {
109 | woeids.push(places[i].woeid);
110 | }
111 | var query = encodeURIComponent('select * from weather.forecast where woeid in (' + JSON.stringify(woeids).replace('[', '').replace(']', '') + ') and u="c"');
112 | var q = 'http://query.yahooapis.com/v1/public/yql?q=' + query + '&format=json';
113 | myApp.showIndicator();
114 | $$.get(q, function (data) {
115 | var weatherData = [];
116 | myApp.hideIndicator();
117 | data = JSON.parse(data);
118 | if (!data.query || !data.query.results) return;
119 | var places = data.query.results.channel;
120 | var place;
121 | if ($$.isArray(places)) {
122 | for (var i = 0; i < places.length; i++) {
123 | place = places[i];
124 | weatherData.push({
125 | city: place.location.city,
126 | country: place.location.country,
127 | region: place.location.region,
128 | humidity: place.atmosphere.humidity,
129 | pressure: place.atmosphere.pressure,
130 | sunrise: place.astronomy.sunrise,
131 | sunset: place.astronomy.sunset,
132 | wind: place.wind,
133 | condition: place.item.condition,
134 | forecast: place.item.forecast,
135 | lat: place.item.lat,
136 | long: place.item.long,
137 | woeid: woeids[i]
138 | });
139 | }
140 | }
141 | else {
142 | place = places;
143 | weatherData.push({
144 | city: place.location.city,
145 | country: place.location.country,
146 | region: place.location.region,
147 | humidity: place.atmosphere.humidity,
148 | pressure: place.atmosphere.pressure,
149 | sunrise: place.astronomy.sunrise,
150 | sunset: place.astronomy.sunset,
151 | wind: place.wind,
152 | condition: place.item.condition,
153 | forecast: place.item.forecast,
154 | lat: place.item.lat,
155 | long: place.item.long,
156 | woeid: woeids[0]
157 | });
158 | }
159 | localStorage.w7Data = JSON.stringify(weatherData);
160 | if (callback) callback();
161 | });
162 | };
163 | // Build list of places on home page
164 | myApp.buildWeatherHTML = function () {
165 | var weatherData = localStorage.w7Data;
166 | if (!weatherData) return;
167 | $$('.places-list ul').html('');
168 | weatherData = JSON.parse(weatherData);
169 | var html = myApp.homeItemsTemplate(weatherData);
170 | $$('.places-list ul').html(html);
171 | };
172 |
173 | // Delete place
174 | $$('.places-list').on('delete', '.swipeout', function () {
175 | var woeid = $$(this).attr('data-woeid');
176 | // Update Places
177 | if (!localStorage.w7Places) return;
178 | var places = JSON.parse(localStorage.w7Places);
179 | for (var i = 0; i < places.length; i++) {
180 | if (places[i].woeid === woeid) places.splice(i, 1);
181 | }
182 | localStorage.w7Places = JSON.stringify(places);
183 | // Update places data
184 | if (!localStorage.w7Data) return;
185 | var data = JSON.parse(localStorage.w7Data);
186 | for (i = 0; i < data.length; i++) {
187 | if (data[i].woeid === woeid) data.splice(i, 1);
188 | }
189 | localStorage.w7Data = JSON.stringify(data);
190 | if (data.length === 0) myApp.buildWeatherHTML();
191 | });
192 |
193 |
194 |
195 | // Update html and weather data on app load
196 | myApp.buildWeatherHTML();
197 | myApp.updateWeatherData(function () {
198 | myApp.buildWeatherHTML();
199 | });
200 |
201 | // Build details page
202 | $$('.places-list').on('click', 'a.item-link', function (e) {
203 | var woeid = $$(this).attr('data-woeid');
204 | var item;
205 | var weatherData = JSON.parse(localStorage.w7Data);
206 | for (var i = 0; i < weatherData.length; i++) {
207 | if (weatherData[i].woeid === woeid) item = weatherData[i];
208 | }
209 | var pageContent = myApp.detailsTemplate(item);
210 | mainView.loadContent(pageContent);
211 | });
212 |
213 | var photoXHR;
214 | var photoCache = {};
215 | myApp.onPageAfterAnimation('detail', function (page) {
216 | var woeid = $$(page.container).attr('data-woeid');
217 | var weatherData = JSON.parse(localStorage.w7Data);
218 | for (var i = 0; i < weatherData.length; i++) {
219 | if (weatherData[i].woeid === woeid) item = weatherData[i];
220 | }
221 |
222 | function placePhotos(photos) {
223 | if (photos && photos.query && photos.query.count > 0) {
224 | var photo = photos.query.results.photo[Math.floor(Math.random() * photos.query.count)];
225 | $$('.detail-page-header').css('background-image', 'url(https://farm'+photo.farm+'.staticflickr.com/'+photo.server+'/'+photo.id+'_'+photo.secret+'_c.jpg)');
226 | }
227 | }
228 | if (photoCache[woeid]) {
229 | placePhotos(photoCache[woeid]);
230 | }
231 | else {
232 | var query = encodeURIComponent('select * from flickr.photos.search where has_geo="true" and woe_id="'+woeid+'" and api_key="92bd0de55a63046155c09f1a06876875"');
233 | var q = 'https://query.yahooapis.com/v1/public/yql?q=' + query + '&format=json';
234 | photoXHR = $$.get(q, function (res) {
235 | if (res) {
236 | photoCache[woeid] = JSON.parse(res);
237 | placePhotos(photoCache[woeid]);
238 | }
239 | });
240 | }
241 | });
242 | myApp.onPageBack('detail', function (page) {
243 | if (photoXHR) photoXHR.abort();
244 | });
245 |
246 | // Update app when manifest updated
247 | // http://www.html5rocks.com/en/tutorials/appcache/beginner/
248 | // Check if a new cache is available on page load.
249 | window.addEventListener('load', function (e) {
250 | window.applicationCache.addEventListener('updateready', function (e) {
251 | if (window.applicationCache.status === window.applicationCache.UPDATEREADY) {
252 | // Browser downloaded a new app cache.
253 | myApp.confirm('A new version of weather7 is available. Do you want to load it right now?', function () {
254 | window.location.reload();
255 | });
256 | } else {
257 | // Manifest didn't changed. Nothing new to server.
258 | }
259 | }, false);
260 | }, false);
261 |
--------------------------------------------------------------------------------
/manifest.php:
--------------------------------------------------------------------------------
1 |
13 | CACHE MANIFEST
14 |
15 | CACHE:
16 |
24 |
25 | NETWORK:
26 | *
27 |
28 | # Hash Version: =md5($hashes)?>
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "weather7-material",
3 | "version": "1.0.0",
4 | "description": "Framework7 weather demo app in Material style",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/nolimits4web/Weather7-Material.git"
8 | },
9 | "author": "Vladimir Kharlampidi",
10 | "license": [
11 | "MIT"
12 | ],
13 | "bugs": {
14 | "url": "https://github.com/nolimits4web/Weather7-Material/issues"
15 | },
16 | "homepage": "http://www.idangero.us/framework7/",
17 | "engines": {
18 | "node": ">= 0.10.0"
19 | },
20 | "devDependencies": {
21 | "gulp": "~3.9.0",
22 | "gulp-less": "~3.0.3",
23 | "gulp-jade": "~1.1.0",
24 | "gulp-connect": "~2.2.0",
25 | "gulp-open": "~1.0.0"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/jade/index.jade:
--------------------------------------------------------------------------------
1 | doctype
2 | html(manifest="manifest.php")
3 | head
4 | meta(charset="utf-8")
5 | meta(name="viewport", content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui")
6 | meta(name='apple-mobile-web-app-capable', content='yes')
7 | meta(name="theme-color", content="#9c27b0")
8 | title Weather7
9 | link(href='http://fonts.googleapis.com/css?family=Roboto:400,300,500,700', rel='stylesheet', type='text/css')
10 | link(rel="stylesheet", href="libs/framework7/dist/css/framework7.material.min.css")
11 | link(rel="stylesheet", href="libs/framework7/dist/css/framework7.material.colors.min.css")
12 | link(rel="stylesheet", href="css/weather7.css")
13 | link(rel="icon", href="img/icon.png")
14 | body
15 | // Main views
16 | .views
17 | .view.view-main.navbar-fixed
18 | .pages
19 | .page(data-page="index")
20 | a(href="#").open-popup.link.floating-button.color-blue
21 | i.icon.icon-plus
22 | .navbar.theme-purple
23 | .navbar-inner
24 | .center Weather7
25 | .fake-navbar.bg-purple
26 | .page-content
27 | .list-block.places-list
28 | ul
29 | .list-block-label
30 | img(src="img/yahoo-logo.png", height="20")
31 | // Search popup
32 | .popup
33 | .view
34 | .pages
35 | .page.navbar-fixed
36 | .navbar
37 | .navbar-inner
38 | form.searchbar
39 | .searchbar-input
40 | input(type="search", placeholder="Search")
41 | a(href="#").searchbar-clear
42 | .preloader.preloader-white
43 | .page-content
44 | .list-block
45 | ul.search-results
46 | // Templates
47 | script(id="search-results-template", type="text/template")
48 | | {{#each this}}
49 | | {{#if admin1}}{{#if admin1.content}}
50 | li.close-popup(data-woeid="{{woeid}}", data-city="{{name}}", data-country="{{country.content}}")
51 | a(href="#").item-content.item-link
52 | .item-inner
53 | .item-title
54 | | {{name}}
55 | span {{admin1.content}}, {{country.content}}
56 | | {{/if}}{{/if}}
57 | | {{/each}}
58 |
59 | script(id="home-items-template", type="text/template")
60 | | {{#each this}}
61 | li.swipeout(data-woeid="{{woeid}}")
62 | .swipeout-content
63 | a(href="#", data-woeid="{{woeid}}").item-content.item-link
64 | .item-inner
65 | .item-title
66 | .city {{city}}
67 | .country {{country}}
68 | .item-after {{condition.temp}}°
69 | .swipeout-actions-right
70 | a(href="#").swipeout-delete
71 | i.icon.icon-delete
72 | | {{else}}
73 | li.item-content
74 | .item-inner
75 | .item-title You haven't added any places yet
76 | | {{/each}}
77 | script(id="details-template", type="text/template")
78 | .pages.navbar-fixed
79 | .page(data-page="detail", data-woeid="{{woeid}}")
80 | .navbar.theme-purple
81 | .navbar-inner
82 | .left
83 | a(href="index.html").back.link.icon-only
84 | i.icon.icon-back
85 | .center {{city}}
86 | .fake-navbar.bg-purple
87 | .page-content
88 | .detail-page-header
89 | .detail-page-header-overlay
90 | .detail-temp {{condition.temp}}°
91 | .detail-condition {{condition.text}}
92 | .list-block.forecast-list
93 | ul
94 | | {{#each forecast}}
95 | li.item-content
96 | .item-inner
97 | .item-title
98 | .day {{dayOfWeek date}}
99 | .date {{formatedDated date}}
100 | .item-after
101 | .state {{text}}
102 | .temps
103 | span.high {{high}}°
104 | span.low {{low}}°
105 | | {{/each}}
106 |
107 | // Path to Framework7 Library JS
108 | script(type="text/javascript", src="libs/framework7/dist/js/framework7.min.js")
109 | // Path to your app js
110 | script(type="text/javascript", src="js/weather7.js")
111 |
--------------------------------------------------------------------------------
/src/less/weather7.less:
--------------------------------------------------------------------------------
1 | //Mixins
2 | .transition(@t) {
3 | -webkit-transition-duration: @t;
4 | -moz-transition-duration: @t;
5 | -ms-transition-duration: @t;
6 | -o-transition-duration: @t;
7 | transition-duration: @t;
8 | }
9 | .transform(@t) {
10 | -webkit-transform: @t;
11 | -moz-transform: @t;
12 | -ms-transform: @t;
13 | -o-transform: @t;
14 | transform: @t;
15 | }
16 | html,body {
17 | overflow: hidden;
18 | height: 100%;
19 | width: 100%;
20 | }
21 |
22 |
23 |
24 | /*==============================
25 | Homepage places list
26 | ==============================*/
27 | .places-list {
28 | margin: 0;
29 | .item-after {
30 | font-size: 24px;
31 | max-height: none;
32 | color: rgba(0,0,0,0.54);
33 | }
34 | .city {
35 | font-size: 20px;
36 | // font-weight: 300;
37 | position: relative;
38 | overflow: hidden;
39 | max-width: 100%;
40 | text-overflow:ellipsis;
41 | white-space: nowrap;
42 | }
43 | .country {
44 | font-size: 14px;
45 | color: rgba(0,0,0,0.54);
46 | }
47 | .list-block-label {
48 | text-align: center;
49 | opacity: 0.6;
50 | }
51 | .item-link .item-inner {
52 | background: none;
53 | padding-right: 16px;
54 | }
55 | .icon-delete {
56 | width: 24px;
57 | height: 24px;
58 | background: url(../img/delete.svg);
59 | opacity: 0.54;
60 | }
61 | .swipeout-actions-right a.swipeout-delete {
62 | background: #d3d3d3;
63 | }
64 | .item-link-more {
65 | position: absolute;
66 | width: 24px;
67 | height: 24px;
68 | right: 16px;
69 | top: 50%;
70 | margin-top: -12px;
71 | text-align: right;
72 | }
73 | .list-block ul:empty:after {
74 | display: none;
75 | }
76 | }
77 | /*==============================
78 | Search popup styling
79 | ==============================*/
80 | .popup {
81 | .searchbar-input {
82 | height: 38px;
83 | }
84 | .searchbar {
85 | height: 100%;
86 | }
87 | .list-block {
88 | margin: 0;
89 | span {
90 | font-size: 14px;
91 | color: rgba(0,0,0,0.54);
92 | margin-left: 5px;
93 | }
94 | .item-link .item-inner {
95 | background: none;
96 | }
97 | }
98 | .preloader {
99 | position: absolute;
100 | right: 40px;
101 | width: 24px;
102 | height: 24px;
103 | top: 50%;
104 | margin-top: -12px;
105 | opacity: 0.8;
106 | pointer-events: none;
107 | display: none;
108 | }
109 | }
110 | /*==============================
111 | Details page styles
112 | ==============================*/
113 | .detail-page-header {
114 | background: #222;
115 | height: ~"-webkit-calc(100vw / 4 * 3)";
116 | height: ~"calc(100vw / 4 * 3)";
117 | max-height: ~"-webkit-calc(100vh - 56px)";
118 | max-height: ~"calc(100vh - 56px)";
119 | background-size: cover;
120 | background-position: center;
121 | position: relative;
122 | color:#fff;
123 | overflow: hidden;
124 | .detail-page-header-overlay {
125 | background: linear-gradient(to top, rgba(0,0,0,0.85), rgba(0,0,0,0) 50%);
126 | position: absolute;
127 | left: 0;
128 | top: 0;
129 | width: 100%;
130 | height: 100%;
131 | }
132 | }
133 | .detail-temp {
134 | font-size: 112px;
135 | line-height: 100px;
136 | font-weight: 300;
137 | position: absolute;
138 | left: 16px;
139 | bottom: 16px;
140 | }
141 | .detail-condition {
142 | text-align: center;
143 | position: absolute;
144 | right: 16px;
145 | bottom: 16px;
146 | font-size: 20px;
147 | font-weight: 300;
148 | z-index: 2;
149 | &:before {
150 | content: '';
151 | left: 50%;
152 | top: 50%;
153 | width: 0%;
154 | height: 0%;
155 | border-radius: 100%;
156 | box-shadow: 0px 0px 50px 20px rgba(0,0,0,0.2);
157 | position: absolute;
158 | z-index: -1;
159 | }
160 | }
161 |
162 | .list-block.forecast-list {
163 | margin: 0;
164 | ul {
165 | &:before, &:after {
166 | display: none;
167 | }
168 | }
169 | span {
170 | display: inline-block;
171 | }
172 | .item-inner {
173 | padding-top: 16px;
174 | padding-bottom: 16px;
175 | }
176 | .item-after {
177 | display: block;
178 | text-align: right;
179 | color: rgba(0,0,0,0.87);
180 | height: auto;
181 | max-height: none;
182 | }
183 | .state {
184 | display: block;
185 | }
186 | .date {
187 | font-size: 14px;
188 | color: rgba(0,0,0,0.54);
189 | }
190 | .temps {
191 | span {
192 | width: 30px;
193 | }
194 | span.low {
195 | color: rgba(0,0,0,0.54);
196 | }
197 | }
198 | }
199 |
200 | /*==============================
201 | Tablet
202 | ==============================*/
203 | @media (min-width:720px) {
204 | .views {
205 | .page {
206 | background: #eee;
207 | }
208 | .navbar {
209 | background-color: transparent !important;
210 | pointer-events: none;
211 | overflow: visible;
212 | .left {
213 | pointer-events: auto;
214 | }
215 | .center {
216 | display: block;
217 | max-width: ~"-webkit-calc(100% - 80% - 56px - 16px)";
218 | max-width: ~"-calc(100% - 80% - 56px - 16px)";
219 | }
220 | }
221 | .navbar-inner {
222 | overflow: visible;
223 | }
224 | .list-block {
225 | background: #fff;
226 | border-radius: 3px;
227 | box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
228 | ul {
229 | &:before {
230 | display: none;
231 | }
232 | }
233 | width: 60%;
234 | margin: 32px auto;
235 | &:first-child {
236 | margin-top: 0;
237 | }
238 |
239 | .list-block-label {
240 | margin: 0;
241 | padding: 16px 0;
242 | font-size: 0;
243 | }
244 | &.forecast-list {
245 | margin: 0 auto 32px;
246 | }
247 | }
248 | }
249 |
250 | .floating-button {
251 | left: 80%;
252 | margin-left: 32px;
253 | top: 48px + 56px - 56/2;
254 | }
255 | .fake-navbar {
256 | height: 56px + 48px;
257 | position: absolute;
258 | left: 0;
259 | top: 0;
260 | width: 100%;
261 | }
262 | .detail-page-header {
263 | width: 60%;
264 | height: ~"-webkit-calc(60vw / 16 * 9)";
265 | height: ~"calc(60vw / 16 * 9)";
266 | margin-left: auto;
267 | margin-right: auto;
268 | border-radius: 3px 3px 0 0;
269 | box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
270 | z-index: 1;
271 | max-height: none;
272 | + .list-block {
273 | border-radius: 0 0 3px 3px;
274 | z-index: 2;
275 | position: relative;
276 | }
277 | }
278 |
279 | }
--------------------------------------------------------------------------------