diff --git a/README.md b/README.md index 4a35ee0f..85fb22c2 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,74 @@ -# wafs -The course repo for 'Web App From Scratch' +# Web-App-from-Scratch +This is an single page web app. It is created from scratch without using any unnecessary libraries. -## Advantages and disadvantages of JavaScript libraries/frameworks -... +## Single page web app in general +*A single-page application (SPA) is an app that works inside a browser and does not require page reloading during use. You are using this type of applications every day. These are, for instance: Gmail, Google Maps, Facebook or GitHub.* -## Advantages and disadvantages of client-side single page web apps -... +### Pro +- SPA is fast, as most resources (HTML+CSS+Scripts) are only loaded once throughout the lifespan of application. Only data is transmitted back and forth. + +- SPA can cache any local storage effectively. An application sends only one request, store all data, then it can use this data and works even offline. + +- The development is simplified and streamlined. There is no need to write code to render pages on the server. It is much easier to get started because you can usually kick off development from a file file://URI, without using any server at all. + +### Con +- It is slow to download because heavy client frameworks are required to be loaded to the client. + +- It requires JavaScript to be present and enabled. If any user disables JavaScript in his or her browser, it won’t be possible to present application and its actions in a correct way. + +Neoteric ('Single-page application vs. multiple-page application'), taken from: https://medium.com/@NeotericEU/single-page-application-vs-multiple-page-application-2591588efe58 + +## Frameworks in general + +### Pro +- A good programmer know how to get the job done well and fast. If you don't need to write code from scratch why should you? Frameworks are just tools, tools that any profession has to work better. + +- Efficiency is also about lines of code. + + +### Con + +- If you don't know the underlying principles of the web, you'll eventually hit a wall thanks to the evolution of the language itself and the constant arrival of new frameworks. + +- People start using frameworks and libraries without even thinking about how to solve the problem without them. Often, a solution in VanillaJS is very easy, but people are so used to work with frameworks and libraries that they load a lot of extra code to do very simple things. + + +Francois-Xavier P. Darveau ('Yes, You Should Learn Vanilla JavaScript Before Fancy JS Frameworks'), taken from: https://snipcart.com/blog/learn-vanilla-javascript-before-using-js-frameworks + +Marco Alka ('Vanilla JavaScript vs. Frameworks & Libraries sFinding a good balance'), taken from : https://hashnode.com/post/vanilla-javascript-vs-frameworks-and-libraries-finding-a-good-balance-civ1zfus90pphdc53q8vtakz5 ## Best practices ... + + +## Inspiration +*The first thing I did was looking for inspiration and and good examples of single page application.* + +### district0x +url: https://district0x.io/ + +District0x makes great use of typography, color, and scroll animation. When viewing the site on mobile, the site is still great to use. The animation that is displayed still plays at around 60fps. And there is alot of whitespaces that gives the content more air to display itself.\ +![district0x](readme-assets/district0x.gif "district0x") + +### Kollergorna +url: https://radar.kollegorna.se/ + +Kollergorna is a beautifull site that doens't use a traditional layout. Also they give the user an option to view their content in a different layout. Lastly the loadying of the content in insanely fast. + +![Kolergona](readme-assets/kollergorna.gif "kolergona") + + +# To do +1. Create an issue for Leonie +2. Create an issue for Kevin +3. create responsive menu +4. Best practices +5. Manage routes en states +6. Get / Post data van/naar API +7. Data manipuleren +8. Data presenteren +9. Web Worker implementeren (extra) +10. Code review + + + diff --git a/app/index.html b/app/index.html index e69de29b..3da69e99 100644 --- a/app/index.html +++ b/app/index.html @@ -0,0 +1,87 @@ + + + + + + + + Web app + + + + + + +
+
+ + +
+ +

+ + +

+
+
+

+ Price USD + +

+

+ Change 1h + +

+

+ Change 24h + +

+
+
+
+
+ +
+
+ + + + +
+ +

+ + +

+
+
+

+ Price USD + + +

+

+ Change 1h + + +

+

+ Change 24h + +

+

+ + + +

+ +
+
+
+ + + + + + + \ No newline at end of file diff --git a/app/static/css/styles.css b/app/static/css/styles.css deleted file mode 100644 index e69de29b..00000000 diff --git a/app/static/js/script.js b/app/static/js/script.js deleted file mode 100644 index e69de29b..00000000 diff --git a/app/static/script/app.js b/app/static/script/app.js new file mode 100644 index 00000000..eec7036c --- /dev/null +++ b/app/static/script/app.js @@ -0,0 +1,188 @@ +//Use IIFE to create variable but only in the IIFE scope +(function () { + 'use strict'; //use strict mode only in this scope + + var app = { + init: function () { + + /*Created promise syntax with the help of Kevin Wang(github: Kyunwang) and stackoverflow: + https://stackoverflow.com/questions/30008114/how-do-i-promisify-native-xhr*/ + let requestNetwork = new Promise(function (resolve, reject) { + let xhr = new XMLHttpRequest(); + let url = "https://api.coinmarketcap.com/v1/ticker/"; + xhr.open("GET", url, true); //create a async request + + xhr.onload = function (e) { + if (xhr.readyState === 4) { + if (xhr.status === 200) { + resolve(xhr.responseText); + } else { + reject({ + status: this.status + }); + } + } + }; + + //Extra error handle if the onload doesn't work + xhr.onerror = function () { + reject({ + status: this.status, + test: 2 + }); + } + + //send request + xhr.send(); + }); + + //handle promise + requestNetwork.then(function (data) { + let dataJson = JSON.parse(data); + routes.init(dataJson); + }) + .catch(function (err) { + console.log(err) + }); + } + } + + //Handel the route + var routes = { + init: function (data) { + this.routie(data); + }, + routie(data) { + routie({ + '': function () { //start page + section.hideDetailPage(); + section.insert(section.mapData(data)); + }, + 'detail/:id': function (id) { + section.detail(data, id); + } + }); + } + } + + //This is the object Function where will manipulate the DOM elements + var section = { + //The insert function will insert data to element with the same 'data-bind' name. + insert: function (data, extraInfo) { + //directive add extra information to the element for example 'class' or 'href' + let directives = { + coin_id: { + href: function () { + name = this.id + return "#detail/" + this.id; // Use this as base for going to detail + } + }, + percent_change_1h: { + class: function () { + let value = this.percent_change_1h; + let className = helper.assignClass(value); // assign class to the value + return 'change ' + className; //'change' is just a classt css that add a '%' sign + } + }, + percent_change_24h: { + class: function () { + let value = this.percent_change_24h; + let className = helper.assignClass(value); // assign class to the value + return 'change ' + className; //'change' is just a classt css that add a '%' sign + } + }, + coin_image: { + src: function () { + /*We want to give a lower resolution picture on mobile. The if/else check + if the screen is a small(mobile) screen*/ + let bigScreen = 799; + let width = helper.checkViewWidth(); + let url; + let name = this.id; // name of the coin we want to get + if (width < bigScreen) { + url = 'https://files.coinmarketcap.com/static/img/coins/64x64/' + name + '.png'; + } else { + url = 'https://files.coinmarketcap.com/static/img/coins/128x128/' + name + '.png'; + } + return url; + }, + alt: function () { + return this.id; + } + } + }; + + if (extraInfo === true) { + //Call Transparency to inject our objects into the Dom + Transparency.render(document.querySelector('#detail'), data, directives); + } else { + //Call Transparency to inject our objects into the Dom + Transparency.render(document.querySelector('#start div'), data, directives); + } + }, + detail: function (data, coinID) { + function findCoin(name) { + return name.id === coinID; + } + let pastAllongData = [data.find(findCoin)]; + let detailPage = true; + this.insert(this.mapData(pastAllongData), detailPage); + document.querySelector('.detail-container').classList.add('active'); + event.backToHome(); + }, + mapData: function (data) { + let dataCoin = data.map(function (i) { //Map function thanks to Keving Wang? + return { + id: i.id, + rank: i.rank, + name: i.name, + price: i.price_usd, + price_btc: i.price_btc, + volume: i['24h_volume_usd'], + market_cap: i.market_cap_usd, + supply: i.available_supply, + percent_change_1h: i.percent_change_1h, + percent_change_24h: i.percent_change_24h, + name_abbreviation: i.symbol + } + }); + return dataCoin; + }, + hideDetailPage: function () { + document.querySelector('.detail-container').classList.remove('active'); + } + } + + var helper = { + assignClass: function (value) { + /*This function assign a class to an element if the value is higher or + lower than 0*/ + let className = ''; + + //Check value + if (value < 0) { + className = 'minus'; + } else if (value > 0) { + className = 'plus'; + } else { + className = 'neutral'; + } + + return className; + }, + checkViewWidth: function () { + let width = window.innerWidth; + return width; + } + } + + var event = { + backToHome() { + document.querySelector('.detail-container button').addEventListener('click', function () { + location.replace(""); + }) + } + } + + app.init(); //start application +})(); \ No newline at end of file diff --git a/app/static/script/routie.js b/app/static/script/routie.js new file mode 100644 index 00000000..9357bb6a --- /dev/null +++ b/app/static/script/routie.js @@ -0,0 +1,218 @@ +/*! + * routie - a tiny hash router + * v0.3.2 + * http://projects.jga.me/routie + * copyright Greg Allen 2016 + * MIT License +*/ +var Routie = function(w, isModule) { + + var routes = []; + var map = {}; + var reference = "routie"; + var oldReference = w[reference]; + + var Route = function(path, name) { + this.name = name; + this.path = path; + this.keys = []; + this.fns = []; + this.params = {}; + this.regex = pathToRegexp(this.path, this.keys, false, false); + + }; + + Route.prototype.addHandler = function(fn) { + this.fns.push(fn); + }; + + Route.prototype.removeHandler = function(fn) { + for (var i = 0, c = this.fns.length; i < c; i++) { + var f = this.fns[i]; + if (fn == f) { + this.fns.splice(i, 1); + return; + } + } + }; + + Route.prototype.run = function(params) { + for (var i = 0, c = this.fns.length; i < c; i++) { + this.fns[i].apply(this, params); + } + }; + + Route.prototype.match = function(path, params){ + var m = this.regex.exec(path); + + if (!m) return false; + + + for (var i = 1, len = m.length; i < len; ++i) { + var key = this.keys[i - 1]; + + var val = ('string' == typeof m[i]) ? decodeURIComponent(m[i]) : m[i]; + + if (key) { + this.params[key.name] = val; + } + params.push(val); + } + + return true; + }; + + Route.prototype.toURL = function(params) { + var path = this.path; + for (var param in params) { + path = path.replace('/:'+param, '/'+params[param]); + } + path = path.replace(/\/:.*\?/g, '/').replace(/\?/g, ''); + if (path.indexOf(':') != -1) { + throw new Error('missing parameters for url: '+path); + } + return path; + }; + + var pathToRegexp = function(path, keys, sensitive, strict) { + if (path instanceof RegExp) return path; + if (path instanceof Array) path = '(' + path.join('|') + ')'; + path = path + .concat(strict ? '' : '/?') + .replace(/\/\(/g, '(?:/') + .replace(/\+/g, '__plus__') + .replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?/g, function(_, slash, format, key, capture, optional){ + keys.push({ name: key, optional: !! optional }); + slash = slash || ''; + return '' + (optional ? '' : slash) + '(?:' + (optional ? slash : '') + (format || '') + (capture || (format && '([^/.]+?)' || '([^/]+?)')) + ')' + (optional || ''); + }) + .replace(/([\/.])/g, '\\$1') + .replace(/__plus__/g, '(.+)') + .replace(/\*/g, '(.*)'); + return new RegExp('^' + path + '$', sensitive ? '' : 'i'); + }; + + var addHandler = function(path, fn) { + var s = path.split(' '); + var name = (s.length == 2) ? s[0] : null; + path = (s.length == 2) ? s[1] : s[0]; + + if (!map[path]) { + map[path] = new Route(path, name); + routes.push(map[path]); + } + map[path].addHandler(fn); + }; + + var routie = function(path, fn) { + if (typeof fn == 'function') { + addHandler(path, fn); + routie.reload(); + } else if (typeof path == 'object') { + for (var p in path) { + addHandler(p, path[p]); + } + routie.reload(); + } else if (typeof fn === 'undefined') { + routie.navigate(path); + } + }; + + routie.lookup = function(name, obj) { + for (var i = 0, c = routes.length; i < c; i++) { + var route = routes[i]; + if (route.name == name) { + return route.toURL(obj); + } + } + }; + + routie.remove = function(path, fn) { + var route = map[path]; + if (!route) + return; + route.removeHandler(fn); + }; + + routie.removeAll = function() { + map = {}; + routes = []; + }; + + routie.navigate = function(path, options) { + options = options || {}; + var silent = options.silent || false; + + if (silent) { + removeListener(); + } + setTimeout(function() { + window.location.hash = path; + + if (silent) { + setTimeout(function() { + addListener(); + }, 1); + } + + }, 1); + }; + + routie.noConflict = function() { + w[reference] = oldReference; + return routie; + }; + + var getHash = function() { + return window.location.hash.substring(1); + }; + + var checkRoute = function(hash, route) { + var params = []; + if (route.match(hash, params)) { + route.run(params); + return true; + } + return false; + }; + + var hashChanged = routie.reload = function() { + var hash = getHash(); + for (var i = 0, c = routes.length; i < c; i++) { + var route = routes[i]; + if (checkRoute(hash, route)) { + return; + } + } + }; + + var addListener = function() { + if (w.addEventListener) { + w.addEventListener('hashchange', hashChanged, false); + } else { + w.attachEvent('onhashchange', hashChanged); + } + }; + + var removeListener = function() { + if (w.removeEventListener) { + w.removeEventListener('hashchange', hashChanged); + } else { + w.detachEvent('onhashchange', hashChanged); + } + }; + addListener(); + + if (isModule){ + return routie; + } else { + w[reference] = routie; + } + +}; + +if (typeof module == 'undefined'){ + Routie(window); +} else { + module.exports = Routie(window,true); +} \ No newline at end of file diff --git a/app/static/script/transparency.js b/app/static/script/transparency.js new file mode 100644 index 00000000..a727a5c3 --- /dev/null +++ b/app/static/script/transparency.js @@ -0,0 +1,867 @@ +(function e(t, n, r) { + function s(o, u) { + if (!n[o]) { + if (!t[o]) { + var a = typeof require == "function" && require; + if (!u && a) return a(o, !0); + if (i) return i(o, !0); + var f = new Error("Cannot find module '" + o + "'"); + throw f.code = "MODULE_NOT_FOUND", f + } + var l = n[o] = { + exports: {} + }; + t[o][0].call(l.exports, function (e) { + var n = t[o][1][e]; + return s(n ? n : e) + }, l, l.exports, e, t, n, r) + } + return n[o].exports + } + var i = typeof require == "function" && require; + for (var o = 0; o < r.length; o++) s(r[o]); + return s +})({ + 1: [function (require, module, exports) { + var $, Context, Transparency, _, helpers, + indexOf = [].indexOf || function (item) { + for (var i = 0, l = this.length; i < l; i++) { + if (i in this && this[i] === item) return i; + } + return -1; + }; + + _ = require('../lib/lodash.js'); + + helpers = require('./helpers'); + + Context = require('./context'); + + Transparency = {}; + + Transparency.render = function (context, models, directives, options) { + var base, log; + if (models == null) { + models = []; + } + if (directives == null) { + directives = {}; + } + if (options == null) { + options = {}; + } + log = options.debug && console ? helpers.consoleLogger : helpers.nullLogger; + log("Transparency.render:", context, models, directives, options); + if (!context) { + return; + } + if (!_.isArray(models)) { + models = [models]; + } + context = (base = helpers.data(context)).context || (base.context = new Context(context, Transparency)); + return context.render(models, directives, options).el; + }; + + Transparency.matcher = function (element, key) { + return element.el.id === key || indexOf.call(element.classNames, key) >= 0 || element.el.name === key || element.el.getAttribute('data-bind') === key; + }; + + Transparency.clone = function (node) { + return $(node).clone()[0]; + }; + + Transparency.jQueryPlugin = helpers.chainable(function (models, directives, options) { + var context, i, len, results; + results = []; + for (i = 0, len = this.length; i < len; i++) { + context = this[i]; + results.push(Transparency.render(context, models, directives, options)); + } + return results; + }); + + if ((typeof jQuery !== "undefined" && jQuery !== null) || (typeof Zepto !== "undefined" && Zepto !== null)) { + $ = jQuery || Zepto; + if ($ != null) { + $.fn.render = Transparency.jQueryPlugin; + } + } + + if (typeof module !== "undefined" && module !== null ? module.exports : void 0) { + module.exports = Transparency; + } + + if (typeof window !== "undefined" && window !== null) { + window.Transparency = Transparency; + } + + if (typeof define !== "undefined" && define !== null ? define.amd : void 0) { + define(function () { + return Transparency; + }); + } + + }, { + "../lib/lodash.js": 7, + "./context": 3, + "./helpers": 5 + }], + 2: [function (require, module, exports) { + var Attribute, AttributeFactory, BooleanAttribute, Class, Html, Text, _, helpers, + extend = function (child, parent) { + for (var key in parent) { + if (hasProp.call(parent, key)) child[key] = parent[key]; + } + + function ctor() { + this.constructor = child; + } + ctor.prototype = parent.prototype; + child.prototype = new ctor(); + child.__super__ = parent.prototype; + return child; + }, + hasProp = {}.hasOwnProperty; + + _ = require('../lib/lodash'); + + helpers = require('./helpers'); + + module.exports = AttributeFactory = { + Attributes: {}, + createAttribute: function (element, name) { + var Attr; + Attr = AttributeFactory.Attributes[name] || Attribute; + return new Attr(element, name); + } + }; + + Attribute = (function () { + function Attribute(el1, name1) { + this.el = el1; + this.name = name1; + this.templateValue = this.el.getAttribute(this.name) || ''; + } + + Attribute.prototype.set = function (value) { + this.el[this.name] = value; + return this.el.setAttribute(this.name, value.toString()); + }; + + return Attribute; + + })(); + + BooleanAttribute = (function (superClass) { + var BOOLEAN_ATTRIBUTES, i, len, name; + + extend(BooleanAttribute, superClass); + + BOOLEAN_ATTRIBUTES = ['hidden', 'async', 'defer', 'autofocus', 'formnovalidate', 'disabled', 'autofocus', 'formnovalidate', 'multiple', 'readonly', 'required', 'checked', 'scoped', 'reversed', 'selected', 'loop', 'muted', 'autoplay', 'controls', 'seamless', 'default', 'ismap', 'novalidate', 'open', 'typemustmatch', 'truespeed']; + + for (i = 0, len = BOOLEAN_ATTRIBUTES.length; i < len; i++) { + name = BOOLEAN_ATTRIBUTES[i]; + AttributeFactory.Attributes[name] = BooleanAttribute; + } + + function BooleanAttribute(el1, name1) { + this.el = el1; + this.name = name1; + this.templateValue = this.el.getAttribute(this.name) || false; + } + + BooleanAttribute.prototype.set = function (value) { + this.el[this.name] = value; + if (value) { + return this.el.setAttribute(this.name, this.name); + } else { + return this.el.removeAttribute(this.name); + } + }; + + return BooleanAttribute; + + })(Attribute); + + Text = (function (superClass) { + extend(Text, superClass); + + AttributeFactory.Attributes['text'] = Text; + + function Text(el1, name1) { + var child; + this.el = el1; + this.name = name1; + this.templateValue = ((function () { + var i, len, ref, results; + ref = this.el.childNodes; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + child = ref[i]; + if (child.nodeType === helpers.TEXT_NODE) { + results.push(child.nodeValue); + } + } + return results; + }).call(this)).join(''); + this.children = _.toArray(this.el.children); + if (!(this.textNode = this.el.firstChild)) { + this.el.appendChild(this.textNode = this.el.ownerDocument.createTextNode('')); + } else if (this.textNode.nodeType !== helpers.TEXT_NODE) { + this.textNode = this.el.insertBefore(this.el.ownerDocument.createTextNode(''), this.textNode); + } + } + + Text.prototype.set = function (text) { + var child, i, len, ref, results; + while (child = this.el.firstChild) { + this.el.removeChild(child); + } + this.textNode.nodeValue = text; + this.el.appendChild(this.textNode); + ref = this.children; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + child = ref[i]; + results.push(this.el.appendChild(child)); + } + return results; + }; + + return Text; + + })(Attribute); + + Html = (function (superClass) { + extend(Html, superClass); + + AttributeFactory.Attributes['html'] = Html; + + function Html(el1) { + this.el = el1; + this.templateValue = ''; + this.children = _.toArray(this.el.children); + } + + Html.prototype.set = function (html) { + var child, i, len, ref, results; + while (child = this.el.firstChild) { + this.el.removeChild(child); + } + this.el.innerHTML = html + this.templateValue; + ref = this.children; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + child = ref[i]; + results.push(this.el.appendChild(child)); + } + return results; + }; + + return Html; + + })(Attribute); + + Class = (function (superClass) { + extend(Class, superClass); + + AttributeFactory.Attributes['class'] = Class; + + function Class(el) { + Class.__super__.constructor.call(this, el, 'class'); + } + + return Class; + + })(Attribute); + + }, { + "../lib/lodash": 7, + "./helpers": 5 + }], + 3: [function (require, module, exports) { + var Context, Instance, after, before, chainable, cloneNode, ref; + + ref = require('./helpers'), before = ref.before, after = ref.after, chainable = ref.chainable, cloneNode = ref.cloneNode; + + Instance = require('./instance'); + + module.exports = Context = (function () { + var attach, detach; + + detach = chainable(function () { + this.parent = this.el.parentNode; + if (this.parent) { + this.nextSibling = this.el.nextSibling; + return this.parent.removeChild(this.el); + } + }); + + attach = chainable(function () { + if (this.parent) { + if (this.nextSibling) { + return this.parent.insertBefore(this.el, this.nextSibling); + } else { + return this.parent.appendChild(this.el); + } + } + }); + + function Context(el, Transparency) { + this.el = el; + this.Transparency = Transparency; + this.template = cloneNode(this.el); + this.instances = [new Instance(this.el, this.Transparency)]; + this.instanceCache = []; + } + + Context.prototype.render = before(detach)(after(attach)(chainable(function (models, directives, options) { + var children, i, index, instance, len, model, results; + while (models.length < this.instances.length) { + this.instanceCache.push(this.instances.pop().remove()); + } + while (models.length > this.instances.length) { + instance = this.instanceCache.pop() || new Instance(cloneNode(this.template), this.Transparency); + this.instances.push(instance.appendTo(this.el)); + } + results = []; + for (index = i = 0, len = models.length; i < len; index = ++i) { + model = models[index]; + instance = this.instances[index]; + children = []; + results.push(instance.prepare(model, children).renderValues(model, children).renderDirectives(model, index, directives).renderChildren(model, children, directives, options)); + } + return results; + }))); + + return Context; + + })(); + + }, { + "./helpers": 5, + "./instance": 6 + }], + 4: [function (require, module, exports) { + var AttributeFactory, Checkbox, Element, ElementFactory, Input, Radio, Select, TextArea, VoidElement, _, helpers, + hasProp = {}.hasOwnProperty, + extend = function (child, parent) { + for (var key in parent) { + if (hasProp.call(parent, key)) child[key] = parent[key]; + } + + function ctor() { + this.constructor = child; + } + ctor.prototype = parent.prototype; + child.prototype = new ctor(); + child.__super__ = parent.prototype; + return child; + }; + + _ = require('../lib/lodash.js'); + + helpers = require('./helpers'); + + AttributeFactory = require('./attributeFactory'); + + module.exports = ElementFactory = { + Elements: { + input: {} + }, + createElement: function (el) { + var El, name; + if ('input' === (name = el.nodeName.toLowerCase())) { + El = ElementFactory.Elements[name][el.type.toLowerCase()] || Input; + } else { + El = ElementFactory.Elements[name] || Element; + } + return new El(el); + } + }; + + Element = (function () { + function Element(el1) { + this.el = el1; + this.attributes = {}; + this.childNodes = _.toArray(this.el.childNodes); + this.nodeName = this.el.nodeName.toLowerCase(); + this.classNames = this.el.className.split(' '); + this.originalAttributes = {}; + } + + Element.prototype.empty = function () { + var child; + while (child = this.el.firstChild) { + this.el.removeChild(child); + } + return this; + }; + + Element.prototype.reset = function () { + var attribute, name, ref, results; + ref = this.attributes; + results = []; + for (name in ref) { + attribute = ref[name]; + results.push(attribute.set(attribute.templateValue)); + } + return results; + }; + + Element.prototype.render = function (value) { + return this.attr('text', value); + }; + + Element.prototype.attr = function (name, value) { + var attribute, base; + attribute = (base = this.attributes)[name] || (base[name] = AttributeFactory.createAttribute(this.el, name, value)); + if (value != null) { + attribute.set(value); + } + return attribute; + }; + + Element.prototype.renderDirectives = function (model, index, attributes) { + var directive, name, results, value; + results = []; + for (name in attributes) { + if (!hasProp.call(attributes, name)) continue; + directive = attributes[name]; + if (!(typeof directive === 'function')) { + continue; + } + value = directive.call(model, { + element: this.el, + index: index, + value: this.attr(name).templateValue + }); + if (value != null) { + results.push(this.attr(name, value)); + } else { + results.push(void 0); + } + } + return results; + }; + + return Element; + + })(); + + Select = (function (superClass) { + extend(Select, superClass); + + ElementFactory.Elements['select'] = Select; + + function Select(el) { + Select.__super__.constructor.call(this, el); + this.elements = helpers.getElements(el); + } + + Select.prototype.render = function (value) { + var i, len, option, ref, results; + value = value.toString(); + ref = this.elements; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + option = ref[i]; + if (option.nodeName === 'option') { + results.push(option.attr('selected', option.el.value === value)); + } + } + return results; + }; + + return Select; + + })(Element); + + VoidElement = (function (superClass) { + var VOID_ELEMENTS, i, len, nodeName; + + extend(VoidElement, superClass); + + function VoidElement() { + return VoidElement.__super__.constructor.apply(this, arguments); + } + + VOID_ELEMENTS = ['area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr']; + + for (i = 0, len = VOID_ELEMENTS.length; i < len; i++) { + nodeName = VOID_ELEMENTS[i]; + ElementFactory.Elements[nodeName] = VoidElement; + } + + VoidElement.prototype.attr = function (name, value) { + if (name !== 'text' && name !== 'html') { + return VoidElement.__super__.attr.call(this, name, value); + } + }; + + return VoidElement; + + })(Element); + + Input = (function (superClass) { + extend(Input, superClass); + + function Input() { + return Input.__super__.constructor.apply(this, arguments); + } + + Input.prototype.render = function (value) { + return this.attr('value', value); + }; + + return Input; + + })(VoidElement); + + TextArea = (function (superClass) { + extend(TextArea, superClass); + + function TextArea() { + return TextArea.__super__.constructor.apply(this, arguments); + } + + ElementFactory.Elements['textarea'] = TextArea; + + return TextArea; + + })(Input); + + Checkbox = (function (superClass) { + extend(Checkbox, superClass); + + function Checkbox() { + return Checkbox.__super__.constructor.apply(this, arguments); + } + + ElementFactory.Elements['input']['checkbox'] = Checkbox; + + Checkbox.prototype.render = function (value) { + return this.attr('checked', Boolean(value)); + }; + + return Checkbox; + + })(Input); + + Radio = (function (superClass) { + extend(Radio, superClass); + + function Radio() { + return Radio.__super__.constructor.apply(this, arguments); + } + + ElementFactory.Elements['input']['radio'] = Radio; + + return Radio; + + })(Checkbox); + + }, { + "../lib/lodash.js": 7, + "./attributeFactory": 2, + "./helpers": 5 + }], + 5: [function (require, module, exports) { + var ElementFactory, _getElements, expando, html5Clone; + + ElementFactory = require('./elementFactory'); + + exports.before = function (decorator) { + return function (method) { + return function () { + decorator.apply(this, arguments); + return method.apply(this, arguments); + }; + }; + }; + + exports.after = function (decorator) { + return function (method) { + return function () { + method.apply(this, arguments); + return decorator.apply(this, arguments); + }; + }; + }; + + exports.chainable = exports.after(function () { + return this; + }); + + exports.onlyWith$ = function (fn) { + if ((typeof jQuery !== "undefined" && jQuery !== null) || (typeof Zepto !== "undefined" && Zepto !== null)) { + return (function ($) { + return fn(arguments); + })(jQuery || Zepto); + } + }; + + exports.getElements = function (el) { + var elements; + elements = []; + _getElements(el, elements); + return elements; + }; + + _getElements = function (template, elements) { + var child, results; + child = template.firstChild; + results = []; + while (child) { + if (child.nodeType === exports.ELEMENT_NODE) { + elements.push(new ElementFactory.createElement(child)); + _getElements(child, elements); + } + results.push(child = child.nextSibling); + } + return results; + }; + + exports.ELEMENT_NODE = 1; + + exports.TEXT_NODE = 3; + + html5Clone = function () { + return document.createElement('nav').cloneNode(true).outerHTML !== '<:nav>'; + }; + + exports.cloneNode = (typeof document === "undefined" || document === null) || html5Clone() ? function (node) { + return node.cloneNode(true); + } : function (node) { + var cloned, element, i, len, ref; + cloned = Transparency.clone(node); + if (cloned.nodeType === exports.ELEMENT_NODE) { + cloned.removeAttribute(expando); + ref = cloned.getElementsByTagName('*'); + for (i = 0, len = ref.length; i < len; i++) { + element = ref[i]; + element.removeAttribute(expando); + } + } + return cloned; + }; + + expando = 'transparency'; + + exports.data = function (element) { + return element[expando] || (element[expando] = {}); + }; + + exports.nullLogger = function () {}; + + exports.consoleLogger = function () { + return console.log(arguments); + }; + + exports.log = exports.nullLogger; + + }, { + "./elementFactory": 4 + }], + 6: [function (require, module, exports) { + var Instance, _, chainable, helpers, + hasProp = {}.hasOwnProperty; + + _ = require('../lib/lodash.js'); + + chainable = (helpers = require('./helpers')).chainable; + + module.exports = Instance = (function () { + function Instance(template, Transparency) { + this.Transparency = Transparency; + this.queryCache = {}; + this.childNodes = _.toArray(template.childNodes); + this.elements = helpers.getElements(template); + } + + Instance.prototype.remove = chainable(function () { + var i, len, node, ref, results; + ref = this.childNodes; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + node = ref[i]; + results.push(node.parentNode.removeChild(node)); + } + return results; + }); + + Instance.prototype.appendTo = chainable(function (parent) { + var i, len, node, ref, results; + ref = this.childNodes; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + node = ref[i]; + results.push(parent.appendChild(node)); + } + return results; + }); + + Instance.prototype.prepare = chainable(function (model) { + var element, i, len, ref, results; + ref = this.elements; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + element = ref[i]; + element.reset(); + results.push(helpers.data(element.el).model = model); + } + return results; + }); + + Instance.prototype.renderValues = chainable(function (model, children) { + var element, key, results, value; + if (_.isElement(model) && (element = this.elements[0])) { + return element.empty().el.appendChild(model); + } else if (typeof model === 'object') { + results = []; + for (key in model) { + if (!hasProp.call(model, key)) continue; + value = model[key]; + if (value != null) { + if (_.isString(value) || _.isNumber(value) || _.isBoolean(value) || _.isDate(value)) { + results.push((function () { + var i, len, ref, results1; + ref = this.matchingElements(key); + results1 = []; + for (i = 0, len = ref.length; i < len; i++) { + element = ref[i]; + results1.push(element.render(value)); + } + return results1; + }).call(this)); + } else if (typeof value === 'object') { + results.push(children.push(key)); + } else { + results.push(void 0); + } + } + } + return results; + } + }); + + Instance.prototype.renderDirectives = chainable(function (model, index, directives) { + var attributes, element, key, results; + results = []; + for (key in directives) { + if (!hasProp.call(directives, key)) continue; + attributes = directives[key]; + if (!(typeof attributes === 'object')) { + continue; + } + if (typeof model !== 'object') { + model = { + value: model + }; + } + results.push((function () { + var i, len, ref, results1; + ref = this.matchingElements(key); + results1 = []; + for (i = 0, len = ref.length; i < len; i++) { + element = ref[i]; + results1.push(element.renderDirectives(model, index, attributes)); + } + return results1; + }).call(this)); + } + return results; + }); + + Instance.prototype.renderChildren = chainable(function (model, children, directives, options) { + var element, i, key, len, results; + results = []; + for (i = 0, len = children.length; i < len; i++) { + key = children[i]; + results.push((function () { + var j, len1, ref, results1; + ref = this.matchingElements(key); + results1 = []; + for (j = 0, len1 = ref.length; j < len1; j++) { + element = ref[j]; + results1.push(this.Transparency.render(element.el, model[key], directives[key], options)); + } + return results1; + }).call(this)); + } + return results; + }); + + Instance.prototype.matchingElements = function (key) { + var base, el, elements; + elements = (base = this.queryCache)[key] || (base[key] = (function () { + var i, len, ref, results; + ref = this.elements; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + el = ref[i]; + if (this.Transparency.matcher(el, key)) { + results.push(el); + } + } + return results; + }).call(this)); + helpers.log("Matching elements for '" + key + "':", elements); + return elements; + }; + + return Instance; + + })(); + + }, { + "../lib/lodash.js": 7, + "./helpers": 5 + }], + 7: [function (require, module, exports) { + var _ = {}; + + _.toString = Object.prototype.toString; + + _.toArray = function (obj) { + var arr = new Array(obj.length); + for (var i = 0; i < obj.length; i++) { + arr[i] = obj[i]; + } + return arr; + }; + + _.isString = function (obj) { + return _.toString.call(obj) == '[object String]'; + }; + + _.isNumber = function (obj) { + return _.toString.call(obj) == '[object Number]'; + }; + + _.isArray = Array.isArray || function (obj) { + return _.toString.call(obj) === '[object Array]'; + }; + + _.isDate = function (obj) { + return _.toString.call(obj) === '[object Date]'; + }; + + _.isElement = function (obj) { + return !!(obj && obj.nodeType === 1); + }; + + _.isPlainValue = function (obj) { + var type; + type = typeof obj; + return (type !== 'object' && type !== 'function') || exports.isDate(obj); + }; + + _.isBoolean = function (obj) { + return obj === true || obj === false; + }; + + module.exports = _; + + }, {}] +}, {}, [1]); \ No newline at end of file diff --git a/app/static/style/style.css b/app/static/style/style.css new file mode 100644 index 00000000..3d6e4d06 --- /dev/null +++ b/app/static/style/style.css @@ -0,0 +1,264 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: 'Roboto', sans-serif; +} + +:root { + --material-shaduw-1: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); + --material-shaduw-4: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22); + --matrail-transition: all 0.3s cubic-bezier(.25, .8, .25, 1); +} + +body { + background-color: rgba(2, 9, 60, 0.73); +} + +ul { + list-style-type: none; +} + +nav { + display: flex; + flex-direction: column; +} + +nav ul { + display: flex; +} + +nav ul li { + display: flex; + width: 100%; +} + +nav ul li a { + text-decoration: none; + color: white; + padding: 0.5rem; + width: 100%; + min-width: 200px; + font-size: 1.4rem; + text-align: center; + transition: all 0.4s; +} + +nav ul li a:hover { + transform: scale(1.2); +} + +section { + display: none; + padding: 2rem; +} + +.crypto { + display: flex; + justify-content: center; +} + +section div { + padding-top: 0.4rem; + padding-bottom: 0.4rem; + max-width: 100%; + display: flex; + flex-wrap: wrap; + justify-content: space-evenly; +} + +section div a { + display: grid; + grid-template-columns: 40% 1fr; + box-shadow: var(--material-shaduw-1); + transition: var(--matrail-transition); + margin-bottom: 1rem; + text-decoration: none; + color: white; + padding: 1.4rem 1rem; + overflow: hidden; + position: relative; + width: 100%; +} + +@media (min-width: 50em){ + section div a{ + overflow: hidden; + width: 27em; + } +} + +section div a:nth-child(even) { + background-color: rgba(0, 0, 0, 0.24); +} + +section div a:nth-child(odd) { + background-color: rgba(0, 0, 0, 0.34); +} + +@media (min-width:50em){ + section div a:hover, section div a:focus { + box-shadow: var(--material-shaduw-4); + transform: scale(1.04); + outline: none; +} +} + +section div a img{ + height: 4em; +} + +section div span { + font-size: 1.8em; + display: flex; + justify-content: center; + align-items: center; +} +@media (min-width: 50em){ + section div span{ + font-size: 150%; + } +} + + +.info{ + display: inline-flex; + width: 100%; + flex-wrap: wrap; + padding-left: 1rem; + animation: slide-in-from-bottom 2s; +} + +.info p:first-of-type{ + justify-content: center; + font-size: 4vw; + width: 100%; + margin-bottom: 1rem; + padding: 0.4rem; +} + + +.info p{ + display: inline-flex; + flex-direction: column; + font-size: 2.7vw; +} + +@media (min-width: 50em){ + .info p{ + font-size: 100%; + } +} + +.info p:last-of-type{ + margin-left: auto; +} + +.rank { + font-weight: bold; + font-size: 30vw; + color:rgba(0, 0, 0, 0.06); + position: absolute; + justify-self: center; + top:0; + bottom:0; +} +@media(min-width:50em){ + .rank{ + font-size: 14em; + } +} + +.container-name{ + display: flex; + flex-wrap: wrap; + justify-content: center; + align-items: center; + height: 100%; + animation: slide-in-from-bottom 2s; +} + +.container-name p{ + width: 100%; + margin-top: auto; +} + +.name{ + display: flex; + justify-content: center; + text-align: center; + padding: 0 0.4em; + font-size: 140%; +} + +.extra-info{ + font-size: 100%; + opacity: 0.4; + margin-top: 0.4rem; +} +@media (min-width: 50em){ + .extra-info.info-price{ + font-size: 20%; + } +} + +.price { + color: #FFA726; +} +@media (min-width: 50em){ + .price{ + font-size: 0.8em; + } +} +@media (min-width: 70em){ + .price{ + font-size: 0.4em; + } +} + +.change::after { + content: "%"; +} + +.change.plus{ + color: #00E676; +} + +.change.minus{ + color: #E53935; +} + +.change.neutral{ + color: grey; +} + +.price::before { + content: "$"; +} + +.active { + display: block; +} + +@keyframes slide-in-from-bottom{ + from{ + transform: translateY(10em); + opacity: 0; + } + + to{ + transform: translateY(0); + opacity: 1; + } +} + +.detail-container{ + position: fixed; + top: 0; + left: 0; + height: 100vh; + width: 100vw; + justify-content: center; + align-items: center; + background-color: grey; +} diff --git a/cmd-geo-script/script.js b/cmd-geo-script/script.js index e69de29b..41ad1234 100644 --- a/cmd-geo-script/script.js +++ b/cmd-geo-script/script.js @@ -0,0 +1,53 @@ +(function () { + + var app = { + init: function () { + position.set(); + } + } + + var position = { + set: function () { + helper.isNumber('1'); + }, + update: function () { + + }, + check: function () { + var el = document.body; + var self = this; + this.set(); + + el.addEventListener('touchart', function(){ + this.update(); + }) + + }, + getDistance: function () { + + } + } + + var googleMap = { + generate: function () { + + }, + update: function () { + + } + } + + var helper = { + isNumber = function () { + + }, + getElement: function (element) { + return document.querySelector(element); + } + } + + var $ = helper.getElement(); + + app.init(); + +})() \ No newline at end of file diff --git a/readme-assets/change-in-color.PNG b/readme-assets/change-in-color.PNG new file mode 100644 index 00000000..bdeb374a Binary files /dev/null and b/readme-assets/change-in-color.PNG differ diff --git a/readme-assets/district0x.gif b/readme-assets/district0x.gif new file mode 100644 index 00000000..7812419d Binary files /dev/null and b/readme-assets/district0x.gif differ diff --git a/readme-assets/kollergorna.gif b/readme-assets/kollergorna.gif new file mode 100644 index 00000000..415faab3 Binary files /dev/null and b/readme-assets/kollergorna.gif differ diff --git a/readme-assets/mobile-version-1.PNG b/readme-assets/mobile-version-1.PNG new file mode 100644 index 00000000..ac50be71 Binary files /dev/null and b/readme-assets/mobile-version-1.PNG differ